aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/libs
diff options
context:
space:
mode:
authorMaxim Yurchuk <maxim-yurchuk@ydb.tech>2024-10-18 20:31:38 +0300
committerGitHub <noreply@github.com>2024-10-18 20:31:38 +0300
commit2a74bac2d2d3bccb4e10120f1ead805640ec9dd0 (patch)
tree047e4818ced5aaf73f58517629e5260b5291f9f0 /contrib/libs
parent2d9656823e9521d8c29ea4c9a1d0eab78391abfc (diff)
parent3d834a1923bbf9403cd4a448e7f32b670aa4124f (diff)
downloadydb-2a74bac2d2d3bccb4e10120f1ead805640ec9dd0.tar.gz
Merge pull request #10502 from ydb-platform/mergelibs-241016-1210
Library import 241016-1210
Diffstat (limited to 'contrib/libs')
-rw-r--r--contrib/libs/croaring/.yandex_meta/override.nix4
-rw-r--r--contrib/libs/croaring/cpp/roaring.hh234
-rw-r--r--contrib/libs/croaring/cpp/roaring64map.hh31
-rw-r--r--contrib/libs/croaring/include/roaring/bitset/bitset.h5
-rw-r--r--contrib/libs/croaring/include/roaring/roaring.h40
-rw-r--r--contrib/libs/croaring/include/roaring/roaring_version.h6
-rw-r--r--contrib/libs/croaring/src/bitset.c11
-rw-r--r--contrib/libs/croaring/src/roaring.c81
-rw-r--r--contrib/libs/croaring/ya.make4
-rw-r--r--contrib/libs/curl/.yandex_meta/__init__.py13
-rw-r--r--contrib/libs/curl/.yandex_meta/devtools.copyrights.report79
-rw-r--r--contrib/libs/curl/.yandex_meta/devtools.licenses.report159
-rw-r--r--contrib/libs/curl/.yandex_meta/licenses.list.txt41
-rw-r--r--contrib/libs/curl/.yandex_meta/override.nix5
-rw-r--r--contrib/libs/curl/CHANGES.md12
-rw-r--r--contrib/libs/curl/COPYING2
-rw-r--r--contrib/libs/curl/RELEASE-NOTES463
-rw-r--r--contrib/libs/curl/bin/.yandex_meta/licenses.list.txt77
-rw-r--r--contrib/libs/curl/bin/ya.make5
-rw-r--r--contrib/libs/curl/include/README.md2
-rw-r--r--contrib/libs/curl/include/curl/curl.h233
-rw-r--r--contrib/libs/curl/include/curl/curlver.h12
-rw-r--r--contrib/libs/curl/include/curl/easy.h2
-rw-r--r--contrib/libs/curl/include/curl/mprintf.h27
-rw-r--r--contrib/libs/curl/include/curl/multi.h30
-rw-r--r--contrib/libs/curl/include/curl/system.h18
-rw-r--r--contrib/libs/curl/include/curl/typecheck-gcc.h11
-rw-r--r--contrib/libs/curl/include/curl/urlapi.h9
-rw-r--r--contrib/libs/curl/lib/altsvc.c105
-rw-r--r--contrib/libs/curl/lib/altsvc.h4
-rw-r--r--contrib/libs/curl/lib/amigaos.c2
-rw-r--r--contrib/libs/curl/lib/arpa_telnet.h2
-rw-r--r--contrib/libs/curl/lib/asyn-ares.c254
-rw-r--r--contrib/libs/curl/lib/asyn-thread.c87
-rw-r--r--contrib/libs/curl/lib/asyn.h16
-rw-r--r--contrib/libs/curl/lib/base64.c2
-rw-r--r--contrib/libs/curl/lib/bufq.c92
-rw-r--r--contrib/libs/curl/lib/bufq.h15
-rw-r--r--contrib/libs/curl/lib/bufref.c8
-rw-r--r--contrib/libs/curl/lib/c-hyper.c645
-rw-r--r--contrib/libs/curl/lib/c-hyper.h8
-rw-r--r--contrib/libs/curl/lib/cf-h1-proxy.c169
-rw-r--r--contrib/libs/curl/lib/cf-h2-proxy.c291
-rw-r--r--contrib/libs/curl/lib/cf-haproxy.c42
-rw-r--r--contrib/libs/curl/lib/cf-https-connect.c104
-rw-r--r--contrib/libs/curl/lib/cf-socket.c855
-rw-r--r--contrib/libs/curl/lib/cf-socket.h35
-rw-r--r--contrib/libs/curl/lib/cfilters.c278
-rw-r--r--contrib/libs/curl/lib/cfilters.h126
-rw-r--r--contrib/libs/curl/lib/conncache.c1442
-rw-r--r--contrib/libs/curl/lib/conncache.h241
-rw-r--r--contrib/libs/curl/lib/connect.c326
-rw-r--r--contrib/libs/curl/lib/connect.h28
-rw-r--r--contrib/libs/curl/lib/content_encoding.c154
-rw-r--r--contrib/libs/curl/lib/cookie.c132
-rw-r--r--contrib/libs/curl/lib/cookie.h2
-rw-r--r--contrib/libs/curl/lib/curl_addrinfo.c38
-rw-r--r--contrib/libs/curl/lib/curl_addrinfo.h6
-rw-r--r--contrib/libs/curl/lib/curl_config-linux.h112
-rw-r--r--contrib/libs/curl/lib/curl_des.c10
-rw-r--r--contrib/libs/curl/lib/curl_des.h8
-rw-r--r--contrib/libs/curl/lib/curl_endian.c6
-rw-r--r--contrib/libs/curl/lib/curl_fnmatch.c2
-rw-r--r--contrib/libs/curl/lib/curl_fnmatch.h2
-rw-r--r--contrib/libs/curl/lib/curl_get_line.c55
-rw-r--r--contrib/libs/curl/lib/curl_get_line.h7
-rw-r--r--contrib/libs/curl/lib/curl_gethostname.c25
-rw-r--r--contrib/libs/curl/lib/curl_memrchr.c4
-rw-r--r--contrib/libs/curl/lib/curl_memrchr.h4
-rw-r--r--contrib/libs/curl/lib/curl_multibyte.c17
-rw-r--r--contrib/libs/curl/lib/curl_multibyte.h13
-rw-r--r--contrib/libs/curl/lib/curl_ntlm_core.c62
-rw-r--r--contrib/libs/curl/lib/curl_ntlm_core.h7
-rw-r--r--contrib/libs/curl/lib/curl_ntlm_wb.c500
-rw-r--r--contrib/libs/curl/lib/curl_ntlm_wb.h (renamed from contrib/libs/curl/lib/cw-out.h)36
-rw-r--r--contrib/libs/curl/lib/curl_path.c68
-rw-r--r--contrib/libs/curl/lib/curl_printf.h9
-rw-r--r--contrib/libs/curl/lib/curl_range.c15
-rw-r--r--contrib/libs/curl/lib/curl_rtmp.c59
-rw-r--r--contrib/libs/curl/lib/curl_rtmp.h2
-rw-r--r--contrib/libs/curl/lib/curl_sasl.c31
-rw-r--r--contrib/libs/curl/lib/curl_setup.h248
-rw-r--r--contrib/libs/curl/lib/curl_setup_once.h22
-rw-r--r--contrib/libs/curl/lib/curl_sha256.h9
-rw-r--r--contrib/libs/curl/lib/curl_sha512_256.c857
-rw-r--r--contrib/libs/curl/lib/curl_sha512_256.h44
-rw-r--r--contrib/libs/curl/lib/curl_sspi.c28
-rw-r--r--contrib/libs/curl/lib/curl_sspi.h4
-rw-r--r--contrib/libs/curl/lib/curl_threads.c18
-rw-r--r--contrib/libs/curl/lib/curl_threads.h9
-rw-r--r--contrib/libs/curl/lib/curl_trc.c279
-rw-r--r--contrib/libs/curl/lib/curl_trc.h140
-rw-r--r--contrib/libs/curl/lib/curlx.h44
-rw-r--r--contrib/libs/curl/lib/cw-out.c474
-rw-r--r--contrib/libs/curl/lib/dict.c29
-rw-r--r--contrib/libs/curl/lib/dllmain.c81
-rw-r--r--contrib/libs/curl/lib/doh.c955
-rw-r--r--contrib/libs/curl/lib/doh.h111
-rw-r--r--contrib/libs/curl/lib/dynbuf.c11
-rw-r--r--contrib/libs/curl/lib/dynbuf.h4
-rw-r--r--contrib/libs/curl/lib/dynhds.c2
-rw-r--r--contrib/libs/curl/lib/dynhds.h36
-rw-r--r--contrib/libs/curl/lib/easy.c346
-rw-r--r--contrib/libs/curl/lib/easygetopt.c4
-rw-r--r--contrib/libs/curl/lib/easyif.h4
-rw-r--r--contrib/libs/curl/lib/easyoptions.c8
-rw-r--r--contrib/libs/curl/lib/escape.c19
-rw-r--r--contrib/libs/curl/lib/file.c211
-rw-r--r--contrib/libs/curl/lib/fileinfo.h2
-rw-r--r--contrib/libs/curl/lib/fopen.c13
-rw-r--r--contrib/libs/curl/lib/formdata.c36
-rw-r--r--contrib/libs/curl/lib/formdata.h4
-rw-r--r--contrib/libs/curl/lib/ftp.c902
-rw-r--r--contrib/libs/curl/lib/ftp.h6
-rw-r--r--contrib/libs/curl/lib/ftplistparser.c2
-rw-r--r--contrib/libs/curl/lib/getenv.c6
-rw-r--r--contrib/libs/curl/lib/getinfo.c89
-rw-r--r--contrib/libs/curl/lib/gopher.c24
-rw-r--r--contrib/libs/curl/lib/hash.c175
-rw-r--r--contrib/libs/curl/lib/hash.h37
-rw-r--r--contrib/libs/curl/lib/headers.c152
-rw-r--r--contrib/libs/curl/lib/headers.h9
-rw-r--r--contrib/libs/curl/lib/hmac.c2
-rw-r--r--contrib/libs/curl/lib/hostasyn.c11
-rw-r--r--contrib/libs/curl/lib/hostip.c215
-rw-r--r--contrib/libs/curl/lib/hostip.h68
-rw-r--r--contrib/libs/curl/lib/hostip4.c26
-rw-r--r--contrib/libs/curl/lib/hostip6.c2
-rw-r--r--contrib/libs/curl/lib/hsts.c117
-rw-r--r--contrib/libs/curl/lib/hsts.h6
-rw-r--r--contrib/libs/curl/lib/http.c3575
-rw-r--r--contrib/libs/curl/lib/http.h93
-rw-r--r--contrib/libs/curl/lib/http1.c2
-rw-r--r--contrib/libs/curl/lib/http2.c1241
-rw-r--r--contrib/libs/curl/lib/http_aws_sigv4.c290
-rw-r--r--contrib/libs/curl/lib/http_chunks.c533
-rw-r--r--contrib/libs/curl/lib/http_chunks.h77
-rw-r--r--contrib/libs/curl/lib/http_negotiate.c46
-rw-r--r--contrib/libs/curl/lib/http_ntlm.c13
-rw-r--r--contrib/libs/curl/lib/http_ntlm.h4
-rw-r--r--contrib/libs/curl/lib/http_proxy.c7
-rw-r--r--contrib/libs/curl/lib/idn.c133
-rw-r--r--contrib/libs/curl/lib/idn.h7
-rw-r--r--contrib/libs/curl/lib/if2ip.c30
-rw-r--r--contrib/libs/curl/lib/if2ip.h6
-rw-r--r--contrib/libs/curl/lib/imap.c153
-rw-r--r--contrib/libs/curl/lib/inet_ntop.c21
-rw-r--r--contrib/libs/curl/lib/inet_ntop.h7
-rw-r--r--contrib/libs/curl/lib/inet_pton.c23
-rw-r--r--contrib/libs/curl/lib/inet_pton.h3
-rw-r--r--contrib/libs/curl/lib/krb5.c153
-rw-r--r--contrib/libs/curl/lib/ldap.c61
-rw-r--r--contrib/libs/curl/lib/llist.c212
-rw-r--r--contrib/libs/curl/lib/llist.h67
-rw-r--r--contrib/libs/curl/lib/macos.c28
-rw-r--r--contrib/libs/curl/lib/md4.c158
-rw-r--r--contrib/libs/curl/lib/md5.c179
-rw-r--r--contrib/libs/curl/lib/memdebug.c51
-rw-r--r--contrib/libs/curl/lib/memdebug.h19
-rw-r--r--contrib/libs/curl/lib/mime.c364
-rw-r--r--contrib/libs/curl/lib/mime.h20
-rw-r--r--contrib/libs/curl/lib/mprintf.c1229
-rw-r--r--contrib/libs/curl/lib/mqtt.c67
-rw-r--r--contrib/libs/curl/lib/mqtt.h1
-rw-r--r--contrib/libs/curl/lib/multi.c2192
-rw-r--r--contrib/libs/curl/lib/multihandle.h88
-rw-r--r--contrib/libs/curl/lib/multiif.h84
-rw-r--r--contrib/libs/curl/lib/netrc.c18
-rw-r--r--contrib/libs/curl/lib/netrc.h2
-rw-r--r--contrib/libs/curl/lib/nonblock.c19
-rw-r--r--contrib/libs/curl/lib/noproxy.c38
-rw-r--r--contrib/libs/curl/lib/noproxy.h6
-rw-r--r--contrib/libs/curl/lib/openldap.c48
-rw-r--r--contrib/libs/curl/lib/parsedate.c14
-rw-r--r--contrib/libs/curl/lib/pingpong.c309
-rw-r--r--contrib/libs/curl/lib/pingpong.h28
-rw-r--r--contrib/libs/curl/lib/pop3.c211
-rw-r--r--contrib/libs/curl/lib/pop3.h4
-rw-r--r--contrib/libs/curl/lib/progress.c292
-rw-r--r--contrib/libs/curl/lib/progress.h11
-rw-r--r--contrib/libs/curl/lib/rand.c161
-rw-r--r--contrib/libs/curl/lib/rand.h12
-rw-r--r--contrib/libs/curl/lib/rename.c2
-rw-r--r--contrib/libs/curl/lib/request.c472
-rw-r--r--contrib/libs/curl/lib/request.h250
-rw-r--r--contrib/libs/curl/lib/rtsp.c318
-rw-r--r--contrib/libs/curl/lib/rtsp.h12
-rw-r--r--contrib/libs/curl/lib/select.c176
-rw-r--r--contrib/libs/curl/lib/select.h33
-rw-r--r--contrib/libs/curl/lib/sendf.c1583
-rw-r--r--contrib/libs/curl/lib/sendf.h272
-rw-r--r--contrib/libs/curl/lib/setopt.c410
-rw-r--r--contrib/libs/curl/lib/setopt.h7
-rw-r--r--contrib/libs/curl/lib/setup-win32.h72
-rw-r--r--contrib/libs/curl/lib/sha256.c38
-rw-r--r--contrib/libs/curl/lib/share.c27
-rw-r--r--contrib/libs/curl/lib/share.h7
-rw-r--r--contrib/libs/curl/lib/sigpipe.h19
-rw-r--r--contrib/libs/curl/lib/smb.c96
-rw-r--r--contrib/libs/curl/lib/smb.h1
-rw-r--r--contrib/libs/curl/lib/smtp.c495
-rw-r--r--contrib/libs/curl/lib/smtp.h13
-rw-r--r--contrib/libs/curl/lib/sockaddr.h2
-rw-r--r--contrib/libs/curl/lib/socketpair.c91
-rw-r--r--contrib/libs/curl/lib/socketpair.h62
-rw-r--r--contrib/libs/curl/lib/socks.c128
-rw-r--r--contrib/libs/curl/lib/socks_gssapi.c34
-rw-r--r--contrib/libs/curl/lib/socks_sspi.c191
-rw-r--r--contrib/libs/curl/lib/splay.c43
-rw-r--r--contrib/libs/curl/lib/splay.h12
-rw-r--r--contrib/libs/curl/lib/strcase.c16
-rw-r--r--contrib/libs/curl/lib/strdup.c12
-rw-r--r--contrib/libs/curl/lib/strdup.h2
-rw-r--r--contrib/libs/curl/lib/strerror.c102
-rw-r--r--contrib/libs/curl/lib/strtok.c2
-rw-r--r--contrib/libs/curl/lib/strtoofft.c37
-rw-r--r--contrib/libs/curl/lib/strtoofft.h2
-rw-r--r--contrib/libs/curl/lib/system_win32.c14
-rw-r--r--contrib/libs/curl/lib/system_win32.h2
-rw-r--r--contrib/libs/curl/lib/telnet.c157
-rw-r--r--contrib/libs/curl/lib/tftp.c97
-rw-r--r--contrib/libs/curl/lib/timediff.h4
-rw-r--r--contrib/libs/curl/lib/timeval.c16
-rw-r--r--contrib/libs/curl/lib/transfer.c1489
-rw-r--r--contrib/libs/curl/lib/transfer.h124
-rw-r--r--contrib/libs/curl/lib/url.c1725
-rw-r--r--contrib/libs/curl/lib/url.h26
-rw-r--r--contrib/libs/curl/lib/urlapi-int.h9
-rw-r--r--contrib/libs/curl/lib/urlapi.c470
-rw-r--r--contrib/libs/curl/lib/urldata.h646
-rw-r--r--contrib/libs/curl/lib/vauth/cleartext.c19
-rw-r--r--contrib/libs/curl/lib/vauth/cram.c2
-rw-r--r--contrib/libs/curl/lib/vauth/digest.c93
-rw-r--r--contrib/libs/curl/lib/vauth/digest_sspi.c72
-rw-r--r--contrib/libs/curl/lib/vauth/krb5_gssapi.c9
-rw-r--r--contrib/libs/curl/lib/vauth/krb5_sspi.c37
-rw-r--r--contrib/libs/curl/lib/vauth/ntlm.c50
-rw-r--r--contrib/libs/curl/lib/vauth/ntlm_sspi.c38
-rw-r--r--contrib/libs/curl/lib/vauth/oauth2.c6
-rw-r--r--contrib/libs/curl/lib/vauth/spnego_gssapi.c20
-rw-r--r--contrib/libs/curl/lib/vauth/spnego_sspi.c59
-rw-r--r--contrib/libs/curl/lib/vauth/vauth.c8
-rw-r--r--contrib/libs/curl/lib/vauth/vauth.h6
-rw-r--r--contrib/libs/curl/lib/version.c95
-rw-r--r--contrib/libs/curl/lib/version_win32.c16
-rw-r--r--contrib/libs/curl/lib/version_win32.h2
-rw-r--r--contrib/libs/curl/lib/vquic/curl_msh3.c194
-rw-r--r--contrib/libs/curl/lib/vquic/curl_ngtcp2.c1497
-rw-r--r--contrib/libs/curl/lib/vquic/curl_osslq.c2389
-rw-r--r--contrib/libs/curl/lib/vquic/curl_osslq.h51
-rw-r--r--contrib/libs/curl/lib/vquic/curl_quiche.c868
-rw-r--r--contrib/libs/curl/lib/vquic/vquic-tls.c347
-rw-r--r--contrib/libs/curl/lib/vquic/vquic.c152
-rw-r--r--contrib/libs/curl/lib/vquic/vquic.h6
-rw-r--r--contrib/libs/curl/lib/vquic/vquic_int.h8
-rw-r--r--contrib/libs/curl/lib/vssh/libssh.c276
-rw-r--r--contrib/libs/curl/lib/vssh/libssh2.c275
-rw-r--r--contrib/libs/curl/lib/vssh/ssh.h8
-rw-r--r--contrib/libs/curl/lib/vssh/wolfssh.c77
-rw-r--r--contrib/libs/curl/lib/vtls/bearssl.c496
-rw-r--r--contrib/libs/curl/lib/vtls/cipher_suite.c891
-rw-r--r--contrib/libs/curl/lib/vtls/gtls.c1094
-rw-r--r--contrib/libs/curl/lib/vtls/gtls.h56
-rw-r--r--contrib/libs/curl/lib/vtls/hostcheck.c2
-rw-r--r--contrib/libs/curl/lib/vtls/hostcheck.h2
-rw-r--r--contrib/libs/curl/lib/vtls/keylog.c1
-rw-r--r--contrib/libs/curl/lib/vtls/mbedtls.c838
-rw-r--r--contrib/libs/curl/lib/vtls/mbedtls_threadlock.c12
-rw-r--r--contrib/libs/curl/lib/vtls/openssl.c1906
-rw-r--r--contrib/libs/curl/lib/vtls/openssl.h63
-rw-r--r--contrib/libs/curl/lib/vtls/rustls.c753
-rw-r--r--contrib/libs/curl/lib/vtls/schannel.c536
-rw-r--r--contrib/libs/curl/lib/vtls/schannel_verify.c31
-rw-r--r--contrib/libs/curl/lib/vtls/sectransp.c1732
-rw-r--r--contrib/libs/curl/lib/vtls/vtls.c575
-rw-r--r--contrib/libs/curl/lib/vtls/vtls.h37
-rw-r--r--contrib/libs/curl/lib/vtls/vtls_int.h67
-rw-r--r--contrib/libs/curl/lib/vtls/wolfssl.c1189
-rw-r--r--contrib/libs/curl/lib/vtls/wolfssl.h19
-rw-r--r--contrib/libs/curl/lib/vtls/x509asn1.c979
-rw-r--r--contrib/libs/curl/lib/vtls/x509asn1.h80
-rw-r--r--contrib/libs/curl/lib/warnless.h14
-rw-r--r--contrib/libs/curl/lib/ws.c660
-rw-r--r--contrib/libs/curl/lib/ws.h17
-rw-r--r--contrib/libs/curl/patches/pr12562-nghttp2-segfault-fix.patch120
-rw-r--r--contrib/libs/curl/patches/pr12633-fix-mpd-streaming.patch74
-rw-r--r--contrib/libs/curl/src/terminal.c91
-rw-r--r--contrib/libs/curl/src/terminal.h30
-rw-r--r--contrib/libs/curl/src/tool_ca_embed.c1
-rw-r--r--contrib/libs/curl/src/tool_cb_dbg.c14
-rw-r--r--contrib/libs/curl/src/tool_cb_hdr.c179
-rw-r--r--contrib/libs/curl/src/tool_cb_prg.c109
-rw-r--r--contrib/libs/curl/src/tool_cb_prg.h2
-rw-r--r--contrib/libs/curl/src/tool_cb_rea.c34
-rw-r--r--contrib/libs/curl/src/tool_cb_see.c49
-rw-r--r--contrib/libs/curl/src/tool_cb_see.h12
-rw-r--r--contrib/libs/curl/src/tool_cb_soc.c58
-rw-r--r--contrib/libs/curl/src/tool_cb_soc.h36
-rw-r--r--contrib/libs/curl/src/tool_cb_wrt.c44
-rw-r--r--contrib/libs/curl/src/tool_cfgable.c15
-rw-r--r--contrib/libs/curl/src/tool_cfgable.h32
-rw-r--r--contrib/libs/curl/src/tool_dirhie.c10
-rw-r--r--contrib/libs/curl/src/tool_doswin.c67
-rw-r--r--contrib/libs/curl/src/tool_easysrc.c4
-rw-r--r--contrib/libs/curl/src/tool_easysrc.h2
-rw-r--r--contrib/libs/curl/src/tool_filetime.c14
-rw-r--r--contrib/libs/curl/src/tool_findfile.c17
-rw-r--r--contrib/libs/curl/src/tool_formparse.c14
-rw-r--r--contrib/libs/curl/src/tool_getparam.c3494
-rw-r--r--contrib/libs/curl/src/tool_getparam.h301
-rw-r--r--contrib/libs/curl/src/tool_getpass.c14
-rw-r--r--contrib/libs/curl/src/tool_getpass.h2
-rw-r--r--contrib/libs/curl/src/tool_help.c296
-rw-r--r--contrib/libs/curl/src/tool_help.h78
-rw-r--r--contrib/libs/curl/src/tool_helpers.c15
-rw-r--r--contrib/libs/curl/src/tool_helpers.h2
-rw-r--r--contrib/libs/curl/src/tool_hugehelp.h2
-rw-r--r--contrib/libs/curl/src/tool_ipfs.c25
-rw-r--r--contrib/libs/curl/src/tool_libinfo.c12
-rw-r--r--contrib/libs/curl/src/tool_libinfo.h3
-rw-r--r--contrib/libs/curl/src/tool_listhelp.c352
-rw-r--r--contrib/libs/curl/src/tool_main.c14
-rw-r--r--contrib/libs/curl/src/tool_msgs.c15
-rw-r--r--contrib/libs/curl/src/tool_msgs.h12
-rw-r--r--contrib/libs/curl/src/tool_operate.c942
-rw-r--r--contrib/libs/curl/src/tool_operate.h21
-rw-r--r--contrib/libs/curl/src/tool_operhlp.c46
-rw-r--r--contrib/libs/curl/src/tool_operhlp.h3
-rw-r--r--contrib/libs/curl/src/tool_paramhlp.c91
-rw-r--r--contrib/libs/curl/src/tool_paramhlp.h6
-rw-r--r--contrib/libs/curl/src/tool_parsecfg.c32
-rw-r--r--contrib/libs/curl/src/tool_progress.c8
-rw-r--r--contrib/libs/curl/src/tool_sdecls.h18
-rw-r--r--contrib/libs/curl/src/tool_setopt.c75
-rw-r--r--contrib/libs/curl/src/tool_setopt.h10
-rw-r--r--contrib/libs/curl/src/tool_setup.h13
-rw-r--r--contrib/libs/curl/src/tool_sleep.c2
-rw-r--r--contrib/libs/curl/src/tool_urlglob.c10
-rw-r--r--contrib/libs/curl/src/tool_util.c33
-rw-r--r--contrib/libs/curl/src/tool_version.h2
-rw-r--r--contrib/libs/curl/src/tool_vms.c15
-rw-r--r--contrib/libs/curl/src/tool_writeout.c156
-rw-r--r--contrib/libs/curl/src/tool_writeout.h5
-rw-r--r--contrib/libs/curl/src/tool_writeout_json.c12
-rw-r--r--contrib/libs/curl/src/tool_writeout_json.h1
-rw-r--r--contrib/libs/curl/src/tool_xattr.c8
-rw-r--r--contrib/libs/curl/src/var.c55
-rw-r--r--contrib/libs/curl/src/var.h2
-rw-r--r--contrib/libs/curl/ya.make12
-rw-r--r--contrib/libs/cxxsupp/builtins/.yandex_meta/build.ym96
-rw-r--r--contrib/libs/cxxsupp/builtins/.yandex_meta/devtools.copyrights.report20
-rw-r--r--contrib/libs/cxxsupp/builtins/.yandex_meta/devtools.licenses.report2136
-rw-r--r--contrib/libs/cxxsupp/builtins/.yandex_meta/licenses.list.txt339
-rw-r--r--contrib/libs/cxxsupp/builtins/CMakeLists.txt786
-rw-r--r--contrib/libs/cxxsupp/builtins/CODE_OWNERS.TXT61
-rw-r--r--contrib/libs/cxxsupp/builtins/CREDITS.TXT36
-rw-r--r--contrib/libs/cxxsupp/builtins/Darwin-excludes/10.4-x86_64.txt35
-rw-r--r--contrib/libs/cxxsupp/builtins/Darwin-excludes/10.4.txt96
-rw-r--r--contrib/libs/cxxsupp/builtins/Darwin-excludes/osx-i386.txt47
-rw-r--r--contrib/libs/cxxsupp/builtins/Darwin-excludes/osx-x86_64.txt12
-rw-r--r--contrib/libs/cxxsupp/builtins/Darwin-excludes/osx.txt6
-rw-r--r--contrib/libs/cxxsupp/builtins/LICENSE.TXT (renamed from contrib/libs/cxxsupp/builtins/LICENSE.os_version_check.c.patch.txt)0
-rw-r--r--contrib/libs/cxxsupp/builtins/LICENSE.os_version_check.c.txt91
-rw-r--r--contrib/libs/cxxsupp/builtins/LICENSE.txt91
-rw-r--r--contrib/libs/cxxsupp/builtins/README.txt64
-rw-r--r--contrib/libs/cxxsupp/builtins/aarch64/chkstk.S35
-rw-r--r--contrib/libs/cxxsupp/builtins/aarch64/fp_mode.c60
-rw-r--r--contrib/libs/cxxsupp/builtins/absvdi2.c42
-rw-r--r--contrib/libs/cxxsupp/builtins/absvsi2.c42
-rw-r--r--contrib/libs/cxxsupp/builtins/absvti2.c45
-rw-r--r--contrib/libs/cxxsupp/builtins/adddf3.c22
-rw-r--r--contrib/libs/cxxsupp/builtins/addsf3.c22
-rw-r--r--contrib/libs/cxxsupp/builtins/addtf3.c14
-rw-r--r--contrib/libs/cxxsupp/builtins/addvdi3.c53
-rw-r--r--contrib/libs/cxxsupp/builtins/addvsi3.c53
-rw-r--r--contrib/libs/cxxsupp/builtins/addvti3.c55
-rw-r--r--contrib/libs/cxxsupp/builtins/apple_versioning.c121
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/Makefile.mk20
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/adddf3vfp.S19
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/addsf3.S276
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/addsf3vfp.S14
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/aeabi_cdcmp.S60
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/aeabi_cdcmpeq_check_nan.c15
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/aeabi_cfcmp.S60
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/aeabi_cfcmpeq_check_nan.c15
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/aeabi_dcmp.S23
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/aeabi_div0.c59
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/aeabi_drsub.c15
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/aeabi_fcmp.S23
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/aeabi_frsub.c15
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/aeabi_idivmod.S30
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/aeabi_ldivmod.S30
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/aeabi_memcmp.S17
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/aeabi_memcpy.S17
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/aeabi_memmove.S16
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/aeabi_memset.S25
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/aeabi_uidivmod.S36
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/aeabi_uldivmod.S30
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/bswapdi2.S18
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/bswapsi2.S18
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/chkstk.S35
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/clzdi2.S85
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/clzsi2.S82
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/comparesf2.S183
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/divdf3vfp.S16
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/divmodsi4.S38
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/divsf3vfp.S14
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/divsi3.S60
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/eqdf2vfp.S22
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/eqsf2vfp.S17
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/extendsfdf2vfp.S16
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/fixdfsivfp.S17
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/fixsfsivfp.S17
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/fixunsdfsivfp.S19
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/fixunssfsivfp.S19
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/floatsidfvfp.S17
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/floatsisfvfp.S17
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/floatunssidfvfp.S17
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/floatunssisfvfp.S17
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/fp_mode.c60
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/gedf2vfp.S17
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/gesf2vfp.S17
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/gtdf2vfp.S17
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/gtsf2vfp.S17
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/ledf2vfp.S17
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/lesf2vfp.S17
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/ltdf2vfp.S17
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/ltsf2vfp.S17
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/modsi3.S36
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/muldf3vfp.S16
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/mulsf3vfp.S14
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/nedf2vfp.S22
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/negdf2vfp.S16
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/negsf2vfp.S16
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/nesf2vfp.S17
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/restore_vfp_d8_d15_regs.S9
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/save_vfp_d8_d15_regs.S9
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/softfloat-alias.list2
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/subdf3vfp.S18
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/subsf3vfp.S16
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/switch16.S9
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/switch32.S9
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/switch8.S9
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/switchu8.S9
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/sync-ops.h119
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_add_4.S29
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_add_8.S27
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_and_4.S28
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_and_8.S28
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_max_4.S27
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_max_8.S28
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_min_4.S27
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_min_8.S28
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_nand_4.S27
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_nand_8.S27
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_or_4.S27
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_or_8.S27
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_sub_4.S29
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_sub_8.S27
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_umax_4.S27
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_umax_8.S28
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_umin_4.S27
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_umin_8.S28
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_xor_4.S27
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_xor_8.S27
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/sync_synchronize.S18
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/truncdfsf2vfp.S20
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/udivmodsi4.S78
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/udivsi3.S219
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/umodsi3.S75
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/unorddf2vfp.S19
-rw-r--r--contrib/libs/cxxsupp/builtins/arm/unordsf2vfp.S17
-rw-r--r--contrib/libs/cxxsupp/builtins/arm64/Makefile.mk20
-rw-r--r--contrib/libs/cxxsupp/builtins/armv6m/Makefile.mk20
-rw-r--r--contrib/libs/cxxsupp/builtins/ashldi3.c69
-rw-r--r--contrib/libs/cxxsupp/builtins/ashlti3.c65
-rw-r--r--contrib/libs/cxxsupp/builtins/ashrdi3.c71
-rw-r--r--contrib/libs/cxxsupp/builtins/ashrti3.c67
-rw-r--r--contrib/libs/cxxsupp/builtins/assembly.h194
-rw-r--r--contrib/libs/cxxsupp/builtins/atomic.c364
-rw-r--r--contrib/libs/cxxsupp/builtins/atomic_flag_clear.c24
-rw-r--r--contrib/libs/cxxsupp/builtins/atomic_flag_clear_explicit.c24
-rw-r--r--contrib/libs/cxxsupp/builtins/atomic_flag_test_and_set.c24
-rw-r--r--contrib/libs/cxxsupp/builtins/atomic_flag_test_and_set_explicit.c24
-rw-r--r--contrib/libs/cxxsupp/builtins/atomic_signal_fence.c24
-rw-r--r--contrib/libs/cxxsupp/builtins/atomic_thread_fence.c24
-rw-r--r--contrib/libs/cxxsupp/builtins/avr/divmodhi4.S57
-rw-r--r--contrib/libs/cxxsupp/builtins/avr/divmodqi4.S44
-rw-r--r--contrib/libs/cxxsupp/builtins/avr/exit.S18
-rw-r--r--contrib/libs/cxxsupp/builtins/avr/mulhi3.S71
-rw-r--r--contrib/libs/cxxsupp/builtins/avr/mulqi3.S53
-rw-r--r--contrib/libs/cxxsupp/builtins/avr/udivmodhi4.S49
-rw-r--r--contrib/libs/cxxsupp/builtins/avr/udivmodqi4.S39
-rw-r--r--contrib/libs/cxxsupp/builtins/bswapdi2.c25
-rw-r--r--contrib/libs/cxxsupp/builtins/bswapsi2.c20
-rw-r--r--contrib/libs/cxxsupp/builtins/clear_cache.c311
-rw-r--r--contrib/libs/cxxsupp/builtins/clzdi2.c52
-rw-r--r--contrib/libs/cxxsupp/builtins/clzsi2.c89
-rw-r--r--contrib/libs/cxxsupp/builtins/clzti2.c44
-rw-r--r--contrib/libs/cxxsupp/builtins/cmpdi2.c75
-rw-r--r--contrib/libs/cxxsupp/builtins/cmpti2.c63
-rw-r--r--contrib/libs/cxxsupp/builtins/comparedf2.c125
-rw-r--r--contrib/libs/cxxsupp/builtins/comparesf2.c124
-rw-r--r--contrib/libs/cxxsupp/builtins/comparetf2.c101
-rw-r--r--contrib/libs/cxxsupp/builtins/cpu_model.c1357
-rw-r--r--contrib/libs/cxxsupp/builtins/ctzdi2.c52
-rw-r--r--contrib/libs/cxxsupp/builtins/ctzsi2.c96
-rw-r--r--contrib/libs/cxxsupp/builtins/ctzti2.c44
-rw-r--r--contrib/libs/cxxsupp/builtins/divdc3.c101
-rw-r--r--contrib/libs/cxxsupp/builtins/divdf3.c188
-rw-r--r--contrib/libs/cxxsupp/builtins/divdi3.c43
-rw-r--r--contrib/libs/cxxsupp/builtins/divmoddi4.c43
-rw-r--r--contrib/libs/cxxsupp/builtins/divmodsi4.c46
-rw-r--r--contrib/libs/cxxsupp/builtins/divmodti4.c32
-rw-r--r--contrib/libs/cxxsupp/builtins/divsc3.c100
-rw-r--r--contrib/libs/cxxsupp/builtins/divsf3.c171
-rw-r--r--contrib/libs/cxxsupp/builtins/divsi3.c57
-rw-r--r--contrib/libs/cxxsupp/builtins/divtc3.c101
-rw-r--r--contrib/libs/cxxsupp/builtins/divtf3.c191
-rw-r--r--contrib/libs/cxxsupp/builtins/divti3.c45
-rw-r--r--contrib/libs/cxxsupp/builtins/divxc3.c96
-rw-r--r--contrib/libs/cxxsupp/builtins/emutls.c485
-rw-r--r--contrib/libs/cxxsupp/builtins/enable_execute_stack.c79
-rw-r--r--contrib/libs/cxxsupp/builtins/eprintf.c46
-rw-r--r--contrib/libs/cxxsupp/builtins/extenddftf2.c12
-rw-r--r--contrib/libs/cxxsupp/builtins/extendhfsf2.c26
-rw-r--r--contrib/libs/cxxsupp/builtins/extendhftf2.c23
-rw-r--r--contrib/libs/cxxsupp/builtins/extendsfdf2.c20
-rw-r--r--contrib/libs/cxxsupp/builtins/extendsftf2.c12
-rw-r--r--contrib/libs/cxxsupp/builtins/ffsdi2.c50
-rw-r--r--contrib/libs/cxxsupp/builtins/ffssi2.c23
-rw-r--r--contrib/libs/cxxsupp/builtins/ffsti2.c52
-rw-r--r--contrib/libs/cxxsupp/builtins/fixdfdi.c60
-rw-r--r--contrib/libs/cxxsupp/builtins/fixdfsi.c29
-rw-r--r--contrib/libs/cxxsupp/builtins/fixdfti.c23
-rw-r--r--contrib/libs/cxxsupp/builtins/fixsfdi.c61
-rw-r--r--contrib/libs/cxxsupp/builtins/fixsfsi.c29
-rw-r--r--contrib/libs/cxxsupp/builtins/fixsfti.c23
-rw-r--r--contrib/libs/cxxsupp/builtins/fixtfdi.c21
-rw-r--r--contrib/libs/cxxsupp/builtins/fixtfsi.c21
-rw-r--r--contrib/libs/cxxsupp/builtins/fixtfti.c21
-rw-r--r--contrib/libs/cxxsupp/builtins/fixunsdfdi.c62
-rw-r--r--contrib/libs/cxxsupp/builtins/fixunsdfsi.c29
-rw-r--r--contrib/libs/cxxsupp/builtins/fixunsdfti.c23
-rw-r--r--contrib/libs/cxxsupp/builtins/fixunssfdi.c66
-rw-r--r--contrib/libs/cxxsupp/builtins/fixunssfsi.c37
-rw-r--r--contrib/libs/cxxsupp/builtins/fixunssfti.c29
-rw-r--r--contrib/libs/cxxsupp/builtins/fixunstfdi.c21
-rw-r--r--contrib/libs/cxxsupp/builtins/fixunstfsi.c21
-rw-r--r--contrib/libs/cxxsupp/builtins/fixunstfti.c21
-rw-r--r--contrib/libs/cxxsupp/builtins/fixunsxfdi.c80
-rw-r--r--contrib/libs/cxxsupp/builtins/fixunsxfsi.c81
-rw-r--r--contrib/libs/cxxsupp/builtins/fixunsxfti.c74
-rw-r--r--contrib/libs/cxxsupp/builtins/fixxfdi.c88
-rw-r--r--contrib/libs/cxxsupp/builtins/fixxfti.c77
-rw-r--r--contrib/libs/cxxsupp/builtins/floatdidf.c184
-rw-r--r--contrib/libs/cxxsupp/builtins/floatdisf.c143
-rw-r--r--contrib/libs/cxxsupp/builtins/floatditf.c49
-rw-r--r--contrib/libs/cxxsupp/builtins/floatdixf.c67
-rw-r--r--contrib/libs/cxxsupp/builtins/floatsidf.c76
-rw-r--r--contrib/libs/cxxsupp/builtins/floatsisf.c90
-rw-r--r--contrib/libs/cxxsupp/builtins/floatsitf.c63
-rw-r--r--contrib/libs/cxxsupp/builtins/floattidf.c134
-rw-r--r--contrib/libs/cxxsupp/builtins/floattisf.c131
-rw-r--r--contrib/libs/cxxsupp/builtins/floattitf.c78
-rw-r--r--contrib/libs/cxxsupp/builtins/floattixf.c135
-rw-r--r--contrib/libs/cxxsupp/builtins/floatundidf.c186
-rw-r--r--contrib/libs/cxxsupp/builtins/floatundisf.c137
-rw-r--r--contrib/libs/cxxsupp/builtins/floatunditf.c32
-rw-r--r--contrib/libs/cxxsupp/builtins/floatundixf.c61
-rw-r--r--contrib/libs/cxxsupp/builtins/floatunsidf.c55
-rw-r--r--contrib/libs/cxxsupp/builtins/floatunsisf.c73
-rw-r--r--contrib/libs/cxxsupp/builtins/floatunsitf.c34
-rw-r--r--contrib/libs/cxxsupp/builtins/floatuntidf.c128
-rw-r--r--contrib/libs/cxxsupp/builtins/floatuntisf.c125
-rw-r--r--contrib/libs/cxxsupp/builtins/floatuntitf.c75
-rw-r--r--contrib/libs/cxxsupp/builtins/floatuntixf.c127
-rw-r--r--contrib/libs/cxxsupp/builtins/fp_add_impl.inc274
-rw-r--r--contrib/libs/cxxsupp/builtins/fp_compare_impl.inc119
-rw-r--r--contrib/libs/cxxsupp/builtins/fp_div_impl.inc419
-rw-r--r--contrib/libs/cxxsupp/builtins/fp_extend.h46
-rw-r--r--contrib/libs/cxxsupp/builtins/fp_extend_impl.inc129
-rw-r--r--contrib/libs/cxxsupp/builtins/fp_fixint_impl.inc47
-rw-r--r--contrib/libs/cxxsupp/builtins/fp_fixuint_impl.inc43
-rw-r--r--contrib/libs/cxxsupp/builtins/fp_lib.h429
-rw-r--r--contrib/libs/cxxsupp/builtins/fp_mode.c22
-rw-r--r--contrib/libs/cxxsupp/builtins/fp_mode.h29
-rw-r--r--contrib/libs/cxxsupp/builtins/fp_mul_impl.inc208
-rw-r--r--contrib/libs/cxxsupp/builtins/fp_trunc.h35
-rw-r--r--contrib/libs/cxxsupp/builtins/fp_trunc_impl.inc175
-rw-r--r--contrib/libs/cxxsupp/builtins/gcc_personality_v0.c412
-rw-r--r--contrib/libs/cxxsupp/builtins/hexagon/common_entry_exit_abi1.S102
-rw-r--r--contrib/libs/cxxsupp/builtins/hexagon/common_entry_exit_abi2.S267
-rw-r--r--contrib/libs/cxxsupp/builtins/hexagon/common_entry_exit_legacy.S156
-rw-r--r--contrib/libs/cxxsupp/builtins/hexagon/dfaddsub.S396
-rw-r--r--contrib/libs/cxxsupp/builtins/hexagon/dfdiv.S491
-rw-r--r--contrib/libs/cxxsupp/builtins/hexagon/dffma.S694
-rw-r--r--contrib/libs/cxxsupp/builtins/hexagon/dfminmax.S75
-rw-r--r--contrib/libs/cxxsupp/builtins/hexagon/dfmul.S413
-rw-r--r--contrib/libs/cxxsupp/builtins/hexagon/dfsqrt.S405
-rw-r--r--contrib/libs/cxxsupp/builtins/hexagon/divdi3.S84
-rw-r--r--contrib/libs/cxxsupp/builtins/hexagon/divsi3.S83
-rw-r--r--contrib/libs/cxxsupp/builtins/hexagon/fastmath2_dlib_asm.S490
-rw-r--r--contrib/libs/cxxsupp/builtins/hexagon/fastmath2_ldlib_asm.S344
-rw-r--r--contrib/libs/cxxsupp/builtins/hexagon/fastmath_dlib_asm.S399
-rw-r--r--contrib/libs/cxxsupp/builtins/hexagon/memcpy_forward_vp4cp4n2.S124
-rw-r--r--contrib/libs/cxxsupp/builtins/hexagon/memcpy_likely_aligned.S63
-rw-r--r--contrib/libs/cxxsupp/builtins/hexagon/moddi3.S82
-rw-r--r--contrib/libs/cxxsupp/builtins/hexagon/modsi3.S65
-rw-r--r--contrib/libs/cxxsupp/builtins/hexagon/sfdiv_opt.S65
-rw-r--r--contrib/libs/cxxsupp/builtins/hexagon/sfsqrt_opt.S81
-rw-r--r--contrib/libs/cxxsupp/builtins/hexagon/udivdi3.S70
-rw-r--r--contrib/libs/cxxsupp/builtins/hexagon/udivmoddi4.S70
-rw-r--r--contrib/libs/cxxsupp/builtins/hexagon/udivmodsi4.S59
-rw-r--r--contrib/libs/cxxsupp/builtins/hexagon/udivsi3.S55
-rw-r--r--contrib/libs/cxxsupp/builtins/hexagon/umoddi3.S73
-rw-r--r--contrib/libs/cxxsupp/builtins/hexagon/umodsi3.S54
-rw-r--r--contrib/libs/cxxsupp/builtins/i386/Makefile.mk20
-rw-r--r--contrib/libs/cxxsupp/builtins/i386/ashldi3.S8
-rw-r--r--contrib/libs/cxxsupp/builtins/i386/ashrdi3.S18
-rw-r--r--contrib/libs/cxxsupp/builtins/i386/chkstk.S5
-rw-r--r--contrib/libs/cxxsupp/builtins/i386/chkstk2.S5
-rw-r--r--contrib/libs/cxxsupp/builtins/i386/divdi3.S46
-rw-r--r--contrib/libs/cxxsupp/builtins/i386/floatdidf.S10
-rw-r--r--contrib/libs/cxxsupp/builtins/i386/floatdisf.S8
-rw-r--r--contrib/libs/cxxsupp/builtins/i386/floatdixf.S10
-rw-r--r--contrib/libs/cxxsupp/builtins/i386/floatundidf.S10
-rw-r--r--contrib/libs/cxxsupp/builtins/i386/floatundisf.S12
-rw-r--r--contrib/libs/cxxsupp/builtins/i386/floatundixf.S8
-rw-r--r--contrib/libs/cxxsupp/builtins/i386/fp_mode.c39
-rw-r--r--contrib/libs/cxxsupp/builtins/i386/lshrdi3.S12
-rw-r--r--contrib/libs/cxxsupp/builtins/i386/moddi3.S44
-rw-r--r--contrib/libs/cxxsupp/builtins/i386/muldi3.S14
-rw-r--r--contrib/libs/cxxsupp/builtins/i386/udivdi3.S32
-rw-r--r--contrib/libs/cxxsupp/builtins/i386/umoddi3.S40
-rw-r--r--contrib/libs/cxxsupp/builtins/int_div_impl.inc95
-rw-r--r--contrib/libs/cxxsupp/builtins/int_endianness.h102
-rw-r--r--contrib/libs/cxxsupp/builtins/int_lib.h168
-rw-r--r--contrib/libs/cxxsupp/builtins/int_math.h77
-rw-r--r--contrib/libs/cxxsupp/builtins/int_mulo_impl.inc49
-rw-r--r--contrib/libs/cxxsupp/builtins/int_mulv_impl.inc47
-rw-r--r--contrib/libs/cxxsupp/builtins/int_types.h239
-rw-r--r--contrib/libs/cxxsupp/builtins/int_util.c56
-rw-r--r--contrib/libs/cxxsupp/builtins/int_util.h58
-rw-r--r--contrib/libs/cxxsupp/builtins/loongarch/fp_mode.c59
-rw-r--r--contrib/libs/cxxsupp/builtins/lshrdi3.c69
-rw-r--r--contrib/libs/cxxsupp/builtins/lshrti3.c65
-rw-r--r--contrib/libs/cxxsupp/builtins/macho_embedded/common.txt1
-rw-r--r--contrib/libs/cxxsupp/builtins/moddi3.c44
-rw-r--r--contrib/libs/cxxsupp/builtins/modsi3.c32
-rw-r--r--contrib/libs/cxxsupp/builtins/modti3.c46
-rw-r--r--contrib/libs/cxxsupp/builtins/muldc3.c124
-rw-r--r--contrib/libs/cxxsupp/builtins/muldf3.c19
-rw-r--r--contrib/libs/cxxsupp/builtins/muldi3.c91
-rw-r--r--contrib/libs/cxxsupp/builtins/mulodi4.c70
-rw-r--r--contrib/libs/cxxsupp/builtins/mulosi4.c70
-rw-r--r--contrib/libs/cxxsupp/builtins/muloti4.c73
-rw-r--r--contrib/libs/cxxsupp/builtins/mulsc3.c123
-rw-r--r--contrib/libs/cxxsupp/builtins/mulsf3.c19
-rw-r--r--contrib/libs/cxxsupp/builtins/multc3.c119
-rw-r--r--contrib/libs/cxxsupp/builtins/multf3.c11
-rw-r--r--contrib/libs/cxxsupp/builtins/multi3.c91
-rw-r--r--contrib/libs/cxxsupp/builtins/mulvdi3.c68
-rw-r--r--contrib/libs/cxxsupp/builtins/mulvsi3.c68
-rw-r--r--contrib/libs/cxxsupp/builtins/mulvti3.c70
-rw-r--r--contrib/libs/cxxsupp/builtins/mulxc3.c124
-rw-r--r--contrib/libs/cxxsupp/builtins/negdf2.c20
-rw-r--r--contrib/libs/cxxsupp/builtins/negdi2.c37
-rw-r--r--contrib/libs/cxxsupp/builtins/negsf2.c20
-rw-r--r--contrib/libs/cxxsupp/builtins/negti2.c39
-rw-r--r--contrib/libs/cxxsupp/builtins/negvdi2.c40
-rw-r--r--contrib/libs/cxxsupp/builtins/negvsi2.c40
-rw-r--r--contrib/libs/cxxsupp/builtins/negvti2.c42
-rw-r--r--contrib/libs/cxxsupp/builtins/os_version_check.c142
-rw-r--r--contrib/libs/cxxsupp/builtins/paritydi2.c40
-rw-r--r--contrib/libs/cxxsupp/builtins/paritysi2.c40
-rw-r--r--contrib/libs/cxxsupp/builtins/parityti2.c44
-rw-r--r--contrib/libs/cxxsupp/builtins/popcountdi2.c58
-rw-r--r--contrib/libs/cxxsupp/builtins/popcountsi2.c52
-rw-r--r--contrib/libs/cxxsupp/builtins/popcountti2.c71
-rw-r--r--contrib/libs/cxxsupp/builtins/powidf2.c53
-rw-r--r--contrib/libs/cxxsupp/builtins/powisf2.c53
-rw-r--r--contrib/libs/cxxsupp/builtins/powitf2.c58
-rw-r--r--contrib/libs/cxxsupp/builtins/powixf2.c53
-rw-r--r--contrib/libs/cxxsupp/builtins/ppc/DD.h22
-rw-r--r--contrib/libs/cxxsupp/builtins/ppc/Makefile.mk20
-rw-r--r--contrib/libs/cxxsupp/builtins/ppc/atomic.exp41
-rw-r--r--contrib/libs/cxxsupp/builtins/ppc/divtc3.c170
-rw-r--r--contrib/libs/cxxsupp/builtins/ppc/fixtfdi.c192
-rw-r--r--contrib/libs/cxxsupp/builtins/ppc/fixtfti.c38
-rw-r--r--contrib/libs/cxxsupp/builtins/ppc/fixunstfdi.c106
-rw-r--r--contrib/libs/cxxsupp/builtins/ppc/fixunstfti.c115
-rw-r--r--contrib/libs/cxxsupp/builtins/ppc/floatditf.c57
-rw-r--r--contrib/libs/cxxsupp/builtins/ppc/floattitf.c46
-rw-r--r--contrib/libs/cxxsupp/builtins/ppc/floatunditf.c68
-rw-r--r--contrib/libs/cxxsupp/builtins/ppc/gcc_qadd.c140
-rw-r--r--contrib/libs/cxxsupp/builtins/ppc/gcc_qdiv.c95
-rw-r--r--contrib/libs/cxxsupp/builtins/ppc/gcc_qmul.c91
-rw-r--r--contrib/libs/cxxsupp/builtins/ppc/gcc_qsub.c140
-rw-r--r--contrib/libs/cxxsupp/builtins/ppc/multc3.c159
-rw-r--r--contrib/libs/cxxsupp/builtins/ppc/restFP.S10
-rw-r--r--contrib/libs/cxxsupp/builtins/ppc/saveFP.S10
-rw-r--r--contrib/libs/cxxsupp/builtins/riscv/fp_mode.c42
-rw-r--r--contrib/libs/cxxsupp/builtins/riscv/int_mul_impl.inc33
-rw-r--r--contrib/libs/cxxsupp/builtins/riscv/muldi3.S11
-rw-r--r--contrib/libs/cxxsupp/builtins/riscv/mulsi3.S12
-rw-r--r--contrib/libs/cxxsupp/builtins/riscv/restore.S166
-rw-r--r--contrib/libs/cxxsupp/builtins/riscv/save.S186
-rw-r--r--contrib/libs/cxxsupp/builtins/subdf3.c24
-rw-r--r--contrib/libs/cxxsupp/builtins/subsf3.c24
-rw-r--r--contrib/libs/cxxsupp/builtins/subtf3.c15
-rw-r--r--contrib/libs/cxxsupp/builtins/subvdi3.c53
-rw-r--r--contrib/libs/cxxsupp/builtins/subvsi3.c53
-rw-r--r--contrib/libs/cxxsupp/builtins/subvti3.c55
-rw-r--r--contrib/libs/cxxsupp/builtins/trampoline_setup.c79
-rw-r--r--contrib/libs/cxxsupp/builtins/truncdfbf2.c13
-rw-r--r--contrib/libs/cxxsupp/builtins/truncdfhf2.c19
-rw-r--r--contrib/libs/cxxsupp/builtins/truncdfsf2.c19
-rw-r--r--contrib/libs/cxxsupp/builtins/truncsfbf2.c13
-rw-r--r--contrib/libs/cxxsupp/builtins/truncsfhf2.c25
-rw-r--r--contrib/libs/cxxsupp/builtins/trunctfdf2.c11
-rw-r--r--contrib/libs/cxxsupp/builtins/trunctfhf2.c23
-rw-r--r--contrib/libs/cxxsupp/builtins/trunctfsf2.c11
-rw-r--r--contrib/libs/cxxsupp/builtins/ucmpdi2.c75
-rw-r--r--contrib/libs/cxxsupp/builtins/ucmpti2.c63
-rw-r--r--contrib/libs/cxxsupp/builtins/udivdi3.c36
-rw-r--r--contrib/libs/cxxsupp/builtins/udivmoddi4.c407
-rw-r--r--contrib/libs/cxxsupp/builtins/udivmodsi4.c36
-rw-r--r--contrib/libs/cxxsupp/builtins/udivmodti4.c378
-rw-r--r--contrib/libs/cxxsupp/builtins/udivsi3.c81
-rw-r--r--contrib/libs/cxxsupp/builtins/udivti3.c34
-rw-r--r--contrib/libs/cxxsupp/builtins/umoddi3.c38
-rw-r--r--contrib/libs/cxxsupp/builtins/umodsi3.c36
-rw-r--r--contrib/libs/cxxsupp/builtins/umodti3.c38
-rw-r--r--contrib/libs/cxxsupp/builtins/unwind-ehabi-helpers.h51
-rw-r--r--contrib/libs/cxxsupp/builtins/ve/grow_stack.S31
-rw-r--r--contrib/libs/cxxsupp/builtins/ve/grow_stack_align.S31
-rw-r--r--contrib/libs/cxxsupp/builtins/x86_64/Makefile.mk20
-rw-r--r--contrib/libs/cxxsupp/builtins/x86_64/chkstk.S5
-rw-r--r--contrib/libs/cxxsupp/builtins/x86_64/chkstk2.S5
-rw-r--r--contrib/libs/cxxsupp/builtins/x86_64/floatdidf.c17
-rw-r--r--contrib/libs/cxxsupp/builtins/x86_64/floatdisf.c15
-rw-r--r--contrib/libs/cxxsupp/builtins/x86_64/floatdixf.c15
-rw-r--r--contrib/libs/cxxsupp/builtins/x86_64/floatundidf.S10
-rw-r--r--contrib/libs/cxxsupp/builtins/x86_64/floatundisf.S10
-rw-r--r--contrib/libs/cxxsupp/builtins/x86_64/floatundixf.S10
-rw-r--r--contrib/libs/cxxsupp/builtins/ya.make162
-rw-r--r--contrib/libs/cxxsupp/libcxxmsvc/ya.make3
-rw-r--r--contrib/libs/isa-l/erasure_code/Makefile.am51
-rw-r--r--contrib/libs/isa-l/erasure_code/aarch64/.yandex_meta/licenses.list.txt (renamed from contrib/libs/isa-l/erasure_code/ut/gf_2vect_dot_prod_sse_test/.yandex_meta/licenses.list.txt)0
-rw-r--r--contrib/libs/isa-l/erasure_code/aarch64/Makefile.am60
-rw-r--r--contrib/libs/isa-l/erasure_code/aarch64/ec_aarch64_dispatcher.c124
-rw-r--r--contrib/libs/isa-l/erasure_code/aarch64/ec_aarch64_highlevel_func.c264
-rw-r--r--contrib/libs/isa-l/erasure_code/aarch64/ec_multibinary_arm.S37
-rw-r--r--contrib/libs/isa-l/erasure_code/aarch64/gf_2vect_dot_prod_neon.S402
-rw-r--r--contrib/libs/isa-l/erasure_code/aarch64/gf_2vect_dot_prod_sve.S168
-rw-r--r--contrib/libs/isa-l/erasure_code/aarch64/gf_2vect_mad_neon.S411
-rw-r--r--contrib/libs/isa-l/erasure_code/aarch64/gf_2vect_mad_sve.S152
-rw-r--r--contrib/libs/isa-l/erasure_code/aarch64/gf_3vect_dot_prod_neon.S361
-rw-r--r--contrib/libs/isa-l/erasure_code/aarch64/gf_3vect_dot_prod_sve.S189
-rw-r--r--contrib/libs/isa-l/erasure_code/aarch64/gf_3vect_mad_neon.S391
-rw-r--r--contrib/libs/isa-l/erasure_code/aarch64/gf_3vect_mad_sve.S175
-rw-r--r--contrib/libs/isa-l/erasure_code/aarch64/gf_4vect_dot_prod_neon.S425
-rw-r--r--contrib/libs/isa-l/erasure_code/aarch64/gf_4vect_dot_prod_sve.S208
-rw-r--r--contrib/libs/isa-l/erasure_code/aarch64/gf_4vect_mad_neon.S464
-rw-r--r--contrib/libs/isa-l/erasure_code/aarch64/gf_4vect_mad_sve.S194
-rw-r--r--contrib/libs/isa-l/erasure_code/aarch64/gf_5vect_dot_prod_neon.S484
-rw-r--r--contrib/libs/isa-l/erasure_code/aarch64/gf_5vect_dot_prod_sve.S237
-rw-r--r--contrib/libs/isa-l/erasure_code/aarch64/gf_5vect_mad_neon.S544
-rw-r--r--contrib/libs/isa-l/erasure_code/aarch64/gf_5vect_mad_sve.S218
-rw-r--r--contrib/libs/isa-l/erasure_code/aarch64/gf_6vect_dot_prod_sve.S258
-rw-r--r--contrib/libs/isa-l/erasure_code/aarch64/gf_6vect_mad_neon.S618
-rw-r--r--contrib/libs/isa-l/erasure_code/aarch64/gf_6vect_mad_sve.S237
-rw-r--r--contrib/libs/isa-l/erasure_code/aarch64/gf_7vect_dot_prod_sve.S281
-rw-r--r--contrib/libs/isa-l/erasure_code/aarch64/gf_8vect_dot_prod_sve.S307
-rw-r--r--contrib/libs/isa-l/erasure_code/aarch64/gf_vect_dot_prod_neon.S303
-rw-r--r--contrib/libs/isa-l/erasure_code/aarch64/gf_vect_dot_prod_sve.S132
-rw-r--r--contrib/libs/isa-l/erasure_code/aarch64/gf_vect_mad_neon.S324
-rw-r--r--contrib/libs/isa-l/erasure_code/aarch64/gf_vect_mad_sve.S126
-rw-r--r--contrib/libs/isa-l/erasure_code/aarch64/gf_vect_mul_neon.S240
-rw-r--r--contrib/libs/isa-l/erasure_code/aarch64/gf_vect_mul_sve.S123
-rw-r--r--contrib/libs/isa-l/erasure_code/aarch64/ya.make51
-rw-r--r--contrib/libs/isa-l/erasure_code/ec_base.c46
-rw-r--r--contrib/libs/isa-l/erasure_code/ec_base.h71
-rw-r--r--contrib/libs/isa-l/erasure_code/ec_base.patch44
-rw-r--r--contrib/libs/isa-l/erasure_code/ec_base_aliases.c8
-rw-r--r--contrib/libs/isa-l/erasure_code/ec_highlevel_func.c277
-rw-r--r--contrib/libs/isa-l/erasure_code/ec_multibinary.asm24
-rw-r--r--contrib/libs/isa-l/erasure_code/ec_multibinary_darwin.asm25
-rw-r--r--contrib/libs/isa-l/erasure_code/erasure_code_base_perf.c33
-rw-r--r--contrib/libs/isa-l/erasure_code/erasure_code_base_test.c36
-rw-r--r--contrib/libs/isa-l/erasure_code/erasure_code_base_test.patch12
-rw-r--r--contrib/libs/isa-l/erasure_code/erasure_code_perf.c171
-rw-r--r--contrib/libs/isa-l/erasure_code/erasure_code_test.c99
-rw-r--r--contrib/libs/isa-l/erasure_code/erasure_code_test.patch8
-rw-r--r--contrib/libs/isa-l/erasure_code/erasure_code_update_perf.c167
-rw-r--r--contrib/libs/isa-l/erasure_code/erasure_code_update_test.c127
-rw-r--r--contrib/libs/isa-l/erasure_code/erasure_code_update_test.patch8
-rw-r--r--contrib/libs/isa-l/erasure_code/gen_rs_matrix_limits.c25
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_2vect_dot_prod_avx.asm21
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_2vect_dot_prod_avx.patch8
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_2vect_dot_prod_avx2.asm17
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_2vect_dot_prod_avx2.patch8
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_2vect_dot_prod_avx2_gfni.asm362
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_2vect_dot_prod_avx512.asm41
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_2vect_dot_prod_avx512.patch6
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_2vect_dot_prod_avx512_gfni.asm209
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_2vect_dot_prod_sse.asm15
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_2vect_dot_prod_sse.patch8
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_2vect_dot_prod_sse_test.c480
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_2vect_dot_prod_sse_test.patch4
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_2vect_mad_avx.asm13
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_2vect_mad_avx.patch8
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_2vect_mad_avx2.asm15
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_2vect_mad_avx2.patch8
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_2vect_mad_avx2_gfni.asm298
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_2vect_mad_avx512.asm13
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_2vect_mad_avx512.patch6
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_2vect_mad_avx512_gfni.asm189
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_2vect_mad_sse.asm12
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_2vect_mad_sse.patch6
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_3vect_dot_prod_avx.asm26
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_3vect_dot_prod_avx.patch6
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_3vect_dot_prod_avx2.asm16
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_3vect_dot_prod_avx2.patch6
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_3vect_dot_prod_avx2_gfni.asm335
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_3vect_dot_prod_avx512.asm41
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_3vect_dot_prod_avx512.patch6
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_3vect_dot_prod_avx512_gfni.asm225
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_3vect_dot_prod_sse.asm14
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_3vect_dot_prod_sse.patch6
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_3vect_dot_prod_sse_test.c586
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_3vect_dot_prod_sse_test.patch4
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_3vect_mad_avx.asm11
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_3vect_mad_avx.patch5
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_3vect_mad_avx2.asm12
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_3vect_mad_avx2.patch6
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_3vect_mad_avx2_gfni.asm276
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_3vect_mad_avx512.asm15
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_3vect_mad_avx512.patch6
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_3vect_mad_avx512_gfni.asm204
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_3vect_mad_sse.asm12
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_3vect_mad_sse.patch6
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_4vect_dot_prod_avx.asm32
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_4vect_dot_prod_avx.patch6
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_4vect_dot_prod_avx2.asm17
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_4vect_dot_prod_avx2.patch8
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_4vect_dot_prod_avx512.asm36
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_4vect_dot_prod_avx512.patch6
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_4vect_dot_prod_avx512_gfni.asm253
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_4vect_dot_prod_sse.asm14
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_4vect_dot_prod_sse.patch6
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_4vect_dot_prod_sse_test.c695
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_4vect_dot_prod_sse_test.patch4
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_4vect_mad_avx.asm12
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_4vect_mad_avx.patch6
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_4vect_mad_avx2.asm12
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_4vect_mad_avx2.patch6
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_4vect_mad_avx2_gfni.asm239
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_4vect_mad_avx512.asm53
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_4vect_mad_avx512.patch6
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_4vect_mad_avx512_gfni.asm223
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_4vect_mad_sse.asm12
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_4vect_mad_sse.patch6
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_5vect_dot_prod_avx.asm32
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_5vect_dot_prod_avx.patch6
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_5vect_dot_prod_avx2.asm14
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_5vect_dot_prod_avx2.patch6
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_5vect_dot_prod_avx512.asm334
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_5vect_dot_prod_avx512_gfni.asm275
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_5vect_dot_prod_sse.asm12
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_5vect_dot_prod_sse.patch6
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_5vect_dot_prod_sse_test.c805
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_5vect_dot_prod_sse_test.patch4
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_5vect_mad_avx.asm12
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_5vect_mad_avx.patch6
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_5vect_mad_avx2.asm12
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_5vect_mad_avx2.patch6
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_5vect_mad_avx2_gfni.asm265
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_5vect_mad_avx512.asm287
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_5vect_mad_avx512_gfni.asm240
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_5vect_mad_sse.asm12
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_5vect_mad_sse.patch6
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_6vect_dot_prod_avx.asm32
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_6vect_dot_prod_avx.patch6
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_6vect_dot_prod_avx2.asm14
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_6vect_dot_prod_avx2.patch6
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_6vect_dot_prod_avx512.asm353
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_6vect_dot_prod_avx512_gfni.asm292
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_6vect_dot_prod_sse.asm12
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_6vect_dot_prod_sse.patch6
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_6vect_dot_prod_sse_test.c911
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_6vect_dot_prod_sse_test.patch4
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_6vect_mad_avx.asm12
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_6vect_mad_avx.patch6
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_6vect_mad_avx2.asm12
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_6vect_mad_avx2.patch6
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_6vect_mad_avx512.asm321
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_6vect_mad_avx512_gfni.asm259
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_6vect_mad_sse.asm12
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_6vect_mad_sse.patch6
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_inverse_test.c33
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_inverse_test.patch4
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_vect_dot_prod_1tbl.c34
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_vect_dot_prod_1tbl.patch8
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_vect_dot_prod_avx.asm14
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_vect_dot_prod_avx.patch6
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_vect_dot_prod_avx2.asm16
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_vect_dot_prod_avx2.patch6
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_vect_dot_prod_avx2_gfni.asm318
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_vect_dot_prod_avx512.asm21
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_vect_dot_prod_avx512.patch6
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_vect_dot_prod_avx512_gfni.asm190
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_vect_dot_prod_base_test.c10
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_vect_dot_prod_base_test.patch4
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_vect_dot_prod_perf.c22
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_vect_dot_prod_sse.asm14
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_vect_dot_prod_sse.patch6
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_vect_dot_prod_test.c19
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_vect_dot_prod_test.patch4
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_vect_gfni.inc72
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_vect_mad_avx.asm12
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_vect_mad_avx.patch6
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_vect_mad_avx2.asm14
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_vect_mad_avx2.patch6
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_vect_mad_avx2_gfni.asm255
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_vect_mad_avx512.asm13
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_vect_mad_avx512.patch6
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_vect_mad_avx512_gfni.asm175
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_vect_mad_sse.asm12
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_vect_mad_sse.patch6
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_vect_mad_test.c16
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_vect_mad_test.patch4
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_vect_mul_avx.asm37
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_vect_mul_avx.patch5
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_vect_mul_base_test.c26
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_vect_mul_base_test.patch28
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_vect_mul_perf.c23
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_vect_mul_sse.asm25
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_vect_mul_sse.patch6
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_vect_mul_test.c75
-rw-r--r--contrib/libs/isa-l/erasure_code/gf_vect_mul_test.patch40
-rw-r--r--contrib/libs/isa-l/erasure_code/ppc64le/Makefile.am15
-rw-r--r--contrib/libs/isa-l/erasure_code/ppc64le/ec_base_vsx.c106
-rw-r--r--contrib/libs/isa-l/erasure_code/ppc64le/ec_base_vsx.h338
-rw-r--r--contrib/libs/isa-l/erasure_code/ppc64le/gf_2vect_dot_prod_vsx.c83
-rw-r--r--contrib/libs/isa-l/erasure_code/ppc64le/gf_2vect_mad_vsx.c65
-rw-r--r--contrib/libs/isa-l/erasure_code/ppc64le/gf_3vect_dot_prod_vsx.c104
-rw-r--r--contrib/libs/isa-l/erasure_code/ppc64le/gf_3vect_mad_vsx.c84
-rw-r--r--contrib/libs/isa-l/erasure_code/ppc64le/gf_4vect_dot_prod_vsx.c124
-rw-r--r--contrib/libs/isa-l/erasure_code/ppc64le/gf_4vect_mad_vsx.c103
-rw-r--r--contrib/libs/isa-l/erasure_code/ppc64le/gf_5vect_dot_prod_vsx.c145
-rw-r--r--contrib/libs/isa-l/erasure_code/ppc64le/gf_5vect_mad_vsx.c122
-rw-r--r--contrib/libs/isa-l/erasure_code/ppc64le/gf_6vect_dot_prod_vsx.c166
-rw-r--r--contrib/libs/isa-l/erasure_code/ppc64le/gf_6vect_mad_vsx.c142
-rw-r--r--contrib/libs/isa-l/erasure_code/ppc64le/gf_vect_dot_prod_vsx.c85
-rw-r--r--contrib/libs/isa-l/erasure_code/ppc64le/gf_vect_mad_vsx.c48
-rw-r--r--contrib/libs/isa-l/erasure_code/ppc64le/gf_vect_mul_vsx.c75
-rw-r--r--contrib/libs/isa-l/erasure_code/ut/erasure_code_base_test/ya.make2
-rw-r--r--contrib/libs/isa-l/erasure_code/ut/erasure_code_test/ya.make2
-rw-r--r--contrib/libs/isa-l/erasure_code/ut/erasure_code_update_test/ya.make2
-rw-r--r--contrib/libs/isa-l/erasure_code/ut/gf_2vect_dot_prod_sse_test/ya.make29
-rw-r--r--contrib/libs/isa-l/erasure_code/ut/gf_3vect_dot_prod_sse_test/.yandex_meta/licenses.list.txt164
-rw-r--r--contrib/libs/isa-l/erasure_code/ut/gf_3vect_dot_prod_sse_test/ya.make29
-rw-r--r--contrib/libs/isa-l/erasure_code/ut/gf_4vect_dot_prod_sse_test/.yandex_meta/licenses.list.txt164
-rw-r--r--contrib/libs/isa-l/erasure_code/ut/gf_4vect_dot_prod_sse_test/ya.make29
-rw-r--r--contrib/libs/isa-l/erasure_code/ut/gf_5vect_dot_prod_sse_test/.yandex_meta/licenses.list.txt164
-rw-r--r--contrib/libs/isa-l/erasure_code/ut/gf_5vect_dot_prod_sse_test/ya.make29
-rw-r--r--contrib/libs/isa-l/erasure_code/ut/gf_6vect_dot_prod_sse_test/.yandex_meta/licenses.list.txt164
-rw-r--r--contrib/libs/isa-l/erasure_code/ut/gf_6vect_dot_prod_sse_test/ya.make29
-rw-r--r--contrib/libs/isa-l/erasure_code/ut/gf_inverse_test/ya.make2
-rw-r--r--contrib/libs/isa-l/erasure_code/ut/gf_vect_dot_prod_base_test/ya.make2
-rw-r--r--contrib/libs/isa-l/erasure_code/ut/gf_vect_dot_prod_test/ya.make2
-rw-r--r--contrib/libs/isa-l/erasure_code/ut/gf_vect_mad_test/ya.make2
-rw-r--r--contrib/libs/isa-l/erasure_code/ut/gf_vect_mul_base_test/ya.make2
-rw-r--r--contrib/libs/isa-l/erasure_code/ut/gf_vect_mul_test/ya.make2
-rw-r--r--contrib/libs/isa-l/erasure_code/ut/ya.make22
-rw-r--r--contrib/libs/isa-l/erasure_code/ya.make115
-rw-r--r--contrib/libs/isa-l/include/aarch64_label.h18
-rw-r--r--contrib/libs/isa-l/include/aarch64_multibinary.h347
-rw-r--r--contrib/libs/isa-l/include/erasure_code.h13
-rw-r--r--contrib/libs/isa-l/include/gf_vect_mul.h5
-rw-r--r--contrib/libs/isa-l/include/memcpy.asm769
-rw-r--r--contrib/libs/isa-l/include/multibinary.asm140
-rw-r--r--contrib/libs/isa-l/include/reg_sizes.asm108
-rw-r--r--contrib/libs/jinja2cpp/.yandex_meta/devtools.copyrights.report52
-rw-r--r--contrib/libs/jinja2cpp/.yandex_meta/devtools.licenses.report125
-rw-r--r--contrib/libs/jinja2cpp/.yandex_meta/licenses.list.txt818
-rw-r--r--contrib/libs/jinja2cpp/LICENSE373
-rw-r--r--contrib/libs/jinja2cpp/README.md384
-rw-r--r--contrib/libs/jinja2cpp/include/jinja2cpp/binding/rapid_json.h201
-rw-r--r--contrib/libs/jinja2cpp/include/jinja2cpp/config.h27
-rw-r--r--contrib/libs/jinja2cpp/include/jinja2cpp/error_info.h185
-rw-r--r--contrib/libs/jinja2cpp/include/jinja2cpp/filesystem_handler.h201
-rw-r--r--contrib/libs/jinja2cpp/include/jinja2cpp/generic_list.h287
-rw-r--r--contrib/libs/jinja2cpp/include/jinja2cpp/generic_list_iterator.h104
-rw-r--r--contrib/libs/jinja2cpp/include/jinja2cpp/polymorphic_value.h447
-rw-r--r--contrib/libs/jinja2cpp/include/jinja2cpp/reflected_value.h601
-rw-r--r--contrib/libs/jinja2cpp/include/jinja2cpp/string_helpers.h296
-rw-r--r--contrib/libs/jinja2cpp/include/jinja2cpp/template.h305
-rw-r--r--contrib/libs/jinja2cpp/include/jinja2cpp/template_env.h320
-rw-r--r--contrib/libs/jinja2cpp/include/jinja2cpp/utils/i_comparable.h16
-rw-r--r--contrib/libs/jinja2cpp/include/jinja2cpp/value.h763
-rw-r--r--contrib/libs/jinja2cpp/include/jinja2cpp/value_ptr.h29
-rw-r--r--contrib/libs/jinja2cpp/src/ast_visitor.h117
-rw-r--r--contrib/libs/jinja2cpp/src/binding/rapid_json_serializer.cpp127
-rw-r--r--contrib/libs/jinja2cpp/src/binding/rapid_json_serializer.h50
-rw-r--r--contrib/libs/jinja2cpp/src/error_handling.h63
-rw-r--r--contrib/libs/jinja2cpp/src/error_info.cpp289
-rw-r--r--contrib/libs/jinja2cpp/src/expression_evaluator.cpp602
-rw-r--r--contrib/libs/jinja2cpp/src/expression_evaluator.h619
-rw-r--r--contrib/libs/jinja2cpp/src/expression_parser.cpp606
-rw-r--r--contrib/libs/jinja2cpp/src/expression_parser.h49
-rw-r--r--contrib/libs/jinja2cpp/src/filesystem_handler.cpp163
-rw-r--r--contrib/libs/jinja2cpp/src/filters.cpp1086
-rw-r--r--contrib/libs/jinja2cpp/src/filters.h474
-rw-r--r--contrib/libs/jinja2cpp/src/function_base.h49
-rw-r--r--contrib/libs/jinja2cpp/src/generic_adapters.h215
-rw-r--r--contrib/libs/jinja2cpp/src/generic_list.cpp38
-rw-r--r--contrib/libs/jinja2cpp/src/helpers.h119
-rw-r--r--contrib/libs/jinja2cpp/src/internal_value.cpp1053
-rw-r--r--contrib/libs/jinja2cpp/src/internal_value.h673
-rw-r--r--contrib/libs/jinja2cpp/src/lexer.cpp122
-rw-r--r--contrib/libs/jinja2cpp/src/lexer.h375
-rw-r--r--contrib/libs/jinja2cpp/src/lexertk.h1842
-rw-r--r--contrib/libs/jinja2cpp/src/out_stream.h43
-rw-r--r--contrib/libs/jinja2cpp/src/render_context.h182
-rw-r--r--contrib/libs/jinja2cpp/src/renderer.h131
-rw-r--r--contrib/libs/jinja2cpp/src/robin_hood.h2544
-rw-r--r--contrib/libs/jinja2cpp/src/serialize_filters.cpp442
-rw-r--r--contrib/libs/jinja2cpp/src/statements.cpp839
-rw-r--r--contrib/libs/jinja2cpp/src/statements.h661
-rw-r--r--contrib/libs/jinja2cpp/src/string_converter_filter.cpp395
-rw-r--r--contrib/libs/jinja2cpp/src/template.cpp190
-rw-r--r--contrib/libs/jinja2cpp/src/template_env.cpp95
-rw-r--r--contrib/libs/jinja2cpp/src/template_impl.h487
-rw-r--r--contrib/libs/jinja2cpp/src/template_parser.cpp972
-rw-r--r--contrib/libs/jinja2cpp/src/template_parser.h1081
-rw-r--r--contrib/libs/jinja2cpp/src/testers.cpp379
-rw-r--r--contrib/libs/jinja2cpp/src/testers.h116
-rw-r--r--contrib/libs/jinja2cpp/src/value.cpp143
-rw-r--r--contrib/libs/jinja2cpp/src/value_helpers.h167
-rw-r--r--contrib/libs/jinja2cpp/src/value_visitors.h1151
-rw-r--r--contrib/libs/jinja2cpp/ya.make68
-rw-r--r--contrib/libs/libc_compat/memfd_create/memfd_create.c (renamed from contrib/libs/libc_compat/memfd_create.c)0
-rw-r--r--contrib/libs/libc_compat/memfd_create/sys/mman.h16
-rw-r--r--contrib/libs/libc_compat/ya.make14
-rw-r--r--contrib/libs/llvm16/include/llvm/Config/llvm-config-linux-aarch64.h35
-rw-r--r--contrib/libs/llvm16/include/llvm/Config/llvm-config.h2
-rw-r--r--contrib/libs/llvm16/tools/lli/ya.make9
-rw-r--r--contrib/libs/openssl/include/openssl/bnerr.h1
-rw-r--r--contrib/libs/openssl/include/openssl/crypto.h4
-rw-r--r--contrib/libs/openssl/include/openssl/dh.h3
-rw-r--r--contrib/libs/openssl/include/openssl/dherr.h1
-rw-r--r--contrib/libs/openssl/include/openssl/evp.h4
-rw-r--r--contrib/libs/openssl/include/openssl/ossl_typ.h2
-rw-r--r--contrib/libs/openssl/include/openssl/ssl.h61
-rw-r--r--contrib/libs/openssl/include/openssl/sslerr.h19
-rw-r--r--contrib/libs/openssl/include/openssl/tls1.h4
-rw-r--r--contrib/libs/openssl/libssl.map30
-rw-r--r--contrib/libs/openssl/ssl/record/rec_layer_s3.c8
-rw-r--r--contrib/libs/openssl/ssl/s3_msg.c10
-rw-r--r--contrib/libs/openssl/ssl/ssl_ciph.c34
-rw-r--r--contrib/libs/openssl/ssl/ssl_err.c37
-rw-r--r--contrib/libs/openssl/ssl/ssl_lib.c118
-rw-r--r--contrib/libs/openssl/ssl/ssl_local.h65
-rw-r--r--contrib/libs/openssl/ssl/ssl_quic.c385
-rw-r--r--contrib/libs/openssl/ssl/statem/extensions.c70
-rw-r--r--contrib/libs/openssl/ssl/statem/extensions_clnt.c91
-rw-r--r--contrib/libs/openssl/ssl/statem/extensions_srvr.c95
-rw-r--r--contrib/libs/openssl/ssl/statem/statem.c26
-rw-r--r--contrib/libs/openssl/ssl/statem/statem_clnt.c8
-rw-r--r--contrib/libs/openssl/ssl/statem/statem_lib.c40
-rw-r--r--contrib/libs/openssl/ssl/statem/statem_local.h38
-rw-r--r--contrib/libs/openssl/ssl/statem/statem_quic.c118
-rw-r--r--contrib/libs/openssl/ssl/statem/statem_srvr.c39
-rw-r--r--contrib/libs/openssl/ssl/tls13_enc.c218
-rw-r--r--contrib/libs/openssl/ya.make2
-rw-r--r--contrib/libs/pire/ut/approx_matching_ut.cpp4
1079 files changed, 91866 insertions, 53681 deletions
diff --git a/contrib/libs/croaring/.yandex_meta/override.nix b/contrib/libs/croaring/.yandex_meta/override.nix
index 1a2152ff69..fa1cd2b260 100644
--- a/contrib/libs/croaring/.yandex_meta/override.nix
+++ b/contrib/libs/croaring/.yandex_meta/override.nix
@@ -1,12 +1,12 @@
pkgs: attrs: with pkgs; with attrs; rec {
pname = "croaring";
- version = "4.1.7";
+ version = "4.2.0";
src = fetchFromGitHub {
owner = "RoaringBitmap";
repo = "CRoaring";
rev = "v${version}";
- hash = "sha256-vven8MrN0GRI3lz4zgquPE+5nBYxVaeY9SalKweux90=";
+ hash = "sha256-PzwtQDAsnRGIjeb3Ax6qqXtdEqtwaCWsj6g46J3Oqm0=";
};
patches = [];
diff --git a/contrib/libs/croaring/cpp/roaring.hh b/contrib/libs/croaring/cpp/roaring.hh
index 231dc5bd4f..8a3b8b6892 100644
--- a/contrib/libs/croaring/cpp/roaring.hh
+++ b/contrib/libs/croaring/cpp/roaring.hh
@@ -7,6 +7,7 @@ A C++ header for Roaring Bitmaps.
#include <algorithm>
#include <cstdarg>
#include <initializer_list>
+#include <limits>
#include <new>
#include <stdexcept>
#include <string>
@@ -39,7 +40,10 @@ A C++ header for Roaring Bitmaps.
namespace roaring {
-class RoaringSetBitForwardIterator;
+class RoaringSetBitBiDirectionalIterator;
+
+/** DEPRECATED, use `RoaringSetBitBiDirectionalIterator`. */
+using RoaringSetBitForwardIterator = RoaringSetBitBiDirectionalIterator;
/**
* A bit of context usable with `*Bulk()` functions.
@@ -92,6 +96,16 @@ class Roaring {
}
/**
+ * Construct a roaring object by taking control of a malloc()'d C struct.
+ *
+ * Passing a NULL pointer is unsafe.
+ * The pointer to the C struct will be invalid after the call.
+ */
+ explicit Roaring(roaring_bitmap_t *s) noexcept : roaring(*s) {
+ roaring_free(s); // deallocate the passed-in pointer
+ }
+
+ /**
* Copy constructor.
* It may throw std::runtime_error if there is insufficient memory.
*/
@@ -119,16 +133,6 @@ class Roaring {
}
/**
- * Construct a roaring object by taking control of a malloc()'d C struct.
- *
- * Passing a NULL pointer is unsafe.
- * The pointer to the C struct will be invalid after the call.
- */
- explicit Roaring(roaring_bitmap_t *s) noexcept : roaring(*s) {
- roaring_free(s); // deallocate the passed-in pointer
- }
-
- /**
* Construct a bitmap from a list of uint32_t values.
*/
static Roaring bitmapOf(size_t n, ...) {
@@ -143,6 +147,44 @@ class Roaring {
}
/**
+ * Copies the content of the provided bitmap, and
+ * discard the current content.
+ * It may throw std::runtime_error if there is insufficient memory.
+ */
+ Roaring &operator=(const Roaring &r) {
+ if (!api::roaring_bitmap_overwrite(&roaring, &r.roaring)) {
+ ROARING_TERMINATE("failed memory alloc in assignment");
+ }
+ api::roaring_bitmap_set_copy_on_write(
+ &roaring, api::roaring_bitmap_get_copy_on_write(&r.roaring));
+ return *this;
+ }
+
+ /**
+ * Moves the content of the provided bitmap, and
+ * discard the current content.
+ */
+ Roaring &operator=(Roaring &&r) noexcept {
+ api::roaring_bitmap_clear(&roaring); // free this class's allocations
+
+ // !!! See notes in the Move Constructor regarding roaring_bitmap_move()
+ //
+ roaring = r.roaring;
+ api::roaring_bitmap_init_cleared(&r.roaring);
+
+ return *this;
+ }
+
+ /**
+ * Assignment from an initializer list.
+ */
+ Roaring &operator=(std::initializer_list<uint32_t> l) {
+ // Delegate to move assignment operator
+ *this = Roaring(l);
+ return *this;
+ }
+
+ /**
* Construct a bitmap from a list of uint32_t values.
* E.g., bitmapOfList({1,2,3}).
*/
@@ -243,6 +285,11 @@ class Roaring {
}
/**
+ * Clears the bitmap.
+ */
+ void clear() { api::roaring_bitmap_clear(&roaring); }
+
+ /**
* Return the largest value (if not empty)
*/
uint32_t maximum() const noexcept {
@@ -270,63 +317,9 @@ class Roaring {
return api::roaring_bitmap_contains_range(&roaring, x, y);
}
- /**
- * Destructor. By contract, calling roaring_bitmap_clear() is enough to
- * release all auxiliary memory used by the structure.
- */
- ~Roaring() {
- if (!(roaring.high_low_container.flags & ROARING_FLAG_FROZEN)) {
- api::roaring_bitmap_clear(&roaring);
- } else {
- // The roaring member variable copies the `roaring_bitmap_t` and
- // nested `roaring_array_t` structures by value and is freed in the
- // constructor, however the underlying memory arena used for the
- // container data is not freed with it. Here we derive the arena
- // pointer from the second arena allocation in
- // `roaring_bitmap_frozen_view` and free it as well.
- roaring_bitmap_free(
- (roaring_bitmap_t *)((char *)
- roaring.high_low_container.containers -
- sizeof(roaring_bitmap_t)));
- }
- }
-
- /**
- * Copies the content of the provided bitmap, and
- * discard the current content.
- * It may throw std::runtime_error if there is insufficient memory.
- */
- Roaring &operator=(const Roaring &r) {
- if (!api::roaring_bitmap_overwrite(&roaring, &r.roaring)) {
- ROARING_TERMINATE("failed memory alloc in assignment");
- }
- api::roaring_bitmap_set_copy_on_write(
- &roaring, api::roaring_bitmap_get_copy_on_write(&r.roaring));
- return *this;
- }
-
- /**
- * Moves the content of the provided bitmap, and
- * discard the current content.
- */
- Roaring &operator=(Roaring &&r) noexcept {
- api::roaring_bitmap_clear(&roaring); // free this class's allocations
-
- // !!! See notes in the Move Constructor regarding roaring_bitmap_move()
- //
- roaring = r.roaring;
- api::roaring_bitmap_init_cleared(&r.roaring);
-
- return *this;
- }
-
- /**
- * Assignment from an initializer list.
- */
- Roaring &operator=(std::initializer_list<uint32_t> l) {
- // Delegate to move assignment operator
- *this = Roaring(l);
- return *this;
+ bool containsRangeClosed(const uint32_t x,
+ const uint32_t y) const noexcept {
+ return api::roaring_bitmap_contains_range_closed(&roaring, x, y);
}
/**
@@ -394,6 +387,16 @@ class Roaring {
}
/**
+ * Returns true if the bitmap is full (cardinality is uint32_t max + 1).
+ * we put std::numeric_limits<>::max/min in parentheses
+ * to avoid a clash with the Windows.h header under Windows.
+ */
+ bool isFull() const noexcept {
+ return api::roaring_bitmap_get_cardinality(&roaring) ==
+ ((uint64_t)(std::numeric_limits<uint32_t>::max)()) + 1;
+ }
+
+ /**
* Returns true if the bitmap is subset of the other.
*/
bool isSubset(const Roaring &r) const noexcept {
@@ -443,8 +446,8 @@ class Roaring {
* [range_start, range_end]. Areas outside the interval are unchanged.
*/
void flipClosed(uint32_t range_start, uint32_t range_end) noexcept {
- api::roaring_bitmap_flip_inplace(&roaring, range_start,
- uint64_t(range_end) + 1);
+ api::roaring_bitmap_flip_inplace_closed(&roaring, range_start,
+ range_end);
}
/**
@@ -868,7 +871,30 @@ class Roaring {
return ans;
}
- typedef RoaringSetBitForwardIterator const_iterator;
+ /**
+ * Destructor. By contract, calling roaring_bitmap_clear() is enough to
+ * release all auxiliary memory used by the structure.
+ */
+ ~Roaring() {
+ if (!(roaring.high_low_container.flags & ROARING_FLAG_FROZEN)) {
+ api::roaring_bitmap_clear(&roaring);
+ } else {
+ // The roaring member variable copies the `roaring_bitmap_t` and
+ // nested `roaring_array_t` structures by value and is freed in the
+ // constructor, however the underlying memory arena used for the
+ // container data is not freed with it. Here we derive the arena
+ // pointer from the second arena allocation in
+ // `roaring_bitmap_frozen_view` and free it as well.
+ roaring_bitmap_free(
+ (roaring_bitmap_t *)((char *)
+ roaring.high_low_container.containers -
+ sizeof(roaring_bitmap_t)));
+ }
+ }
+
+ friend class RoaringSetBitBiDirectionalIterator;
+ typedef RoaringSetBitBiDirectionalIterator const_iterator;
+ typedef RoaringSetBitBiDirectionalIterator const_bidirectional_iterator;
/**
* Returns an iterator that can be used to access the position of the set
@@ -893,14 +919,26 @@ class Roaring {
/**
* Used to go through the set bits. Not optimally fast, but convenient.
*/
-class RoaringSetBitForwardIterator final {
+class RoaringSetBitBiDirectionalIterator final {
public:
- typedef std::forward_iterator_tag iterator_category;
+ typedef std::bidirectional_iterator_tag iterator_category;
typedef uint32_t *pointer;
typedef uint32_t &reference_type;
typedef uint32_t value_type;
typedef int32_t difference_type;
- typedef RoaringSetBitForwardIterator type_of_iterator;
+ typedef RoaringSetBitBiDirectionalIterator type_of_iterator;
+
+ explicit RoaringSetBitBiDirectionalIterator(const Roaring &parent,
+ bool exhausted = false) {
+ if (exhausted) {
+ i.parent = &parent.roaring;
+ i.container_index = INT32_MAX;
+ i.has_value = false;
+ i.current_value = UINT32_MAX;
+ } else {
+ api::roaring_iterator_init(&parent.roaring, &i);
+ }
+ }
/**
* Provides the location of the set bit.
@@ -931,66 +969,60 @@ class RoaringSetBitForwardIterator final {
return i.current_value >= *o;
}
- /**
- * Move the iterator to the first value >= val.
- */
- void equalorlarger(uint32_t val) {
- api::roaring_uint32_iterator_move_equalorlarger(&i, val);
- }
-
type_of_iterator &operator++() { // ++i, must returned inc. value
api::roaring_uint32_iterator_advance(&i);
return *this;
}
type_of_iterator operator++(int) { // i++, must return orig. value
- RoaringSetBitForwardIterator orig(*this);
+ RoaringSetBitBiDirectionalIterator orig(*this);
api::roaring_uint32_iterator_advance(&i);
return orig;
}
+ /**
+ * Move the iterator to the first value >= val.
+ * Return true if there is such a value.
+ */
+ bool move_equalorlarger(value_type val) {
+ return api::roaring_uint32_iterator_move_equalorlarger(&i, val);
+ }
+
+ /** DEPRECATED, use `move_equalorlarger`.*/
+ CROARING_DEPRECATED void equalorlarger(uint32_t val) {
+ api::roaring_uint32_iterator_move_equalorlarger(&i, val);
+ }
+
type_of_iterator &operator--() { // prefix --
api::roaring_uint32_iterator_previous(&i);
return *this;
}
type_of_iterator operator--(int) { // postfix --
- RoaringSetBitForwardIterator orig(*this);
+ RoaringSetBitBiDirectionalIterator orig(*this);
api::roaring_uint32_iterator_previous(&i);
return orig;
}
- bool operator==(const RoaringSetBitForwardIterator &o) const {
+ bool operator==(const RoaringSetBitBiDirectionalIterator &o) const {
return i.current_value == *o && i.has_value == o.i.has_value;
}
- bool operator!=(const RoaringSetBitForwardIterator &o) const {
+ bool operator!=(const RoaringSetBitBiDirectionalIterator &o) const {
return i.current_value != *o || i.has_value != o.i.has_value;
}
- explicit RoaringSetBitForwardIterator(const Roaring &parent,
- bool exhausted = false) {
- if (exhausted) {
- i.parent = &parent.roaring;
- i.container_index = INT32_MAX;
- i.has_value = false;
- i.current_value = UINT32_MAX;
- } else {
- api::roaring_iterator_init(&parent.roaring, &i);
- }
- }
-
api::roaring_uint32_iterator_t
i{}; // The empty constructor silences warnings from pedantic static
// analyzers.
};
-inline RoaringSetBitForwardIterator Roaring::begin() const {
- return RoaringSetBitForwardIterator(*this);
+inline RoaringSetBitBiDirectionalIterator Roaring::begin() const {
+ return RoaringSetBitBiDirectionalIterator(*this);
}
-inline RoaringSetBitForwardIterator &Roaring::end() const {
- static RoaringSetBitForwardIterator e(*this, true);
+inline RoaringSetBitBiDirectionalIterator &Roaring::end() const {
+ static RoaringSetBitBiDirectionalIterator e(*this, true);
return e;
}
diff --git a/contrib/libs/croaring/cpp/roaring64map.hh b/contrib/libs/croaring/cpp/roaring64map.hh
index 46e726a2d9..7de53cbd45 100644
--- a/contrib/libs/croaring/cpp/roaring64map.hh
+++ b/contrib/libs/croaring/cpp/roaring64map.hh
@@ -493,6 +493,8 @@ class Roaring64Map {
return iter->second.contains(lowBytes(x));
}
+ // TODO: implement `containsRange`
+
/**
* Compute the intersection of the current bitmap and the provided bitmap,
* writing the result in the current bitmap. The provided bitmap is not
@@ -785,17 +787,11 @@ class Roaring64Map {
// to avoid a clash with the Windows.h header under Windows
return roarings.size() ==
((uint64_t)(std::numeric_limits<uint32_t>::max)()) + 1
- ? std::all_of(
- roarings.cbegin(), roarings.cend(),
- [](const std::pair<const uint32_t, Roaring>
- &roaring_map_entry) {
- // roarings within map are saturated if cardinality
- // is uint32_t max + 1
- return roaring_map_entry.second.cardinality() ==
- ((uint64_t)(std::numeric_limits<
- uint32_t>::max)()) +
- 1;
- })
+ ? std::all_of(roarings.cbegin(), roarings.cend(),
+ [](const std::pair<const uint32_t, Roaring>
+ &roaring_map_entry) {
+ return roaring_map_entry.second.isFull();
+ })
: false;
}
@@ -1712,6 +1708,8 @@ class Roaring64Map {
/**
* Used to go through the set bits. Not optimally fast, but convenient.
+ *
+ * Recommend to explicitly construct this iterator.
*/
class Roaring64MapSetBitBiDirectionalIterator {
public:
@@ -1790,7 +1788,11 @@ class Roaring64MapSetBitBiDirectionalIterator {
return orig;
}
- bool move(const value_type &x) {
+ /**
+ * Move the iterator to the first value >= val.
+ * Return true if there is such a value.
+ */
+ bool move_equalorlarger(const value_type &x) {
map_iter = p->lower_bound(Roaring64Map::highBytes(x));
if (map_iter != p->cend()) {
roaring_iterator_init(&map_iter->second.roaring, &i);
@@ -1807,6 +1809,11 @@ class Roaring64MapSetBitBiDirectionalIterator {
return false;
}
+ /** DEPRECATED, use `move_equalorlarger`. */
+ CROARING_DEPRECATED bool move(const value_type &x) {
+ return move_equalorlarger(x);
+ }
+
type_of_iterator &operator--() { // --i, must return dec.value
if (map_iter == p->cend()) {
--map_iter;
diff --git a/contrib/libs/croaring/include/roaring/bitset/bitset.h b/contrib/libs/croaring/include/roaring/bitset/bitset.h
index c57d73d108..38ed39e806 100644
--- a/contrib/libs/croaring/include/roaring/bitset/bitset.h
+++ b/contrib/libs/croaring/include/roaring/bitset/bitset.h
@@ -131,7 +131,10 @@ inline bool bitset_get(const bitset_t *bitset, size_t i) {
/* Count number of bits set. */
size_t bitset_count(const bitset_t *bitset);
-/* Find the index of the first bit set. Or zero if the bitset is empty. */
+/* Returns true if no bit is set. */
+bool bitset_empty(const bitset_t *bitset);
+
+/* Find the index of the first bit set. Or SIZE_MAX if the bitset is empty. */
size_t bitset_minimum(const bitset_t *bitset);
/* Find the index of the last bit set. Or zero if the bitset is empty. */
diff --git a/contrib/libs/croaring/include/roaring/roaring.h b/contrib/libs/croaring/include/roaring/roaring.h
index 4256ad0ca5..7880e3f3d9 100644
--- a/contrib/libs/croaring/include/roaring/roaring.h
+++ b/contrib/libs/croaring/include/roaring/roaring.h
@@ -387,7 +387,9 @@ void roaring_bitmap_add_range_closed(roaring_bitmap_t *r, uint32_t min,
*/
inline void roaring_bitmap_add_range(roaring_bitmap_t *r, uint64_t min,
uint64_t max) {
- if (max <= min) return;
+ if (max <= min || min > (uint64_t)UINT32_MAX + 1) {
+ return;
+ }
roaring_bitmap_add_range_closed(r, (uint32_t)min, (uint32_t)(max - 1));
}
@@ -407,7 +409,9 @@ void roaring_bitmap_remove_range_closed(roaring_bitmap_t *r, uint32_t min,
*/
inline void roaring_bitmap_remove_range(roaring_bitmap_t *r, uint64_t min,
uint64_t max) {
- if (max <= min) return;
+ if (max <= min || min > (uint64_t)UINT32_MAX + 1) {
+ return;
+ }
roaring_bitmap_remove_range_closed(r, (uint32_t)min, (uint32_t)(max - 1));
}
@@ -436,6 +440,14 @@ bool roaring_bitmap_contains_range(const roaring_bitmap_t *r,
uint64_t range_start, uint64_t range_end);
/**
+ * Check whether a range of values from range_start (included)
+ * to range_end (included) is present
+ */
+bool roaring_bitmap_contains_range_closed(const roaring_bitmap_t *r,
+ uint32_t range_start,
+ uint32_t range_end);
+
+/**
* Check if an items is present, using context from a previous insert or search
* for speed optimization.
*
@@ -467,6 +479,12 @@ uint64_t roaring_bitmap_range_cardinality(const roaring_bitmap_t *r,
uint64_t range_end);
/**
+ * Returns the number of elements in the range [range_start, range_end].
+ */
+uint64_t roaring_bitmap_range_cardinality_closed(const roaring_bitmap_t *r,
+ uint32_t range_start,
+ uint32_t range_end);
+/**
* Returns true if the bitmap is empty (cardinality is zero).
*/
bool roaring_bitmap_is_empty(const roaring_bitmap_t *r);
@@ -868,6 +886,14 @@ roaring_bitmap_t *roaring_bitmap_flip(const roaring_bitmap_t *r1,
uint64_t range_start, uint64_t range_end);
/**
+ * Compute the negation of the bitmap in the interval [range_start, range_end].
+ * The number of negated values is range_end - range_start + 1.
+ * Areas outside the range are passed through unchanged.
+ */
+roaring_bitmap_t *roaring_bitmap_flip_closed(const roaring_bitmap_t *x1,
+ uint32_t range_start,
+ uint32_t range_end);
+/**
* compute (in place) the negation of the roaring bitmap within a specified
* interval: [range_start, range_end). The number of negated values is
* range_end - range_start.
@@ -877,6 +903,16 @@ void roaring_bitmap_flip_inplace(roaring_bitmap_t *r1, uint64_t range_start,
uint64_t range_end);
/**
+ * compute (in place) the negation of the roaring bitmap within a specified
+ * interval: [range_start, range_end]. The number of negated values is
+ * range_end - range_start + 1.
+ * Areas outside the range are passed through unchanged.
+ */
+void roaring_bitmap_flip_inplace_closed(roaring_bitmap_t *r1,
+ uint32_t range_start,
+ uint32_t range_end);
+
+/**
* Selects the element at index 'rank' where the smallest element is at index 0.
* If the size of the roaring bitmap is strictly greater than rank, then this
* function returns true and sets element to the element of given rank.
diff --git a/contrib/libs/croaring/include/roaring/roaring_version.h b/contrib/libs/croaring/include/roaring/roaring_version.h
index f211339f45..33926a2102 100644
--- a/contrib/libs/croaring/include/roaring/roaring_version.h
+++ b/contrib/libs/croaring/include/roaring/roaring_version.h
@@ -2,11 +2,11 @@
// /include/roaring/roaring_version.h automatically generated by release.py, do not change by hand
#ifndef ROARING_INCLUDE_ROARING_VERSION
#define ROARING_INCLUDE_ROARING_VERSION
-#define ROARING_VERSION "4.1.7"
+#define ROARING_VERSION "4.2.0"
enum {
ROARING_VERSION_MAJOR = 4,
- ROARING_VERSION_MINOR = 1,
- ROARING_VERSION_REVISION = 7
+ ROARING_VERSION_MINOR = 2,
+ ROARING_VERSION_REVISION = 0
};
#endif // ROARING_INCLUDE_ROARING_VERSION
// clang-format on \ No newline at end of file
diff --git a/contrib/libs/croaring/src/bitset.c b/contrib/libs/croaring/src/bitset.c
index 5d23af1e7b..96fee905ce 100644
--- a/contrib/libs/croaring/src/bitset.c
+++ b/contrib/libs/croaring/src/bitset.c
@@ -216,6 +216,15 @@ bool bitset_inplace_union(bitset_t *CROARING_CBITSET_RESTRICT b1,
return true;
}
+bool bitset_empty(const bitset_t *bitset) {
+ for (size_t k = 0; k < bitset->arraysize; k++) {
+ if (bitset->array[k] != 0) {
+ return false;
+ }
+ }
+ return true;
+}
+
size_t bitset_minimum(const bitset_t *bitset) {
for (size_t k = 0; k < bitset->arraysize; k++) {
uint64_t w = bitset->array[k];
@@ -223,7 +232,7 @@ size_t bitset_minimum(const bitset_t *bitset) {
return roaring_trailing_zeroes(w) + k * 64;
}
}
- return 0;
+ return SIZE_MAX;
}
bool bitset_grow(bitset_t *bitset, size_t newarraysize) {
diff --git a/contrib/libs/croaring/src/roaring.c b/contrib/libs/croaring/src/roaring.c
index 5a71fd39c3..8f6b5a4f37 100644
--- a/contrib/libs/croaring/src/roaring.c
+++ b/contrib/libs/croaring/src/roaring.c
@@ -1,5 +1,6 @@
#include <assert.h>
#include <inttypes.h>
+#include <limits.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
@@ -1330,15 +1331,22 @@ uint64_t roaring_bitmap_get_cardinality(const roaring_bitmap_t *r) {
uint64_t roaring_bitmap_range_cardinality(const roaring_bitmap_t *r,
uint64_t range_start,
uint64_t range_end) {
+ if (range_start >= range_end || range_start > (uint64_t)UINT32_MAX + 1) {
+ return 0;
+ }
+ return roaring_bitmap_range_cardinality_closed(r, (uint32_t)range_start,
+ (uint32_t)(range_end - 1));
+}
+
+uint64_t roaring_bitmap_range_cardinality_closed(const roaring_bitmap_t *r,
+ uint32_t range_start,
+ uint32_t range_end) {
const roaring_array_t *ra = &r->high_low_container;
- if (range_end > UINT32_MAX) {
- range_end = UINT32_MAX + UINT64_C(1);
- }
- if (range_start >= range_end) {
+ if (range_start > range_end) {
return 0;
}
- range_end--; // make range_end inclusive
+
// now we have: 0 <= range_start <= range_end <= UINT32_MAX
uint16_t minhb = (uint16_t)(range_start >> 16);
@@ -2005,11 +2013,18 @@ static void inplace_fully_flip_container(roaring_array_t *x1_arr, uint16_t hb) {
roaring_bitmap_t *roaring_bitmap_flip(const roaring_bitmap_t *x1,
uint64_t range_start,
uint64_t range_end) {
- if (range_start >= range_end) {
+ if (range_start >= range_end || range_start > (uint64_t)UINT32_MAX + 1) {
return roaring_bitmap_copy(x1);
}
- if (range_end >= UINT64_C(0x100000000)) {
- range_end = UINT64_C(0x100000000);
+ return roaring_bitmap_flip_closed(x1, (uint32_t)range_start,
+ (uint32_t)(range_end - 1));
+}
+
+roaring_bitmap_t *roaring_bitmap_flip_closed(const roaring_bitmap_t *x1,
+ uint32_t range_start,
+ uint32_t range_end) {
+ if (range_start > range_end) {
+ return roaring_bitmap_copy(x1);
}
roaring_bitmap_t *ans = roaring_bitmap_create();
@@ -2017,8 +2032,8 @@ roaring_bitmap_t *roaring_bitmap_flip(const roaring_bitmap_t *x1,
uint16_t hb_start = (uint16_t)(range_start >> 16);
const uint16_t lb_start = (uint16_t)range_start; // & 0xFFFF;
- uint16_t hb_end = (uint16_t)((range_end - 1) >> 16);
- const uint16_t lb_end = (uint16_t)(range_end - 1); // & 0xFFFF;
+ uint16_t hb_end = (uint16_t)(range_end >> 16);
+ const uint16_t lb_end = (uint16_t)range_end; // & 0xFFFF;
ra_append_copies_until(&ans->high_low_container, &x1->high_low_container,
hb_start, is_cow(x1));
@@ -2059,17 +2074,24 @@ roaring_bitmap_t *roaring_bitmap_flip(const roaring_bitmap_t *x1,
void roaring_bitmap_flip_inplace(roaring_bitmap_t *x1, uint64_t range_start,
uint64_t range_end) {
- if (range_start >= range_end) {
- return; // empty range
+ if (range_start >= range_end || range_start > (uint64_t)UINT32_MAX + 1) {
+ return;
}
- if (range_end >= UINT64_C(0x100000000)) {
- range_end = UINT64_C(0x100000000);
+ roaring_bitmap_flip_inplace_closed(x1, (uint32_t)range_start,
+ (uint32_t)(range_end - 1));
+}
+
+void roaring_bitmap_flip_inplace_closed(roaring_bitmap_t *x1,
+ uint32_t range_start,
+ uint32_t range_end) {
+ if (range_start > range_end) {
+ return; // empty range
}
uint16_t hb_start = (uint16_t)(range_start >> 16);
const uint16_t lb_start = (uint16_t)range_start;
- uint16_t hb_end = (uint16_t)((range_end - 1) >> 16);
- const uint16_t lb_end = (uint16_t)(range_end - 1);
+ uint16_t hb_end = (uint16_t)(range_end >> 16);
+ const uint16_t lb_end = (uint16_t)range_end;
if (hb_start == hb_end) {
inplace_flip_container(&x1->high_low_container, hb_start, lb_start,
@@ -2827,15 +2849,28 @@ bool roaring_bitmap_contains(const roaring_bitmap_t *r, uint32_t val) {
*/
bool roaring_bitmap_contains_range(const roaring_bitmap_t *r,
uint64_t range_start, uint64_t range_end) {
- if (range_end >= UINT64_C(0x100000000)) {
- range_end = UINT64_C(0x100000000);
+ if (range_start >= range_end || range_start > (uint64_t)UINT32_MAX + 1) {
+ return true;
}
- if (range_start >= range_end)
- return true; // empty range are always contained!
- if (range_end - range_start == 1)
+ return roaring_bitmap_contains_range_closed(r, (uint32_t)range_start,
+ (uint32_t)(range_end - 1));
+}
+
+/**
+ * Check whether a range of values from range_start (included) to range_end
+ * (included) is present
+ */
+bool roaring_bitmap_contains_range_closed(const roaring_bitmap_t *r,
+ uint32_t range_start,
+ uint32_t range_end) {
+ if (range_start > range_end) {
+ return true;
+ } // empty range are always contained!
+ if (range_end == range_start) {
return roaring_bitmap_contains(r, (uint32_t)range_start);
+ }
uint16_t hb_rs = (uint16_t)(range_start >> 16);
- uint16_t hb_re = (uint16_t)((range_end - 1) >> 16);
+ uint16_t hb_re = (uint16_t)(range_end >> 16);
const int32_t span = hb_re - hb_rs;
const int32_t hlc_sz = ra_get_size(&r->high_low_container);
if (hlc_sz < span + 1) {
@@ -2847,7 +2882,7 @@ bool roaring_bitmap_contains_range(const roaring_bitmap_t *r,
return false;
}
const uint32_t lb_rs = range_start & 0xFFFF;
- const uint32_t lb_re = ((range_end - 1) & 0xFFFF) + 1;
+ const uint32_t lb_re = (range_end & 0xFFFF) + 1;
uint8_t type;
container_t *c =
ra_get_container_at_index(&r->high_low_container, (uint16_t)is, &type);
diff --git a/contrib/libs/croaring/ya.make b/contrib/libs/croaring/ya.make
index 03863f4f54..78b8b40c9d 100644
--- a/contrib/libs/croaring/ya.make
+++ b/contrib/libs/croaring/ya.make
@@ -10,9 +10,9 @@ LICENSE(
LICENSE_TEXTS(.yandex_meta/licenses.list.txt)
-VERSION(4.1.7)
+VERSION(4.2.0)
-ORIGINAL_SOURCE(https://github.com/RoaringBitmap/CRoaring/archive/v4.1.7.tar.gz)
+ORIGINAL_SOURCE(https://github.com/RoaringBitmap/CRoaring/archive/v4.2.0.tar.gz)
ADDINCL(
GLOBAL contrib/libs/croaring/include
diff --git a/contrib/libs/curl/.yandex_meta/__init__.py b/contrib/libs/curl/.yandex_meta/__init__.py
index c0b275ea21..f0181761de 100644
--- a/contrib/libs/curl/.yandex_meta/__init__.py
+++ b/contrib/libs/curl/.yandex_meta/__init__.py
@@ -184,7 +184,6 @@ curl = GNUMakeNixProject(
"nwconio.h",
# NB: openssl/core_names.h appeared in OpenSSL 3.0, while we have only 1.1.1l at the time
"openssl/core_names.h",
- "openssl/ech.h",
"plarenas.h",
"proto/",
"quiche.h",
@@ -192,18 +191,16 @@ curl = GNUMakeNixProject(
"setup-vms.h",
"stabs.h",
"subauth.h",
- "unicode/uidna.h",
- "uv.h",
- "vquic-*",
- "wolfssh/*",
- "wolfssl/*",
+ "vquic/msh3.h",
+ "vquic/ngtcp2.h",
+ "vquic/quiche.h",
+ "wolfssh/",
+ "wolfssl/",
"hyper.h",
"gsasl.h",
"descrip",
"iodef",
"starlet",
- "x509asn1.h",
- "cipher_suite.h",
# Disable system includes of these headers, yet allow including lib/vtls/{rustls,bearssl}.h
"<rustls.h>",
"<bearssl.h>",
diff --git a/contrib/libs/curl/.yandex_meta/devtools.copyrights.report b/contrib/libs/curl/.yandex_meta/devtools.copyrights.report
index 94e1ba4538..533e4d8a58 100644
--- a/contrib/libs/curl/.yandex_meta/devtools.copyrights.report
+++ b/contrib/libs/curl/.yandex_meta/devtools.copyrights.report
@@ -105,17 +105,6 @@ BELONGS bin/ya.make ya.make
Belongs difference:
+ bin/ya.make
-KEEP COPYRIGHT_SERVICE_LABEL 29aec767c30e97ea136c9d10e5b07b99
-BELONGS ya.make
- License text:
- * Copyright (C) Jan Venekamp, <jan@venekamp.net>
- Scancode info:
- Original SPDX id: COPYRIGHT_SERVICE_LABEL
- Score : 100.00
- Match type : COPYRIGHT
- Files with this license:
- lib/vtls/cipher_suite.c [8:8]
-
KEEP COPYRIGHT_SERVICE_LABEL 38cad413a2ebb8a3334028596a877e60
BELONGS ya.make
License text:
@@ -131,18 +120,6 @@ BELONGS ya.make
lib/vtls/schannel.h [10:11]
lib/vtls/schannel_verify.c [8:10]
-KEEP COPYRIGHT_SERVICE_LABEL 4197a3d01f0ba1b0db6df039d59067a7
-BELONGS ya.make
- License text:
- * Copyright (C) Evgeny Grin (Karlson2k), <k2k@narod.ru>.
- Scancode info:
- Original SPDX id: COPYRIGHT_SERVICE_LABEL
- Score : 100.00
- Match type : COPYRIGHT
- Files with this license:
- lib/curl_sha512_256.c [8:8]
- lib/curl_sha512_256.h [10:10]
-
KEEP COPYRIGHT_SERVICE_LABEL 45323df52808e24e39741bd52fa522fb
BELONGS ya.make
License text:
@@ -197,15 +174,26 @@ BELONGS ya.make
License text:
* Copyright (C) Jacob Hoffman-Andrews,
* <github@hoffman-andrews.com>
- * Copyright (C) kpcyrd, <kpcyrd@archlinux.org>
Scancode info:
Original SPDX id: COPYRIGHT_SERVICE_LABEL
Score : 100.00
Match type : COPYRIGHT
Files with this license:
- lib/vtls/rustls.c [8:10]
+ lib/vtls/rustls.c [8:9]
lib/vtls/rustls.h [8:9]
+KEEP COPYRIGHT_SERVICE_LABEL 6acfa3297df1dc97d507e572a0645cd9
+BELONGS ya.make
+ License text:
+ Copyright (c) 1996 - 2023, Daniel Stenberg, <daniel@haxx.se>, and many
+ contributors, see the THANKS file.
+ Scancode info:
+ Original SPDX id: COPYRIGHT_SERVICE_LABEL
+ Score : 100.00
+ Match type : COPYRIGHT
+ Files with this license:
+ COPYING [3:4]
+
KEEP COPYRIGHT_SERVICE_LABEL 84500f86b97af8062c8463ad37fdf711
BELONGS bin/ya.make ya.make
License text:
@@ -232,30 +220,17 @@ BELONGS ya.make
lib/smb.c [8:9]
lib/smb.h [10:11]
-KEEP COPYRIGHT_SERVICE_LABEL 95a6917b277d6cc5ac045c9c8bbca830
-BELONGS ya.make
- License text:
- Copyright (c) 1996 - 2024, Daniel Stenberg, <daniel@haxx.se>, and many
- contributors, see the THANKS file.
- Scancode info:
- Original SPDX id: COPYRIGHT_SERVICE_LABEL
- Score : 100.00
- Match type : COPYRIGHT
- Files with this license:
- COPYING [3:4]
-
KEEP COPYRIGHT_SERVICE_LABEL 998d598c0b2c4665183fefe5ae17d48c
BELONGS ya.make
License text:
- * Copyright (c) 1995, 1996, 1997, 1998, 1999 Kungliga Tekniska Högskolan
- * (Royal Institute of Technology, Stockholm, Sweden).
- * Copyright (C) Daniel Stenberg
- * All rights reserved.
+ * Copyright (C) Daniel Stenberg, <daniel.se>, et al.
Scancode info:
Original SPDX id: COPYRIGHT_SERVICE_LABEL
Score : 100.00
Match type : COPYRIGHT
Files with this license:
+ lib/easygetopt.c [8:8]
+ lib/easyoptions.c [8:8]
lib/krb5.c [3:6]
KEEP COPYRIGHT_SERVICE_LABEL 9c50cbe37ab155bc81052d66295612bf
@@ -278,7 +253,6 @@ BELONGS ya.make
Score : 100.00
Match type : COPYRIGHT
Files with this license:
- CHANGES.md [2:2]
include/README.md [2:2]
include/curl/curl.h [10:10]
include/curl/curlver.h [10:10]
@@ -352,6 +326,8 @@ BELONGS ya.make
lib/curl_multibyte.h [10:10]
lib/curl_ntlm_core.c [8:8]
lib/curl_ntlm_core.h [10:10]
+ lib/curl_ntlm_wb.c [8:8]
+ lib/curl_ntlm_wb.h [10:10]
lib/curl_path.c [8:8]
lib/curl_printf.h [10:10]
lib/curl_range.c [8:8]
@@ -369,11 +345,8 @@ BELONGS ya.make
lib/curl_trc.c [8:8]
lib/curl_trc.h [10:10]
lib/curlx.h [10:10]
- lib/cw-out.c [8:8]
- lib/cw-out.h [10:10]
lib/dict.c [8:8]
lib/dict.h [10:10]
- lib/dllmain.c [8:8]
lib/doh.c [8:8]
lib/doh.h [10:10]
lib/dynbuf.c [8:8]
@@ -382,9 +355,7 @@ BELONGS ya.make
lib/dynhds.h [10:10]
lib/easy.c [8:8]
lib/easy_lock.h [10:10]
- lib/easygetopt.c [8:8]
lib/easyif.h [10:10]
- lib/easyoptions.c [8:8]
lib/easyoptions.h [10:10]
lib/escape.c [8:8]
lib/escape.h [10:10]
@@ -482,8 +453,6 @@ BELONGS ya.make
lib/rand.h [10:10]
lib/rename.c [8:8]
lib/rename.h [10:10]
- lib/request.c [8:8]
- lib/request.h [10:10]
lib/rtsp.c [8:8]
lib/rtsp.h [10:10]
lib/select.c [8:8]
@@ -556,11 +525,8 @@ BELONGS ya.make
lib/vquic/curl_msh3.h [10:10]
lib/vquic/curl_ngtcp2.c [8:8]
lib/vquic/curl_ngtcp2.h [10:10]
- lib/vquic/curl_osslq.c [8:8]
- lib/vquic/curl_osslq.h [10:10]
lib/vquic/curl_quiche.c [8:8]
lib/vquic/curl_quiche.h [10:10]
- lib/vquic/vquic-tls.c [8:8]
lib/vquic/vquic.c [8:8]
lib/vquic/vquic.h [10:10]
lib/vquic/vquic_int.h [10:10]
@@ -589,14 +555,13 @@ BELONGS ya.make
lib/vtls/wolfssl.c [8:8]
lib/vtls/wolfssl.h [10:10]
lib/vtls/x509asn1.c [8:8]
+ lib/vtls/x509asn1.h [11:11]
lib/warnless.c [8:8]
lib/warnless.h [10:10]
lib/ws.c [8:8]
lib/ws.h [10:10]
src/slist_wc.c [8:8]
src/slist_wc.h [10:10]
- src/terminal.c [8:8]
- src/terminal.h [10:10]
src/tool_binmode.c [8:8]
src/tool_binmode.h [10:10]
src/tool_bname.c [8:8]
@@ -611,8 +576,6 @@ BELONGS ya.make
src/tool_cb_rea.h [10:10]
src/tool_cb_see.c [8:8]
src/tool_cb_see.h [10:10]
- src/tool_cb_soc.c [8:8]
- src/tool_cb_soc.h [10:10]
src/tool_cb_wrt.c [8:8]
src/tool_cb_wrt.h [10:10]
src/tool_cfgable.c [8:8]
@@ -742,7 +705,7 @@ BELONGS ya.make
Score : 100.00
Match type : COPYRIGHT
Files with this license:
- lib/urlapi.c [138:138]
+ lib/urlapi.c [132:132]
KEEP COPYRIGHT_SERVICE_LABEL f38404a02e69976b94505df0c691bed0
BELONGS bin/ya.make ya.make
@@ -752,7 +715,7 @@ BELONGS bin/ya.make ya.make
Score : 100.00
Match type : COPYRIGHT
Files with this license:
- lib/md4.c [235:240]
+ lib/md4.c [232:237]
lib/md5.c [257:262]
Belongs difference:
+ bin/ya.make
diff --git a/contrib/libs/curl/.yandex_meta/devtools.licenses.report b/contrib/libs/curl/.yandex_meta/devtools.licenses.report
index b63b5522d6..b29469bc1a 100644
--- a/contrib/libs/curl/.yandex_meta/devtools.licenses.report
+++ b/contrib/libs/curl/.yandex_meta/devtools.licenses.report
@@ -50,8 +50,28 @@ BELONGS bin/ya.make ya.make
Belongs difference:
+ bin/ya.make
-KEEP Public-Domain 1f82bf70a14dc992db88e780ad169086
-BELONGS ya.make
+KEEP Public-Domain 18d8c996d50e6190086b35c34caec698
+BELONGS bin/ya.make ya.make
+ Note: matched license text is too long. Read it in the source files.
+ Scancode info:
+ Original SPDX id: LicenseRef-scancode-public-domain
+ Score : 98.04
+ Match type : NOTICE
+ Links : http://www.linfo.org/publicdomain.html, https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/licenses/public-domain.LICENSE
+ Files with this license:
+ lib/md5.c [252:269]
+ Scancode info:
+ Original SPDX id: LicenseRef-scancode-other-permissive
+ Score : 98.04
+ Match type : NOTICE
+ Links : https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/licenses/other-permissive.LICENSE
+ Files with this license:
+ lib/md5.c [252:269]
+ Belongs difference:
+ + bin/ya.make
+
+KEEP Public-Domain 18ed429b519e9abeeb3f768979574386
+BELONGS bin/ya.make ya.make
Note: matched license text is too long. Read it in the source files.
Scancode info:
Original SPDX id: LicenseRef-scancode-public-domain
@@ -59,14 +79,16 @@ BELONGS ya.make
Match type : NOTICE
Links : http://www.linfo.org/publicdomain.html, https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/licenses/public-domain.LICENSE
Files with this license:
- lib/md4.c [230:247]
+ lib/md4.c [227:244]
Scancode info:
Original SPDX id: LicenseRef-scancode-other-permissive
Score : 97.06
Match type : NOTICE
Links : https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/licenses/other-permissive.LICENSE
Files with this license:
- lib/md4.c [230:247]
+ lib/md4.c [227:244]
+ Belongs difference:
+ + bin/ya.make
KEEP ISC 42403c461b20603be5f466a4d8f336e4
BELONGS bin/ya.make ya.make
@@ -167,6 +189,8 @@ BELONGS bin/ya.make ya.make
lib/curl_multibyte.h [23:23]
lib/curl_ntlm_core.c [21:21]
lib/curl_ntlm_core.h [23:23]
+ lib/curl_ntlm_wb.c [21:21]
+ lib/curl_ntlm_wb.h [23:23]
lib/curl_printf.h [23:23]
lib/curl_range.c [21:21]
lib/curl_range.h [23:23]
@@ -177,8 +201,6 @@ BELONGS bin/ya.make ya.make
lib/curl_setup.h [23:23]
lib/curl_setup_once.h [23:23]
lib/curl_sha256.h [24:24]
- lib/curl_sha512_256.c [21:21]
- lib/curl_sha512_256.h [23:23]
lib/curl_sspi.c [21:21]
lib/curl_sspi.h [23:23]
lib/curl_threads.c [21:21]
@@ -186,11 +208,8 @@ BELONGS bin/ya.make ya.make
lib/curl_trc.c [21:21]
lib/curl_trc.h [23:23]
lib/curlx.h [23:23]
- lib/cw-out.c [21:21]
- lib/cw-out.h [23:23]
lib/dict.c [21:21]
lib/dict.h [23:23]
- lib/dllmain.c [21:21]
lib/doh.c [21:21]
lib/doh.h [23:23]
lib/dynbuf.c [21:21]
@@ -300,8 +319,6 @@ BELONGS bin/ya.make ya.make
lib/rand.h [23:23]
lib/rename.c [21:21]
lib/rename.h [23:23]
- lib/request.c [21:21]
- lib/request.h [23:23]
lib/rtsp.c [21:21]
lib/rtsp.h [23:23]
lib/select.c [21:21]
@@ -382,11 +399,8 @@ BELONGS bin/ya.make ya.make
lib/vquic/curl_msh3.h [23:23]
lib/vquic/curl_ngtcp2.c [21:21]
lib/vquic/curl_ngtcp2.h [23:23]
- lib/vquic/curl_osslq.c [21:21]
- lib/vquic/curl_osslq.h [23:23]
lib/vquic/curl_quiche.c [21:21]
lib/vquic/curl_quiche.h [23:23]
- lib/vquic/vquic-tls.c [21:21]
lib/vquic/vquic.c [21:21]
lib/vquic/vquic.h [23:23]
lib/vquic/vquic_int.h [23:23]
@@ -396,7 +410,6 @@ BELONGS bin/ya.make ya.make
lib/vssh/wolfssh.c [21:21]
lib/vtls/bearssl.c [21:21]
lib/vtls/bearssl.h [23:23]
- lib/vtls/cipher_suite.c [21:21]
lib/vtls/gtls.c [21:21]
lib/vtls/gtls.h [23:23]
lib/vtls/hostcheck.c [21:21]
@@ -408,7 +421,7 @@ BELONGS bin/ya.make ya.make
lib/vtls/mbedtls_threadlock.c [22:22]
lib/vtls/openssl.c [21:21]
lib/vtls/openssl.h [23:23]
- lib/vtls/rustls.c [23:23]
+ lib/vtls/rustls.c [22:22]
lib/vtls/rustls.h [22:22]
lib/vtls/schannel.c [23:23]
lib/vtls/schannel.h [24:24]
@@ -421,14 +434,13 @@ BELONGS bin/ya.make ya.make
lib/vtls/wolfssl.c [21:21]
lib/vtls/wolfssl.h [23:23]
lib/vtls/x509asn1.c [21:21]
+ lib/vtls/x509asn1.h [24:24]
lib/warnless.c [21:21]
lib/warnless.h [23:23]
lib/ws.c [21:21]
lib/ws.h [23:23]
src/slist_wc.c [21:21]
src/slist_wc.h [23:23]
- src/terminal.c [21:21]
- src/terminal.h [23:23]
src/tool_binmode.c [21:21]
src/tool_binmode.h [23:23]
src/tool_bname.c [21:21]
@@ -443,8 +455,6 @@ BELONGS bin/ya.make ya.make
src/tool_cb_rea.h [23:23]
src/tool_cb_see.c [21:21]
src/tool_cb_see.h [23:23]
- src/tool_cb_soc.c [21:21]
- src/tool_cb_soc.h [23:23]
src/tool_cb_wrt.c [21:21]
src/tool_cb_wrt.h [23:23]
src/tool_cfgable.c [21:21]
@@ -527,23 +537,10 @@ BELONGS bin/ya.make ya.make
Match type : TAG
Links : http://curl.haxx.se/, http://curl.haxx.se/docs/copyright.html, https://spdx.org/licenses/curl
Files with this license:
- CHANGES.md [4:4]
include/README.md [4:4]
Belongs difference:
+ bin/ya.make
-KEEP BSD-3-Clause 9c78af133154143779e53adf7bb85a8a
-BELONGS ya.make
- License text:
- /* BSD-style lwIP TCP/IP stack SPECIFIC */
- Scancode info:
- Original SPDX id: BSD-3-Clause
- Score : 90.00
- Match type : REFERENCE
- Links : http://www.opensource.org/licenses/BSD-3-Clause, https://spdx.org/licenses/BSD-3-Clause
- Files with this license:
- lib/setup-win32.h [42:42]
-
KEEP ISC a320c8c85dbcdf0a6f3f24f0dc7abbbb
BELONGS bin/ya.make ya.make
Note: matched license text is too long. Read it in the source files.
@@ -572,7 +569,7 @@ BELONGS bin/ya.make ya.make
KEEP curl a3ae8291721a79f582bf5823c43adb47
BELONGS bin/ya.make ya.make
-FILE_INCLUDE COPYING found in files: include/curl/curl.h at line 12, include/curl/curl.h at line 18, include/curl/curlver.h at line 12, include/curl/curlver.h at line 18, include/curl/easy.h at line 12, include/curl/easy.h at line 18, include/curl/header.h at line 12, include/curl/header.h at line 18, include/curl/mprintf.h at line 12, include/curl/mprintf.h at line 18, include/curl/multi.h at line 12, include/curl/multi.h at line 18, include/curl/options.h at line 12, include/curl/options.h at line 18, include/curl/stdcheaders.h at line 12, include/curl/stdcheaders.h at line 18, include/curl/system.h at line 12, include/curl/system.h at line 18, include/curl/typecheck-gcc.h at line 12, include/curl/typecheck-gcc.h at line 18, include/curl/urlapi.h at line 12, include/curl/urlapi.h at line 18, include/curl/websockets.h at line 12, include/curl/websockets.h at line 18, lib/altsvc.c at line 10, lib/altsvc.c at line 16, lib/altsvc.h at line 12, lib/altsvc.h at line 18, lib/amigaos.c at line 10, lib/amigaos.c at line 16, lib/amigaos.h at line 12, lib/amigaos.h at line 18, lib/arpa_telnet.h at line 12, lib/arpa_telnet.h at line 18, lib/asyn-ares.c at line 10, lib/asyn-ares.c at line 16, lib/asyn-thread.c at line 10, lib/asyn-thread.c at line 16, lib/asyn.h at line 12, lib/asyn.h at line 18, lib/base64.c at line 10, lib/base64.c at line 16, lib/bufq.c at line 10, lib/bufq.c at line 16, lib/bufq.h at line 12, lib/bufq.h at line 18, lib/bufref.c at line 10, lib/bufref.c at line 16, lib/bufref.h at line 12, lib/bufref.h at line 18, lib/cf-h1-proxy.c at line 10, lib/cf-h1-proxy.c at line 16, lib/cf-h1-proxy.h at line 12, lib/cf-h1-proxy.h at line 18, lib/cf-h2-proxy.c at line 10, lib/cf-h2-proxy.c at line 16, lib/cf-h2-proxy.h at line 12, lib/cf-h2-proxy.h at line 18, lib/cf-haproxy.c at line 10, lib/cf-haproxy.c at line 16, lib/cf-haproxy.h at line 12, lib/cf-haproxy.h at line 18, lib/cf-https-connect.c at line 10, lib/cf-https-connect.c at line 16, lib/cf-https-connect.h at line 12, lib/cf-https-connect.h at line 18, lib/cf-socket.c at line 10, lib/cf-socket.c at line 16, lib/cf-socket.h at line 12, lib/cf-socket.h at line 18, lib/cfilters.c at line 10, lib/cfilters.c at line 16, lib/cfilters.h at line 12, lib/cfilters.h at line 18, lib/conncache.c at line 11, lib/conncache.c at line 17, lib/conncache.h at line 13, lib/conncache.h at line 19, lib/connect.c at line 10, lib/connect.c at line 16, lib/connect.h at line 12, lib/connect.h at line 18, lib/content_encoding.c at line 10, lib/content_encoding.c at line 16, lib/content_encoding.h at line 12, lib/content_encoding.h at line 18, lib/cookie.c at line 10, lib/cookie.c at line 16, lib/cookie.h at line 12, lib/cookie.h at line 18, lib/curl_addrinfo.c at line 10, lib/curl_addrinfo.c at line 16, lib/curl_addrinfo.h at line 12, lib/curl_addrinfo.h at line 18, lib/curl_base64.h at line 12, lib/curl_base64.h at line 18, lib/curl_ctype.h at line 12, lib/curl_ctype.h at line 18, lib/curl_des.c at line 10, lib/curl_des.c at line 16, lib/curl_des.h at line 12, lib/curl_des.h at line 18, lib/curl_endian.c at line 10, lib/curl_endian.c at line 16, lib/curl_endian.h at line 12, lib/curl_endian.h at line 18, lib/curl_fnmatch.c at line 10, lib/curl_fnmatch.c at line 16, lib/curl_fnmatch.h at line 12, lib/curl_fnmatch.h at line 18, lib/curl_get_line.c at line 10, lib/curl_get_line.c at line 16, lib/curl_get_line.h at line 12, lib/curl_get_line.h at line 18, lib/curl_gethostname.c at line 10, lib/curl_gethostname.c at line 16, lib/curl_gethostname.h at line 12, lib/curl_gethostname.h at line 18, lib/curl_gssapi.c at line 10, lib/curl_gssapi.c at line 16, lib/curl_hmac.h at line 12, lib/curl_hmac.h at line 18, lib/curl_krb5.h at line 12, lib/curl_krb5.h at line 18, lib/curl_ldap.h at line 12, lib/curl_ldap.h at line 18, lib/curl_md4.h at line 12, lib/curl_md4.h at line 18, lib/curl_md5.h at line 12, lib/curl_md5.h at line 18, lib/curl_memory.h at line 12, lib/curl_memory.h at line 18, lib/curl_memrchr.c at line 10, lib/curl_memrchr.c at line 16, lib/curl_memrchr.h at line 12, lib/curl_memrchr.h at line 18, lib/curl_multibyte.c at line 10, lib/curl_multibyte.c at line 16, lib/curl_multibyte.h at line 12, lib/curl_multibyte.h at line 18, lib/curl_ntlm_core.c at line 10, lib/curl_ntlm_core.c at line 16, lib/curl_ntlm_core.h at line 12, lib/curl_ntlm_core.h at line 18, lib/curl_path.c at line 10, lib/curl_path.c at line 16, lib/curl_printf.h at line 12, lib/curl_printf.h at line 18, lib/curl_range.c at line 10, lib/curl_range.c at line 16, lib/curl_range.h at line 12, lib/curl_range.h at line 18, lib/curl_rtmp.c at line 11, lib/curl_rtmp.c at line 17, lib/curl_rtmp.h at line 12, lib/curl_rtmp.h at line 18, lib/curl_sasl.c at line 10, lib/curl_sasl.c at line 16, lib/curl_sasl.h at line 12, lib/curl_sasl.h at line 18, lib/curl_setup.h at line 12, lib/curl_setup.h at line 18, lib/curl_setup_once.h at line 12, lib/curl_setup_once.h at line 18, lib/curl_sha256.h at line 13, lib/curl_sha256.h at line 19, lib/curl_sha512_256.c at line 10, lib/curl_sha512_256.c at line 16, lib/curl_sha512_256.h at line 12, lib/curl_sha512_256.h at line 18, lib/curl_sspi.c at line 10, lib/curl_sspi.c at line 16, lib/curl_sspi.h at line 12, lib/curl_sspi.h at line 18, lib/curl_threads.c at line 10, lib/curl_threads.c at line 16, lib/curl_threads.h at line 12, lib/curl_threads.h at line 18, lib/curl_trc.c at line 10, lib/curl_trc.c at line 16, lib/curl_trc.h at line 12, lib/curl_trc.h at line 18, lib/curlx.h at line 12, lib/curlx.h at line 18, lib/cw-out.c at line 10, lib/cw-out.c at line 16, lib/cw-out.h at line 12, lib/cw-out.h at line 18, lib/dict.c at line 10, lib/dict.c at line 16, lib/dict.h at line 12, lib/dict.h at line 18, lib/dllmain.c at line 10, lib/dllmain.c at line 16, lib/doh.c at line 10, lib/doh.c at line 16, lib/doh.h at line 12, lib/doh.h at line 18, lib/dynbuf.c at line 10, lib/dynbuf.c at line 16, lib/dynbuf.h at line 12, lib/dynbuf.h at line 18, lib/dynhds.c at line 10, lib/dynhds.c at line 16, lib/dynhds.h at line 12, lib/dynhds.h at line 18, lib/easy.c at line 10, lib/easy.c at line 16, lib/easy_lock.h at line 12, lib/easy_lock.h at line 18, lib/easygetopt.c at line 10, lib/easygetopt.c at line 16, lib/easyif.h at line 12, lib/easyif.h at line 18, lib/easyoptions.c at line 10, lib/easyoptions.c at line 16, lib/easyoptions.h at line 12, lib/easyoptions.h at line 18, lib/escape.c at line 10, lib/escape.c at line 16, lib/escape.h at line 12, lib/escape.h at line 18, lib/file.c at line 10, lib/file.c at line 16, lib/file.h at line 12, lib/file.h at line 18, lib/fileinfo.c at line 10, lib/fileinfo.c at line 16, lib/fileinfo.h at line 12, lib/fileinfo.h at line 18, lib/fopen.c at line 10, lib/fopen.c at line 16, lib/fopen.h at line 12, lib/fopen.h at line 18, lib/formdata.c at line 10, lib/formdata.c at line 16, lib/formdata.h at line 12, lib/formdata.h at line 18, lib/ftp.c at line 10, lib/ftp.c at line 16, lib/ftp.h at line 12, lib/ftp.h at line 18, lib/ftplistparser.c at line 10, lib/ftplistparser.c at line 16, lib/ftplistparser.h at line 12, lib/ftplistparser.h at line 18, lib/functypes.h at line 12, lib/functypes.h at line 18, lib/getenv.c at line 10, lib/getenv.c at line 16, lib/getinfo.c at line 10, lib/getinfo.c at line 16, lib/getinfo.h at line 12, lib/getinfo.h at line 18, lib/gopher.c at line 10, lib/gopher.c at line 16, lib/gopher.h at line 12, lib/gopher.h at line 18, lib/hash.c at line 10, lib/hash.c at line 16, lib/hash.h at line 12, lib/hash.h at line 18, lib/headers.c at line 10, lib/headers.c at line 16, lib/headers.h at line 12, lib/headers.h at line 18, lib/hmac.c at line 10, lib/hmac.c at line 16, lib/hostasyn.c at line 10, lib/hostasyn.c at line 16, lib/hostip.c at line 10, lib/hostip.c at line 16, lib/hostip.h at line 12, lib/hostip.h at line 18, lib/hostip4.c at line 10, lib/hostip4.c at line 16, lib/hostip6.c at line 10, lib/hostip6.c at line 16, lib/hostsyn.c at line 10, lib/hostsyn.c at line 16, lib/hsts.c at line 10, lib/hsts.c at line 16, lib/hsts.h at line 12, lib/hsts.h at line 18, lib/http.c at line 10, lib/http.c at line 16, lib/http.h at line 12, lib/http.h at line 18, lib/http1.c at line 10, lib/http1.c at line 16, lib/http1.h at line 12, lib/http1.h at line 18, lib/http2.c at line 10, lib/http2.c at line 16, lib/http2.h at line 12, lib/http2.h at line 18, lib/http_chunks.c at line 10, lib/http_chunks.c at line 16, lib/http_chunks.h at line 12, lib/http_chunks.h at line 18, lib/http_digest.c at line 10, lib/http_digest.c at line 16, lib/http_digest.h at line 12, lib/http_digest.h at line 18, lib/http_negotiate.c at line 10, lib/http_negotiate.c at line 16, lib/http_negotiate.h at line 12, lib/http_negotiate.h at line 18, lib/http_ntlm.c at line 10, lib/http_ntlm.c at line 16, lib/http_ntlm.h at line 12, lib/http_ntlm.h at line 18, lib/http_proxy.c at line 10, lib/http_proxy.c at line 16, lib/http_proxy.h at line 12, lib/http_proxy.h at line 18, lib/idn.c at line 10, lib/idn.c at line 16, lib/idn.h at line 12, lib/idn.h at line 18, lib/if2ip.c at line 10, lib/if2ip.c at line 16, lib/if2ip.h at line 12, lib/if2ip.h at line 18, lib/imap.c at line 10, lib/imap.c at line 16, lib/imap.h at line 12, lib/imap.h at line 18, lib/inet_ntop.h at line 12, lib/inet_ntop.h at line 18, lib/inet_pton.h at line 12, lib/inet_pton.h at line 18, lib/ldap.c at line 10, lib/ldap.c at line 16, lib/llist.c at line 10, lib/llist.c at line 16, lib/llist.h at line 12, lib/llist.h at line 18, lib/macos.c at line 10, lib/macos.c at line 16, lib/macos.h at line 12, lib/macos.h at line 18, lib/md4.c at line 10, lib/md4.c at line 16, lib/md5.c at line 10, lib/md5.c at line 16, lib/memdebug.c at line 10, lib/memdebug.c at line 16, lib/memdebug.h at line 13, lib/memdebug.h at line 19, lib/mime.c at line 10, lib/mime.c at line 16, lib/mime.h at line 12, lib/mime.h at line 18, lib/mprintf.c at line 10, lib/mprintf.c at line 16, lib/mqtt.c at line 11, lib/mqtt.c at line 17, lib/mqtt.h at line 12, lib/mqtt.h at line 18, lib/multi.c at line 10, lib/multi.c at line 16, lib/multihandle.h at line 12, lib/multihandle.h at line 18, lib/multiif.h at line 12, lib/multiif.h at line 18, lib/netrc.c at line 10, lib/netrc.c at line 16, lib/netrc.h at line 12, lib/netrc.h at line 18, lib/nonblock.c at line 10, lib/nonblock.c at line 16, lib/nonblock.h at line 12, lib/nonblock.h at line 18, lib/noproxy.c at line 10, lib/noproxy.c at line 16, lib/noproxy.h at line 12, lib/noproxy.h at line 18, lib/openldap.c at line 11, lib/openldap.c at line 17, lib/parsedate.c at line 10, lib/parsedate.c at line 16, lib/parsedate.h at line 12, lib/parsedate.h at line 18, lib/pingpong.c at line 10, lib/pingpong.c at line 16, lib/pingpong.h at line 12, lib/pingpong.h at line 18, lib/pop3.c at line 10, lib/pop3.c at line 16, lib/pop3.h at line 12, lib/pop3.h at line 18, lib/progress.c at line 10, lib/progress.c at line 16, lib/progress.h at line 12, lib/progress.h at line 18, lib/psl.c at line 10, lib/psl.c at line 16, lib/psl.h at line 12, lib/psl.h at line 18, lib/rand.c at line 10, lib/rand.c at line 16, lib/rand.h at line 12, lib/rand.h at line 18, lib/rename.c at line 10, lib/rename.c at line 16, lib/rename.h at line 12, lib/rename.h at line 18, lib/request.c at line 10, lib/request.c at line 16, lib/request.h at line 12, lib/request.h at line 18, lib/rtsp.c at line 10, lib/rtsp.c at line 16, lib/rtsp.h at line 12, lib/rtsp.h at line 18, lib/select.c at line 10, lib/select.c at line 16, lib/select.h at line 12, lib/select.h at line 18, lib/sendf.c at line 10, lib/sendf.c at line 16, lib/sendf.h at line 12, lib/sendf.h at line 18, lib/setopt.c at line 10, lib/setopt.c at line 16, lib/setopt.h at line 12, lib/setopt.h at line 18, lib/setup-win32.h at line 12, lib/setup-win32.h at line 18, lib/sha256.c at line 11, lib/sha256.c at line 17, lib/share.c at line 10, lib/share.c at line 16, lib/share.h at line 12, lib/share.h at line 18, lib/sigpipe.h at line 12, lib/sigpipe.h at line 18, lib/slist.c at line 10, lib/slist.c at line 16, lib/slist.h at line 12, lib/slist.h at line 18, lib/smb.c at line 11, lib/smb.c at line 17, lib/smb.h at line 13, lib/smb.h at line 19, lib/smtp.c at line 10, lib/smtp.c at line 16, lib/smtp.h at line 12, lib/smtp.h at line 18, lib/sockaddr.h at line 12, lib/sockaddr.h at line 18, lib/socketpair.c at line 10, lib/socketpair.c at line 16, lib/socketpair.h at line 12, lib/socketpair.h at line 18, lib/socks.c at line 10, lib/socks.c at line 16, lib/socks.h at line 12, lib/socks.h at line 18, lib/socks_gssapi.c at line 11, lib/socks_gssapi.c at line 17, lib/socks_sspi.c at line 11, lib/socks_sspi.c at line 17, lib/speedcheck.c at line 10, lib/speedcheck.c at line 16, lib/speedcheck.h at line 12, lib/speedcheck.h at line 18, lib/splay.c at line 10, lib/splay.c at line 16, lib/splay.h at line 12, lib/splay.h at line 18, lib/strcase.c at line 10, lib/strcase.c at line 16, lib/strcase.h at line 12, lib/strcase.h at line 18, lib/strdup.c at line 10, lib/strdup.c at line 16, lib/strdup.h at line 12, lib/strdup.h at line 18, lib/strerror.c at line 10, lib/strerror.c at line 16, lib/strerror.h at line 12, lib/strerror.h at line 18, lib/strtok.c at line 10, lib/strtok.c at line 16, lib/strtok.h at line 12, lib/strtok.h at line 18, lib/strtoofft.c at line 10, lib/strtoofft.c at line 16, lib/strtoofft.h at line 12, lib/strtoofft.h at line 18, lib/system_win32.c at line 10, lib/system_win32.c at line 16, lib/system_win32.h at line 12, lib/system_win32.h at line 18, lib/telnet.c at line 10, lib/telnet.c at line 16, lib/telnet.h at line 12, lib/telnet.h at line 18, lib/tftp.c at line 10, lib/tftp.c at line 16, lib/tftp.h at line 12, lib/tftp.h at line 18, lib/timediff.c at line 10, lib/timediff.c at line 16, lib/timediff.h at line 12, lib/timediff.h at line 18, lib/timeval.c at line 10, lib/timeval.c at line 16, lib/timeval.h at line 12, lib/timeval.h at line 18, lib/transfer.c at line 10, lib/transfer.c at line 16, lib/transfer.h at line 12, lib/transfer.h at line 18, lib/url.c at line 10, lib/url.c at line 16, lib/url.h at line 12, lib/url.h at line 18, lib/urlapi-int.h at line 12, lib/urlapi-int.h at line 18, lib/urlapi.c at line 10, lib/urlapi.c at line 16, lib/urldata.h at line 12, lib/urldata.h at line 18, lib/vauth/cleartext.c at line 10, lib/vauth/cleartext.c at line 16, lib/vauth/cram.c at line 10, lib/vauth/cram.c at line 16, lib/vauth/digest.c at line 10, lib/vauth/digest.c at line 16, lib/vauth/digest.h at line 12, lib/vauth/digest.h at line 18, lib/vauth/digest_sspi.c at line 11, lib/vauth/digest_sspi.c at line 17, lib/vauth/gsasl.c at line 10, lib/vauth/gsasl.c at line 16, lib/vauth/krb5_gssapi.c at line 11, lib/vauth/krb5_gssapi.c at line 17, lib/vauth/krb5_sspi.c at line 10, lib/vauth/krb5_sspi.c at line 16, lib/vauth/ntlm.c at line 10, lib/vauth/ntlm.c at line 16, lib/vauth/ntlm.h at line 12, lib/vauth/ntlm.h at line 18, lib/vauth/ntlm_sspi.c at line 10, lib/vauth/ntlm_sspi.c at line 16, lib/vauth/oauth2.c at line 10, lib/vauth/oauth2.c at line 16, lib/vauth/spnego_gssapi.c at line 10, lib/vauth/spnego_gssapi.c at line 16, lib/vauth/spnego_sspi.c at line 10, lib/vauth/spnego_sspi.c at line 16, lib/vauth/vauth.c at line 10, lib/vauth/vauth.c at line 16, lib/vauth/vauth.h at line 12, lib/vauth/vauth.h at line 18, lib/version.c at line 10, lib/version.c at line 16, lib/version_win32.c at line 10, lib/version_win32.c at line 16, lib/version_win32.h at line 12, lib/version_win32.h at line 18, lib/vquic/curl_msh3.c at line 10, lib/vquic/curl_msh3.c at line 16, lib/vquic/curl_msh3.h at line 12, lib/vquic/curl_msh3.h at line 18, lib/vquic/curl_ngtcp2.c at line 10, lib/vquic/curl_ngtcp2.c at line 16, lib/vquic/curl_ngtcp2.h at line 12, lib/vquic/curl_ngtcp2.h at line 18, lib/vquic/curl_osslq.c at line 10, lib/vquic/curl_osslq.c at line 16, lib/vquic/curl_osslq.h at line 12, lib/vquic/curl_osslq.h at line 18, lib/vquic/curl_quiche.c at line 10, lib/vquic/curl_quiche.c at line 16, lib/vquic/curl_quiche.h at line 12, lib/vquic/curl_quiche.h at line 18, lib/vquic/vquic-tls.c at line 10, lib/vquic/vquic-tls.c at line 16, lib/vquic/vquic.c at line 10, lib/vquic/vquic.c at line 16, lib/vquic/vquic.h at line 12, lib/vquic/vquic.h at line 18, lib/vquic/vquic_int.h at line 12, lib/vquic/vquic_int.h at line 18, lib/vssh/libssh.c at line 13, lib/vssh/libssh.c at line 19, lib/vssh/libssh2.c at line 10, lib/vssh/libssh2.c at line 16, lib/vssh/ssh.h at line 12, lib/vssh/ssh.h at line 18, lib/vssh/wolfssh.c at line 10, lib/vssh/wolfssh.c at line 16, lib/vtls/bearssl.c at line 10, lib/vtls/bearssl.c at line 16, lib/vtls/bearssl.h at line 12, lib/vtls/bearssl.h at line 18, lib/vtls/cipher_suite.c at line 10, lib/vtls/cipher_suite.c at line 16, lib/vtls/gtls.c at line 10, lib/vtls/gtls.c at line 16, lib/vtls/gtls.h at line 12, lib/vtls/gtls.h at line 18, lib/vtls/hostcheck.c at line 10, lib/vtls/hostcheck.c at line 16, lib/vtls/hostcheck.h at line 12, lib/vtls/hostcheck.h at line 18, lib/vtls/keylog.c at line 10, lib/vtls/keylog.c at line 16, lib/vtls/keylog.h at line 12, lib/vtls/keylog.h at line 18, lib/vtls/mbedtls.c at line 11, lib/vtls/mbedtls.c at line 17, lib/vtls/mbedtls.h at line 13, lib/vtls/mbedtls.h at line 19, lib/vtls/mbedtls_threadlock.c at line 11, lib/vtls/mbedtls_threadlock.c at line 17, lib/vtls/openssl.c at line 10, lib/vtls/openssl.c at line 16, lib/vtls/openssl.h at line 12, lib/vtls/openssl.h at line 18, lib/vtls/rustls.c at line 12, lib/vtls/rustls.c at line 18, lib/vtls/rustls.h at line 11, lib/vtls/rustls.h at line 17, lib/vtls/schannel.c at line 12, lib/vtls/schannel.c at line 18, lib/vtls/schannel.h at line 13, lib/vtls/schannel.h at line 19, lib/vtls/schannel_verify.c at line 12, lib/vtls/schannel_verify.c at line 18, lib/vtls/sectransp.c at line 11, lib/vtls/sectransp.c at line 17, lib/vtls/sectransp.h at line 13, lib/vtls/sectransp.h at line 19, lib/vtls/vtls.c at line 10, lib/vtls/vtls.c at line 16, lib/vtls/vtls.h at line 12, lib/vtls/vtls.h at line 18, lib/vtls/vtls_int.h at line 12, lib/vtls/vtls_int.h at line 18, lib/vtls/wolfssl.c at line 10, lib/vtls/wolfssl.c at line 16, lib/vtls/wolfssl.h at line 12, lib/vtls/wolfssl.h at line 18, lib/vtls/x509asn1.c at line 10, lib/vtls/x509asn1.c at line 16, lib/warnless.c at line 10, lib/warnless.c at line 16, lib/warnless.h at line 12, lib/warnless.h at line 18, lib/ws.c at line 10, lib/ws.c at line 16, lib/ws.h at line 12, lib/ws.h at line 18, src/slist_wc.c at line 10, src/slist_wc.c at line 16, src/slist_wc.h at line 12, src/slist_wc.h at line 18, src/terminal.c at line 10, src/terminal.c at line 16, src/terminal.h at line 12, src/terminal.h at line 18, src/tool_binmode.c at line 10, src/tool_binmode.c at line 16, src/tool_binmode.h at line 12, src/tool_binmode.h at line 18, src/tool_bname.c at line 10, src/tool_bname.c at line 16, src/tool_bname.h at line 12, src/tool_bname.h at line 18, src/tool_cb_dbg.c at line 10, src/tool_cb_dbg.c at line 16, src/tool_cb_dbg.h at line 12, src/tool_cb_dbg.h at line 18, src/tool_cb_hdr.c at line 10, src/tool_cb_hdr.c at line 16, src/tool_cb_hdr.h at line 12, src/tool_cb_hdr.h at line 18, src/tool_cb_prg.c at line 10, src/tool_cb_prg.c at line 16, src/tool_cb_prg.h at line 12, src/tool_cb_prg.h at line 18, src/tool_cb_rea.c at line 10, src/tool_cb_rea.c at line 16, src/tool_cb_rea.h at line 12, src/tool_cb_rea.h at line 18, src/tool_cb_see.c at line 10, src/tool_cb_see.c at line 16, src/tool_cb_see.h at line 12, src/tool_cb_see.h at line 18, src/tool_cb_soc.c at line 10, src/tool_cb_soc.c at line 16, src/tool_cb_soc.h at line 12, src/tool_cb_soc.h at line 18, src/tool_cb_wrt.c at line 10, src/tool_cb_wrt.c at line 16, src/tool_cb_wrt.h at line 12, src/tool_cb_wrt.h at line 18, src/tool_cfgable.c at line 10, src/tool_cfgable.c at line 16, src/tool_cfgable.h at line 12, src/tool_cfgable.h at line 18, src/tool_dirhie.c at line 10, src/tool_dirhie.c at line 16, src/tool_dirhie.h at line 12, src/tool_dirhie.h at line 18, src/tool_doswin.c at line 10, src/tool_doswin.c at line 16, src/tool_doswin.h at line 12, src/tool_doswin.h at line 18, src/tool_easysrc.c at line 10, src/tool_easysrc.c at line 16, src/tool_easysrc.h at line 12, src/tool_easysrc.h at line 18, src/tool_filetime.c at line 10, src/tool_filetime.c at line 16, src/tool_filetime.h at line 12, src/tool_filetime.h at line 18, src/tool_findfile.c at line 10, src/tool_findfile.c at line 16, src/tool_findfile.h at line 12, src/tool_findfile.h at line 18, src/tool_formparse.c at line 10, src/tool_formparse.c at line 16, src/tool_formparse.h at line 12, src/tool_formparse.h at line 18, src/tool_getparam.c at line 10, src/tool_getparam.c at line 16, src/tool_getparam.h at line 12, src/tool_getparam.h at line 18, src/tool_getpass.c at line 10, src/tool_getpass.c at line 16, src/tool_getpass.h at line 12, src/tool_getpass.h at line 18, src/tool_help.c at line 10, src/tool_help.c at line 16, src/tool_help.h at line 12, src/tool_help.h at line 18, src/tool_helpers.c at line 10, src/tool_helpers.c at line 16, src/tool_helpers.h at line 12, src/tool_helpers.h at line 18, src/tool_hugehelp.h at line 12, src/tool_hugehelp.h at line 18, src/tool_ipfs.c at line 10, src/tool_ipfs.c at line 16, src/tool_ipfs.h at line 12, src/tool_ipfs.h at line 18, src/tool_libinfo.c at line 10, src/tool_libinfo.c at line 16, src/tool_libinfo.h at line 12, src/tool_libinfo.h at line 18, src/tool_listhelp.c at line 10, src/tool_listhelp.c at line 16, src/tool_main.c at line 10, src/tool_main.c at line 16, src/tool_main.h at line 12, src/tool_main.h at line 18, src/tool_msgs.c at line 10, src/tool_msgs.c at line 16, src/tool_msgs.h at line 12, src/tool_msgs.h at line 18, src/tool_operate.c at line 10, src/tool_operate.c at line 16, src/tool_operate.h at line 12, src/tool_operate.h at line 18, src/tool_operhlp.c at line 10, src/tool_operhlp.c at line 16, src/tool_operhlp.h at line 12, src/tool_operhlp.h at line 18, src/tool_paramhlp.c at line 10, src/tool_paramhlp.c at line 16, src/tool_paramhlp.h at line 12, src/tool_paramhlp.h at line 18, src/tool_parsecfg.c at line 10, src/tool_parsecfg.c at line 16, src/tool_parsecfg.h at line 12, src/tool_parsecfg.h at line 18, src/tool_progress.c at line 10, src/tool_progress.c at line 16, src/tool_progress.h at line 12, src/tool_progress.h at line 18, src/tool_sdecls.h at line 12, src/tool_sdecls.h at line 18, src/tool_setopt.c at line 10, src/tool_setopt.c at line 16, src/tool_setopt.h at line 12, src/tool_setopt.h at line 18, src/tool_setup.h at line 12, src/tool_setup.h at line 18, src/tool_sleep.c at line 10, src/tool_sleep.c at line 16, src/tool_sleep.h at line 12, src/tool_sleep.h at line 18, src/tool_stderr.c at line 10, src/tool_stderr.c at line 16, src/tool_stderr.h at line 12, src/tool_stderr.h at line 18, src/tool_strdup.c at line 10, src/tool_strdup.c at line 16, src/tool_strdup.h at line 12, src/tool_strdup.h at line 18, src/tool_urlglob.c at line 10, src/tool_urlglob.c at line 16, src/tool_urlglob.h at line 12, src/tool_urlglob.h at line 18, src/tool_util.c at line 10, src/tool_util.c at line 16, src/tool_util.h at line 12, src/tool_util.h at line 18, src/tool_version.h at line 12, src/tool_version.h at line 18, src/tool_vms.c at line 10, src/tool_vms.c at line 16, src/tool_vms.h at line 12, src/tool_vms.h at line 18, src/tool_writeout.c at line 10, src/tool_writeout.c at line 16, src/tool_writeout.h at line 12, src/tool_writeout.h at line 18, src/tool_writeout_json.c at line 10, src/tool_writeout_json.c at line 16, src/tool_writeout_json.h at line 12, src/tool_writeout_json.h at line 18, src/tool_xattr.c at line 10, src/tool_xattr.c at line 16, src/tool_xattr.h at line 12, src/tool_xattr.h at line 18, src/var.c at line 10, src/var.c at line 16, src/var.h at line 12, src/var.h at line 18
+FILE_INCLUDE COPYING found in files: include/curl/curl.h at line 12, include/curl/curl.h at line 18, include/curl/curlver.h at line 12, include/curl/curlver.h at line 18, include/curl/easy.h at line 12, include/curl/easy.h at line 18, include/curl/header.h at line 12, include/curl/header.h at line 18, include/curl/mprintf.h at line 12, include/curl/mprintf.h at line 18, include/curl/multi.h at line 12, include/curl/multi.h at line 18, include/curl/options.h at line 12, include/curl/options.h at line 18, include/curl/stdcheaders.h at line 12, include/curl/stdcheaders.h at line 18, include/curl/system.h at line 12, include/curl/system.h at line 18, include/curl/typecheck-gcc.h at line 12, include/curl/typecheck-gcc.h at line 18, include/curl/urlapi.h at line 12, include/curl/urlapi.h at line 18, include/curl/websockets.h at line 12, include/curl/websockets.h at line 18, lib/altsvc.c at line 10, lib/altsvc.c at line 16, lib/altsvc.h at line 12, lib/altsvc.h at line 18, lib/amigaos.c at line 10, lib/amigaos.c at line 16, lib/amigaos.h at line 12, lib/amigaos.h at line 18, lib/arpa_telnet.h at line 12, lib/arpa_telnet.h at line 18, lib/asyn-ares.c at line 10, lib/asyn-ares.c at line 16, lib/asyn-thread.c at line 10, lib/asyn-thread.c at line 16, lib/asyn.h at line 12, lib/asyn.h at line 18, lib/base64.c at line 10, lib/base64.c at line 16, lib/bufq.c at line 10, lib/bufq.c at line 16, lib/bufq.h at line 12, lib/bufq.h at line 18, lib/bufref.c at line 10, lib/bufref.c at line 16, lib/bufref.h at line 12, lib/bufref.h at line 18, lib/cf-h1-proxy.c at line 10, lib/cf-h1-proxy.c at line 16, lib/cf-h1-proxy.h at line 12, lib/cf-h1-proxy.h at line 18, lib/cf-h2-proxy.c at line 10, lib/cf-h2-proxy.c at line 16, lib/cf-h2-proxy.h at line 12, lib/cf-h2-proxy.h at line 18, lib/cf-haproxy.c at line 10, lib/cf-haproxy.c at line 16, lib/cf-haproxy.h at line 12, lib/cf-haproxy.h at line 18, lib/cf-https-connect.c at line 10, lib/cf-https-connect.c at line 16, lib/cf-https-connect.h at line 12, lib/cf-https-connect.h at line 18, lib/cf-socket.c at line 10, lib/cf-socket.c at line 16, lib/cf-socket.h at line 12, lib/cf-socket.h at line 18, lib/cfilters.c at line 10, lib/cfilters.c at line 16, lib/cfilters.h at line 12, lib/cfilters.h at line 18, lib/conncache.c at line 11, lib/conncache.c at line 17, lib/conncache.h at line 13, lib/conncache.h at line 19, lib/connect.c at line 10, lib/connect.c at line 16, lib/connect.h at line 12, lib/connect.h at line 18, lib/content_encoding.c at line 10, lib/content_encoding.c at line 16, lib/content_encoding.h at line 12, lib/content_encoding.h at line 18, lib/cookie.c at line 10, lib/cookie.c at line 16, lib/cookie.h at line 12, lib/cookie.h at line 18, lib/curl_addrinfo.c at line 10, lib/curl_addrinfo.c at line 16, lib/curl_addrinfo.h at line 12, lib/curl_addrinfo.h at line 18, lib/curl_base64.h at line 12, lib/curl_base64.h at line 18, lib/curl_ctype.h at line 12, lib/curl_ctype.h at line 18, lib/curl_des.c at line 10, lib/curl_des.c at line 16, lib/curl_des.h at line 12, lib/curl_des.h at line 18, lib/curl_endian.c at line 10, lib/curl_endian.c at line 16, lib/curl_endian.h at line 12, lib/curl_endian.h at line 18, lib/curl_fnmatch.c at line 10, lib/curl_fnmatch.c at line 16, lib/curl_fnmatch.h at line 12, lib/curl_fnmatch.h at line 18, lib/curl_get_line.c at line 10, lib/curl_get_line.c at line 16, lib/curl_get_line.h at line 12, lib/curl_get_line.h at line 18, lib/curl_gethostname.c at line 10, lib/curl_gethostname.c at line 16, lib/curl_gethostname.h at line 12, lib/curl_gethostname.h at line 18, lib/curl_gssapi.c at line 10, lib/curl_gssapi.c at line 16, lib/curl_hmac.h at line 12, lib/curl_hmac.h at line 18, lib/curl_krb5.h at line 12, lib/curl_krb5.h at line 18, lib/curl_ldap.h at line 12, lib/curl_ldap.h at line 18, lib/curl_md4.h at line 12, lib/curl_md4.h at line 18, lib/curl_md5.h at line 12, lib/curl_md5.h at line 18, lib/curl_memory.h at line 12, lib/curl_memory.h at line 18, lib/curl_memrchr.c at line 10, lib/curl_memrchr.c at line 16, lib/curl_memrchr.h at line 12, lib/curl_memrchr.h at line 18, lib/curl_multibyte.c at line 10, lib/curl_multibyte.c at line 16, lib/curl_multibyte.h at line 12, lib/curl_multibyte.h at line 18, lib/curl_ntlm_core.c at line 10, lib/curl_ntlm_core.c at line 16, lib/curl_ntlm_core.h at line 12, lib/curl_ntlm_core.h at line 18, lib/curl_ntlm_wb.c at line 10, lib/curl_ntlm_wb.c at line 16, lib/curl_ntlm_wb.h at line 12, lib/curl_ntlm_wb.h at line 18, lib/curl_path.c at line 10, lib/curl_path.c at line 16, lib/curl_printf.h at line 12, lib/curl_printf.h at line 18, lib/curl_range.c at line 10, lib/curl_range.c at line 16, lib/curl_range.h at line 12, lib/curl_range.h at line 18, lib/curl_rtmp.c at line 11, lib/curl_rtmp.c at line 17, lib/curl_rtmp.h at line 12, lib/curl_rtmp.h at line 18, lib/curl_sasl.c at line 10, lib/curl_sasl.c at line 16, lib/curl_sasl.h at line 12, lib/curl_sasl.h at line 18, lib/curl_setup.h at line 12, lib/curl_setup.h at line 18, lib/curl_setup_once.h at line 12, lib/curl_setup_once.h at line 18, lib/curl_sha256.h at line 13, lib/curl_sha256.h at line 19, lib/curl_sspi.c at line 10, lib/curl_sspi.c at line 16, lib/curl_sspi.h at line 12, lib/curl_sspi.h at line 18, lib/curl_threads.c at line 10, lib/curl_threads.c at line 16, lib/curl_threads.h at line 12, lib/curl_threads.h at line 18, lib/curl_trc.c at line 10, lib/curl_trc.c at line 16, lib/curl_trc.h at line 12, lib/curl_trc.h at line 18, lib/curlx.h at line 12, lib/curlx.h at line 18, lib/dict.c at line 10, lib/dict.c at line 16, lib/dict.h at line 12, lib/dict.h at line 18, lib/doh.c at line 10, lib/doh.c at line 16, lib/doh.h at line 12, lib/doh.h at line 18, lib/dynbuf.c at line 10, lib/dynbuf.c at line 16, lib/dynbuf.h at line 12, lib/dynbuf.h at line 18, lib/dynhds.c at line 10, lib/dynhds.c at line 16, lib/dynhds.h at line 12, lib/dynhds.h at line 18, lib/easy.c at line 10, lib/easy.c at line 16, lib/easy_lock.h at line 12, lib/easy_lock.h at line 18, lib/easygetopt.c at line 10, lib/easygetopt.c at line 16, lib/easyif.h at line 12, lib/easyif.h at line 18, lib/easyoptions.c at line 10, lib/easyoptions.c at line 16, lib/easyoptions.h at line 12, lib/easyoptions.h at line 18, lib/escape.c at line 10, lib/escape.c at line 16, lib/escape.h at line 12, lib/escape.h at line 18, lib/file.c at line 10, lib/file.c at line 16, lib/file.h at line 12, lib/file.h at line 18, lib/fileinfo.c at line 10, lib/fileinfo.c at line 16, lib/fileinfo.h at line 12, lib/fileinfo.h at line 18, lib/fopen.c at line 10, lib/fopen.c at line 16, lib/fopen.h at line 12, lib/fopen.h at line 18, lib/formdata.c at line 10, lib/formdata.c at line 16, lib/formdata.h at line 12, lib/formdata.h at line 18, lib/ftp.c at line 10, lib/ftp.c at line 16, lib/ftp.h at line 12, lib/ftp.h at line 18, lib/ftplistparser.c at line 10, lib/ftplistparser.c at line 16, lib/ftplistparser.h at line 12, lib/ftplistparser.h at line 18, lib/functypes.h at line 12, lib/functypes.h at line 18, lib/getenv.c at line 10, lib/getenv.c at line 16, lib/getinfo.c at line 10, lib/getinfo.c at line 16, lib/getinfo.h at line 12, lib/getinfo.h at line 18, lib/gopher.c at line 10, lib/gopher.c at line 16, lib/gopher.h at line 12, lib/gopher.h at line 18, lib/hash.c at line 10, lib/hash.c at line 16, lib/hash.h at line 12, lib/hash.h at line 18, lib/headers.c at line 10, lib/headers.c at line 16, lib/headers.h at line 12, lib/headers.h at line 18, lib/hmac.c at line 10, lib/hmac.c at line 16, lib/hostasyn.c at line 10, lib/hostasyn.c at line 16, lib/hostip.c at line 10, lib/hostip.c at line 16, lib/hostip.h at line 12, lib/hostip.h at line 18, lib/hostip4.c at line 10, lib/hostip4.c at line 16, lib/hostip6.c at line 10, lib/hostip6.c at line 16, lib/hostsyn.c at line 10, lib/hostsyn.c at line 16, lib/hsts.c at line 10, lib/hsts.c at line 16, lib/hsts.h at line 12, lib/hsts.h at line 18, lib/http.c at line 10, lib/http.c at line 16, lib/http.h at line 12, lib/http.h at line 18, lib/http1.c at line 10, lib/http1.c at line 16, lib/http1.h at line 12, lib/http1.h at line 18, lib/http2.c at line 10, lib/http2.c at line 16, lib/http2.h at line 12, lib/http2.h at line 18, lib/http_chunks.c at line 10, lib/http_chunks.c at line 16, lib/http_chunks.h at line 12, lib/http_chunks.h at line 18, lib/http_digest.c at line 10, lib/http_digest.c at line 16, lib/http_digest.h at line 12, lib/http_digest.h at line 18, lib/http_negotiate.c at line 10, lib/http_negotiate.c at line 16, lib/http_negotiate.h at line 12, lib/http_negotiate.h at line 18, lib/http_ntlm.c at line 10, lib/http_ntlm.c at line 16, lib/http_ntlm.h at line 12, lib/http_ntlm.h at line 18, lib/http_proxy.c at line 10, lib/http_proxy.c at line 16, lib/http_proxy.h at line 12, lib/http_proxy.h at line 18, lib/idn.c at line 10, lib/idn.c at line 16, lib/idn.h at line 12, lib/idn.h at line 18, lib/if2ip.c at line 10, lib/if2ip.c at line 16, lib/if2ip.h at line 12, lib/if2ip.h at line 18, lib/imap.c at line 10, lib/imap.c at line 16, lib/imap.h at line 12, lib/imap.h at line 18, lib/inet_ntop.h at line 12, lib/inet_ntop.h at line 18, lib/inet_pton.h at line 12, lib/inet_pton.h at line 18, lib/ldap.c at line 10, lib/ldap.c at line 16, lib/llist.c at line 10, lib/llist.c at line 16, lib/llist.h at line 12, lib/llist.h at line 18, lib/macos.c at line 10, lib/macos.c at line 16, lib/macos.h at line 12, lib/macos.h at line 18, lib/md4.c at line 10, lib/md4.c at line 16, lib/md5.c at line 10, lib/md5.c at line 16, lib/memdebug.c at line 10, lib/memdebug.c at line 16, lib/memdebug.h at line 13, lib/memdebug.h at line 19, lib/mime.c at line 10, lib/mime.c at line 16, lib/mime.h at line 12, lib/mime.h at line 18, lib/mprintf.c at line 10, lib/mprintf.c at line 16, lib/mqtt.c at line 11, lib/mqtt.c at line 17, lib/mqtt.h at line 12, lib/mqtt.h at line 18, lib/multi.c at line 10, lib/multi.c at line 16, lib/multihandle.h at line 12, lib/multihandle.h at line 18, lib/multiif.h at line 12, lib/multiif.h at line 18, lib/netrc.c at line 10, lib/netrc.c at line 16, lib/netrc.h at line 12, lib/netrc.h at line 18, lib/nonblock.c at line 10, lib/nonblock.c at line 16, lib/nonblock.h at line 12, lib/nonblock.h at line 18, lib/noproxy.c at line 10, lib/noproxy.c at line 16, lib/noproxy.h at line 12, lib/noproxy.h at line 18, lib/openldap.c at line 11, lib/openldap.c at line 17, lib/parsedate.c at line 10, lib/parsedate.c at line 16, lib/parsedate.h at line 12, lib/parsedate.h at line 18, lib/pingpong.c at line 10, lib/pingpong.c at line 16, lib/pingpong.h at line 12, lib/pingpong.h at line 18, lib/pop3.c at line 10, lib/pop3.c at line 16, lib/pop3.h at line 12, lib/pop3.h at line 18, lib/progress.c at line 10, lib/progress.c at line 16, lib/progress.h at line 12, lib/progress.h at line 18, lib/psl.c at line 10, lib/psl.c at line 16, lib/psl.h at line 12, lib/psl.h at line 18, lib/rand.c at line 10, lib/rand.c at line 16, lib/rand.h at line 12, lib/rand.h at line 18, lib/rename.c at line 10, lib/rename.c at line 16, lib/rename.h at line 12, lib/rename.h at line 18, lib/rtsp.c at line 10, lib/rtsp.c at line 16, lib/rtsp.h at line 12, lib/rtsp.h at line 18, lib/select.c at line 10, lib/select.c at line 16, lib/select.h at line 12, lib/select.h at line 18, lib/sendf.c at line 10, lib/sendf.c at line 16, lib/sendf.h at line 12, lib/sendf.h at line 18, lib/setopt.c at line 10, lib/setopt.c at line 16, lib/setopt.h at line 12, lib/setopt.h at line 18, lib/setup-win32.h at line 12, lib/setup-win32.h at line 18, lib/sha256.c at line 11, lib/sha256.c at line 17, lib/share.c at line 10, lib/share.c at line 16, lib/share.h at line 12, lib/share.h at line 18, lib/sigpipe.h at line 12, lib/sigpipe.h at line 18, lib/slist.c at line 10, lib/slist.c at line 16, lib/slist.h at line 12, lib/slist.h at line 18, lib/smb.c at line 11, lib/smb.c at line 17, lib/smb.h at line 13, lib/smb.h at line 19, lib/smtp.c at line 10, lib/smtp.c at line 16, lib/smtp.h at line 12, lib/smtp.h at line 18, lib/sockaddr.h at line 12, lib/sockaddr.h at line 18, lib/socketpair.c at line 10, lib/socketpair.c at line 16, lib/socketpair.h at line 12, lib/socketpair.h at line 18, lib/socks.c at line 10, lib/socks.c at line 16, lib/socks.h at line 12, lib/socks.h at line 18, lib/socks_gssapi.c at line 11, lib/socks_gssapi.c at line 17, lib/socks_sspi.c at line 11, lib/socks_sspi.c at line 17, lib/speedcheck.c at line 10, lib/speedcheck.c at line 16, lib/speedcheck.h at line 12, lib/speedcheck.h at line 18, lib/splay.c at line 10, lib/splay.c at line 16, lib/splay.h at line 12, lib/splay.h at line 18, lib/strcase.c at line 10, lib/strcase.c at line 16, lib/strcase.h at line 12, lib/strcase.h at line 18, lib/strdup.c at line 10, lib/strdup.c at line 16, lib/strdup.h at line 12, lib/strdup.h at line 18, lib/strerror.c at line 10, lib/strerror.c at line 16, lib/strerror.h at line 12, lib/strerror.h at line 18, lib/strtok.c at line 10, lib/strtok.c at line 16, lib/strtok.h at line 12, lib/strtok.h at line 18, lib/strtoofft.c at line 10, lib/strtoofft.c at line 16, lib/strtoofft.h at line 12, lib/strtoofft.h at line 18, lib/system_win32.c at line 10, lib/system_win32.c at line 16, lib/system_win32.h at line 12, lib/system_win32.h at line 18, lib/telnet.c at line 10, lib/telnet.c at line 16, lib/telnet.h at line 12, lib/telnet.h at line 18, lib/tftp.c at line 10, lib/tftp.c at line 16, lib/tftp.h at line 12, lib/tftp.h at line 18, lib/timediff.c at line 10, lib/timediff.c at line 16, lib/timediff.h at line 12, lib/timediff.h at line 18, lib/timeval.c at line 10, lib/timeval.c at line 16, lib/timeval.h at line 12, lib/timeval.h at line 18, lib/transfer.c at line 10, lib/transfer.c at line 16, lib/transfer.h at line 12, lib/transfer.h at line 18, lib/url.c at line 10, lib/url.c at line 16, lib/url.h at line 12, lib/url.h at line 18, lib/urlapi-int.h at line 12, lib/urlapi-int.h at line 18, lib/urlapi.c at line 10, lib/urlapi.c at line 16, lib/urldata.h at line 12, lib/urldata.h at line 18, lib/vauth/cleartext.c at line 10, lib/vauth/cleartext.c at line 16, lib/vauth/cram.c at line 10, lib/vauth/cram.c at line 16, lib/vauth/digest.c at line 10, lib/vauth/digest.c at line 16, lib/vauth/digest.h at line 12, lib/vauth/digest.h at line 18, lib/vauth/digest_sspi.c at line 11, lib/vauth/digest_sspi.c at line 17, lib/vauth/gsasl.c at line 10, lib/vauth/gsasl.c at line 16, lib/vauth/krb5_gssapi.c at line 11, lib/vauth/krb5_gssapi.c at line 17, lib/vauth/krb5_sspi.c at line 10, lib/vauth/krb5_sspi.c at line 16, lib/vauth/ntlm.c at line 10, lib/vauth/ntlm.c at line 16, lib/vauth/ntlm.h at line 12, lib/vauth/ntlm.h at line 18, lib/vauth/ntlm_sspi.c at line 10, lib/vauth/ntlm_sspi.c at line 16, lib/vauth/oauth2.c at line 10, lib/vauth/oauth2.c at line 16, lib/vauth/spnego_gssapi.c at line 10, lib/vauth/spnego_gssapi.c at line 16, lib/vauth/spnego_sspi.c at line 10, lib/vauth/spnego_sspi.c at line 16, lib/vauth/vauth.c at line 10, lib/vauth/vauth.c at line 16, lib/vauth/vauth.h at line 12, lib/vauth/vauth.h at line 18, lib/version.c at line 10, lib/version.c at line 16, lib/version_win32.c at line 10, lib/version_win32.c at line 16, lib/version_win32.h at line 12, lib/version_win32.h at line 18, lib/vquic/curl_msh3.c at line 10, lib/vquic/curl_msh3.c at line 16, lib/vquic/curl_msh3.h at line 12, lib/vquic/curl_msh3.h at line 18, lib/vquic/curl_ngtcp2.c at line 10, lib/vquic/curl_ngtcp2.c at line 16, lib/vquic/curl_ngtcp2.h at line 12, lib/vquic/curl_ngtcp2.h at line 18, lib/vquic/curl_quiche.c at line 10, lib/vquic/curl_quiche.c at line 16, lib/vquic/curl_quiche.h at line 12, lib/vquic/curl_quiche.h at line 18, lib/vquic/vquic.c at line 10, lib/vquic/vquic.c at line 16, lib/vquic/vquic.h at line 12, lib/vquic/vquic.h at line 18, lib/vquic/vquic_int.h at line 12, lib/vquic/vquic_int.h at line 18, lib/vssh/libssh.c at line 13, lib/vssh/libssh.c at line 19, lib/vssh/libssh2.c at line 10, lib/vssh/libssh2.c at line 16, lib/vssh/ssh.h at line 12, lib/vssh/ssh.h at line 18, lib/vssh/wolfssh.c at line 10, lib/vssh/wolfssh.c at line 16, lib/vtls/bearssl.c at line 10, lib/vtls/bearssl.c at line 16, lib/vtls/bearssl.h at line 12, lib/vtls/bearssl.h at line 18, lib/vtls/gtls.c at line 10, lib/vtls/gtls.c at line 16, lib/vtls/gtls.h at line 12, lib/vtls/gtls.h at line 18, lib/vtls/hostcheck.c at line 10, lib/vtls/hostcheck.c at line 16, lib/vtls/hostcheck.h at line 12, lib/vtls/hostcheck.h at line 18, lib/vtls/keylog.c at line 10, lib/vtls/keylog.c at line 16, lib/vtls/keylog.h at line 12, lib/vtls/keylog.h at line 18, lib/vtls/mbedtls.c at line 11, lib/vtls/mbedtls.c at line 17, lib/vtls/mbedtls.h at line 13, lib/vtls/mbedtls.h at line 19, lib/vtls/mbedtls_threadlock.c at line 11, lib/vtls/mbedtls_threadlock.c at line 17, lib/vtls/openssl.c at line 10, lib/vtls/openssl.c at line 16, lib/vtls/openssl.h at line 12, lib/vtls/openssl.h at line 18, lib/vtls/rustls.c at line 11, lib/vtls/rustls.c at line 17, lib/vtls/rustls.h at line 11, lib/vtls/rustls.h at line 17, lib/vtls/schannel.c at line 12, lib/vtls/schannel.c at line 18, lib/vtls/schannel.h at line 13, lib/vtls/schannel.h at line 19, lib/vtls/schannel_verify.c at line 12, lib/vtls/schannel_verify.c at line 18, lib/vtls/sectransp.c at line 11, lib/vtls/sectransp.c at line 17, lib/vtls/sectransp.h at line 13, lib/vtls/sectransp.h at line 19, lib/vtls/vtls.c at line 10, lib/vtls/vtls.c at line 16, lib/vtls/vtls.h at line 12, lib/vtls/vtls.h at line 18, lib/vtls/vtls_int.h at line 12, lib/vtls/vtls_int.h at line 18, lib/vtls/wolfssl.c at line 10, lib/vtls/wolfssl.c at line 16, lib/vtls/wolfssl.h at line 12, lib/vtls/wolfssl.h at line 18, lib/vtls/x509asn1.c at line 10, lib/vtls/x509asn1.c at line 16, lib/vtls/x509asn1.h at line 13, lib/vtls/x509asn1.h at line 19, lib/warnless.c at line 10, lib/warnless.c at line 16, lib/warnless.h at line 12, lib/warnless.h at line 18, lib/ws.c at line 10, lib/ws.c at line 16, lib/ws.h at line 12, lib/ws.h at line 18, src/slist_wc.c at line 10, src/slist_wc.c at line 16, src/slist_wc.h at line 12, src/slist_wc.h at line 18, src/tool_binmode.c at line 10, src/tool_binmode.c at line 16, src/tool_binmode.h at line 12, src/tool_binmode.h at line 18, src/tool_bname.c at line 10, src/tool_bname.c at line 16, src/tool_bname.h at line 12, src/tool_bname.h at line 18, src/tool_cb_dbg.c at line 10, src/tool_cb_dbg.c at line 16, src/tool_cb_dbg.h at line 12, src/tool_cb_dbg.h at line 18, src/tool_cb_hdr.c at line 10, src/tool_cb_hdr.c at line 16, src/tool_cb_hdr.h at line 12, src/tool_cb_hdr.h at line 18, src/tool_cb_prg.c at line 10, src/tool_cb_prg.c at line 16, src/tool_cb_prg.h at line 12, src/tool_cb_prg.h at line 18, src/tool_cb_rea.c at line 10, src/tool_cb_rea.c at line 16, src/tool_cb_rea.h at line 12, src/tool_cb_rea.h at line 18, src/tool_cb_see.c at line 10, src/tool_cb_see.c at line 16, src/tool_cb_see.h at line 12, src/tool_cb_see.h at line 18, src/tool_cb_wrt.c at line 10, src/tool_cb_wrt.c at line 16, src/tool_cb_wrt.h at line 12, src/tool_cb_wrt.h at line 18, src/tool_cfgable.c at line 10, src/tool_cfgable.c at line 16, src/tool_cfgable.h at line 12, src/tool_cfgable.h at line 18, src/tool_dirhie.c at line 10, src/tool_dirhie.c at line 16, src/tool_dirhie.h at line 12, src/tool_dirhie.h at line 18, src/tool_doswin.c at line 10, src/tool_doswin.c at line 16, src/tool_doswin.h at line 12, src/tool_doswin.h at line 18, src/tool_easysrc.c at line 10, src/tool_easysrc.c at line 16, src/tool_easysrc.h at line 12, src/tool_easysrc.h at line 18, src/tool_filetime.c at line 10, src/tool_filetime.c at line 16, src/tool_filetime.h at line 12, src/tool_filetime.h at line 18, src/tool_findfile.c at line 10, src/tool_findfile.c at line 16, src/tool_findfile.h at line 12, src/tool_findfile.h at line 18, src/tool_formparse.c at line 10, src/tool_formparse.c at line 16, src/tool_formparse.h at line 12, src/tool_formparse.h at line 18, src/tool_getparam.c at line 10, src/tool_getparam.c at line 16, src/tool_getparam.h at line 12, src/tool_getparam.h at line 18, src/tool_getpass.c at line 10, src/tool_getpass.c at line 16, src/tool_getpass.h at line 12, src/tool_getpass.h at line 18, src/tool_help.c at line 10, src/tool_help.c at line 16, src/tool_help.h at line 12, src/tool_help.h at line 18, src/tool_helpers.c at line 10, src/tool_helpers.c at line 16, src/tool_helpers.h at line 12, src/tool_helpers.h at line 18, src/tool_hugehelp.h at line 12, src/tool_hugehelp.h at line 18, src/tool_ipfs.c at line 10, src/tool_ipfs.c at line 16, src/tool_ipfs.h at line 12, src/tool_ipfs.h at line 18, src/tool_libinfo.c at line 10, src/tool_libinfo.c at line 16, src/tool_libinfo.h at line 12, src/tool_libinfo.h at line 18, src/tool_listhelp.c at line 10, src/tool_listhelp.c at line 16, src/tool_main.c at line 10, src/tool_main.c at line 16, src/tool_main.h at line 12, src/tool_main.h at line 18, src/tool_msgs.c at line 10, src/tool_msgs.c at line 16, src/tool_msgs.h at line 12, src/tool_msgs.h at line 18, src/tool_operate.c at line 10, src/tool_operate.c at line 16, src/tool_operate.h at line 12, src/tool_operate.h at line 18, src/tool_operhlp.c at line 10, src/tool_operhlp.c at line 16, src/tool_operhlp.h at line 12, src/tool_operhlp.h at line 18, src/tool_paramhlp.c at line 10, src/tool_paramhlp.c at line 16, src/tool_paramhlp.h at line 12, src/tool_paramhlp.h at line 18, src/tool_parsecfg.c at line 10, src/tool_parsecfg.c at line 16, src/tool_parsecfg.h at line 12, src/tool_parsecfg.h at line 18, src/tool_progress.c at line 10, src/tool_progress.c at line 16, src/tool_progress.h at line 12, src/tool_progress.h at line 18, src/tool_sdecls.h at line 12, src/tool_sdecls.h at line 18, src/tool_setopt.c at line 10, src/tool_setopt.c at line 16, src/tool_setopt.h at line 12, src/tool_setopt.h at line 18, src/tool_setup.h at line 12, src/tool_setup.h at line 18, src/tool_sleep.c at line 10, src/tool_sleep.c at line 16, src/tool_sleep.h at line 12, src/tool_sleep.h at line 18, src/tool_stderr.c at line 10, src/tool_stderr.c at line 16, src/tool_stderr.h at line 12, src/tool_stderr.h at line 18, src/tool_strdup.c at line 10, src/tool_strdup.c at line 16, src/tool_strdup.h at line 12, src/tool_strdup.h at line 18, src/tool_urlglob.c at line 10, src/tool_urlglob.c at line 16, src/tool_urlglob.h at line 12, src/tool_urlglob.h at line 18, src/tool_util.c at line 10, src/tool_util.c at line 16, src/tool_util.h at line 12, src/tool_util.h at line 18, src/tool_version.h at line 12, src/tool_version.h at line 18, src/tool_vms.c at line 10, src/tool_vms.c at line 16, src/tool_vms.h at line 12, src/tool_vms.h at line 18, src/tool_writeout.c at line 10, src/tool_writeout.c at line 16, src/tool_writeout.h at line 12, src/tool_writeout.h at line 18, src/tool_writeout_json.c at line 10, src/tool_writeout_json.c at line 16, src/tool_writeout_json.h at line 12, src/tool_writeout_json.h at line 18, src/tool_xattr.c at line 10, src/tool_xattr.c at line 16, src/tool_xattr.h at line 12, src/tool_xattr.h at line 18, src/var.c at line 10, src/var.c at line 16, src/var.h at line 12, src/var.h at line 18
Note: matched license text is too long. Read it in the source files.
Scancode info:
Original SPDX id: curl
@@ -652,6 +649,8 @@ FILE_INCLUDE COPYING found in files: include/curl/curl.h at line 12, include/cur
lib/curl_multibyte.h [12:21]
lib/curl_ntlm_core.c [10:19]
lib/curl_ntlm_core.h [12:21]
+ lib/curl_ntlm_wb.c [10:19]
+ lib/curl_ntlm_wb.h [12:21]
lib/curl_path.c [10:19]
lib/curl_printf.h [12:21]
lib/curl_range.c [10:19]
@@ -663,8 +662,6 @@ FILE_INCLUDE COPYING found in files: include/curl/curl.h at line 12, include/cur
lib/curl_setup.h [12:21]
lib/curl_setup_once.h [12:21]
lib/curl_sha256.h [13:22]
- lib/curl_sha512_256.c [10:19]
- lib/curl_sha512_256.h [12:21]
lib/curl_sspi.c [10:19]
lib/curl_sspi.h [12:21]
lib/curl_threads.c [10:19]
@@ -672,11 +669,8 @@ FILE_INCLUDE COPYING found in files: include/curl/curl.h at line 12, include/cur
lib/curl_trc.c [10:19]
lib/curl_trc.h [12:21]
lib/curlx.h [12:21]
- lib/cw-out.c [10:19]
- lib/cw-out.h [12:21]
lib/dict.c [10:19]
lib/dict.h [12:21]
- lib/dllmain.c [10:19]
lib/doh.c [10:19]
lib/doh.h [12:21]
lib/dynbuf.c [10:19]
@@ -784,8 +778,6 @@ FILE_INCLUDE COPYING found in files: include/curl/curl.h at line 12, include/cur
lib/rand.h [12:21]
lib/rename.c [10:19]
lib/rename.h [12:21]
- lib/request.c [10:19]
- lib/request.h [12:21]
lib/rtsp.c [10:19]
lib/rtsp.h [12:21]
lib/select.c [10:19]
@@ -866,11 +858,8 @@ FILE_INCLUDE COPYING found in files: include/curl/curl.h at line 12, include/cur
lib/vquic/curl_msh3.h [12:21]
lib/vquic/curl_ngtcp2.c [10:19]
lib/vquic/curl_ngtcp2.h [12:21]
- lib/vquic/curl_osslq.c [10:19]
- lib/vquic/curl_osslq.h [12:21]
lib/vquic/curl_quiche.c [10:19]
lib/vquic/curl_quiche.h [12:21]
- lib/vquic/vquic-tls.c [10:19]
lib/vquic/vquic.c [10:19]
lib/vquic/vquic.h [12:21]
lib/vquic/vquic_int.h [12:21]
@@ -880,7 +869,6 @@ FILE_INCLUDE COPYING found in files: include/curl/curl.h at line 12, include/cur
lib/vssh/wolfssh.c [10:19]
lib/vtls/bearssl.c [10:19]
lib/vtls/bearssl.h [12:21]
- lib/vtls/cipher_suite.c [10:19]
lib/vtls/gtls.c [10:19]
lib/vtls/gtls.h [12:21]
lib/vtls/hostcheck.c [10:19]
@@ -892,7 +880,7 @@ FILE_INCLUDE COPYING found in files: include/curl/curl.h at line 12, include/cur
lib/vtls/mbedtls_threadlock.c [11:20]
lib/vtls/openssl.c [10:19]
lib/vtls/openssl.h [12:21]
- lib/vtls/rustls.c [12:21]
+ lib/vtls/rustls.c [11:20]
lib/vtls/rustls.h [11:20]
lib/vtls/schannel.c [12:21]
lib/vtls/schannel.h [13:22]
@@ -905,14 +893,13 @@ FILE_INCLUDE COPYING found in files: include/curl/curl.h at line 12, include/cur
lib/vtls/wolfssl.c [10:19]
lib/vtls/wolfssl.h [12:21]
lib/vtls/x509asn1.c [10:19]
+ lib/vtls/x509asn1.h [13:22]
lib/warnless.c [10:19]
lib/warnless.h [12:21]
lib/ws.c [10:19]
lib/ws.h [12:21]
src/slist_wc.c [10:19]
src/slist_wc.h [12:21]
- src/terminal.c [10:19]
- src/terminal.h [12:21]
src/tool_binmode.c [10:19]
src/tool_binmode.h [12:21]
src/tool_bname.c [10:19]
@@ -927,8 +914,6 @@ FILE_INCLUDE COPYING found in files: include/curl/curl.h at line 12, include/cur
src/tool_cb_rea.h [12:21]
src/tool_cb_see.c [10:19]
src/tool_cb_see.h [12:21]
- src/tool_cb_soc.c [10:19]
- src/tool_cb_soc.h [12:21]
src/tool_cb_wrt.c [10:19]
src/tool_cb_wrt.h [12:21]
src/tool_cfgable.c [10:19]
@@ -1001,57 +986,30 @@ FILE_INCLUDE COPYING found in files: include/curl/curl.h at line 12, include/cur
Belongs difference:
+ bin/ya.make
-KEEP BSD-3-Clause a8d7dbe01f5cffda79d9477f7546f3ab
-BELONGS ya.make
- Note: matched license text is too long. Read it in the source files.
+KEEP BSD-3-Clause bcd96bf495243cd22767952d056c373c
+BELONGS bin/ya.make ya.make
+ License text:
+ * SPDX-License-Identifier: BSD-3-Clause
Scancode info:
Original SPDX id: BSD-3-Clause
Score : 100.00
- Match type : TEXT
+ Match type : TAG
Links : http://www.opensource.org/licenses/BSD-3-Clause, https://spdx.org/licenses/BSD-3-Clause
Files with this license:
- lib/krb5.c [10:35]
-
-KEEP curl badd2415ffbdcff675c84bef7309f4b2
-BELONGS ya.make
- Note: matched license text is too long. Read it in the source files.
- Scancode info:
- Original SPDX id: curl
- Score : 90.06
- Match type : TEXT
- Links : http://curl.haxx.se/, http://curl.haxx.se/docs/copyright.html, https://spdx.org/licenses/curl
- Files with this license:
- COPYING [1:22]
-
-KEEP Public-Domain bc15107235708b7b989bd2f53f2d02c0
-BELONGS ya.make
- Note: matched license text is too long. Read it in the source files.
- Scancode info:
- Original SPDX id: LicenseRef-scancode-public-domain
- Score : 98.04
- Match type : NOTICE
- Links : http://www.linfo.org/publicdomain.html, https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/licenses/public-domain.LICENSE
- Files with this license:
- lib/md5.c [252:269]
- Scancode info:
- Original SPDX id: LicenseRef-scancode-other-permissive
- Score : 98.04
- Match type : NOTICE
- Links : https://github.com/nexB/scancode-toolkit/tree/develop/src/licensedcode/data/licenses/other-permissive.LICENSE
- Files with this license:
- lib/md5.c [252:269]
+ lib/krb5.c [8:8]
+ Belongs difference:
+ + bin/ya.make
-KEEP BSD-3-Clause bcd96bf495243cd22767952d056c373c
+KEEP BSD-3-Clause be4b0ef51fe3fb41b94214ba4614bf94
BELONGS bin/ya.make ya.make
- License text:
- * SPDX-License-Identifier: BSD-3-Clause
+ Note: matched license text is too long. Read it in the source files.
Scancode info:
Original SPDX id: BSD-3-Clause
Score : 100.00
- Match type : TAG
+ Match type : TEXT
Links : http://www.opensource.org/licenses/BSD-3-Clause, https://spdx.org/licenses/BSD-3-Clause
Files with this license:
- lib/krb5.c [8:8]
+ lib/krb5.c [10:35]
Belongs difference:
+ bin/ya.make
@@ -1072,18 +1030,6 @@ FILE_INCLUDE COPYING found in files: lib/c-hyper.c at line 10, lib/c-hyper.c at
Belongs difference:
+ bin/ya.make
-KEEP BSD-3-Clause e002d0e71759f5b418fb792a173cf534
-BELONGS ya.make
- License text:
- /* Define to use BSD-style lwIP TCP/IP stack. */
- Scancode info:
- Original SPDX id: BSD-3-Clause
- Score : 90.00
- Match type : REFERENCE
- Links : http://www.opensource.org/licenses/BSD-3-Clause, https://spdx.org/licenses/BSD-3-Clause
- Files with this license:
- lib/setup-win32.h [45:45]
-
KEEP Public-Domain e1407be30f6023cfd2ef48b215bac4c2
BELONGS bin/ya.make ya.make
License text:
@@ -1111,3 +1057,14 @@ BELONGS bin/ya.make ya.make
lib/curl_path.c [106:116]
Belongs difference:
+ bin/ya.make
+
+KEEP curl fd7b0b2c4f7f164b0fa5c2f9cf4ef41a
+BELONGS ya.make
+ Note: matched license text is too long. Read it in the source files.
+ Scancode info:
+ Original SPDX id: curl
+ Score : 90.06
+ Match type : TEXT
+ Links : http://curl.haxx.se/, http://curl.haxx.se/docs/copyright.html, https://spdx.org/licenses/curl
+ Files with this license:
+ COPYING [1:22]
diff --git a/contrib/libs/curl/.yandex_meta/licenses.list.txt b/contrib/libs/curl/.yandex_meta/licenses.list.txt
index 228081f6ca..17a0b9f2de 100644
--- a/contrib/libs/curl/.yandex_meta/licenses.list.txt
+++ b/contrib/libs/curl/.yandex_meta/licenses.list.txt
@@ -1,8 +1,4 @@
====================BSD-3-Clause====================
- /* Define to use BSD-style lwIP TCP/IP stack. */
-
-
-====================BSD-3-Clause====================
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -21,7 +17,7 @@
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
@@ -35,12 +31,12 @@
* SPDX-License-Identifier: BSD-3-Clause
-====================BSD-3-Clause====================
-/* BSD-style lwIP TCP/IP stack SPECIFIC */
+====================COPYRIGHT====================
+ * Copyright (C) 1996-2022 Internet Software Consortium.
====================COPYRIGHT====================
- * Copyright (C) 1996-2022 Internet Software Consortium.
+ * Copyright (C) Daniel Stenberg, <daniel.se>, et al.
====================COPYRIGHT====================
@@ -85,10 +81,6 @@
====================COPYRIGHT====================
- * Copyright (C) Evgeny Grin (Karlson2k), <k2k@narod.ru>.
-
-
-====================COPYRIGHT====================
* Copyright (C) Florin Petriuc, <petriuc.florin@gmail.com>
* Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
@@ -96,11 +88,6 @@
====================COPYRIGHT====================
* Copyright (C) Jacob Hoffman-Andrews,
* <github@hoffman-andrews.com>
- * Copyright (C) kpcyrd, <kpcyrd@archlinux.org>
-
-
-====================COPYRIGHT====================
- * Copyright (C) Jan Venekamp, <jan@venekamp.net>
====================COPYRIGHT====================
@@ -136,8 +123,8 @@
====================COPYRIGHT====================
- * This software was written by Alexander Peslyak in 2001. No copyright is
- * claimed, and the software is hereby placed in the public domain. In case
+ * This software was written by Alexander Peslyak in 2001. No copyright is
+ * claimed, and the software is hereby placed in the public domain. In case
* this attempt to disclaim copyright and place the software in the public
* domain is deemed null and void, then the software is Copyright (c) 2001
* Alexander Peslyak and it is hereby released to the general public under the
@@ -157,14 +144,14 @@ Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
====================COPYRIGHT====================
-Copyright (c) 1996 - 2024, Daniel Stenberg, <daniel@haxx.se>, and many
+Copyright (c) 1996 - 2023, Daniel Stenberg, <daniel@haxx.se>, and many
contributors, see the THANKS file.
====================File: COPYING====================
COPYRIGHT AND PERMISSION NOTICE
-Copyright (c) 1996 - 2024, Daniel Stenberg, <daniel@haxx.se>, and many
+Copyright (c) 1996 - 2023, Daniel Stenberg, <daniel@haxx.se>, and many
contributors, see the THANKS file.
All rights reserved.
@@ -240,8 +227,8 @@ in this Software without prior written authorization of the copyright holder.
* Author:
* Alexander Peslyak, better known as Solar Designer <solar at openwall.com>
*
- * This software was written by Alexander Peslyak in 2001. No copyright is
- * claimed, and the software is hereby placed in the public domain. In case
+ * This software was written by Alexander Peslyak in 2001. No copyright is
+ * claimed, and the software is hereby placed in the public domain. In case
* this attempt to disclaim copyright and place the software in the public
* domain is deemed null and void, then the software is Copyright (c) 2001
* Alexander Peslyak and it is hereby released to the general public under the
@@ -250,7 +237,7 @@ in this Software without prior written authorization of the copyright holder.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted.
*
- * There is ABSOLUTELY NO WARRANTY, express or implied.
+ * There's ABSOLUTELY NO WARRANTY, express or implied.
*
* (This is a heavily cut-down "BSD license".)
@@ -261,7 +248,7 @@ in this Software without prior written authorization of the copyright holder.
* Author:
* Alexander Peslyak, better known as Solar Designer <solar at openwall.com>
*
- * This software was written by Alexander Peslyak in 2001. No copyright is
+ * This software was written by Alexander Peslyak in 2001. No copyright is
* claimed, and the software is hereby placed in the public domain.
* In case this attempt to disclaim copyright and place the software in the
* public domain is deemed null and void, then the software is
@@ -271,7 +258,7 @@ in this Software without prior written authorization of the copyright holder.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted.
*
- * There is ABSOLUTELY NO WARRANTY, express or implied.
+ * There's ABSOLUTELY NO WARRANTY, express or implied.
*
* (This is a heavily cut-down "BSD license".)
@@ -314,7 +301,7 @@ in this Software without prior written authorization of the copyright holder.
====================curl====================
COPYRIGHT AND PERMISSION NOTICE
-Copyright (c) 1996 - 2024, Daniel Stenberg, <daniel@haxx.se>, and many
+Copyright (c) 1996 - 2023, Daniel Stenberg, <daniel@haxx.se>, and many
contributors, see the THANKS file.
All rights reserved.
diff --git a/contrib/libs/curl/.yandex_meta/override.nix b/contrib/libs/curl/.yandex_meta/override.nix
index 897b77d9c8..c836e6b03f 100644
--- a/contrib/libs/curl/.yandex_meta/override.nix
+++ b/contrib/libs/curl/.yandex_meta/override.nix
@@ -1,10 +1,10 @@
pkgs: attrs: with pkgs; rec {
- version = "8.10.1";
+ version = "8.5.0";
versionWithUnderscores = "${lib.replaceStrings ["."] ["_"] version}";
src = fetchurl {
url = "https://github.com/curl/curl/releases/download/curl-${versionWithUnderscores}/curl-${version}.tar.bz2";
- hash = "sha256-N2PNl6rkHc9BlQ0j6HriOy7bLOOlsM9nivBYw5G2rjE=";
+ hash = "sha256-zktqZlVDEUdiSq9YJjKjb+Gt4mLV+rOFxg94lC3Y2Hs=";
};
patches = [];
@@ -26,7 +26,6 @@ pkgs: attrs: with pkgs; rec {
"--with-brotli=${brotli.dev}"
"--without-gnutls"
"--without-libidn2"
- "--without-libpsl"
"--without-librtmp"
"--without-nghttp3"
"--without-ngtcp2"
diff --git a/contrib/libs/curl/CHANGES.md b/contrib/libs/curl/CHANGES.md
deleted file mode 100644
index 6e2f7c6bcc..0000000000
--- a/contrib/libs/curl/CHANGES.md
+++ /dev/null
@@ -1,12 +0,0 @@
-<!--
-Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
-
-SPDX-License-Identifier: curl
--->
-
-In a release tarball, check the RELEASES-NOTES file for what was done in the
-most recent release. In a git check-out, that file mentions changes that have
-been done since the previous release.
-
-See the online [changelog](https://curl.se/changes.html) for the edited and
-human readable version of what has changed in different curl releases.
diff --git a/contrib/libs/curl/COPYING b/contrib/libs/curl/COPYING
index d9e7e0bef3..d1eab3eb93 100644
--- a/contrib/libs/curl/COPYING
+++ b/contrib/libs/curl/COPYING
@@ -1,6 +1,6 @@
COPYRIGHT AND PERMISSION NOTICE
-Copyright (c) 1996 - 2024, Daniel Stenberg, <daniel@haxx.se>, and many
+Copyright (c) 1996 - 2023, Daniel Stenberg, <daniel@haxx.se>, and many
contributors, see the THANKS file.
All rights reserved.
diff --git a/contrib/libs/curl/RELEASE-NOTES b/contrib/libs/curl/RELEASE-NOTES
index 9b282e3d4b..3f7dc99f68 100644
--- a/contrib/libs/curl/RELEASE-NOTES
+++ b/contrib/libs/curl/RELEASE-NOTES
@@ -1,89 +1,418 @@
-curl and libcurl 8.10.1
+curl and libcurl 8.5.0
- Public curl releases: 261
- Command line options: 265
- curl_easy_setopt() options: 306
- Public functions in libcurl: 94
- Contributors: 3246
+ Public curl releases: 253
+ Command line options: 258
+ curl_easy_setopt() options: 303
+ Public functions in libcurl: 93
+ Contributors: 3039
This release includes the following changes:
+ o gnutls: support CURLSSLOPT_NATIVE_CA [31]
+ o HTTP3: ngtcp2 builds are no longer experimental [77]
This release includes the following bugfixes:
- o autotools: fix `--with-ca-embed` build rule [3]
- o cmake: ensure `CURL_USE_OPENSSL`/`USE_OPENSSL_QUIC` are set in sync [8]
- o cmake: fix MSH3 to appear on the feature list [20]
- o connect: store connection info when really done [9]
- o CURLMOPT_TIMERFUNCTION.md: emphasize that only a single timer should run [5]
- o FTP: partly revert eeb7c1280742f5c8fa48a4340fc1e1a1a2c7075a [34]
- o http2: when uploading data from stdin, fix eos forwarding [7]
- o http: make max-filesize check not count ignored bodies [33]
- o lib: fix AF_INET6 use outside of USE_IPV6 [13]
- o libcurl-docs: CURLINFO_LOCAL_* work for QUIC as well as TCP [1]
- o multi: check that the multi handle is valid in curl_multi_assign [14]
- o QUIC: on connect, keep on trying on draining server [11]
- o request: correctly reset the eos_sent flag [21]
- o runtests: accecpt 'quictls' as OpenSSL compatible [2]
- o rustls: fixed minor logic bug in default cipher selection [12]
- o rustls: rustls-ffi 0.14.0 update [18]
- o rustls: support strong CSRNG data [16]
- o setopt: remove superfluous use of ternary expressions [4]
- o singleuse: drop `Curl_memrchr()` for no-HTTP builds [24]
- o test537: cap the rlimit max this test runs [10]
- o tests: tweak lock file handling and timers [22]
- o tool_cb_wrt: use "curl_response" if no file name in URL [19]
- o transfer: fix sendrecv() without interim poll [15]
- o vtls: fix `Curl_ssl_conn_config_match` doc param [6]
+ o appveyor: make VS2008-built curl tool runnable [93]
+ o asyn-thread: use pipe instead of socketpair for IPC when available [4]
+ o autotools: accept linker flags via `CURL_LDFLAGS_{LIB,BIN}` [128]
+ o autotools: avoid passing `LDFLAGS` twice to libcurl [127]
+ o autotools: delete LCC compiler support bits [137]
+ o autotools: fix/improve gcc and Apple clang version detection [136]
+ o autotools: stop setting `-std=gnu89` with `--enable-warnings` [135]
+ o autotools: update references to deleted `crypt-auth` option [46]
+ o BINDINGS: add V binding [54]
+ o build: add `src/.checksrc` to source tarball [1]
+ o build: add more picky warnings and fix them [172]
+ o build: always revert `#pragma GCC diagnostic` after use [143]
+ o build: delete `HAVE_STDINT_H` and `HAVE_INTTYPES_H` [107]
+ o build: delete support bits for obsolete Windows compilers [106]
+ o build: fix 'threadsafe' feature detection for older gcc [19]
+ o build: fix builds that disable protocols but not digest auth [174]
+ o build: fix compiler warning with auths disabled [85]
+ o build: fix libssh2 + `CURL_DISABLE_DIGEST_AUTH` + `CURL_DISABLE_AWS` [120]
+ o build: picky warning updates [125]
+ o build: require Windows XP or newer [86]
+ o cfilter: provide call to tell connection to forget a socket [65]
+ o checksrc.pl: support #line instructions
+ o CI: add autotools, out-of-tree, debug build to distro check job [14]
+ o CI: ignore test 286 on Appveyor gcc 9 build [6]
+ o cmake: add `CURL_DISABLE_BINDLOCAL` option [146]
+ o cmake: add test for `DISABLE` options, add `CURL_DISABLE_HEADERS_API` [138]
+ o cmake: dedupe Windows system libs [114]
+ o cmake: fix `HAVE_H_ERRNO_ASSIGNABLE` detection [2]
+ o cmake: fix CURL_DISABLE_GETOPTIONS [12]
+ o cmake: fix multiple include of CURL package [96]
+ o cmake: fix OpenSSL quic detection in quiche builds [56]
+ o cmake: option to disable install & drop `curlu` target when unused [72]
+ o cmake: pre-fill rest of detection values for Windows [50]
+ o cmake: replace `check_library_exists_concat()` [23]
+ o cmake: speed up threads setup for Windows [68]
+ o cmake: speed up zstd detection [69]
+ o config-win32: set `HAVE_SNPRINTF` for mingw-w64 [123]
+ o configure: better --disable-http [80]
+ o configure: check for the fseeko declaration too [55]
+ o conncache: use the closure handle when disconnecting surplus connections [173]
+ o content_encoding: make Curl_all_content_encodings allocless [101]
+ o cookie: lowercase the domain names before PSL checks [160]
+ o curl.h: delete Symbian OS references [162]
+ o curl.h: on FreeBSD include sys/param.h instead of osreldate.h [21]
+ o curl.rc: switch out the copyright symbol for plain ASCII [167]
+ o curl: improved IPFS and IPNS URL support [87]
+ o curl_easy_duphandle.3: clarify how HSTS and alt-svc are duped [99]
+ o Curl_http_body: cleanup properly when Curl_getformdata errors [152]
+ o curl_setup: disallow Windows IPv6 builds missing getaddrinfo [57]
+ o curl_sspi: support more revocation error names in error messages [95]
+ o CURLINFO_PRETRANSFER_TIME_T.3: fix time explanation [181]
+ o CURLMOPT_MAX_CONCURRENT_STREAMS: make sure the set value is within range [165]
+ o CURLOPT_CAINFO_BLOB.3: explain what CURL_BLOB_COPY does [113]
+ o CURLOPT_WRITEFUNCTION.3: clarify libcurl returns for CURL_WRITEFUNC_ERROR [45]
+ o CURPOST_POSTFIELDS.3: add CURLOPT_COPYPOSTFIELDS in SEE ALSO
+ o docs/example/keepalive.c: show TCP keep-alive options [73]
+ o docs/example/localport.c: show off CURLOPT_LOCALPORT [83]
+ o docs/examples/interface.c: show CURLOPT_INTERFACE use [84]
+ o docs/libcurl: fix three minor man page format mistakes [26]
+ o docs/libcurl: SYNSOPSIS cleanup [150]
+ o docs: add supported version for the json write-out [92]
+ o docs: clarify that curl passes on input unfiltered [47]
+ o docs: fix function typo in curl_easy_option_next.3 [36]
+ o docs: KNOWN_BUGS cleanup
+ o docs: make all examples in all libcurl man pages compile [175]
+ o docs: preserve the modification date when copying the prebuilt man page [89]
+ o docs: remove bold from some man page SYNOPSIS sections [90]
+ o docs: use SOURCE_DATE_EPOCH for generated manpages [16]
+ o doh: provide better return code for responses w/o addresses [133]
+ o doh: use PIPEWAIT when HTTP/2 is attempted [63]
+ o duphandle: also free 'outcurl->cookies' in error path [122]
+ o duphandle: make dupset() not return with pointers to old alloced data [109]
+ o duphandle: use strdup to clone *COPYPOSTFIELDS if size is not set [132]
+ o easy: in duphandle, init the cookies for the new handle [131]
+ o easy: remove duplicate wolfSSH init call [37]
+ o easy_lock: add a pthread_mutex_t fallback [13]
+ o examples/rtsp-options.c: add [157]
+ o fopen: create new file using old file's mode [153]
+ o fopen: create short(er) temporary file name [155]
+ o getenv: PlayStation doesn't have getenv() [41]
+ o GHA: move mod_h2 version in CI to v2.0.25 [43]
+ o hostip: show the list of IPs when resolving is done [35]
+ o hostip: silence compiler warning `-Wparentheses-equality` [62]
+ o hsts: skip single-dot hostname [67]
+ o HTTP/2, HTTP/3: handle detach of onoing transfers [134]
+ o http2: header conversion tightening [33]
+ o http2: provide an error callback and failf the message [53]
+ o http2: safer invocation of populate_binsettings [8]
+ o http: allow longer HTTP/2 request method names [112]
+ o http: avoid Expect: 100-continue if Upgrade: is used [15]
+ o http: consider resume with CURLOPT_FAILONERRROR and 416 to be fine [81]
+ o http: fix `-Wunused-parameter` with no auth and no proxy [149]
+ o http: fix `-Wunused-variable` compiler warning [115]
+ o http: fix empty-body warning [76]
+ o http_aws_sigv4: canonicalise valueless query params [88]
+ o hyper: temporarily remove HTTP/2 support [139]
+ o INSTALL: update list of ports and CPU archs
+ o IPFS: fix IPFS_PATH and file parsing [119]
+ o keylog: disable if unused [145]
+ o lib: add and use Curl_strndup() [97]
+ o lib: apache style infof and trace macros/functions [71]
+ o lib: fix gcc warning in printf call [7]
+ o libcurl-errors.3: sync with current public headers [156]
+ o libcurl-thread.3: simplify the TLS section [79]
+ o Makefile.am: drop vc10, vc11 and vc12 projects from dist [103]
+ o Makefile.mk: fix `-rtmp` option for non-Windows
+ o mime: store "form escape" as a single bit [170]
+ o misc: fix -Walloc-size warnings [118]
+ o msh3: error when built with CURL_DISABLE_SOCKETPAIR set [61]
+ o multi: during ratelimit multi_getsock should return no sockets [182]
+ o multi: use pipe instead of socketpair to *wakeup() [18]
+ o ngtcp2: fix races in stream handling [178]
+ o ngtcp2: ignore errors on unknown streams [158]
+ o ntlm_wb: use pipe instead of socketpair when possible [44]
+ o openldap: move the alloc of ldapconninfo to *connect() [29]
+ o openldap: set the callback argument in oldap_do [30]
+ o openssl: avoid BN_num_bits() NULL pointer derefs [9]
+ o openssl: fix building with v3 `no-deprecated` + add CI test [161]
+ o openssl: fix infof() to avoid compiler warning for %s with null [70]
+ o openssl: identify the "quictls" backend correctly [82]
+ o openssl: include SIG and KEM algorithms in verbose [52]
+ o openssl: make CURLSSLOPT_NATIVE_CA import Windows intermediate CAs [58]
+ o openssl: two multi pointer checks should probably rather be asserts [91]
+ o openssl: when a session-ID is reused, skip OCSP stapling [142]
+ o page-footer: clarify exit code 25 [51]
+ o projects: add VC14.20 project files [104]
+ o pytest: use lower count in repeat tests [98]
+ o quic: make eyeballers connect retries stop at weird replies [140]
+ o quic: manage connection idle timeouts [5]
+ o quiche: use quiche_conn_peer_transport_params() [116]
+ o rand: fix build error with autotools + LibreSSL [111]
+ o resolve.d: drop a multi use-sentence [100]
+ o RTSP: improved RTP parser [32]
+ o rustls: implement connect_blocking [154]
+ o sasl: fix `-Wunused-function` compiler warning [124]
+ o schannel: add CA cache support for files and memory blobs [121]
+ o setopt: check CURLOPT_TFTP_BLKSIZE range on set [171]
+ o setopt: remove outdated cookie comment [64]
+ o setopt: remove superfluous use of ternary expressions [169]
+ o socks: better buffer size checks for socks4a user and hostname [20]
+ o socks: make SOCKS5 use the CURLOPT_IPRESOLVE choice [38]
+ o symbols-in-versions: the CLOSEPOLICY options are deprecated
+ o test1683: remove commented-out check alternatives
+ o test3103: add missing quotes around a test tag attribute
+ o test613: stop showing an error on missing output file
+ o tests/README: SOCKS tests are not using OpenSSH, it has its own server [48]
+ o tests/server: add more SOCKS5 handshake error checking [27]
+ o tests: Fix Windows test helper tool search & use it for handle64 [17]
+ o tidy-up: casing typos, delete unused Windows version aliases [144]
+ o tool: fix --capath when proxy support is disabled [28]
+ o tool: support bold headers in Windows [117]
+ o tool_cb_hdr: add an additional parsing check [129]
+ o tool_cb_prg: make the carriage return fit for wide progress bars [159]
+ o tool_cb_wrt: fix write output for very old Windows versions [24]
+ o tool_getparam: limit --rate to be smaller than number of ms [3]
+ o tool_operate: do not mix memory models [108]
+ o tool_operate: fix links in ipfs errors [22]
+ o tool_parsecfg: make warning output propose double-quoting [164]
+ o tool_urlglob: fix build for old gcc versions [25]
+ o tool_urlglob: make multiply() bail out on negative values [11]
+ o tool_writeout_json: fix JSON encoding of non-ascii bytes [179]
+ o transfer: abort pause send when connection is marked for closing [183]
+ o transfer: avoid calling the read callback again after EOF [130]
+ o transfer: only reset the FTP wildcard engine in CLEAR state [42]
+ o url: don't touch the multi handle when closing internal handles [40]
+ o url: find scheme with a "perfect hash" [141]
+ o url: fix `-Wzero-length-array` with no protocols [147]
+ o url: fix builds with `CURL_DISABLE_HTTP` [148]
+ o url: protocol handler lookup tidy-up [66]
+ o url: proxy ssl connection reuse fix [94]
+ o urlapi: avoid null deref if setting blank host to url encode [75]
+ o urlapi: skip appending NULL pointer query [74]
+ o urlapi: when URL encoding the fragment, pass in the right length [59]
+ o urldata: make maxconnects a 32 bit value [166]
+ o urldata: move async resolver state from easy handle to connectdata [34]
+ o urldata: move cookielist from UserDefined to UrlState [126]
+ o urldata: move hstslist from 'set' to 'state' [105]
+ o urldata: move the 'internal' boolean to the state struct [39]
+ o vssh: remove the #ifdef for Curl_ssh_init, use empty macro
+ o vtls: cleanup SSL config management [78]
+ o vtls: consistently use typedef names for OpenSSL structs [176]
+ o vtls: late clone of connection ssl config [60]
+ o vtls: use ALPN "http/1.1" for HTTP/1.x, including HTTP/1.0 [102]
+ o VULN-DISCLOSURE-POLICY: escape sequences are not a security flaw [110]
+ o windows: use built-in `_WIN32` macro to detect Windows [163]
+ o wolfssh: remove redundant static prototypes [168]
+ o wolfssl: add default case for wolfssl_connect_step1 switch [49]
+ o wolfssl: require WOLFSSL_SYS_CA_CERTS for loading system CA [10]
This release includes the following known bugs:
- See docs/KNOWN_BUGS (https://curl.se/docs/knownbugs.html)
-
-For all changes ever done in curl:
-
- See https://curl.se/changes.html
+ o see docs/KNOWN_BUGS (https://curl.se/docs/knownbugs.html)
Planned upcoming removals include:
- o Hyper support after February 2025 [89]
- o TLS libraries not supporting TLS 1.3
+ o support for space-separated NOPROXY patterns
See https://curl.se/dev/deprecate.html for details
This release would not have looked like this without help, code, reports and
advice from friends like these:
- Brian Inglis, Carlo Cabrera, Daniel McCarney, Daniel Stenberg,
- dependabot[bot], finkjsc on github, Gabriel Marin, Harry Sintonen,
- Jan Venekamp, Julian K., MasterInQuestion on github, Michael Osipov,
- nekopsykose on github, Patrick Steinhardt, rampageX on github,
- Stefan Eissing, Tal Regev, Victor Kislov, Viktor Szakats
- (19 contributors)
+ 12932 on github, Alex Bozarth, Alexey Larikov, Alex Klyubin, Ammar Faizi,
+ Andrew Kurushin, Anubhav Rai, boilingoden, calvin2021y on github,
+ Carlos Henrique Lima Melara, Casey Bodley, Charlie C, Dan Fandrich,
+ Daniel Jeliński, Daniel Stenberg, David Benjamin, David Suter, Dmitry Karpov,
+ eeverettrbx on github, Emanuele Torre, Enno Boland, enWILLYado on github,
+ Faraz Fallahi, Gisle Vanem, Goro FUJI, Graham Campbell, Harry Mallon,
+ Harry Sintonen, iconoclasthero, icy17 on github, Jacob Hoffman-Andrews,
+ Jan Alexander Steffens, Jeroen Ooms, Jiehong on github, Jiri Hruska,
+ Junho Choi, Kai Pastor, Kareem, Kartatz on Github, kirbyn17 on hackerone,
+ Lau, lkordos on github, Loïc Yhuel, LoRd_MuldeR, lRoccoon on github,
+ Maksymilian Arciemowicz, Manfred Schwarb, Marcel Raad, Marcin Rataj,
+ Mark Gaiser, Martin Schmatz, Michael Kaufmann, Michał Antoniak, Nico Rieck,
+ Niracler Li, ohyeaah on github, Ophir Lojkine, Paweł Wegner, Philip Heiduck,
+ Ray Satiro, rilysh, Robert Southee, Romain Geissler, Sam James,
+ Samuel Henrique, sd0 on hackerone, Smackd0wn, Sohom Datta, Stefan Eissing,
+ Steven Allen, Tim Hill, Torben Dury, Turiiya, Viktor Szakats,
+ yushicheng7788 on github, z2_, zhengqwe on github, 積丹尼 Dan Jacobson
+ (78 contributors)
References to bug reports and discussions on issues:
- [1] = https://curl.se/bug/?i=14852
- [2] = https://curl.se/bug/?i=14850
- [3] = https://curl.se/bug/?i=14879
- [4] = https://curl.se/bug/?i=14884
- [5] = https://curl.se/bug/?i=14886
- [6] = https://curl.se/bug/?i=14887
- [7] = https://curl.se/bug/?i=14870
- [8] = https://curl.se/bug/?i=14872
- [9] = https://curl.se/bug/?i=14897
- [10] = https://curl.se/bug/?i=14857
- [11] = https://curl.se/bug/?i=14863
- [12] = https://curl.se/bug/?i=14840
- [13] = https://curl.se/bug/?i=14858
- [14] = https://curl.se/bug/?i=14860
- [15] = https://curl.se/bug/?i=14898
- [16] = https://curl.se/bug/?i=14889
- [18] = https://curl.se/bug/?i=14889
- [19] = https://curl.se/bug/?i=14939
- [20] = https://curl.se/bug/?i=14927
- [21] = https://marc.info/?l=git&m=172620452502747&w=2
- [22] = https://curl.se/bug/?i=14835
- [24] = https://curl.se/bug/?i=14919
- [33] = https://curl.se/bug/?i=14899
- [34] = https://curl.se/bug/?i=14873
+ [1] = https://curl.se/bug/?i=12084
+ [2] = https://curl.se/bug/?i=12093
+ [3] = https://curl.se/bug/?i=12116
+ [4] = https://curl.se/bug/?i=12146
+ [5] = https://curl.se/bug/?i=12064
+ [6] = https://curl.se/bug/?i=12040
+ [7] = https://curl.se/bug/?i=12082
+ [8] = https://curl.se/bug/?i=12101
+ [9] = https://curl.se/bug/?i=12099
+ [10] = https://curl.se/bug/?i=12108
+ [11] = https://curl.se/bug/?i=12102
+ [12] = https://curl.se/bug/?i=12091
+ [13] = https://curl.se/bug/?i=12090
+ [14] = https://curl.se/bug/?i=12088
+ [15] = https://curl.se/bug/?i=12022
+ [16] = https://curl.se/bug/?i=12092
+ [17] = https://curl.se/bug/?i=12115
+ [18] = https://curl.se/bug/?i=12142
+ [19] = https://curl.se/bug/?i=12125
+ [20] = https://curl.se/bug/?i=12139
+ [21] = https://curl.se/bug/?i=12107
+ [22] = https://curl.se/bug/?i=12133
+ [23] = https://curl.se/bug/?i=11285
+ [24] = https://curl.se/bug/?i=12131
+ [25] = https://curl.se/bug/?i=12124
+ [26] = https://curl.se/bug/?i=12126
+ [27] = https://curl.se/bug/?i=12117
+ [28] = https://curl.se/bug/?i=12089
+ [29] = https://curl.se/bug/?i=12166
+ [30] = https://curl.se/bug/?i=12166
+ [31] = https://curl.se/bug/?i=12137
+ [32] = https://curl.se/bug/?i=12052
+ [33] = https://curl.se/bug/?i=12097
+ [34] = https://curl.se/bug/?i=12198
+ [35] = https://curl.se/bug/?i=12145
+ [36] = https://curl.se/bug/?i=12170
+ [37] = https://curl.se/bug/?i=12168
+ [38] = https://curl.se/bug/?i=11949
+ [39] = https://curl.se/bug/?i=12165
+ [40] = https://curl.se/bug/?i=12165
+ [41] = https://curl.se/bug/?i=12140
+ [42] = https://curl.se/bug/?i=11775
+ [43] = https://curl.se/bug/?i=12157
+ [44] = https://curl.se/bug/?i=12149
+ [45] = https://curl.se/bug/?i=12201
+ [46] = https://curl.se/bug/?i=12194
+ [47] = https://curl.se/bug/?i=12249
+ [48] = https://curl.se/bug/?i=12195
+ [49] = https://curl.se/bug/?i=12218
+ [50] = https://curl.se/bug/?i=12044
+ [51] = https://curl.se/bug/?i=12189
+ [52] = https://curl.se/bug/?i=12030
+ [53] = https://curl.se/bug/?i=12179
+ [54] = https://curl.se/bug/?i=12182
+ [55] = https://curl.se/bug/?i=12086
+ [56] = https://curl.se/bug/?i=12160
+ [57] = https://curl.se/bug/?i=12221
+ [58] = https://curl.se/bug/?i=12155
+ [59] = https://curl.se/bug/?i=12250
+ [60] = https://curl.se/bug/?i=12237
+ [61] = https://curl.se/bug/?i=12213
+ [62] = https://curl.se/bug/?i=12215
+ [63] = https://curl.se/bug/?i=12214
+ [64] = https://curl.se/bug/?i=12206
+ [65] = https://curl.se/bug/?i=12207
+ [66] = https://curl.se/bug/?i=12216
+ [67] = https://curl.se/bug/?i=12247
+ [68] = https://curl.se/bug/?i=12202
+ [69] = https://curl.se/bug/?i=12200
+ [70] = https://curl.se/bug/?i=12196
+ [71] = https://curl.se/bug/?i=12083
+ [72] = https://curl.se/bug/?i=12287
+ [73] = https://curl.se/bug/?i=12242
+ [74] = https://curl.se/bug/?i=12240
+ [75] = https://curl.se/bug/?i=12240
+ [76] = https://curl.se/bug/?i=12262
+ [77] = https://curl.se/bug/?i=12235
+ [78] = https://curl.se/bug/?i=12204
+ [79] = https://curl.se/bug/?i=12233
+ [80] = https://curl.se/bug/?i=12223
+ [81] = https://curl.se/bug/?i=10521
+ [82] = https://curl.se/bug/?i=12270
+ [83] = https://curl.se/bug/?i=12230
+ [84] = https://curl.se/bug/?i=12229
+ [85] = https://curl.se/bug/?i=12227
+ [86] = https://curl.se/bug/?i=12225
+ [87] = https://curl.se/bug/?i=12148
+ [88] = https://curl.se/bug/?i=8107
+ [89] = https://curl.se/bug/?i=12199
+ [90] = https://curl.se/bug/?i=12267
+ [91] = https://curl.se/bug/?i=12264
+ [92] = https://curl.se/bug/?i=12266
+ [93] = https://curl.se/bug/?i=12263
+ [94] = https://curl.se/bug/?i=12255
+ [95] = https://curl.se/bug/?i=12239
+ [96] = https://curl.se/bug/?i=11913
+ [97] = https://curl.se/bug/?i=12251
+ [98] = https://curl.se/bug/?i=12248
+ [99] = https://curl.se/bug/?i=12315
+ [100] = https://curl.se/bug/?i=12294
+ [101] = https://curl.se/bug/?i=12289
+ [102] = https://curl.se/bug/?i=12259
+ [103] = https://curl.se/bug/?i=12288
+ [104] = https://curl.se/bug/?i=12282
+ [105] = https://curl.se/bug/?i=12315
+ [106] = https://curl.se/bug/?i=12222
+ [107] = https://curl.se/bug/?i=12275
+ [108] = https://curl.se/bug/?i=12280
+ [109] = https://curl.se/bug/?i=12337
+ [110] = https://curl.se/bug/?i=12278
+ [111] = https://curl.se/bug/?i=12257
+ [112] = https://curl.se/bug/?i=12311
+ [113] = https://curl.se/bug/?i=12277
+ [114] = https://curl.se/bug/?i=12307
+ [115] = https://curl.se/bug/?i=12228
+ [116] = https://curl.se/bug/?i=12180
+ [117] = https://curl.se/bug/?i=12321
+ [118] = https://curl.se/bug/?i=12292
+ [119] = https://curl.se/bug/?i=12152
+ [120] = https://curl.se/bug/?i=12273
+ [121] = https://curl.se/bug/?i=12261
+ [122] = https://curl.se/bug/?i=12329
+ [123] = https://curl.se/bug/?i=12325
+ [124] = https://curl.se/bug/?i=12326
+ [125] = https://curl.se/bug/?i=12324
+ [126] = https://curl.se/bug/?i=12323
+ [127] = https://curl.se/bug/?i=12310
+ [128] = https://curl.se/bug/?i=12312
+ [129] = https://curl.se/bug/?i=12320
+ [130] = https://curl.se/mail/lib-2023-11/0017.html
+ [131] = https://curl.se/bug/?i=12318
+ [132] = https://curl.se/bug/?i=12317
+ [133] = https://curl.se/bug/?i=12365
+ [134] = https://curl.se/bug/?i=12356
+ [135] = https://curl.se/bug/?i=12346
+ [136] = https://curl.se/bug/?i=12362
+ [137] = https://curl.se/bug/?i=12357
+ [138] = https://curl.se/bug/?i=12353
+ [139] = https://curl.se/bug/?i=12191
+ [140] = https://curl.se/bug/?i=12400
+ [141] = https://curl.se/bug/?i=12347
+ [142] = https://curl.se/bug/?i=12399
+ [143] = https://curl.se/bug/?i=12352
+ [144] = https://curl.se/bug/?i=12351
+ [145] = https://curl.se/bug/?i=12350
+ [146] = https://curl.se/bug/?i=12345
+ [147] = https://curl.se/bug/?i=12344
+ [148] = https://curl.se/bug/?i=12343
+ [149] = https://curl.se/bug/?i=12338
+ [150] = https://curl.se/bug/?i=12402
+ [152] = https://curl.se/bug/?i=12410
+ [153] = https://curl.se/bug/?i=12299
+ [154] = https://curl.se/bug/?i=11647
+ [155] = https://curl.se/bug/?i=12388
+ [156] = https://curl.se/bug/?i=12424
+ [157] = https://curl.se/bug/?i=12452
+ [158] = https://curl.se/bug/?i=12449
+ [159] = https://curl.se/bug/?i=12407
+ [160] = https://curl.se/bug/?i=12387
+ [161] = https://curl.se/bug/?i=12384
+ [162] = https://curl.se/bug/?i=12378
+ [163] = https://curl.se/bug/?i=12376
+ [164] = https://curl.se/bug/?i=12409
+ [165] = https://curl.se/bug/?i=12382
+ [166] = https://curl.se/bug/?i=12375
+ [167] = https://curl.se/bug/?i=12403
+ [168] = https://curl.se/bug/?i=12381
+ [169] = https://curl.se/bug/?i=12374
+ [170] = https://curl.se/bug/?i=12374
+ [171] = https://curl.se/bug/?i=12374
+ [172] = https://curl.se/bug/?i=12331
+ [173] = https://curl.se/bug/?i=12367
+ [174] = https://curl.se/bug/?i=12440
+ [175] = https://curl.se/bug/?i=12448
+ [176] = https://curl.se/bug/?i=12439
+ [178] = https://curl.se/bug/?i=12435
+ [179] = https://curl.se/bug/?i=12434
+ [181] = https://curl.se/bug/?i=12431
+ [182] = https://curl.se/bug/?i=12430
+ [183] = https://curl.se/bug/?i=12428
diff --git a/contrib/libs/curl/bin/.yandex_meta/licenses.list.txt b/contrib/libs/curl/bin/.yandex_meta/licenses.list.txt
index edd9a78a77..88ccb632f5 100644
--- a/contrib/libs/curl/bin/.yandex_meta/licenses.list.txt
+++ b/contrib/libs/curl/bin/.yandex_meta/licenses.list.txt
@@ -1,4 +1,33 @@
====================BSD-3-Clause====================
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE. */
+
+
+====================BSD-3-Clause====================
* SPDX-License-Identifier: BSD-3-Clause
@@ -18,8 +47,8 @@
====================COPYRIGHT====================
- * This software was written by Alexander Peslyak in 2001. No copyright is
- * claimed, and the software is hereby placed in the public domain. In case
+ * This software was written by Alexander Peslyak in 2001. No copyright is
+ * claimed, and the software is hereby placed in the public domain. In case
* this attempt to disclaim copyright and place the software in the public
* domain is deemed null and void, then the software is Copyright (c) 2001
* Alexander Peslyak and it is hereby released to the general public under the
@@ -29,7 +58,7 @@
====================File: COPYING====================
COPYRIGHT AND PERMISSION NOTICE
-Copyright (c) 1996 - 2024, Daniel Stenberg, <daniel@haxx.se>, and many
+Copyright (c) 1996 - 2023, Daniel Stenberg, <daniel@haxx.se>, and many
contributors, see the THANKS file.
All rights reserved.
@@ -100,6 +129,48 @@ in this Software without prior written authorization of the copyright holder.
====================Public-Domain====================
+ https://openwall.info/wiki/people/solar/software/public-domain-source-code/md4
+ *
+ * Author:
+ * Alexander Peslyak, better known as Solar Designer <solar at openwall.com>
+ *
+ * This software was written by Alexander Peslyak in 2001. No copyright is
+ * claimed, and the software is hereby placed in the public domain. In case
+ * this attempt to disclaim copyright and place the software in the public
+ * domain is deemed null and void, then the software is Copyright (c) 2001
+ * Alexander Peslyak and it is hereby released to the general public under the
+ * following terms:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted.
+ *
+ * There's ABSOLUTELY NO WARRANTY, express or implied.
+ *
+ * (This is a heavily cut-down "BSD license".)
+
+
+====================Public-Domain====================
+ https://openwall.info/wiki/people/solar/software/public-domain-source-code/md5
+ *
+ * Author:
+ * Alexander Peslyak, better known as Solar Designer <solar at openwall.com>
+ *
+ * This software was written by Alexander Peslyak in 2001. No copyright is
+ * claimed, and the software is hereby placed in the public domain.
+ * In case this attempt to disclaim copyright and place the software in the
+ * public domain is deemed null and void, then the software is
+ * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the
+ * general public under the following terms:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted.
+ *
+ * There's ABSOLUTELY NO WARRANTY, express or implied.
+ *
+ * (This is a heavily cut-down "BSD license".)
+
+
+====================Public-Domain====================
/* This is based on SHA256 implementation in LibTomCrypt that was released into
* public domain by Tom St Denis. */
diff --git a/contrib/libs/curl/bin/ya.make b/contrib/libs/curl/bin/ya.make
index 3aaf655b29..bc7c458aea 100644
--- a/contrib/libs/curl/bin/ya.make
+++ b/contrib/libs/curl/bin/ya.make
@@ -11,7 +11,7 @@ LICENSE(
LICENSE_TEXTS(.yandex_meta/licenses.list.txt)
-VERSION(8.10.1)
+VERSION(8.5.0)
PEERDIR(
contrib/libs/c-ares
@@ -46,16 +46,13 @@ SRCS(
lib/version_win32.c
lib/warnless.c
src/slist_wc.c
- src/terminal.c
src/tool_binmode.c
src/tool_bname.c
- src/tool_ca_embed.c
src/tool_cb_dbg.c
src/tool_cb_hdr.c
src/tool_cb_prg.c
src/tool_cb_rea.c
src/tool_cb_see.c
- src/tool_cb_soc.c
src/tool_cb_wrt.c
src/tool_cfgable.c
src/tool_dirhie.c
diff --git a/contrib/libs/curl/include/README.md b/contrib/libs/curl/include/README.md
index b155d8c13b..c96593263f 100644
--- a/contrib/libs/curl/include/README.md
+++ b/contrib/libs/curl/include/README.md
@@ -8,7 +8,7 @@ SPDX-License-Identifier: curl
Public include files for libcurl, external users.
-They are all placed in the curl subdirectory here for better fit in any kind of
+They're all placed in the curl subdirectory here for better fit in any kind of
environment. You must include files from here using...
#include <curl/curl.h>
diff --git a/contrib/libs/curl/include/curl/curl.h b/contrib/libs/curl/include/curl/curl.h
index c4fae4d446..cc24c05065 100644
--- a/contrib/libs/curl/include/curl/curl.h
+++ b/contrib/libs/curl/include/curl/curl.h
@@ -34,32 +34,24 @@
#endif
/* Compile-time deprecation macros. */
-#if (defined(__GNUC__) && \
- ((__GNUC__ > 12) || ((__GNUC__ == 12) && (__GNUC_MINOR__ >= 1 ))) || \
- defined(__IAR_SYSTEMS_ICC__)) && \
+#if defined(__GNUC__) && \
+ ((__GNUC__ > 12) || ((__GNUC__ == 12) && (__GNUC_MINOR__ >= 1 ))) && \
!defined(__INTEL_COMPILER) && \
!defined(CURL_DISABLE_DEPRECATION) && !defined(BUILDING_LIBCURL)
#define CURL_DEPRECATED(version, message) \
__attribute__((deprecated("since " # version ". " message)))
-#if defined(__IAR_SYSTEMS_ICC__)
-#define CURL_IGNORE_DEPRECATION(statements) \
- _Pragma("diag_suppress=Pe1444") \
- statements \
- _Pragma("diag_default=Pe1444")
-#else
#define CURL_IGNORE_DEPRECATION(statements) \
_Pragma("GCC diagnostic push") \
_Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") \
statements \
_Pragma("GCC diagnostic pop")
-#endif
#else
#define CURL_DEPRECATED(version, message)
#define CURL_IGNORE_DEPRECATION(statements) statements
#endif
#include "curlver.h" /* libcurl version defines */
-#include "system.h" /* determine things runtime */
+#include "system.h" /* determine things run-time */
#include <stdio.h>
#include <limits.h>
@@ -76,8 +68,8 @@
#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__CYGWIN__)
#if !(defined(_WINSOCKAPI_) || defined(_WINSOCK_H) || \
defined(__LWIP_OPT_H__) || defined(LWIP_HDR_OPT_H))
-/* The check above prevents the winsock2.h inclusion if winsock.h already was
- included, since they cannot co-exist without problems */
+/* The check above prevents the winsock2 inclusion if winsock.h already was
+ included, since they can't co-exist without problems */
#include <winsock2.h>
#include <ws2tcpip.h>
#endif
@@ -197,9 +189,9 @@ struct curl_httppost {
files */
long flags; /* as defined below */
-/* specified content is a filename */
+/* specified content is a file name */
#define CURL_HTTPPOST_FILENAME (1<<0)
-/* specified content is a filename */
+/* specified content is a file name */
#define CURL_HTTPPOST_READFILE (1<<1)
/* name is only stored pointer do not free in formfree */
#define CURL_HTTPPOST_PTRNAME (1<<2)
@@ -215,8 +207,8 @@ struct curl_httppost {
/* use size in 'contentlen', added in 7.46.0 */
#define CURL_HTTPPOST_LARGE (1<<7)
- char *showfilename; /* The filename to show. If not set, the
- actual filename will be used (if this
+ char *showfilename; /* The file name to show. If not set, the
+ actual file name will be used (if this
is a file part) */
void *userp; /* custom pointer used for
HTTPPOST_CALLBACK posts */
@@ -358,13 +350,13 @@ typedef long (*curl_chunk_bgn_callback)(const void *transfer_info,
download of an individual chunk finished.
Note! After this callback was set then it have to be called FOR ALL chunks.
Even if downloading of this chunk was skipped in CHUNK_BGN_FUNC.
- This is the reason why we do not need "transfer_info" parameter in this
+ This is the reason why we don't need "transfer_info" parameter in this
callback and we are not interested in "remains" parameter too. */
typedef long (*curl_chunk_end_callback)(void *ptr);
/* return codes for FNMATCHFUNCTION */
#define CURL_FNMATCHFUNC_MATCH 0 /* string corresponds to the pattern */
-#define CURL_FNMATCHFUNC_NOMATCH 1 /* pattern does not match the string */
+#define CURL_FNMATCHFUNC_NOMATCH 1 /* pattern doesn't match the string */
#define CURL_FNMATCHFUNC_FAIL 2 /* an error occurred */
/* callback type for wildcard downloading pattern matching. If the
@@ -376,7 +368,7 @@ typedef int (*curl_fnmatch_callback)(void *ptr,
/* These are the return codes for the seek callbacks */
#define CURL_SEEKFUNC_OK 0
#define CURL_SEEKFUNC_FAIL 1 /* fail the entire transfer */
-#define CURL_SEEKFUNC_CANTSEEK 2 /* tell libcurl seeking cannot be done, so
+#define CURL_SEEKFUNC_CANTSEEK 2 /* tell libcurl seeking can't be done, so
libcurl might try other means instead */
typedef int (*curl_seek_callback)(void *instream,
curl_off_t offset,
@@ -459,7 +451,7 @@ typedef curlioerr (*curl_ioctl_callback)(CURL *handle,
#ifndef CURL_DID_MEMORY_FUNC_TYPEDEFS
/*
* The following typedef's are signatures of malloc, free, realloc, strdup and
- * calloc respectively. Function pointers of these types can be passed to the
+ * calloc respectively. Function pointers of these types can be passed to the
* curl_global_init_mem() function to set user defined memory management
* callback routines.
*/
@@ -547,17 +539,17 @@ typedef enum {
CURLE_WRITE_ERROR, /* 23 */
CURLE_OBSOLETE24, /* 24 - NOT USED */
CURLE_UPLOAD_FAILED, /* 25 - failed upload "command" */
- CURLE_READ_ERROR, /* 26 - could not open/read from file */
+ CURLE_READ_ERROR, /* 26 - couldn't open/read from file */
CURLE_OUT_OF_MEMORY, /* 27 */
CURLE_OPERATION_TIMEDOUT, /* 28 - the timeout time was reached */
CURLE_OBSOLETE29, /* 29 - NOT USED */
CURLE_FTP_PORT_FAILED, /* 30 - FTP PORT operation failed */
CURLE_FTP_COULDNT_USE_REST, /* 31 - the REST command failed */
CURLE_OBSOLETE32, /* 32 - NOT USED */
- CURLE_RANGE_ERROR, /* 33 - RANGE "command" did not work */
+ CURLE_RANGE_ERROR, /* 33 - RANGE "command" didn't work */
CURLE_HTTP_POST_ERROR, /* 34 */
CURLE_SSL_CONNECT_ERROR, /* 35 - wrong when connecting with SSL */
- CURLE_BAD_DOWNLOAD_RESUME, /* 36 - could not resume download */
+ CURLE_BAD_DOWNLOAD_RESUME, /* 36 - couldn't resume download */
CURLE_FILE_COULDNT_READ_FILE, /* 37 */
CURLE_LDAP_CANNOT_BIND, /* 38 */
CURLE_LDAP_SEARCH_FAILED, /* 39 */
@@ -581,9 +573,9 @@ typedef enum {
CURLE_RECV_ERROR, /* 56 - failure in receiving network data */
CURLE_OBSOLETE57, /* 57 - NOT IN USE */
CURLE_SSL_CERTPROBLEM, /* 58 - problem with the local certificate */
- CURLE_SSL_CIPHER, /* 59 - could not use specified cipher */
+ CURLE_SSL_CIPHER, /* 59 - couldn't use specified cipher */
CURLE_PEER_FAILED_VERIFICATION, /* 60 - peer's certificate or fingerprint
- was not verified fine */
+ wasn't verified fine */
CURLE_BAD_CONTENT_ENCODING, /* 61 - Unrecognized/bad encoding */
CURLE_OBSOLETE62, /* 62 - NOT IN USE since 7.82.0 */
CURLE_FILESIZE_EXCEEDED, /* 63 - Maximum file size exceeded */
@@ -612,7 +604,7 @@ typedef enum {
CURLE_SSL_SHUTDOWN_FAILED, /* 80 - Failed to shut down the SSL
connection */
CURLE_AGAIN, /* 81 - socket is not ready for send/recv,
- wait till it is ready and try again (Added
+ wait till it's ready and try again (Added
in 7.18.2) */
CURLE_SSL_CRL_BADFILE, /* 82 - could not load CRL file, missing or
wrong format (Added in 7.19.0) */
@@ -639,8 +631,6 @@ typedef enum {
CURLE_PROXY, /* 97 - proxy handshake error */
CURLE_SSL_CLIENTCERT, /* 98 - client-side certificate required */
CURLE_UNRECOVERABLE_POLL, /* 99 - poll/select returned fatal error */
- CURLE_TOO_LARGE, /* 100 - a value/data met its maximum */
- CURLE_ECH_REQUIRED, /* 101 - ECH tried but failed */
CURL_LAST /* never use! */
} CURLcode;
@@ -721,8 +711,6 @@ typedef enum {
with them. */
#define CURLOPT_WRITEINFO CURLOPT_OBSOLETE40
#define CURLOPT_CLOSEPOLICY CURLOPT_OBSOLETE72
-#define CURLOPT_OBSOLETE72 9999
-#define CURLOPT_OBSOLETE40 9999
#endif /* !CURL_NO_OLDIES */
@@ -773,7 +761,7 @@ typedef CURLcode (*curl_conv_callback)(char *buffer, size_t length);
typedef CURLcode (*curl_ssl_ctx_callback)(CURL *curl, /* easy handle */
void *ssl_ctx, /* actually an OpenSSL
- or wolfSSL SSL_CTX,
+ or WolfSSL SSL_CTX,
or an mbedTLS
mbedtls_ssl_config */
void *userptr);
@@ -790,7 +778,7 @@ typedef enum {
CURLPROXY_SOCKS5 = 5, /* added in 7.10 */
CURLPROXY_SOCKS4A = 6, /* added in 7.18.0 */
CURLPROXY_SOCKS5_HOSTNAME = 7 /* Use the SOCKS5 protocol but pass along the
- hostname rather than the IP address. added
+ host name rather than the IP address. added
in 7.18.0 */
} curl_proxytype; /* this enum was added in 7.10 */
@@ -822,10 +810,7 @@ typedef enum {
#define CURLAUTH_GSSAPI CURLAUTH_NEGOTIATE
#define CURLAUTH_NTLM (((unsigned long)1)<<3)
#define CURLAUTH_DIGEST_IE (((unsigned long)1)<<4)
-#ifndef CURL_NO_OLDIES
- /* functionality removed since 8.8.0 */
#define CURLAUTH_NTLM_WB (((unsigned long)1)<<5)
-#endif
#define CURLAUTH_BEARER (((unsigned long)1)<<6)
#define CURLAUTH_AWS_SIGV4 (((unsigned long)1)<<7)
#define CURLAUTH_ONLY (((unsigned long)1)<<31)
@@ -870,7 +855,7 @@ enum curl_khstat {
CURLKHSTAT_FINE_ADD_TO_FILE,
CURLKHSTAT_FINE,
CURLKHSTAT_REJECT, /* reject the connection, return an error */
- CURLKHSTAT_DEFER, /* do not accept it, but we cannot answer right now.
+ CURLKHSTAT_DEFER, /* do not accept it, but we can't answer right now.
Causes a CURLE_PEER_FAILED_VERIFICATION error but the
connection will be left intact etc */
CURLKHSTAT_FINE_REPLACE, /* accept and replace the wrong key */
@@ -1090,7 +1075,7 @@ typedef CURLSTScode (*curl_hstswrite_callback)(CURL *easy,
#define CURLOPT(na,t,nu) na = t + nu
#define CURLOPTDEPRECATED(na,t,nu,v,m) na CURL_DEPRECATED(v,m) = t + nu
-/* CURLOPT aliases that make no runtime difference */
+/* CURLOPT aliases that make no run-time difference */
/* 'char *' argument to a string with a trailing zero */
#define CURLOPTTYPE_STRINGPOINT CURLOPTTYPE_OBJECTPOINT
@@ -1157,7 +1142,7 @@ typedef enum {
*
* For large file support, there is also a _LARGE version of the key
* which takes an off_t type, allowing platforms with larger off_t
- * sizes to handle larger files. See below for INFILESIZE_LARGE.
+ * sizes to handle larger files. See below for INFILESIZE_LARGE.
*/
CURLOPT(CURLOPT_INFILESIZE, CURLOPTTYPE_LONG, 14),
@@ -1190,7 +1175,7 @@ typedef enum {
*
* Note there is also a _LARGE version of this key which uses
* off_t types, allowing for large file offsets on platforms which
- * use larger-than-32-bit off_t's. Look below for RESUME_FROM_LARGE.
+ * use larger-than-32-bit off_t's. Look below for RESUME_FROM_LARGE.
*/
CURLOPT(CURLOPT_RESUME_FROM, CURLOPTTYPE_LONG, 21),
@@ -1252,7 +1237,8 @@ typedef enum {
/* send linked-list of post-transfer QUOTE commands */
CURLOPT(CURLOPT_POSTQUOTE, CURLOPTTYPE_SLISTPOINT, 39),
- /* 40 is not used */
+ /* OBSOLETE, do not use! */
+ CURLOPT(CURLOPT_OBSOLETE40, CURLOPTTYPE_OBJECTPOINT, 40),
/* talk a lot */
CURLOPT(CURLOPT_VERBOSE, CURLOPTTYPE_LONG, 41),
@@ -1325,9 +1311,9 @@ typedef enum {
/* Set the interface string to use as outgoing network interface */
CURLOPT(CURLOPT_INTERFACE, CURLOPTTYPE_STRINGPOINT, 62),
- /* Set the krb4/5 security level, this also enables krb4/5 awareness. This
- * is a string, 'clear', 'safe', 'confidential' or 'private'. If the string
- * is set but does not match one of these, 'private' will be used. */
+ /* Set the krb4/5 security level, this also enables krb4/5 awareness. This
+ * is a string, 'clear', 'safe', 'confidential' or 'private'. If the string
+ * is set but doesn't match one of these, 'private' will be used. */
CURLOPT(CURLOPT_KRBLEVEL, CURLOPTTYPE_STRINGPOINT, 63),
/* Set if we should verify the peer in ssl handshake, set 1 to verify. */
@@ -1353,20 +1339,22 @@ typedef enum {
/* Max amount of cached alive connections */
CURLOPT(CURLOPT_MAXCONNECTS, CURLOPTTYPE_LONG, 71),
- /* 72 = OBSOLETE */
+ /* OBSOLETE, do not use! */
+ CURLOPT(CURLOPT_OBSOLETE72, CURLOPTTYPE_LONG, 72),
+
/* 73 = OBSOLETE */
/* Set to explicitly use a new connection for the upcoming transfer.
- Do not use this unless you are absolutely sure of this, as it makes the
+ Do not use this unless you're absolutely sure of this, as it makes the
operation slower and is less friendly for the network. */
CURLOPT(CURLOPT_FRESH_CONNECT, CURLOPTTYPE_LONG, 74),
/* Set to explicitly forbid the upcoming transfer's connection to be reused
- when done. Do not use this unless you are absolutely sure of this, as it
+ when done. Do not use this unless you're absolutely sure of this, as it
makes the operation slower and is less friendly for the network. */
CURLOPT(CURLOPT_FORBID_REUSE, CURLOPTTYPE_LONG, 75),
- /* Set to a filename that contains random data for libcurl to use to
+ /* Set to a file name that contains random data for libcurl to use to
seed the random engine when doing SSL connects. */
CURLOPTDEPRECATED(CURLOPT_RANDOM_FILE, CURLOPTTYPE_STRINGPOINT, 76,
7.84.0, "Serves no purpose anymore"),
@@ -1393,11 +1381,11 @@ typedef enum {
* provided hostname. */
CURLOPT(CURLOPT_SSL_VERIFYHOST, CURLOPTTYPE_LONG, 81),
- /* Specify which filename to write all known cookies in after completed
- operation. Set filename to "-" (dash) to make it go to stdout. */
+ /* Specify which file name to write all known cookies in after completed
+ operation. Set file name to "-" (dash) to make it go to stdout. */
CURLOPT(CURLOPT_COOKIEJAR, CURLOPTTYPE_STRINGPOINT, 82),
- /* Specify which TLS 1.2 (1.1, 1.0) ciphers to use */
+ /* Specify which SSL ciphers to use */
CURLOPT(CURLOPT_SSL_CIPHER_LIST, CURLOPTTYPE_STRINGPOINT, 83),
/* Specify which HTTP version to use! This must be set to one of the
@@ -1493,7 +1481,7 @@ typedef enum {
CURLOPT(CURLOPT_HTTPAUTH, CURLOPTTYPE_VALUES, 107),
/* Set the ssl context callback function, currently only for OpenSSL or
- wolfSSL ssl_ctx, or mbedTLS mbedtls_ssl_config in the second argument.
+ WolfSSL ssl_ctx, or mbedTLS mbedtls_ssl_config in the second argument.
The function must match the curl_ssl_ctx_callback prototype. */
CURLOPT(CURLOPT_SSL_CTX_FUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 108),
@@ -1513,7 +1501,7 @@ typedef enum {
CURLOPT(CURLOPT_PROXYAUTH, CURLOPTTYPE_VALUES, 111),
/* Option that changes the timeout, in seconds, associated with getting a
- response. This is different from transfer timeout time and essentially
+ response. This is different from transfer timeout time and essentially
places a demand on the server to acknowledge commands in a timely
manner. For FTP, SMTP, IMAP and POP3. */
CURLOPT(CURLOPT_SERVER_RESPONSE_TIMEOUT, CURLOPTTYPE_LONG, 112),
@@ -1527,7 +1515,7 @@ typedef enum {
an HTTP or FTP server.
Note there is also _LARGE version which adds large file support for
- platforms which have larger off_t sizes. See MAXFILESIZE_LARGE below. */
+ platforms which have larger off_t sizes. See MAXFILESIZE_LARGE below. */
CURLOPT(CURLOPT_MAXFILESIZE, CURLOPTTYPE_LONG, 114),
/* See the comment for INFILESIZE above, but in short, specifies
@@ -1535,17 +1523,17 @@ typedef enum {
*/
CURLOPT(CURLOPT_INFILESIZE_LARGE, CURLOPTTYPE_OFF_T, 115),
- /* Sets the continuation offset. There is also a CURLOPTTYPE_LONG version
+ /* Sets the continuation offset. There is also a CURLOPTTYPE_LONG version
* of this; look above for RESUME_FROM.
*/
CURLOPT(CURLOPT_RESUME_FROM_LARGE, CURLOPTTYPE_OFF_T, 116),
/* Sets the maximum size of data that will be downloaded from
- * an HTTP or FTP server. See MAXFILESIZE above for the LONG version.
+ * an HTTP or FTP server. See MAXFILESIZE above for the LONG version.
*/
CURLOPT(CURLOPT_MAXFILESIZE_LARGE, CURLOPTTYPE_OFF_T, 117),
- /* Set this option to the filename of your .netrc file you want libcurl
+ /* Set this option to the file name of your .netrc file you want libcurl
to parse (using the CURLOPT_NETRC option). If not set, libcurl will do
a poor attempt to find the user's home directory and check for a .netrc
file in there. */
@@ -1692,7 +1680,7 @@ typedef enum {
/* Callback function for opening socket (instead of socket(2)). Optionally,
callback is able change the address or refuse to connect returning
- CURL_SOCKET_BAD. The callback should have type
+ CURL_SOCKET_BAD. The callback should have type
curl_opensocket_callback */
CURLOPT(CURLOPT_OPENSOCKETFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 163),
CURLOPT(CURLOPT_OPENSOCKETDATA, CURLOPTTYPE_CBPOINT, 164),
@@ -1762,7 +1750,7 @@ typedef enum {
CURLOPTDEPRECATED(CURLOPT_REDIR_PROTOCOLS, CURLOPTTYPE_LONG, 182,
7.85.0, "Use CURLOPT_REDIR_PROTOCOLS_STR"),
- /* set the SSH knownhost filename to use */
+ /* set the SSH knownhost file name to use */
CURLOPT(CURLOPT_SSH_KNOWNHOSTS, CURLOPTTYPE_STRINGPOINT, 183),
/* set the SSH host key callback, must point to a curl_sshkeycallback
@@ -1843,7 +1831,7 @@ typedef enum {
future libcurl release.
libcurl will ask for the compressed methods it knows of, and if that
- is not any, it will not ask for transfer-encoding at all even if this
+ isn't any, it will not ask for transfer-encoding at all even if this
option is set to 1.
*/
@@ -1857,8 +1845,7 @@ typedef enum {
/* allow GSSAPI credential delegation */
CURLOPT(CURLOPT_GSSAPI_DELEGATION, CURLOPTTYPE_VALUES, 210),
- /* Set the name servers to use for DNS resolution.
- * Only supported by the c-ares DNS backend */
+ /* Set the name servers to use for DNS resolution */
CURLOPT(CURLOPT_DNS_SERVERS, CURLOPTTYPE_STRINGPOINT, 211),
/* Time-out accept operations (currently for FTP only) after this amount
@@ -1945,7 +1932,7 @@ typedef enum {
/* Service Name */
CURLOPT(CURLOPT_SERVICE_NAME, CURLOPTTYPE_STRINGPOINT, 236),
- /* Wait/do not wait for pipe/mutex to clarify */
+ /* Wait/don't wait for pipe/mutex to clarify */
CURLOPT(CURLOPT_PIPEWAIT, CURLOPTTYPE_LONG, 237),
/* Set the protocol used when curl is given a URL without a protocol */
@@ -2021,7 +2008,7 @@ typedef enum {
/* password for the SSL private key for proxy */
CURLOPT(CURLOPT_PROXY_KEYPASSWD, CURLOPTTYPE_STRINGPOINT, 258),
- /* Specify which TLS 1.2 (1.1, 1.0) ciphers to use for proxy */
+ /* Specify which SSL ciphers to use for proxy */
CURLOPT(CURLOPT_PROXY_SSL_CIPHER_LIST, CURLOPTTYPE_STRINGPOINT, 259),
/* CRL file for proxy */
@@ -2106,7 +2093,7 @@ typedef enum {
/* alt-svc control bitmask */
CURLOPT(CURLOPT_ALTSVC_CTRL, CURLOPTTYPE_LONG, 286),
- /* alt-svc cache filename to possibly read from/write to */
+ /* alt-svc cache file name to possibly read from/write to */
CURLOPT(CURLOPT_ALTSVC, CURLOPTTYPE_STRINGPOINT, 287),
/* maximum age (idle time) of a connection to consider it for reuse
@@ -2132,13 +2119,13 @@ typedef enum {
/* the EC curves requested by the TLS client (RFC 8422, 5.1);
* OpenSSL support via 'set_groups'/'set_curves':
- * https://docs.openssl.org/master/man3/SSL_CTX_set1_curves/
+ * https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set1_groups.html
*/
CURLOPT(CURLOPT_SSL_EC_CURVES, CURLOPTTYPE_STRINGPOINT, 298),
/* HSTS bitmask */
CURLOPT(CURLOPT_HSTS_CTRL, CURLOPTTYPE_LONG, 299),
- /* HSTS filename */
+ /* HSTS file name */
CURLOPT(CURLOPT_HSTS, CURLOPTTYPE_STRINGPOINT, 300),
/* HSTS read callback */
@@ -2202,7 +2189,7 @@ typedef enum {
/* specify which protocols that libcurl is allowed to follow directs to */
CURLOPT(CURLOPT_REDIR_PROTOCOLS_STR, CURLOPTTYPE_STRINGPOINT, 319),
- /* WebSockets options */
+ /* websockets options */
CURLOPT(CURLOPT_WS_OPTIONS, CURLOPTTYPE_LONG, 320),
/* CA cache timeout */
@@ -2214,15 +2201,6 @@ typedef enum {
/* set a specific client IP for HAProxy PROXY protocol header? */
CURLOPT(CURLOPT_HAPROXY_CLIENT_IP, CURLOPTTYPE_STRINGPOINT, 323),
- /* millisecond version */
- CURLOPT(CURLOPT_SERVER_RESPONSE_TIMEOUT_MS, CURLOPTTYPE_LONG, 324),
-
- /* set ECH configuration */
- CURLOPT(CURLOPT_ECH, CURLOPTTYPE_STRINGPOINT, 325),
-
- /* maximum number of keepalive probes (Linux, *BSD, macOS, etc.) */
- CURLOPT(CURLOPT_TCP_KEEPCNT, CURLOPTTYPE_LONG, 326),
-
CURLOPT_LASTENTRY /* the last unused */
} CURLoption;
@@ -2273,9 +2251,9 @@ typedef enum {
/* These enums are for use with the CURLOPT_HTTP_VERSION option. */
enum {
- CURL_HTTP_VERSION_NONE, /* setting this means we do not care, and that we
- would like the library to choose the best
- possible for us! */
+ CURL_HTTP_VERSION_NONE, /* setting this means we don't care, and that we'd
+ like the library to choose the best possible
+ for us! */
CURL_HTTP_VERSION_1_0, /* please use HTTP 1.0 in the request */
CURL_HTTP_VERSION_1_1, /* please use HTTP 1.1 in the request */
CURL_HTTP_VERSION_2_0, /* please use HTTP 2 in the request */
@@ -2328,26 +2306,30 @@ enum CURL_NETRC_OPTION {
CURL_NETRC_LAST
};
-#define CURL_SSLVERSION_DEFAULT 0
-#define CURL_SSLVERSION_TLSv1 1 /* TLS 1.x */
-#define CURL_SSLVERSION_SSLv2 2
-#define CURL_SSLVERSION_SSLv3 3
-#define CURL_SSLVERSION_TLSv1_0 4
-#define CURL_SSLVERSION_TLSv1_1 5
-#define CURL_SSLVERSION_TLSv1_2 6
-#define CURL_SSLVERSION_TLSv1_3 7
-
-#define CURL_SSLVERSION_LAST 8 /* never use, keep last */
+enum {
+ CURL_SSLVERSION_DEFAULT,
+ CURL_SSLVERSION_TLSv1, /* TLS 1.x */
+ CURL_SSLVERSION_SSLv2,
+ CURL_SSLVERSION_SSLv3,
+ CURL_SSLVERSION_TLSv1_0,
+ CURL_SSLVERSION_TLSv1_1,
+ CURL_SSLVERSION_TLSv1_2,
+ CURL_SSLVERSION_TLSv1_3,
+
+ CURL_SSLVERSION_LAST /* never use, keep last */
+};
-#define CURL_SSLVERSION_MAX_NONE 0
-#define CURL_SSLVERSION_MAX_DEFAULT (CURL_SSLVERSION_TLSv1 << 16)
-#define CURL_SSLVERSION_MAX_TLSv1_0 (CURL_SSLVERSION_TLSv1_0 << 16)
-#define CURL_SSLVERSION_MAX_TLSv1_1 (CURL_SSLVERSION_TLSv1_1 << 16)
-#define CURL_SSLVERSION_MAX_TLSv1_2 (CURL_SSLVERSION_TLSv1_2 << 16)
-#define CURL_SSLVERSION_MAX_TLSv1_3 (CURL_SSLVERSION_TLSv1_3 << 16)
+enum {
+ CURL_SSLVERSION_MAX_NONE = 0,
+ CURL_SSLVERSION_MAX_DEFAULT = (CURL_SSLVERSION_TLSv1 << 16),
+ CURL_SSLVERSION_MAX_TLSv1_0 = (CURL_SSLVERSION_TLSv1_0 << 16),
+ CURL_SSLVERSION_MAX_TLSv1_1 = (CURL_SSLVERSION_TLSv1_1 << 16),
+ CURL_SSLVERSION_MAX_TLSv1_2 = (CURL_SSLVERSION_TLSv1_2 << 16),
+ CURL_SSLVERSION_MAX_TLSv1_3 = (CURL_SSLVERSION_TLSv1_3 << 16),
/* never use, keep last */
-#define CURL_SSLVERSION_MAX_LAST (CURL_SSLVERSION_LAST << 16)
+ CURL_SSLVERSION_MAX_LAST = (CURL_SSLVERSION_LAST << 16)
+};
enum CURL_TLSAUTH {
CURL_TLSAUTH_NONE,
@@ -2435,7 +2417,7 @@ CURL_EXTERN CURLcode curl_mime_name(curl_mimepart *part, const char *name);
*
* DESCRIPTION
*
- * Set mime part remote filename.
+ * Set mime part remote file name.
*/
CURL_EXTERN CURLcode curl_mime_filename(curl_mimepart *part,
const char *filename);
@@ -2644,7 +2626,7 @@ CURL_EXTERN char *curl_getenv(const char *variable);
*
* DESCRIPTION
*
- * Returns a static ASCII string of the libcurl version.
+ * Returns a static ascii string of the libcurl version.
*/
CURL_EXTERN char *curl_version(void);
@@ -2716,10 +2698,10 @@ CURL_EXTERN CURLcode curl_global_init(long flags);
* DESCRIPTION
*
* curl_global_init() or curl_global_init_mem() should be invoked exactly once
- * for each application that uses libcurl. This function can be used to
+ * for each application that uses libcurl. This function can be used to
* initialize libcurl and set user defined memory management callback
- * functions. Users can implement memory management routines to check for
- * memory leaks, check for mis-use of the curl library etc. User registered
+ * functions. Users can implement memory management routines to check for
+ * memory leaks, check for mis-use of the curl library etc. User registered
* callback routines will be invoked by this library instead of the system
* memory management routines like malloc, free etc.
*/
@@ -2837,7 +2819,7 @@ CURL_EXTERN time_t curl_getdate(const char *p, const time_t *unused);
for with CURLOPT_CERTINFO / CURLINFO_CERTINFO */
struct curl_certinfo {
int num_of_certs; /* number of certificates with information */
- struct curl_slist **certinfo; /* for each index in this array, there is a
+ struct curl_slist **certinfo; /* for each index in this array, there's a
linked list with textual information for a
certificate in the format "name:content".
eg "Subject:foo", "Issuer:bar", etc. */
@@ -2950,10 +2932,7 @@ typedef enum {
CURLINFO_CAPATH = CURLINFO_STRING + 62,
CURLINFO_XFER_ID = CURLINFO_OFF_T + 63,
CURLINFO_CONN_ID = CURLINFO_OFF_T + 64,
- CURLINFO_QUEUE_TIME_T = CURLINFO_OFF_T + 65,
- CURLINFO_USED_PROXY = CURLINFO_LONG + 66,
- CURLINFO_POSTTRANSFER_TIME_T = CURLINFO_OFF_T + 67,
- CURLINFO_LASTONE = 67
+ CURLINFO_LASTONE = 64
} CURLINFO;
/* CURLINFO_RESPONSE_CODE is the new name for the option previously known as
@@ -3029,7 +3008,7 @@ typedef enum {
} CURLSHcode;
typedef enum {
- CURLSHOPT_NONE, /* do not use */
+ CURLSHOPT_NONE, /* don't use */
CURLSHOPT_SHARE, /* specify a data type to share */
CURLSHOPT_UNSHARE, /* specify which data type to stop sharing */
CURLSHOPT_LOCKFUNC, /* pass in a 'curl_lock_function' pointer */
@@ -3049,18 +3028,17 @@ CURL_EXTERN CURLSHcode curl_share_cleanup(CURLSH *share);
*/
typedef enum {
- CURLVERSION_FIRST, /* 7.10 */
- CURLVERSION_SECOND, /* 7.11.1 */
- CURLVERSION_THIRD, /* 7.12.0 */
- CURLVERSION_FOURTH, /* 7.16.1 */
- CURLVERSION_FIFTH, /* 7.57.0 */
- CURLVERSION_SIXTH, /* 7.66.0 */
- CURLVERSION_SEVENTH, /* 7.70.0 */
- CURLVERSION_EIGHTH, /* 7.72.0 */
- CURLVERSION_NINTH, /* 7.75.0 */
- CURLVERSION_TENTH, /* 7.77.0 */
- CURLVERSION_ELEVENTH, /* 7.87.0 */
- CURLVERSION_TWELFTH, /* 8.8.0 */
+ CURLVERSION_FIRST,
+ CURLVERSION_SECOND,
+ CURLVERSION_THIRD,
+ CURLVERSION_FOURTH,
+ CURLVERSION_FIFTH,
+ CURLVERSION_SIXTH,
+ CURLVERSION_SEVENTH,
+ CURLVERSION_EIGHTH,
+ CURLVERSION_NINTH,
+ CURLVERSION_TENTH,
+ CURLVERSION_ELEVENTH,
CURLVERSION_LAST /* never actually use this */
} CURLversion;
@@ -3069,7 +3047,7 @@ typedef enum {
meant to be a built-in version number for what kind of struct the caller
expects. If the struct ever changes, we redefine the NOW to another enum
from above. */
-#define CURLVERSION_NOW CURLVERSION_TWELFTH
+#define CURLVERSION_NOW CURLVERSION_ELEVENTH
struct curl_version_info_data {
CURLversion age; /* age of the returned struct */
@@ -3129,9 +3107,6 @@ struct curl_version_info_data {
/* These fields were added in CURLVERSION_ELEVENTH */
/* feature_names is terminated by an entry with a NULL feature name */
const char * const *feature_names;
-
- /* These fields were added in CURLVERSION_TWELFTH */
- const char *rtmp_version; /* human readable string. */
};
typedef struct curl_version_info_data curl_version_info_data;
@@ -3172,7 +3147,7 @@ typedef struct curl_version_info_data curl_version_info_data;
#define CURL_VERSION_GSASL (1<<29) /* libgsasl is supported */
#define CURL_VERSION_THREADSAFE (1<<30) /* libcurl API is thread-safe */
-/*
+ /*
* NAME curl_version_info()
*
* DESCRIPTION
@@ -3188,7 +3163,7 @@ CURL_EXTERN curl_version_info_data *curl_version_info(CURLversion);
* DESCRIPTION
*
* The curl_easy_strerror function may be used to turn a CURLcode value
- * into the equivalent human readable error string. This is useful
+ * into the equivalent human readable error string. This is useful
* for printing meaningful error messages.
*/
CURL_EXTERN const char *curl_easy_strerror(CURLcode);
@@ -3199,7 +3174,7 @@ CURL_EXTERN const char *curl_easy_strerror(CURLcode);
* DESCRIPTION
*
* The curl_share_strerror function may be used to turn a CURLSHcode value
- * into the equivalent human readable error string. This is useful
+ * into the equivalent human readable error string. This is useful
* for printing meaningful error messages.
*/
CURL_EXTERN const char *curl_share_strerror(CURLSHcode);
@@ -3236,11 +3211,9 @@ CURL_EXTERN CURLcode curl_easy_pause(CURL *handle, int bitmask);
#include "options.h"
#include "header.h"
#include "websockets.h"
-#ifndef CURL_SKIP_INCLUDE_MPRINTF
#include "mprintf.h"
-#endif
-/* the typechecker does not work in C++ (yet) */
+/* the typechecker doesn't work in C++ (yet) */
#if defined(__GNUC__) && defined(__GNUC_MINOR__) && \
((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) && \
!defined(__cplusplus) && !defined(CURL_DISABLE_TYPECHECK)
diff --git a/contrib/libs/curl/include/curl/curlver.h b/contrib/libs/curl/include/curl/curlver.h
index 45ecdcef74..73b37e8ffd 100644
--- a/contrib/libs/curl/include/curl/curlver.h
+++ b/contrib/libs/curl/include/curl/curlver.h
@@ -32,13 +32,13 @@
/* This is the version number of the libcurl package from which this header
file origins: */
-#define LIBCURL_VERSION "8.10.1"
+#define LIBCURL_VERSION "8.5.0"
/* The numeric version number is also available "in parts" by using these
defines: */
#define LIBCURL_VERSION_MAJOR 8
-#define LIBCURL_VERSION_MINOR 10
-#define LIBCURL_VERSION_PATCH 1
+#define LIBCURL_VERSION_MINOR 5
+#define LIBCURL_VERSION_PATCH 0
/* This is the numeric version of the libcurl version number, meant for easier
parsing and comparisons by programs. The LIBCURL_VERSION_NUM define will
@@ -48,7 +48,7 @@
Where XX, YY and ZZ are the main version, release and patch numbers in
hexadecimal (using 8 bits each). All three numbers are always represented
- using two digits. 1.2 would appear as "0x010200" while version 9.11.7
+ using two digits. 1.2 would appear as "0x010200" while version 9.11.7
appears as "0x090b07".
This 6-digit (24 bits) hexadecimal number does not show pre-release number,
@@ -59,7 +59,7 @@
CURL_VERSION_BITS() macro since curl's own configure script greps for it
and needs it to contain the full number.
*/
-#define LIBCURL_VERSION_NUM 0x080a01
+#define LIBCURL_VERSION_NUM 0x080500
/*
* This is the date and time when the full source package was created. The
@@ -70,7 +70,7 @@
*
* "2007-11-23"
*/
-#define LIBCURL_TIMESTAMP "2024-09-18"
+#define LIBCURL_TIMESTAMP "2023-12-06"
#define CURL_VERSION_BITS(x,y,z) ((x)<<16|(y)<<8|(z))
#define CURL_AT_LEAST_VERSION(x,y,z) \
diff --git a/contrib/libs/curl/include/curl/easy.h b/contrib/libs/curl/include/curl/easy.h
index 71b8dd4674..1285101c58 100644
--- a/contrib/libs/curl/include/curl/easy.h
+++ b/contrib/libs/curl/include/curl/easy.h
@@ -50,7 +50,7 @@ CURL_EXTERN void curl_easy_cleanup(CURL *curl);
*
* Request internal information from the curl session with this function.
* The third argument MUST be pointing to the specific type of the used option
- * which is documented in each manpage of the option. The data pointed to
+ * which is documented in each man page of the option. The data pointed to
* will be filled in accordingly and can be relied upon only if the function
* returns CURLE_OK. This function is intended to get used *AFTER* a performed
* transfer, all results from this function are undefined until the transfer
diff --git a/contrib/libs/curl/include/curl/mprintf.h b/contrib/libs/curl/include/curl/mprintf.h
index 88059c851f..dc5664bc53 100644
--- a/contrib/libs/curl/include/curl/mprintf.h
+++ b/contrib/libs/curl/include/curl/mprintf.h
@@ -32,36 +32,21 @@
extern "C" {
#endif
-#ifndef CURL_TEMP_PRINTF
-#if (defined(__GNUC__) || defined(__clang__) || \
- defined(__IAR_SYSTEMS_ICC__)) && \
+#if (defined(__GNUC__) || defined(__clang__)) && \
defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \
- !defined(CURL_NO_FMT_CHECKS)
-#if defined(__MINGW32__) && !defined(__clang__)
-#if defined(__MINGW_PRINTF_FORMAT) /* mingw-w64 3.0.0+. Needs stdio.h. */
-#define CURL_TEMP_PRINTF(fmt, arg) \
- __attribute__((format(__MINGW_PRINTF_FORMAT, fmt, arg)))
+ !defined(__MINGW32__) && !defined(CURL_NO_FMT_CHECKS)
+#define CURL_TEMP_PRINTF(a,b) __attribute__ ((format(printf, a, b)))
#else
-#define CURL_TEMP_PRINTF(fmt, arg)
-#endif
-#else
-#define CURL_TEMP_PRINTF(fmt, arg) \
- __attribute__((format(printf, fmt, arg)))
-#endif
-#else
-#define CURL_TEMP_PRINTF(fmt, arg)
-#endif
+#define CURL_TEMP_PRINTF(a,b)
#endif
-CURL_EXTERN int curl_mprintf(const char *format, ...)
- CURL_TEMP_PRINTF(1, 2);
+CURL_EXTERN int curl_mprintf(const char *format, ...) CURL_TEMP_PRINTF(1, 2);
CURL_EXTERN int curl_mfprintf(FILE *fd, const char *format, ...)
CURL_TEMP_PRINTF(2, 3);
CURL_EXTERN int curl_msprintf(char *buffer, const char *format, ...)
CURL_TEMP_PRINTF(2, 3);
CURL_EXTERN int curl_msnprintf(char *buffer, size_t maxlength,
- const char *format, ...)
- CURL_TEMP_PRINTF(3, 4);
+ const char *format, ...) CURL_TEMP_PRINTF(3, 4);
CURL_EXTERN int curl_mvprintf(const char *format, va_list args)
CURL_TEMP_PRINTF(1, 0);
CURL_EXTERN int curl_mvfprintf(FILE *fd, const char *format, va_list args)
diff --git a/contrib/libs/curl/include/curl/multi.h b/contrib/libs/curl/include/curl/multi.h
index 7b6c351ada..e79b48ff32 100644
--- a/contrib/libs/curl/include/curl/multi.h
+++ b/contrib/libs/curl/include/curl/multi.h
@@ -24,7 +24,7 @@
*
***************************************************************************/
/*
- This is an "external" header file. Do not give away any internals here!
+ This is an "external" header file. Don't give away any internals here!
GOALS
@@ -66,7 +66,7 @@ typedef enum {
CURLM_OK,
CURLM_BAD_HANDLE, /* the passed-in handle is not a valid CURLM handle */
CURLM_BAD_EASY_HANDLE, /* an easy handle was not good/valid */
- CURLM_OUT_OF_MEMORY, /* if you ever get this, you are in deep sh*t */
+ CURLM_OUT_OF_MEMORY, /* if you ever get this, you're in deep sh*t */
CURLM_INTERNAL_ERROR, /* this is a libcurl bug */
CURLM_BAD_SOCKET, /* the passed in socket argument did not match */
CURLM_UNKNOWN_OPTION, /* curl_multi_setopt() with unsupported option */
@@ -109,7 +109,7 @@ struct CURLMsg {
typedef struct CURLMsg CURLMsg;
/* Based on poll(2) structure and values.
- * We do not use pollfd and POLL* constants explicitly
+ * We don't use pollfd and POLL* constants explicitly
* to cover platforms without poll(). */
#define CURL_WAIT_POLLIN 0x0001
#define CURL_WAIT_POLLPRI 0x0002
@@ -205,7 +205,7 @@ CURL_EXTERN CURLMcode curl_multi_wakeup(CURLM *multi_handle);
/*
* Name: curl_multi_perform()
*
- * Desc: When the app thinks there is data available for curl it calls this
+ * Desc: When the app thinks there's data available for curl it calls this
* function to read/write whatever there is right now. This returns
* as soon as the reads and writes are done. This function does not
* require that there actually is data available for reading or that
@@ -236,7 +236,7 @@ CURL_EXTERN CURLMcode curl_multi_cleanup(CURLM *multi_handle);
/*
* Name: curl_multi_info_read()
*
- * Desc: Ask the multi handle if there is any messages/informationals from
+ * Desc: Ask the multi handle if there's any messages/informationals from
* the individual transfers. Messages include informationals such as
* error code from the transfer or just the fact that a transfer is
* completed. More details on these should be written down as well.
@@ -253,7 +253,7 @@ CURL_EXTERN CURLMcode curl_multi_cleanup(CURLM *multi_handle);
* we will provide the particular "transfer handle" in that struct
* and that should/could/would be used in subsequent
* curl_easy_getinfo() calls (or similar). The point being that we
- * must never expose complex structs to applications, as then we will
+ * must never expose complex structs to applications, as then we'll
* undoubtably get backwards compatibility problems in the future.
*
* Returns: A pointer to a filled-in struct, or NULL if it failed or ran out
@@ -268,7 +268,7 @@ CURL_EXTERN CURLMsg *curl_multi_info_read(CURLM *multi_handle,
* Name: curl_multi_strerror()
*
* Desc: The curl_multi_strerror function may be used to turn a CURLMcode
- * value into the equivalent human readable error string. This is
+ * value into the equivalent human readable error string. This is
* useful for printing meaningful error messages.
*
* Returns: A pointer to a null-terminated error message.
@@ -282,7 +282,7 @@ CURL_EXTERN const char *curl_multi_strerror(CURLMcode);
* Desc: An alternative version of curl_multi_perform() that allows the
* application to pass in one of the file descriptors that have been
* detected to have "action" on them and let libcurl perform.
- * See manpage for details.
+ * See man page for details.
*/
#define CURL_POLL_NONE 0
#define CURL_POLL_IN 1
@@ -464,20 +464,6 @@ typedef int (*curl_push_callback)(CURL *parent,
struct curl_pushheaders *headers,
void *userp);
-/*
- * Name: curl_multi_waitfds()
- *
- * Desc: Ask curl for fds for polling. The app can use these to poll on.
- * We want curl_multi_perform() called as soon as one of them are
- * ready. Passing zero size allows to get just a number of fds.
- *
- * Returns: CURLMcode type, general multi error code.
- */
-CURL_EXTERN CURLMcode curl_multi_waitfds(CURLM *multi,
- struct curl_waitfd *ufds,
- unsigned int size,
- unsigned int *fd_count);
-
#ifdef __cplusplus
} /* end of extern "C" */
#endif
diff --git a/contrib/libs/curl/include/curl/system.h b/contrib/libs/curl/include/curl/system.h
index e5be256845..f2554b4a90 100644
--- a/contrib/libs/curl/include/curl/system.h
+++ b/contrib/libs/curl/include/curl/system.h
@@ -31,7 +31,7 @@
* changed.
*
* In order to differentiate between platforms/compilers/architectures use
- * only compiler built-in predefined preprocessor symbols.
+ * only compiler built in predefined preprocessor symbols.
*
* curl_off_t
* ----------
@@ -46,7 +46,7 @@
* As a general rule, curl_off_t shall not be mapped to off_t. This rule shall
* only be violated if off_t is the only 64-bit data type available and the
* size of off_t is independent of large file support settings. Keep your
- * build on the safe side avoiding an off_t gating. If you have a 64-bit
+ * build on the safe side avoiding an off_t gating. If you have a 64-bit
* off_t then take for sure that another 64-bit data type exists, dig deeper
* and you will find it.
*
@@ -184,8 +184,9 @@
# define CURL_FORMAT_CURL_OFF_TU PRIu64
# define CURL_SUFFIX_CURL_OFF_T LL
# define CURL_SUFFIX_CURL_OFF_TU ULL
-# define CURL_TYPEOF_CURL_SOCKLEN_T int
+# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t
# define CURL_PULL_SYS_TYPES_H 1
+# define CURL_PULL_WS2TCPIP_H 1
#elif defined(__VMS)
# if defined(__VAX)
@@ -402,7 +403,7 @@
# define CURL_PULL_SYS_SOCKET_H 1
#else
-/* generic "safe guess" on old 32-bit style */
+/* generic "safe guess" on old 32 bit style */
# define CURL_TYPEOF_CURL_OFF_T long
# define CURL_FORMAT_CURL_OFF_T "ld"
# define CURL_FORMAT_CURL_OFF_TU "lu"
@@ -416,6 +417,15 @@
#define CURL_PULL_SYS_POLL_H
#endif
+
+/* CURL_PULL_WS2TCPIP_H is defined above when inclusion of header file */
+/* ws2tcpip.h is required here to properly make type definitions below. */
+#ifdef CURL_PULL_WS2TCPIP_H
+# include <winsock2.h>
+# include <windows.h>
+# include <ws2tcpip.h>
+#endif
+
/* CURL_PULL_SYS_TYPES_H is defined above when inclusion of header file */
/* sys/types.h is required here to properly make type definitions below. */
#ifdef CURL_PULL_SYS_TYPES_H
diff --git a/contrib/libs/curl/include/curl/typecheck-gcc.h b/contrib/libs/curl/include/curl/typecheck-gcc.h
index e532e6997d..b880f3dc60 100644
--- a/contrib/libs/curl/include/curl/typecheck-gcc.h
+++ b/contrib/libs/curl/include/curl/typecheck-gcc.h
@@ -34,11 +34,11 @@
* _curl_easy_setopt_err_sometype below
*
* NOTE: We use two nested 'if' statements here instead of the && operator, in
- * order to work around gcc bug #32061. It affects only gcc 4.3.x/4.4.x
+ * order to work around gcc bug #32061. It affects only gcc 4.3.x/4.4.x
* when compiling with -Wlogical-op.
*
- * To add an option that uses the same type as an existing option, you will
- * just need to extend the appropriate _curl_*_option macro
+ * To add an option that uses the same type as an existing option, you'll just
+ * need to extend the appropriate _curl_*_option macro
*/
#define curl_easy_setopt(handle, option, value) \
__extension__({ \
@@ -245,7 +245,7 @@ CURLWARNING(_curl_easy_getinfo_err_curl_off_t,
/* To add a new option to one of the groups, just add
* (option) == CURLOPT_SOMETHING
- * to the or-expression. If the option takes a long or curl_off_t, you do not
+ * to the or-expression. If the option takes a long or curl_off_t, you don't
* have to do anything
*/
@@ -275,7 +275,6 @@ CURLWARNING(_curl_easy_getinfo_err_curl_off_t,
(option) == CURLOPT_DNS_LOCAL_IP6 || \
(option) == CURLOPT_DNS_SERVERS || \
(option) == CURLOPT_DOH_URL || \
- (option) == CURLOPT_ECH || \
(option) == CURLOPT_EGDSOCKET || \
(option) == CURLOPT_FTP_ACCOUNT || \
(option) == CURLOPT_FTP_ALTERNATIVE_TO_USER || \
@@ -678,7 +677,7 @@ typedef CURLcode (*_curl_ssl_ctx_callback4)(CURL *, const void *,
const void *);
#ifdef HEADER_SSL_H
/* hack: if we included OpenSSL's ssl.h, we know about SSL_CTX
- * this will of course break if we are included before OpenSSL headers...
+ * this will of course break if we're included before OpenSSL headers...
*/
typedef CURLcode (*_curl_ssl_ctx_callback5)(CURL *, SSL_CTX *, void *);
typedef CURLcode (*_curl_ssl_ctx_callback6)(CURL *, SSL_CTX *, const void *);
diff --git a/contrib/libs/curl/include/curl/urlapi.h b/contrib/libs/curl/include/curl/urlapi.h
index b4a6e5d567..88cdeb3bca 100644
--- a/contrib/libs/curl/include/curl/urlapi.h
+++ b/contrib/libs/curl/include/curl/urlapi.h
@@ -63,7 +63,6 @@ typedef enum {
CURLUE_BAD_SLASHES, /* 28 */
CURLUE_BAD_USER, /* 29 */
CURLUE_LACKS_IDN, /* 30 */
- CURLUE_TOO_LARGE, /* 31 */
CURLUE_LAST
} CURLUcode;
@@ -97,12 +96,8 @@ typedef enum {
#define CURLU_NO_AUTHORITY (1<<10) /* Allow empty authority when the
scheme is unknown. */
#define CURLU_ALLOW_SPACE (1<<11) /* Allow spaces in the URL */
-#define CURLU_PUNYCODE (1<<12) /* get the hostname in punycode */
+#define CURLU_PUNYCODE (1<<12) /* get the host name in punycode */
#define CURLU_PUNY2IDN (1<<13) /* punycode => IDN conversion */
-#define CURLU_GET_EMPTY (1<<14) /* allow empty queries and fragments
- when extracting the URL or the
- components */
-#define CURLU_NO_GUESS_SCHEME (1<<15) /* for get, do not accept a guess */
typedef struct Curl_URL CURLU;
@@ -143,7 +138,7 @@ CURL_EXTERN CURLUcode curl_url_set(CURLU *handle, CURLUPart what,
/*
* curl_url_strerror() turns a CURLUcode value into the equivalent human
- * readable error string. This is useful for printing meaningful error
+ * readable error string. This is useful for printing meaningful error
* messages.
*/
CURL_EXTERN const char *curl_url_strerror(CURLUcode);
diff --git a/contrib/libs/curl/lib/altsvc.c b/contrib/libs/curl/lib/altsvc.c
index dcedc491c5..35450d6b1c 100644
--- a/contrib/libs/curl/lib/altsvc.c
+++ b/contrib/libs/curl/lib/altsvc.c
@@ -106,11 +106,9 @@ static struct altsvc *altsvc_createid(const char *srchost,
dlen = strlen(dsthost);
DEBUGASSERT(hlen);
DEBUGASSERT(dlen);
- if(!hlen || !dlen) {
+ if(!hlen || !dlen)
/* bad input */
- free(as);
return NULL;
- }
if((hlen > 2) && srchost[0] == '[') {
/* IPv6 address, strip off brackets */
srchost++;
@@ -125,11 +123,11 @@ static struct altsvc *altsvc_createid(const char *srchost,
dlen -= 2;
}
- as->src.host = Curl_memdup0(srchost, hlen);
+ as->src.host = Curl_strndup(srchost, hlen);
if(!as->src.host)
goto error;
- as->dst.host = Curl_memdup0(dsthost, dlen);
+ as->dst.host = Curl_strndup(dsthost, dlen);
if(!as->dst.host)
goto error;
@@ -191,7 +189,7 @@ static CURLcode altsvc_add(struct altsvcinfo *asi, char *line)
as->expires = expires;
as->prio = prio;
as->persist = persist ? 1 : 0;
- Curl_llist_append(&asi->list, as, &as->node);
+ Curl_llist_insert_next(&asi->list, asi->list.tail, as, &as->node);
}
}
@@ -209,9 +207,10 @@ static CURLcode altsvc_add(struct altsvcinfo *asi, char *line)
static CURLcode altsvc_load(struct altsvcinfo *asi, const char *file)
{
CURLcode result = CURLE_OK;
+ char *line = NULL;
FILE *fp;
- /* we need a private copy of the filename so that the altsvc cache file
+ /* we need a private copy of the file name so that the altsvc cache file
name survives an easy handle reset */
free(asi->filename);
asi->filename = strdup(file);
@@ -220,10 +219,11 @@ static CURLcode altsvc_load(struct altsvcinfo *asi, const char *file)
fp = fopen(file, FOPEN_READTEXT);
if(fp) {
- struct dynbuf buf;
- Curl_dyn_init(&buf, MAX_ALTSVC_LINE);
- while(Curl_get_line(&buf, fp)) {
- char *lineptr = Curl_dyn_ptr(&buf);
+ line = malloc(MAX_ALTSVC_LINE);
+ if(!line)
+ goto fail;
+ while(Curl_get_line(line, MAX_ALTSVC_LINE, fp)) {
+ char *lineptr = line;
while(*lineptr && ISBLANK(*lineptr))
lineptr++;
if(*lineptr == '#')
@@ -232,10 +232,16 @@ static CURLcode altsvc_load(struct altsvcinfo *asi, const char *file)
altsvc_add(asi, lineptr);
}
- Curl_dyn_free(&buf); /* free the line buffer */
+ free(line); /* free the line buffer */
fclose(fp);
}
return result;
+
+fail:
+ Curl_safefree(asi->filename);
+ free(line);
+ fclose(fp);
+ return CURLE_OUT_OF_MEMORY;
}
/*
@@ -252,7 +258,7 @@ static CURLcode altsvc_out(struct altsvc *as, FILE *fp)
CURLcode result = Curl_gmtime(as->expires, &stamp);
if(result)
return result;
-#ifdef USE_IPV6
+#ifdef ENABLE_IPV6
else {
char ipv6_unused[16];
if(1 == Curl_inet_pton(AF_INET6, as->dst.host, ipv6_unused)) {
@@ -270,7 +276,7 @@ static CURLcode altsvc_out(struct altsvc *as, FILE *fp)
"%s %s%s%s %u "
"\"%d%02d%02d "
"%02d:%02d:%02d\" "
- "%u %u\n",
+ "%u %d\n",
Curl_alpnid2str(as->src.alpnid),
src6_pre, as->src.host, src6_post,
as->src.port,
@@ -303,7 +309,7 @@ struct altsvcinfo *Curl_altsvc_init(void)
#ifdef USE_HTTP2
| CURLALTSVC_H2
#endif
-#ifdef USE_HTTP3
+#ifdef ENABLE_QUIC
| CURLALTSVC_H3
#endif
;
@@ -327,6 +333,9 @@ CURLcode Curl_altsvc_load(struct altsvcinfo *asi, const char *file)
CURLcode Curl_altsvc_ctrl(struct altsvcinfo *asi, const long ctrl)
{
DEBUGASSERT(asi);
+ if(!ctrl)
+ /* unexpected */
+ return CURLE_BAD_FUNCTION_ARGUMENT;
asi->flags = ctrl;
return CURLE_OK;
}
@@ -337,13 +346,13 @@ CURLcode Curl_altsvc_ctrl(struct altsvcinfo *asi, const long ctrl)
*/
void Curl_altsvc_cleanup(struct altsvcinfo **altsvcp)
{
+ struct Curl_llist_element *e;
+ struct Curl_llist_element *n;
if(*altsvcp) {
- struct Curl_llist_node *e;
- struct Curl_llist_node *n;
struct altsvcinfo *altsvc = *altsvcp;
- for(e = Curl_llist_head(&altsvc->list); e; e = n) {
- struct altsvc *as = Curl_node_elem(e);
- n = Curl_node_next(e);
+ for(e = altsvc->list.head; e; e = n) {
+ struct altsvc *as = e->ptr;
+ n = e->next;
altsvc_free(as);
}
free(altsvc->filename);
@@ -358,6 +367,8 @@ void Curl_altsvc_cleanup(struct altsvcinfo **altsvcp)
CURLcode Curl_altsvc_save(struct Curl_easy *data,
struct altsvcinfo *altsvc, const char *file)
{
+ struct Curl_llist_element *e;
+ struct Curl_llist_element *n;
CURLcode result = CURLE_OK;
FILE *out;
char *tempstore = NULL;
@@ -371,19 +382,17 @@ CURLcode Curl_altsvc_save(struct Curl_easy *data,
file = altsvc->filename;
if((altsvc->flags & CURLALTSVC_READONLYFILE) || !file || !file[0])
- /* marked as read-only, no file or zero length filename */
+ /* marked as read-only, no file or zero length file name */
return CURLE_OK;
result = Curl_fopen(data, file, &out, &tempstore);
if(!result) {
- struct Curl_llist_node *e;
- struct Curl_llist_node *n;
fputs("# Your alt-svc cache. https://curl.se/docs/alt-svc.html\n"
"# This file was generated by libcurl! Edit at your own risk.\n",
out);
- for(e = Curl_llist_head(&altsvc->list); e; e = n) {
- struct altsvc *as = Curl_node_elem(e);
- n = Curl_node_next(e);
+ for(e = altsvc->list.head; e; e = n) {
+ struct altsvc *as = e->ptr;
+ n = e->next;
result = altsvc_out(as, out);
if(result)
break;
@@ -430,7 +439,7 @@ static bool hostcompare(const char *host, const char *check)
if(hlen && (host[hlen - 1] == '.'))
hlen--;
if(hlen != clen)
- /* they cannot match if they have different lengths */
+ /* they can't match if they have different lengths */
return FALSE;
return strncasecompare(host, check, hlen);
}
@@ -440,15 +449,15 @@ static bool hostcompare(const char *host, const char *check)
static void altsvc_flush(struct altsvcinfo *asi, enum alpnid srcalpnid,
const char *srchost, unsigned short srcport)
{
- struct Curl_llist_node *e;
- struct Curl_llist_node *n;
- for(e = Curl_llist_head(&asi->list); e; e = n) {
- struct altsvc *as = Curl_node_elem(e);
- n = Curl_node_next(e);
+ struct Curl_llist_element *e;
+ struct Curl_llist_element *n;
+ for(e = asi->list.head; e; e = n) {
+ struct altsvc *as = e->ptr;
+ n = e->next;
if((srcalpnid == as->src.alpnid) &&
(srcport == as->src.port) &&
hostcompare(srchost, as->src.host)) {
- Curl_node_remove(e);
+ Curl_llist_remove(&asi->list, e, NULL);
altsvc_free(as);
}
}
@@ -462,7 +471,7 @@ static time_t altsvc_debugtime(void *unused)
char *timestr = getenv("CURL_TIME");
(void)unused;
if(timestr) {
- long val = strtol(timestr, NULL, 10);
+ unsigned long val = strtol(timestr, NULL, 10);
return (time_t)val;
}
return time(NULL);
@@ -477,11 +486,11 @@ static time_t altsvc_debugtime(void *unused)
* Curl_altsvc_parse() takes an incoming alt-svc response header and stores
* the data correctly in the cache.
*
- * 'value' points to the header *value*. That is contents to the right of the
+ * 'value' points to the header *value*. That's contents to the right of the
* header name.
*
* Currently this function rejects invalid data without returning an error.
- * Invalid hostname, port number will result in the specific alternative
+ * Invalid host name, port number will result in the specific alternative
* being rejected. Unknown protocols are skipped.
*/
CURLcode Curl_altsvc_parse(struct Curl_easy *data,
@@ -531,7 +540,7 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data,
bool valid = TRUE;
p++;
if(*p != ':') {
- /* hostname starts here */
+ /* host name starts here */
const char *hostp = p;
if(*p == '[') {
/* pass all valid IPv6 letters - does not handle zone id */
@@ -549,7 +558,7 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data,
len = p - hostp;
}
if(!len || (len >= MAX_ALTSVC_HOSTLEN)) {
- infof(data, "Excessive alt-svc hostname, ignoring.");
+ infof(data, "Excessive alt-svc host name, ignoring.");
valid = FALSE;
}
else {
@@ -624,7 +633,7 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data,
num = strtoul(value_ptr, &end_ptr, 10);
if((end_ptr != value_ptr) && (num < ULONG_MAX)) {
if(strcasecompare("ma", option))
- maxage = (time_t)num;
+ maxage = num;
else if(strcasecompare("persist", option) && (num == 1))
persist = TRUE;
}
@@ -643,7 +652,7 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data,
account. [See RFC 7838 section 3.1] */
as->expires = maxage + time(NULL);
as->persist = persist;
- Curl_llist_append(&asi->list, as, &as->node);
+ Curl_llist_insert_next(&asi->list, asi->list.tail, as, &as->node);
infof(data, "Added alt-svc: %s:%d over %s", dsthost, dstport,
Curl_alpnid2str(dstalpnid));
}
@@ -651,7 +660,7 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data,
}
else
break;
- /* after the double quote there can be a comma if there is another
+ /* after the double quote there can be a comma if there's another
string or a semicolon if no more */
if(*p == ',') {
/* comma means another alternative is presented */
@@ -677,26 +686,26 @@ bool Curl_altsvc_lookup(struct altsvcinfo *asi,
struct altsvc **dstentry,
const int versions) /* one or more bits */
{
- struct Curl_llist_node *e;
- struct Curl_llist_node *n;
+ struct Curl_llist_element *e;
+ struct Curl_llist_element *n;
time_t now = time(NULL);
DEBUGASSERT(asi);
DEBUGASSERT(srchost);
DEBUGASSERT(dstentry);
- for(e = Curl_llist_head(&asi->list); e; e = n) {
- struct altsvc *as = Curl_node_elem(e);
- n = Curl_node_next(e);
+ for(e = asi->list.head; e; e = n) {
+ struct altsvc *as = e->ptr;
+ n = e->next;
if(as->expires < now) {
/* an expired entry, remove */
- Curl_node_remove(e);
+ Curl_llist_remove(&asi->list, e, NULL);
altsvc_free(as);
continue;
}
if((as->src.alpnid == srcalpnid) &&
hostcompare(srchost, as->src.host) &&
(as->src.port == srcport) &&
- (versions & (int)as->dst.alpnid)) {
+ (versions & as->dst.alpnid)) {
/* match */
*dstentry = as;
return TRUE;
diff --git a/contrib/libs/curl/lib/altsvc.h b/contrib/libs/curl/lib/altsvc.h
index 48999efb31..7fea1434a5 100644
--- a/contrib/libs/curl/lib/altsvc.h
+++ b/contrib/libs/curl/lib/altsvc.h
@@ -47,8 +47,8 @@ struct altsvc {
struct althost dst;
time_t expires;
bool persist;
- unsigned int prio;
- struct Curl_llist_node node;
+ int prio;
+ struct Curl_llist_element node;
};
struct altsvcinfo {
diff --git a/contrib/libs/curl/lib/amigaos.c b/contrib/libs/curl/lib/amigaos.c
index d2656fd892..9c8806c9d9 100644
--- a/contrib/libs/curl/lib/amigaos.c
+++ b/contrib/libs/curl/lib/amigaos.c
@@ -117,7 +117,7 @@ void Curl_amiga_cleanup(void)
#ifdef CURLRES_AMIGA
/*
- * Because we need to handle the different cases in hostip4.c at runtime,
+ * Because we need to handle the different cases in hostip4.c at run-time,
* not at compile-time, based on what was detected in Curl_amiga_init(),
* we replace it completely with our own as to not complicate the baseline
* code. Assumes malloc/calloc/free are thread safe because Curl_he2ai()
diff --git a/contrib/libs/curl/lib/arpa_telnet.h b/contrib/libs/curl/lib/arpa_telnet.h
index d641a01da8..228b4466ed 100644
--- a/contrib/libs/curl/lib/arpa_telnet.h
+++ b/contrib/libs/curl/lib/arpa_telnet.h
@@ -77,7 +77,7 @@ static const char * const telnetoptions[]=
#define CURL_GA 249 /* Go Ahead, reverse the line */
#define CURL_SB 250 /* SuBnegotiation */
#define CURL_WILL 251 /* Our side WILL use this option */
-#define CURL_WONT 252 /* Our side will not use this option */
+#define CURL_WONT 252 /* Our side WON'T use this option */
#define CURL_DO 253 /* DO use this option! */
#define CURL_DONT 254 /* DON'T use this option! */
#define CURL_IAC 255 /* Interpret As Command */
diff --git a/contrib/libs/curl/lib/asyn-ares.c b/contrib/libs/curl/lib/asyn-ares.c
index 782e3ac659..437c9337fc 100644
--- a/contrib/libs/curl/lib/asyn-ares.c
+++ b/contrib/libs/curl/lib/asyn-ares.c
@@ -65,7 +65,7 @@
# define CARES_STATICLIB
#endif
#include <ares.h>
-#include <ares_version.h> /* really old c-ares did not include this by
+#include <ares_version.h> /* really old c-ares didn't include this by
itself */
#if ARES_VERSION >= 0x010500
@@ -112,8 +112,8 @@ struct thread_data {
/* How long we are willing to wait for additional parallel responses after
obtaining a "definitive" one. For old c-ares without getaddrinfo.
- This is intended to equal the c-ares default timeout. cURL always uses that
- default value. Unfortunately, c-ares does not expose its default timeout in
+ This is intended to equal the c-ares default timeout. cURL always uses that
+ default value. Unfortunately, c-ares doesn't expose its default timeout in
its API, but it is officially documented as 5 seconds.
See query_completed_cb() for an explanation of how this is used.
@@ -122,12 +122,10 @@ struct thread_data {
#define CARES_TIMEOUT_PER_ATTEMPT 2000
-static int ares_ver = 0;
-
/*
* Curl_resolver_global_init() - the generic low-level asynchronous name
- * resolve API. Called from curl_global_init() to initialize global resolver
- * environment. Initializes ares library.
+ * resolve API. Called from curl_global_init() to initialize global resolver
+ * environment. Initializes ares library.
*/
int Curl_resolver_global_init(void)
{
@@ -136,7 +134,6 @@ int Curl_resolver_global_init(void)
return CURLE_FAILED_INIT;
}
#endif
- ares_version(&ares_ver);
return CURLE_OK;
}
@@ -169,7 +166,7 @@ static void sock_state_cb(void *data, ares_socket_t socket_fd,
*
* Called from curl_easy_init() -> Curl_open() to initialize resolver
* URL-state specific environment ('resolver' member of the UrlState
- * structure). Fills the passed pointer by the initialized ares_channel.
+ * structure). Fills the passed pointer by the initialized ares_channel.
*/
CURLcode Curl_resolver_init(struct Curl_easy *easy, void **resolver)
{
@@ -178,21 +175,8 @@ CURLcode Curl_resolver_init(struct Curl_easy *easy, void **resolver)
int optmask = ARES_OPT_SOCK_STATE_CB;
options.sock_state_cb = sock_state_cb;
options.sock_state_cb_data = easy;
-
- /*
- if c ares < 1.20.0: curl set timeout to CARES_TIMEOUT_PER_ATTEMPT (2s)
-
- if c-ares >= 1.20.0 it already has the timeout to 2s, curl does not need
- to set the timeout value;
-
- if c-ares >= 1.24.0, user can set the timeout via /etc/resolv.conf to
- overwrite c-ares' timeout.
- */
- DEBUGASSERT(ares_ver);
- if(ares_ver < 0x011400) {
- options.timeout = CARES_TIMEOUT_PER_ATTEMPT;
- optmask |= ARES_OPT_TIMEOUTMS;
- }
+ options.timeout = CARES_TIMEOUT_PER_ATTEMPT;
+ optmask |= ARES_OPT_TIMEOUTMS;
status = ares_init_options((ares_channel*)resolver, &options, optmask);
if(status != ARES_SUCCESS) {
@@ -211,7 +195,7 @@ CURLcode Curl_resolver_init(struct Curl_easy *easy, void **resolver)
*
* Called from curl_easy_cleanup() -> Curl_close() to cleanup resolver
* URL-state specific environment ('resolver' member of the UrlState
- * structure). Destroys the ares channel.
+ * structure). Destroys the ares channel.
*/
void Curl_resolver_cleanup(void *resolver)
{
@@ -222,7 +206,7 @@ void Curl_resolver_cleanup(void *resolver)
* Curl_resolver_duphandle()
*
* Called from curl_easy_duphandle() to duplicate resolver URL-state specific
- * environment ('resolver' member of the UrlState structure). Duplicates the
+ * environment ('resolver' member of the UrlState structure). Duplicates the
* 'from' ares channel and passes the resulting channel to the 'to' pointer.
*/
CURLcode Curl_resolver_duphandle(struct Curl_easy *easy, void **to, void *from)
@@ -244,18 +228,18 @@ static void destroy_async_data(struct Curl_async *async);
void Curl_resolver_cancel(struct Curl_easy *data)
{
DEBUGASSERT(data);
- if(data->state.async.resolver)
- ares_cancel((ares_channel)data->state.async.resolver);
- destroy_async_data(&data->state.async);
+ if(data->conn->resolve_async.resolver)
+ ares_cancel((ares_channel)data->conn->resolve_async.resolver);
+ destroy_async_data(&data->conn->resolve_async);
}
/*
- * We are equivalent to Curl_resolver_cancel() for the c-ares resolver. We
+ * We're equivalent to Curl_resolver_cancel() for the c-ares resolver. We
* never block.
*/
void Curl_resolver_kill(struct Curl_easy *data)
{
- /* We do not need to check the resolver state because we can be called safely
+ /* We don't need to check the resolver state because we can be called safely
at any time and we always do the same thing. */
Curl_resolver_cancel(data);
}
@@ -280,7 +264,7 @@ static void destroy_async_data(struct Curl_async *async)
/*
* Curl_resolver_getsock() is called when someone from the outside world
- * (using curl_multi_fdset()) wants to get our fd_set setup and we are talking
+ * (using curl_multi_fdset()) wants to get our fd_set setup and we're talking
* with ares. The caller must make sure that this function is only called when
* we have a working ares channel.
*
@@ -294,14 +278,14 @@ int Curl_resolver_getsock(struct Curl_easy *data,
struct timeval timebuf;
struct timeval *timeout;
long milli;
- int max = ares_getsock((ares_channel)data->state.async.resolver,
+ int max = ares_getsock((ares_channel)data->conn->resolve_async.resolver,
(ares_socket_t *)socks, MAX_SOCKSPEREASYHANDLE);
maxtime.tv_sec = CURL_TIMEOUT_RESOLVE;
maxtime.tv_usec = 0;
- timeout = ares_timeout((ares_channel)data->state.async.resolver, &maxtime,
- &timebuf);
+ timeout = ares_timeout((ares_channel)data->conn->resolve_async.resolver,
+ &maxtime, &timebuf);
milli = (long)curlx_tvtoms(timeout);
if(milli == 0)
milli += 10;
@@ -329,8 +313,8 @@ static int waitperform(struct Curl_easy *data, timediff_t timeout_ms)
int i;
int num = 0;
- bitmask = ares_getsock((ares_channel)data->state.async.resolver, socks,
- ARES_GETSOCK_MAXNUM);
+ bitmask = ares_getsock((ares_channel)data->conn->resolve_async.resolver,
+ socks, ARES_GETSOCK_MAXNUM);
for(i = 0; i < ARES_GETSOCK_MAXNUM; i++) {
pfd[i].events = 0;
@@ -350,7 +334,7 @@ static int waitperform(struct Curl_easy *data, timediff_t timeout_ms)
}
if(num) {
- nfds = Curl_poll(pfd, (unsigned int)num, timeout_ms);
+ nfds = Curl_poll(pfd, num, timeout_ms);
if(nfds < 0)
return -1;
}
@@ -359,13 +343,13 @@ static int waitperform(struct Curl_easy *data, timediff_t timeout_ms)
if(!nfds)
/* Call ares_process() unconditionally here, even if we simply timed out
- above, as otherwise the ares name resolve will not timeout! */
- ares_process_fd((ares_channel)data->state.async.resolver, ARES_SOCKET_BAD,
- ARES_SOCKET_BAD);
+ above, as otherwise the ares name resolve won't timeout! */
+ ares_process_fd((ares_channel)data->conn->resolve_async.resolver,
+ ARES_SOCKET_BAD, ARES_SOCKET_BAD);
else {
/* move through the descriptors and ask for processing on them */
for(i = 0; i < num; i++)
- ares_process_fd((ares_channel)data->state.async.resolver,
+ ares_process_fd((ares_channel)data->conn->resolve_async.resolver,
(pfd[i].revents & (POLLRDNORM|POLLIN))?
pfd[i].fd:ARES_SOCKET_BAD,
(pfd[i].revents & (POLLWRNORM|POLLOUT))?
@@ -384,7 +368,7 @@ static int waitperform(struct Curl_easy *data, timediff_t timeout_ms)
CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
struct Curl_dns_entry **dns)
{
- struct thread_data *res = data->state.async.tdata;
+ struct thread_data *res = data->conn->resolve_async.tdata;
CURLcode result = CURLE_OK;
DEBUGASSERT(dns);
@@ -394,8 +378,8 @@ CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
return CURLE_UNRECOVERABLE_POLL;
#ifndef HAVE_CARES_GETADDRINFO
- /* Now that we have checked for any last minute results above, see if there
- are any responses still pending when the EXPIRE_HAPPY_EYEBALLS_DNS timer
+ /* Now that we've checked for any last minute results above, see if there are
+ any responses still pending when the EXPIRE_HAPPY_EYEBALLS_DNS timer
expires. */
if(res
&& res->num_pending
@@ -410,10 +394,10 @@ CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
&res->happy_eyeballs_dns_time, 0, sizeof(res->happy_eyeballs_dns_time));
/* Cancel the raw c-ares request, which will fire query_completed_cb() with
- ARES_ECANCELLED synchronously for all pending responses. This will
+ ARES_ECANCELLED synchronously for all pending responses. This will
leave us with res->num_pending == 0, which is perfect for the next
block. */
- ares_cancel((ares_channel)data->state.async.resolver);
+ ares_cancel((ares_channel)data->conn->resolve_async.resolver);
DEBUGASSERT(res->num_pending == 0);
}
#endif
@@ -424,12 +408,12 @@ CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
them */
res->temp_ai = NULL;
- if(!data->state.async.dns)
+ if(!data->conn->resolve_async.dns)
result = Curl_resolver_error(data);
else
- *dns = data->state.async.dns;
+ *dns = data->conn->resolve_async.dns;
- destroy_async_data(&data->state.async);
+ destroy_async_data(&data->conn->resolve_async);
}
return result;
@@ -480,7 +464,8 @@ CURLcode Curl_resolver_wait_resolv(struct Curl_easy *data,
store.tv_sec = itimeout/1000;
store.tv_usec = (itimeout%1000)*1000;
- tvp = ares_timeout((ares_channel)data->state.async.resolver, &store, &tv);
+ tvp = ares_timeout((ares_channel)data->conn->resolve_async.resolver,
+ &store, &tv);
/* use the timeout period ares returned to us above if less than one
second is left, otherwise just use 1000ms to make sure the progress
@@ -494,7 +479,7 @@ CURLcode Curl_resolver_wait_resolv(struct Curl_easy *data,
return CURLE_UNRECOVERABLE_POLL;
result = Curl_resolver_is_resolved(data, entry);
- if(result || data->state.async.done)
+ if(result || data->conn->resolve_async.done)
break;
if(Curl_pgrsUpdate(data))
@@ -515,15 +500,15 @@ CURLcode Curl_resolver_wait_resolv(struct Curl_easy *data,
}
if(result)
/* failure, so we cancel the ares operation */
- ares_cancel((ares_channel)data->state.async.resolver);
+ ares_cancel((ares_channel)data->conn->resolve_async.resolver);
/* Operation complete, if the lookup was successful we now have the entry
in the cache. */
if(entry)
- *entry = data->state.async.dns;
+ *entry = data->conn->resolve_async.dns;
if(result)
- /* close the connection, since we cannot return failure here without
+ /* close the connection, since we can't return failure here without
cleaning up this connection properly. */
connclose(data->conn, "c-ares resolve failed");
@@ -539,7 +524,7 @@ static void compound_results(struct thread_data *res,
if(!ai)
return;
-#ifdef USE_IPV6 /* CURLRES_IPV6 */
+#ifdef ENABLE_IPV6 /* CURLRES_IPV6 */
if(res->temp_ai && res->temp_ai->ai_family == PF_INET6) {
/* We have results already, put the new IPv6 entries at the head of the
list. */
@@ -587,12 +572,13 @@ static void query_completed_cb(void *arg, /* (struct connectdata *) */
be valid so only defer it when we know the 'status' says its fine! */
return;
- res = data->state.async.tdata;
+ res = data->conn->resolve_async.tdata;
if(res) {
res->num_pending--;
if(CURL_ASYNC_SUCCESS == status) {
- struct Curl_addrinfo *ai = Curl_he2ai(hostent, data->state.async.port);
+ struct Curl_addrinfo *ai = Curl_he2ai(hostent,
+ data->conn->resolve_async.port);
if(ai) {
compound_results(res, ai);
}
@@ -603,57 +589,57 @@ static void query_completed_cb(void *arg, /* (struct connectdata *) */
/* If there are responses still pending, we presume they must be the
complementary IPv4 or IPv6 lookups that we started in parallel in
- Curl_resolver_getaddrinfo() (for Happy Eyeballs). If we have got a
+ Curl_resolver_getaddrinfo() (for Happy Eyeballs). If we've got a
"definitive" response from one of a set of parallel queries, we need to
- think about how long we are willing to wait for more responses. */
+ think about how long we're willing to wait for more responses. */
if(res->num_pending
/* Only these c-ares status values count as "definitive" for these
- purposes. For example, ARES_ENODATA is what we expect when there is
- no IPv6 entry for a domain name, and that is not a reason to get more
- aggressive in our timeouts for the other response. Other errors are
+ purposes. For example, ARES_ENODATA is what we expect when there is
+ no IPv6 entry for a domain name, and that's not a reason to get more
+ aggressive in our timeouts for the other response. Other errors are
either a result of bad input (which should affect all parallel
requests), local or network conditions, non-definitive server
responses, or us cancelling the request. */
&& (status == ARES_SUCCESS || status == ARES_ENOTFOUND)) {
- /* Right now, there can only be up to two parallel queries, so do not
+ /* Right now, there can only be up to two parallel queries, so don't
bother handling any other cases. */
DEBUGASSERT(res->num_pending == 1);
- /* it is possible that one of these parallel queries could succeed
- quickly, but the other could always fail or timeout (when we are
+ /* It's possible that one of these parallel queries could succeed
+ quickly, but the other could always fail or timeout (when we're
talking to a pool of DNS servers that can only successfully resolve
IPv4 address, for example).
- it is also possible that the other request could always just take
+ It's also possible that the other request could always just take
longer because it needs more time or only the second DNS server can
- fulfill it successfully. But, to align with the philosophy of Happy
- Eyeballs, we do not want to wait _too_ long or users will think
- requests are slow when IPv6 lookups do not actually work (but IPv4
- ones do).
+ fulfill it successfully. But, to align with the philosophy of Happy
+ Eyeballs, we don't want to wait _too_ long or users will think
+ requests are slow when IPv6 lookups don't actually work (but IPv4 ones
+ do).
So, now that we have a usable answer (some IPv4 addresses, some IPv6
addresses, or "no such domain"), we start a timeout for the remaining
- pending responses. Even though it is typical that this resolved
- request came back quickly, that needn't be the case. It might be that
- this completing request did not get a result from the first DNS
- server or even the first round of the whole DNS server pool. So it
- could already be quite some time after we issued the DNS queries in
- the first place. Without modifying c-ares, we cannot know exactly
- where in its retry cycle we are. We could guess based on how much
- time has gone by, but it does not really matter. Happy Eyeballs tells
- us that, given usable information in hand, we simply do not want to
- wait "too much longer" after we get a result.
+ pending responses. Even though it is typical that this resolved
+ request came back quickly, that needn't be the case. It might be that
+ this completing request didn't get a result from the first DNS server
+ or even the first round of the whole DNS server pool. So it could
+ already be quite some time after we issued the DNS queries in the
+ first place. Without modifying c-ares, we can't know exactly where in
+ its retry cycle we are. We could guess based on how much time has
+ gone by, but it doesn't really matter. Happy Eyeballs tells us that,
+ given usable information in hand, we simply don't want to wait "too
+ much longer" after we get a result.
We simply wait an additional amount of time equal to the default
- c-ares query timeout. That is enough time for a typical parallel
- response to arrive without being "too long". Even on a network
+ c-ares query timeout. That is enough time for a typical parallel
+ response to arrive without being "too long". Even on a network
where one of the two types of queries is failing or timing out
constantly, this will usually mean we wait a total of the default
c-ares timeout (5 seconds) plus the round trip time for the successful
- request, which seems bearable. The downside is that c-ares might race
+ request, which seems bearable. The downside is that c-ares might race
with us to issue one more retry just before we give up, but it seems
better to "waste" that request instead of trying to guess the perfect
- timeout to prevent it. After all, we do not even know where in the
+ timeout to prevent it. After all, we don't even know where in the
c-ares retry cycle each request is.
*/
res->happy_eyeballs_dns_time = Curl_now();
@@ -684,7 +670,7 @@ static struct Curl_addrinfo *ares2addr(struct ares_addrinfo_node *node)
/* settle family-specific sockaddr structure size. */
if(ai->ai_family == AF_INET)
ss_size = sizeof(struct sockaddr_in);
-#ifdef USE_IPV6
+#ifdef ENABLE_IPV6
else if(ai->ai_family == AF_INET6)
ss_size = sizeof(struct sockaddr_in6);
#endif
@@ -743,14 +729,16 @@ static void addrinfo_cb(void *arg, int status, int timeouts,
struct ares_addrinfo *result)
{
struct Curl_easy *data = (struct Curl_easy *)arg;
- struct thread_data *res = data->state.async.tdata;
- (void)timeouts;
- if(ARES_SUCCESS == status) {
- res->temp_ai = ares2addr(result->nodes);
- res->last_status = CURL_ASYNC_SUCCESS;
- ares_freeaddrinfo(result);
+ if(data->conn) {
+ struct thread_data *res = data->conn->resolve_async.tdata;
+ (void)timeouts;
+ if(ARES_SUCCESS == status) {
+ res->temp_ai = ares2addr(result->nodes);
+ res->last_status = CURL_ASYNC_SUCCESS;
+ ares_freeaddrinfo(result);
+ }
+ res->num_pending--;
}
- res->num_pending--;
}
#endif
@@ -774,12 +762,12 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
res = calloc(1, sizeof(struct thread_data) + namelen);
if(res) {
strcpy(res->hostname, hostname);
- data->state.async.hostname = res->hostname;
- data->state.async.port = port;
- data->state.async.done = FALSE; /* not done */
- data->state.async.status = 0; /* clear */
- data->state.async.dns = NULL; /* clear */
- data->state.async.tdata = res;
+ data->conn->resolve_async.hostname = res->hostname;
+ data->conn->resolve_async.port = port;
+ data->conn->resolve_async.done = FALSE; /* not done */
+ data->conn->resolve_async.status = 0; /* clear */
+ data->conn->resolve_async.dns = NULL; /* clear */
+ data->conn->resolve_async.tdata = res;
/* initial status - failed */
res->last_status = ARES_ENOTFOUND;
@@ -809,8 +797,8 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
hints.ai_flags = ARES_AI_NUMERICSERV;
msnprintf(service, sizeof(service), "%d", port);
res->num_pending = 1;
- ares_getaddrinfo((ares_channel)data->state.async.resolver, hostname,
- service, &hints, addrinfo_cb, data);
+ ares_getaddrinfo((ares_channel)data->conn->resolve_async.resolver,
+ hostname, service, &hints, addrinfo_cb, data);
}
#else
@@ -820,10 +808,10 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
res->num_pending = 2;
/* areschannel is already setup in the Curl_open() function */
- ares_gethostbyname((ares_channel)data->state.async.resolver, hostname,
- PF_INET, query_completed_cb, data);
- ares_gethostbyname((ares_channel)data->state.async.resolver, hostname,
- PF_INET6, query_completed_cb, data);
+ ares_gethostbyname((ares_channel)data->conn->resolve_async.resolver,
+ hostname, PF_INET, query_completed_cb, data);
+ ares_gethostbyname((ares_channel)data->conn->resolve_async.resolver,
+ hostname, PF_INET6, query_completed_cb, data);
}
else
#endif
@@ -831,7 +819,7 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
res->num_pending = 1;
/* areschannel is already setup in the Curl_open() function */
- ares_gethostbyname((ares_channel)data->state.async.resolver,
+ ares_gethostbyname((ares_channel)data->conn->resolve_async.resolver,
hostname, PF_INET,
query_completed_cb, data);
}
@@ -845,23 +833,36 @@ CURLcode Curl_set_dns_servers(struct Curl_easy *data,
char *servers)
{
CURLcode result = CURLE_NOT_BUILT_IN;
+ ares_channel channel, lchannel = NULL;
int ares_result;
/* If server is NULL or empty, this would purge all DNS servers
* from ares library, which will cause any and all queries to fail.
- * So, just return OK if none are configured and do not actually make
- * any changes to c-ares. This lets c-ares use its defaults, which
+ * So, just return OK if none are configured and don't actually make
+ * any changes to c-ares. This lets c-ares use it's defaults, which
* it gets from the OS (for instance from /etc/resolv.conf on Linux).
*/
if(!(servers && servers[0]))
return CURLE_OK;
#ifdef HAVE_CARES_SERVERS_CSV
+ if(data->conn)
+ channel = data->conn->resolve_async.resolver;
+ else {
+ /* we are called by setopt on a data without a connection (yet). In that
+ * case we set the value on a local instance for checking.
+ * The configured data options are set when the connection for this
+ * transfer is created. */
+ result = Curl_resolver_init(data, (void **)&lchannel);
+ if(result)
+ goto out;
+ channel = lchannel;
+ }
+
#ifdef HAVE_CARES_PORTS_CSV
- ares_result = ares_set_servers_ports_csv(data->state.async.resolver,
- servers);
+ ares_result = ares_set_servers_ports_csv(channel, servers);
#else
- ares_result = ares_set_servers_csv(data->state.async.resolver, servers);
+ ares_result = ares_set_servers_csv(channel, servers);
#endif
switch(ares_result) {
case ARES_SUCCESS:
@@ -874,10 +875,12 @@ CURLcode Curl_set_dns_servers(struct Curl_easy *data,
case ARES_ENODATA:
case ARES_EBADSTR:
default:
- DEBUGF(infof(data, "bad servers set"));
result = CURLE_BAD_FUNCTION_ARGUMENT;
break;
}
+out:
+ if(lchannel)
+ Curl_resolver_cleanup(lchannel);
#else /* too old c-ares version! */
(void)data;
(void)(ares_result);
@@ -889,11 +892,14 @@ CURLcode Curl_set_dns_interface(struct Curl_easy *data,
const char *interf)
{
#ifdef HAVE_CARES_LOCAL_DEV
- if(!interf)
- interf = "";
-
- ares_set_local_dev((ares_channel)data->state.async.resolver, interf);
+ if(data->conn) {
+ /* not a setopt test run, set the value */
+ if(!interf)
+ interf = "";
+ ares_set_local_dev((ares_channel)data->conn->resolve_async.resolver,
+ interf);
+ }
return CURLE_OK;
#else /* c-ares version too old! */
(void)data;
@@ -913,13 +919,15 @@ CURLcode Curl_set_dns_local_ip4(struct Curl_easy *data,
}
else {
if(Curl_inet_pton(AF_INET, local_ip4, &a4) != 1) {
- DEBUGF(infof(data, "bad DNS IPv4 address"));
return CURLE_BAD_FUNCTION_ARGUMENT;
}
}
- ares_set_local_ip4((ares_channel)data->state.async.resolver,
- ntohl(a4.s_addr));
+ if(data->conn) {
+ /* not a setopt test run, set the value */
+ ares_set_local_ip4((ares_channel)data->conn->resolve_async.resolver,
+ ntohl(a4.s_addr));
+ }
return CURLE_OK;
#else /* c-ares version too old! */
@@ -932,7 +940,7 @@ CURLcode Curl_set_dns_local_ip4(struct Curl_easy *data,
CURLcode Curl_set_dns_local_ip6(struct Curl_easy *data,
const char *local_ip6)
{
-#if defined(HAVE_CARES_SET_LOCAL) && defined(USE_IPV6)
+#if defined(HAVE_CARES_SET_LOCAL) && defined(ENABLE_IPV6)
unsigned char a6[INET6_ADDRSTRLEN];
if((!local_ip6) || (local_ip6[0] == 0)) {
@@ -941,12 +949,14 @@ CURLcode Curl_set_dns_local_ip6(struct Curl_easy *data,
}
else {
if(Curl_inet_pton(AF_INET6, local_ip6, a6) != 1) {
- DEBUGF(infof(data, "bad DNS IPv6 address"));
return CURLE_BAD_FUNCTION_ARGUMENT;
}
}
- ares_set_local_ip6((ares_channel)data->state.async.resolver, a6);
+ if(data->conn) {
+ /* not a setopt test run, set the value */
+ ares_set_local_ip6((ares_channel)data->conn->resolve_async.resolver, a6);
+ }
return CURLE_OK;
#else /* c-ares version too old! */
diff --git a/contrib/libs/curl/lib/asyn-thread.c b/contrib/libs/curl/lib/asyn-thread.c
index 79b9c239cf..63414b6174 100644
--- a/contrib/libs/curl/lib/asyn-thread.c
+++ b/contrib/libs/curl/lib/asyn-thread.c
@@ -136,7 +136,7 @@ static void destroy_async_data(struct Curl_async *);
*/
void Curl_resolver_cancel(struct Curl_easy *data)
{
- destroy_async_data(&data->state.async);
+ destroy_async_data(&data->conn->resolve_async);
}
/* This function is used to init a threaded resolve */
@@ -154,7 +154,7 @@ struct thread_sync_data {
duplicate */
#ifndef CURL_DISABLE_SOCKETPAIR
struct Curl_easy *data;
- curl_socket_t sock_pair[2]; /* eventfd/pipes/socket pair */
+ curl_socket_t sock_pair[2]; /* socket pair */
#endif
int sock_error;
struct Curl_addrinfo *res;
@@ -173,7 +173,7 @@ struct thread_data {
static struct thread_sync_data *conn_thread_sync_data(struct Curl_easy *data)
{
- return &(data->state.async.tdata->tsd);
+ return &(data->conn->resolve_async.tdata->tsd);
}
/* Destroy resolver thread synchronization data */
@@ -234,7 +234,7 @@ int init_thread_sync_data(struct thread_data *td,
#ifndef CURL_DISABLE_SOCKETPAIR
/* create socket pair or pipe */
- if(wakeup_create(tsd->sock_pair, FALSE) < 0) {
+ if(wakeup_create(&tsd->sock_pair[0]) < 0) {
tsd->sock_pair[0] = CURL_SOCKET_BAD;
tsd->sock_pair[1] = CURL_SOCKET_BAD;
goto err_exit;
@@ -269,7 +269,7 @@ static CURLcode getaddrinfo_complete(struct Curl_easy *data)
result = Curl_addrinfo_callback(data, tsd->sock_error, tsd->res);
/* The tsd->res structure has been copied to async.dns and perhaps the DNS
- cache. Set our copy to NULL so destroy_thread_sync_data does not free it.
+ cache. Set our copy to NULL so destroy_thread_sync_data doesn't free it.
*/
tsd->res = NULL;
@@ -282,29 +282,18 @@ static CURLcode getaddrinfo_complete(struct Curl_easy *data)
/*
* getaddrinfo_thread() resolves a name and then exits.
*
- * For builds without ARES, but with USE_IPV6, create a resolver thread
+ * For builds without ARES, but with ENABLE_IPV6, create a resolver thread
* and wait on it.
*/
-static
-#if defined(_WIN32_WCE) || defined(CURL_WINDOWS_APP)
-DWORD
-#else
-unsigned int
-#endif
-CURL_STDCALL getaddrinfo_thread(void *arg)
+static unsigned int CURL_STDCALL getaddrinfo_thread(void *arg)
{
struct thread_sync_data *tsd = (struct thread_sync_data *)arg;
struct thread_data *td = tsd->td;
char service[12];
int rc;
#ifndef CURL_DISABLE_SOCKETPAIR
-#ifdef USE_EVENTFD
- const void *buf;
- const uint64_t val = 1;
-#else
char buf[1];
#endif
-#endif
msnprintf(service, sizeof(service), "%d", tsd->port);
@@ -329,13 +318,9 @@ CURL_STDCALL getaddrinfo_thread(void *arg)
else {
#ifndef CURL_DISABLE_SOCKETPAIR
if(tsd->sock_pair[1] != CURL_SOCKET_BAD) {
-#ifdef USE_EVENTFD
- buf = &val;
-#else
- buf[0] = 1;
-#endif
/* DNS has been resolved, signal client task */
- if(wakeup_write(tsd->sock_pair[1], buf, sizeof(buf)) < 0) {
+ buf[0] = 1;
+ if(wakeup_write(tsd->sock_pair[1], buf, sizeof(buf)) < 0) {
/* update sock_erro to errno */
tsd->sock_error = SOCKERRNO;
}
@@ -353,13 +338,7 @@ CURL_STDCALL getaddrinfo_thread(void *arg)
/*
* gethostbyname_thread() resolves a name and then exits.
*/
-static
-#if defined(_WIN32_WCE) || defined(CURL_WINDOWS_APP)
-DWORD
-#else
-unsigned int
-#endif
-CURL_STDCALL gethostbyname_thread(void *arg)
+static unsigned int CURL_STDCALL gethostbyname_thread(void *arg)
{
struct thread_sync_data *tsd = (struct thread_sync_data *)arg;
struct thread_data *td = tsd->td;
@@ -428,7 +407,7 @@ static void destroy_async_data(struct Curl_async *async)
* before the FD is invalidated to avoid EBADF on EPOLL_CTL_DEL
*/
Curl_multi_closed(data, sock_rd);
- wakeup_close(sock_rd);
+ sclose(sock_rd);
#endif
}
async->tdata = NULL;
@@ -449,9 +428,9 @@ static bool init_resolve_thread(struct Curl_easy *data,
{
struct thread_data *td = calloc(1, sizeof(struct thread_data));
int err = ENOMEM;
- struct Curl_async *asp = &data->state.async;
+ struct Curl_async *asp = &data->conn->resolve_async;
- data->state.async.tdata = td;
+ data->conn->resolve_async.tdata = td;
if(!td)
goto errno_exit;
@@ -481,7 +460,7 @@ static bool init_resolve_thread(struct Curl_easy *data,
td->thread_hnd = Curl_thread_create(gethostbyname_thread, &td->tsd);
#endif
- if(td->thread_hnd == curl_thread_t_null) {
+ if(!td->thread_hnd) {
/* The thread never started, so mark it as done here for proper cleanup. */
td->tsd.done = 1;
err = errno;
@@ -509,7 +488,7 @@ static CURLcode thread_wait_resolv(struct Curl_easy *data,
CURLcode result = CURLE_OK;
DEBUGASSERT(data);
- td = data->state.async.tdata;
+ td = data->conn->resolve_async.tdata;
DEBUGASSERT(td);
DEBUGASSERT(td->thread_hnd != curl_thread_t_null);
@@ -521,18 +500,18 @@ static CURLcode thread_wait_resolv(struct Curl_easy *data,
else
DEBUGASSERT(0);
- data->state.async.done = TRUE;
+ data->conn->resolve_async.done = TRUE;
if(entry)
- *entry = data->state.async.dns;
+ *entry = data->conn->resolve_async.dns;
- if(!data->state.async.dns && report)
+ if(!data->conn->resolve_async.dns && report)
/* a name was not resolved, report error */
result = Curl_resolver_error(data);
- destroy_async_data(&data->state.async);
+ destroy_async_data(&data->conn->resolve_async);
- if(!data->state.async.dns && report)
+ if(!data->conn->resolve_async.dns && report)
connclose(data->conn, "asynch resolve failed");
return result;
@@ -545,10 +524,10 @@ static CURLcode thread_wait_resolv(struct Curl_easy *data,
*/
void Curl_resolver_kill(struct Curl_easy *data)
{
- struct thread_data *td = data->state.async.tdata;
+ struct thread_data *td = data->conn->resolve_async.tdata;
- /* If we are still resolving, we must wait for the threads to fully clean up,
- unfortunately. Otherwise, we can simply cancel to clean up any resolver
+ /* If we're still resolving, we must wait for the threads to fully clean up,
+ unfortunately. Otherwise, we can simply cancel to clean up any resolver
data. */
if(td && td->thread_hnd != curl_thread_t_null
&& (data->set.quick_exit != 1L))
@@ -584,7 +563,7 @@ CURLcode Curl_resolver_wait_resolv(struct Curl_easy *data,
CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
struct Curl_dns_entry **entry)
{
- struct thread_data *td = data->state.async.tdata;
+ struct thread_data *td = data->conn->resolve_async.tdata;
int done = 0;
DEBUGASSERT(entry);
@@ -602,17 +581,17 @@ CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
if(done) {
getaddrinfo_complete(data);
- if(!data->state.async.dns) {
+ if(!data->conn->resolve_async.dns) {
CURLcode result = Curl_resolver_error(data);
- destroy_async_data(&data->state.async);
+ destroy_async_data(&data->conn->resolve_async);
return result;
}
- destroy_async_data(&data->state.async);
- *entry = data->state.async.dns;
+ destroy_async_data(&data->conn->resolve_async);
+ *entry = data->conn->resolve_async.dns;
}
else {
/* poll for name lookup done with exponential backoff up to 250ms */
- /* should be fine even if this converts to 32-bit */
+ /* should be fine even if this converts to 32 bit */
timediff_t elapsed = Curl_timediff(Curl_now(),
data->progress.t_startsingle);
if(elapsed < 0)
@@ -640,9 +619,9 @@ int Curl_resolver_getsock(struct Curl_easy *data, curl_socket_t *socks)
int ret_val = 0;
timediff_t milli;
timediff_t ms;
- struct resdata *reslv = (struct resdata *)data->state.async.resolver;
+ struct resdata *reslv = (struct resdata *)data->conn->resolve_async.resolver;
#ifndef CURL_DISABLE_SOCKETPAIR
- struct thread_data *td = data->state.async.tdata;
+ struct thread_data *td = data->conn->resolve_async.tdata;
#else
(void)socks;
#endif
@@ -683,7 +662,7 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
int port,
int *waitp)
{
- struct resdata *reslv = (struct resdata *)data->state.async.resolver;
+ struct resdata *reslv = (struct resdata *)data->conn->resolve_async.resolver;
*waitp = 0; /* default to synchronous response */
@@ -712,7 +691,7 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
{
struct addrinfo hints;
int pf = PF_INET;
- struct resdata *reslv = (struct resdata *)data->state.async.resolver;
+ struct resdata *reslv = (struct resdata *)data->conn->resolve_async.resolver;
*waitp = 0; /* default to synchronous response */
diff --git a/contrib/libs/curl/lib/asyn.h b/contrib/libs/curl/lib/asyn.h
index 0ff2048845..7e207c4f56 100644
--- a/contrib/libs/curl/lib/asyn.h
+++ b/contrib/libs/curl/lib/asyn.h
@@ -58,7 +58,7 @@ void Curl_resolver_global_cleanup(void);
* Curl_resolver_init()
* Called from curl_easy_init() -> Curl_open() to initialize resolver
* URL-state specific environment ('resolver' member of the UrlState
- * structure). Should fill the passed pointer by the initialized handler.
+ * structure). Should fill the passed pointer by the initialized handler.
* Returning anything else than CURLE_OK fails curl_easy_init() with the
* correspondent code.
*/
@@ -68,7 +68,7 @@ CURLcode Curl_resolver_init(struct Curl_easy *easy, void **resolver);
* Curl_resolver_cleanup()
* Called from curl_easy_cleanup() -> Curl_close() to cleanup resolver
* URL-state specific environment ('resolver' member of the UrlState
- * structure). Should destroy the handler and free all resources connected to
+ * structure). Should destroy the handler and free all resources connected to
* it.
*/
void Curl_resolver_cleanup(void *resolver);
@@ -76,9 +76,9 @@ void Curl_resolver_cleanup(void *resolver);
/*
* Curl_resolver_duphandle()
* Called from curl_easy_duphandle() to duplicate resolver URL-state specific
- * environment ('resolver' member of the UrlState structure). Should
+ * environment ('resolver' member of the UrlState structure). Should
* duplicate the 'from' handle and pass the resulting handle to the 'to'
- * pointer. Returning anything else than CURLE_OK causes failed
+ * pointer. Returning anything else than CURLE_OK causes failed
* curl_easy_duphandle() call.
*/
CURLcode Curl_resolver_duphandle(struct Curl_easy *easy, void **to,
@@ -89,7 +89,7 @@ CURLcode Curl_resolver_duphandle(struct Curl_easy *easy, void **to,
*
* It is called from inside other functions to cancel currently performing
* resolver request. Should also free any temporary resources allocated to
- * perform a request. This never waits for resolver threads to complete.
+ * perform a request. This never waits for resolver threads to complete.
*
* It is safe to call this when conn is in any state.
*/
@@ -99,8 +99,8 @@ void Curl_resolver_cancel(struct Curl_easy *data);
* Curl_resolver_kill().
*
* This acts like Curl_resolver_cancel() except it will block until any threads
- * associated with the resolver are complete. This never blocks for resolvers
- * that do not use threads. This is intended to be the "last chance" function
+ * associated with the resolver are complete. This never blocks for resolvers
+ * that do not use threads. This is intended to be the "last chance" function
* that cleans up an in-progress resolver completely (before its owner is about
* to die).
*
@@ -161,7 +161,7 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
int *waitp);
#ifndef CURLRES_ASYNCH
-/* convert these functions if an asynch resolver is not used */
+/* convert these functions if an asynch resolver isn't used */
#define Curl_resolver_cancel(x) Curl_nop_stmt
#define Curl_resolver_kill(x) Curl_nop_stmt
#define Curl_resolver_is_resolved(x,y) CURLE_COULDNT_RESOLVE_HOST
diff --git a/contrib/libs/curl/lib/base64.c b/contrib/libs/curl/lib/base64.c
index 8373115d20..919eb62359 100644
--- a/contrib/libs/curl/lib/base64.c
+++ b/contrib/libs/curl/lib/base64.c
@@ -243,7 +243,7 @@ static CURLcode base64_encode(const char *table64,
*outptr = base64data;
/* Return the length of the new data */
- *outlen = (size_t)(output - base64data);
+ *outlen = output - base64data;
return CURLE_OK;
}
diff --git a/contrib/libs/curl/lib/bufq.c b/contrib/libs/curl/lib/bufq.c
index 46e6eaa386..d03906d166 100644
--- a/contrib/libs/curl/lib/bufq.c
+++ b/contrib/libs/curl/lib/bufq.c
@@ -91,23 +91,6 @@ static size_t chunk_read(struct buf_chunk *chunk,
}
}
-static size_t chunk_unwrite(struct buf_chunk *chunk, size_t len)
-{
- size_t n = chunk->w_offset - chunk->r_offset;
- DEBUGASSERT(chunk->w_offset >= chunk->r_offset);
- if(!n) {
- return 0;
- }
- else if(n <= len) {
- chunk->r_offset = chunk->w_offset = 0;
- return n;
- }
- else {
- chunk->w_offset -= len;
- return len;
- }
-}
-
static ssize_t chunk_slurpn(struct buf_chunk *chunk, size_t max_len,
Curl_bufq_reader *reader,
void *reader_ctx, CURLcode *err)
@@ -380,49 +363,6 @@ static void prune_head(struct bufq *q)
}
}
-static struct buf_chunk *chunk_prev(struct buf_chunk *head,
- struct buf_chunk *chunk)
-{
- while(head) {
- if(head == chunk)
- return NULL;
- if(head->next == chunk)
- return head;
- head = head->next;
- }
- return NULL;
-}
-
-static void prune_tail(struct bufq *q)
-{
- struct buf_chunk *chunk;
-
- while(q->tail && chunk_is_empty(q->tail)) {
- chunk = q->tail;
- q->tail = chunk_prev(q->head, chunk);
- if(q->tail)
- q->tail->next = NULL;
- if(q->head == chunk)
- q->head = q->tail;
- if(q->pool) {
- bufcp_put(q->pool, chunk);
- --q->chunk_count;
- }
- else if((q->chunk_count > q->max_chunks) ||
- (q->opts & BUFQ_OPT_NO_SPARES)) {
- /* SOFT_LIMIT allowed us more than max. free spares until
- * we are at max again. Or free them if we are configured
- * to not use spares. */
- free(chunk);
- --q->chunk_count;
- }
- else {
- chunk->next = q->spare;
- q->spare = chunk;
- }
- }
-}
-
static struct buf_chunk *get_non_full_tail(struct bufq *q)
{
struct buf_chunk *chunk;
@@ -456,7 +396,7 @@ ssize_t Curl_bufq_write(struct bufq *q,
while(len) {
tail = get_non_full_tail(q);
if(!tail) {
- if((q->chunk_count < q->max_chunks) || (q->opts & BUFQ_OPT_SOFT_LIMIT)) {
+ if(q->chunk_count < q->max_chunks) {
*err = CURLE_OUT_OF_MEMORY;
return -1;
}
@@ -477,26 +417,6 @@ ssize_t Curl_bufq_write(struct bufq *q,
return nwritten;
}
-CURLcode Curl_bufq_cwrite(struct bufq *q,
- const char *buf, size_t len,
- size_t *pnwritten)
-{
- ssize_t n;
- CURLcode result;
- n = Curl_bufq_write(q, (const unsigned char *)buf, len, &result);
- *pnwritten = (n < 0)? 0 : (size_t)n;
- return result;
-}
-
-CURLcode Curl_bufq_unwrite(struct bufq *q, size_t len)
-{
- while(len && q->tail) {
- len -= chunk_unwrite(q->head, len);
- prune_tail(q);
- }
- return len? CURLE_AGAIN : CURLE_OK;
-}
-
ssize_t Curl_bufq_read(struct bufq *q, unsigned char *buf, size_t len,
CURLcode *err)
{
@@ -520,16 +440,6 @@ ssize_t Curl_bufq_read(struct bufq *q, unsigned char *buf, size_t len,
return nread;
}
-CURLcode Curl_bufq_cread(struct bufq *q, char *buf, size_t len,
- size_t *pnread)
-{
- ssize_t n;
- CURLcode result;
- n = Curl_bufq_read(q, (unsigned char *)buf, len, &result);
- *pnread = (n < 0)? 0 : (size_t)n;
- return result;
-}
-
bool Curl_bufq_peek(struct bufq *q,
const unsigned char **pbuf, size_t *plen)
{
diff --git a/contrib/libs/curl/lib/bufq.h b/contrib/libs/curl/lib/bufq.h
index ec415648fd..089d61bfe4 100644
--- a/contrib/libs/curl/lib/bufq.h
+++ b/contrib/libs/curl/lib/bufq.h
@@ -85,7 +85,7 @@ void Curl_bufcp_free(struct bufc_pool *pool);
* preferably never fail (except for memory exhaustion).
*
* By default and without a pool, a bufq will keep chunks that read
- * empty in its `spare` list. Option `BUFQ_OPT_NO_SPARES` will
+ * read empty in its `spare` list. Option `BUFQ_OPT_NO_SPARES` will
* disable that and free chunks once they become empty.
*
* When providing a pool to a bufq, all chunk creation and spare handling
@@ -178,16 +178,6 @@ ssize_t Curl_bufq_write(struct bufq *q,
const unsigned char *buf, size_t len,
CURLcode *err);
-CURLcode Curl_bufq_cwrite(struct bufq *q,
- const char *buf, size_t len,
- size_t *pnwritten);
-
-/**
- * Remove `len` bytes from the end of the buffer queue again.
- * Returns CURLE_AGAIN if less than `len` bytes were in the queue.
- */
-CURLcode Curl_bufq_unwrite(struct bufq *q, size_t len);
-
/**
* Read buf from the start of the buffer queue. The buf is copied
* and the amount of copied bytes is returned.
@@ -197,9 +187,6 @@ CURLcode Curl_bufq_unwrite(struct bufq *q, size_t len);
ssize_t Curl_bufq_read(struct bufq *q, unsigned char *buf, size_t len,
CURLcode *err);
-CURLcode Curl_bufq_cread(struct bufq *q, char *buf, size_t len,
- size_t *pnread);
-
/**
* Peek at the head chunk in the buffer queue. Returns a pointer to
* the chunk buf (at the current offset) and its length. Does not
diff --git a/contrib/libs/curl/lib/bufref.c b/contrib/libs/curl/lib/bufref.c
index f048b57011..ce686b6f37 100644
--- a/contrib/libs/curl/lib/bufref.c
+++ b/contrib/libs/curl/lib/bufref.c
@@ -25,7 +25,6 @@
#include "curl_setup.h"
#include "urldata.h"
#include "bufref.h"
-#include "strdup.h"
#include "curl_memory.h"
#include "memdebug.h"
@@ -48,7 +47,7 @@ void Curl_bufref_init(struct bufref *br)
}
/*
- * Free the buffer and re-init the necessary fields. It does not touch the
+ * Free the buffer and re-init the necessary fields. It doesn't touch the
* 'signature' field and thus this buffer reference can be reused.
*/
@@ -117,9 +116,12 @@ CURLcode Curl_bufref_memdup(struct bufref *br, const void *ptr, size_t len)
DEBUGASSERT(len <= CURL_MAX_INPUT_LENGTH);
if(ptr) {
- cpy = Curl_memdup0(ptr, len);
+ cpy = malloc(len + 1);
if(!cpy)
return CURLE_OUT_OF_MEMORY;
+ if(len)
+ memcpy(cpy, ptr, len);
+ cpy[len] = '\0';
}
Curl_bufref_set(br, cpy, len, curl_free);
diff --git a/contrib/libs/curl/lib/c-hyper.c b/contrib/libs/curl/lib/c-hyper.c
index d341f78b47..d524d8c427 100644
--- a/contrib/libs/curl/lib/c-hyper.c
+++ b/contrib/libs/curl/lib/c-hyper.c
@@ -53,9 +53,7 @@
#error #include <hyper.h>
#include "urldata.h"
-#include "cfilters.h"
#include "sendf.h"
-#include "headers.h"
#include "transfer.h"
#include "multiif.h"
#include "progress.h"
@@ -67,9 +65,6 @@
#include "curl_memory.h"
#include "memdebug.h"
-
-static CURLcode cr_hyper_add(struct Curl_easy *data);
-
typedef enum {
USERDATA_NOT_SET = 0, /* for tasks with no userdata set; must be zero */
USERDATA_RESP_BODY
@@ -78,8 +73,7 @@ typedef enum {
size_t Curl_hyper_recv(void *userp, hyper_context *ctx,
uint8_t *buf, size_t buflen)
{
- struct hyp_io_ctx *io_ctx = userp;
- struct Curl_easy *data = io_ctx->data;
+ struct Curl_easy *data = userp;
struct connectdata *conn = data->conn;
CURLcode result;
ssize_t nread;
@@ -87,8 +81,7 @@ size_t Curl_hyper_recv(void *userp, hyper_context *ctx,
(void)ctx;
DEBUGF(infof(data, "Curl_hyper_recv(%zu)", buflen));
- result = Curl_conn_recv(data, io_ctx->sockindex,
- (char *)buf, buflen, &nread);
+ result = Curl_read(data, conn->sockfd, (char *)buf, buflen, &nread);
if(result == CURLE_AGAIN) {
/* would block, register interest */
DEBUGF(infof(data, "Curl_hyper_recv(%zu) -> EAGAIN", buflen));
@@ -112,14 +105,15 @@ size_t Curl_hyper_recv(void *userp, hyper_context *ctx,
size_t Curl_hyper_send(void *userp, hyper_context *ctx,
const uint8_t *buf, size_t buflen)
{
- struct hyp_io_ctx *io_ctx = userp;
- struct Curl_easy *data = io_ctx->data;
+ struct Curl_easy *data = userp;
+ struct connectdata *conn = data->conn;
CURLcode result;
- size_t nwrote;
+ ssize_t nwrote;
DEBUGF(infof(data, "Curl_hyper_send(%zu)", buflen));
- result = Curl_conn_send(data, io_ctx->sockindex,
- (void *)buf, buflen, FALSE, &nwrote);
+ result = Curl_write(data, conn->sockfd, (void *)buf, buflen, &nwrote);
+ if(!result && !nwrote)
+ result = CURLE_AGAIN;
if(result == CURLE_AGAIN) {
DEBUGF(infof(data, "Curl_hyper_send(%zu) -> EAGAIN", buflen));
/* would block, register interest */
@@ -154,10 +148,13 @@ static int hyper_each_header(void *userdata,
if(name_len + value_len + 2 > CURL_MAX_HTTP_HEADER) {
failf(data, "Too long response header");
- data->state.hresult = CURLE_TOO_LARGE;
+ data->state.hresult = CURLE_OUT_OF_MEMORY;
return HYPER_ITER_BREAK;
}
+ if(!data->req.bytecount)
+ Curl_pgrsTime(data, TIMER_STARTTRANSFER);
+
Curl_dyn_reset(&data->state.headerb);
if(name_len) {
if(Curl_dyn_addf(&data->state.headerb, "%.*s: %.*s\r\n",
@@ -171,7 +168,7 @@ static int hyper_each_header(void *userdata,
len = Curl_dyn_len(&data->state.headerb);
headp = Curl_dyn_ptr(&data->state.headerb);
- result = Curl_http_header(data, headp, len);
+ result = Curl_http_header(data, data->conn, headp);
if(result) {
data->state.hresult = result;
return HYPER_ITER_BREAK;
@@ -206,7 +203,8 @@ static int hyper_body_chunk(void *userdata, const hyper_buf *chunk)
struct SingleRequest *k = &data->req;
CURLcode result = CURLE_OK;
- if(!k->bodywritten) {
+ if(0 == k->bodywrites) {
+ bool done = FALSE;
#if defined(USE_NTLM)
struct connectdata *conn = data->conn;
if(conn->bits.close &&
@@ -219,26 +217,27 @@ static int hyper_body_chunk(void *userdata, const hyper_buf *chunk)
Curl_safefree(data->req.newurl);
}
#endif
- if(Curl_http_exp100_is_selected(data)) {
+ if(data->state.expect100header) {
+ Curl_expire_done(data, EXPIRE_100_TIMEOUT);
if(data->req.httpcode < 400) {
- Curl_http_exp100_got100(data);
- if(data->hyp.send_body_waker) {
- hyper_waker_wake(data->hyp.send_body_waker);
- data->hyp.send_body_waker = NULL;
+ k->exp100 = EXP100_SEND_DATA;
+ if(data->hyp.exp100_waker) {
+ hyper_waker_wake(data->hyp.exp100_waker);
+ data->hyp.exp100_waker = NULL;
}
}
else { /* >= 4xx */
- Curl_req_abort_sending(data);
+ k->exp100 = EXP100_FAILED;
}
}
if(data->state.hconnect && (data->req.httpcode/100 != 2) &&
data->state.authproxy.done) {
- data->req.done = TRUE;
+ done = TRUE;
result = CURLE_OK;
}
else
- result = Curl_http_firstwrite(data);
- if(result || data->req.done) {
+ result = Curl_http_firstwrite(data, data->conn, &done);
+ if(result || done) {
infof(data, "Return early from hyper_body_chunk");
data->state.hresult = result;
return HYPER_ITER_BREAK;
@@ -274,13 +273,14 @@ static CURLcode status_line(struct Curl_easy *data,
/* We need to set 'httpcodeq' for functions that check the response code in
a single place. */
data->req.httpcode = http_status;
- data->req.httpversion = http_version == HYPER_HTTP_VERSION_1_1? 11 :
- (http_version == HYPER_HTTP_VERSION_2 ? 20 : 10);
+
if(data->state.hconnect)
/* CONNECT */
data->info.httpproxycode = http_status;
else {
- conn->httpversion = (unsigned char)data->req.httpversion;
+ conn->httpversion =
+ http_version == HYPER_HTTP_VERSION_1_1 ? 11 :
+ (http_version == HYPER_HTTP_VERSION_2 ? 20 : 10);
if(http_version == HYPER_HTTP_VERSION_1_0)
data->state.httpwant = CURL_HTTP_VERSION_1_0;
@@ -324,10 +324,7 @@ static CURLcode empty_header(struct Curl_easy *data)
result = hyper_each_header(data, NULL, 0, NULL, 0) ?
CURLE_WRITE_ERROR : CURLE_OK;
if(result)
- failf(data, "hyperstream: could not pass blank header");
- /* Hyper does chunked decoding itself. If it was added during
- * response header processing, remove it again. */
- Curl_cwriter_remove_by_name(data, "chunked");
+ failf(data, "hyperstream: couldn't pass blank header");
}
return result;
}
@@ -335,6 +332,7 @@ static CURLcode empty_header(struct Curl_easy *data)
CURLcode Curl_hyper_stream(struct Curl_easy *data,
struct connectdata *conn,
int *didwhat,
+ bool *done,
int select_res)
{
hyper_response *resp = NULL;
@@ -351,11 +349,20 @@ CURLcode Curl_hyper_stream(struct Curl_easy *data,
struct SingleRequest *k = &data->req;
(void)conn;
- if(data->hyp.send_body_waker) {
- /* If there is still something to upload, wake it to give it
- * another try. */
- hyper_waker_wake(data->hyp.send_body_waker);
- data->hyp.send_body_waker = NULL;
+ if(k->exp100 > EXP100_SEND_DATA) {
+ struct curltime now = Curl_now();
+ timediff_t ms = Curl_timediff(now, k->start100);
+ if(ms >= data->set.expect_100_timeout) {
+ /* we've waited long enough, continue anyway */
+ k->exp100 = EXP100_SEND_DATA;
+ k->keepon |= KEEP_SEND;
+ Curl_expire_done(data, EXPIRE_100_TIMEOUT);
+ infof(data, "Done waiting for 100-continue");
+ if(data->hyp.exp100_waker) {
+ hyper_waker_wake(data->hyp.exp100_waker);
+ data->hyp.exp100_waker = NULL;
+ }
+ }
}
if(select_res & CURL_CSELECT_IN) {
@@ -369,7 +376,8 @@ CURLcode Curl_hyper_stream(struct Curl_easy *data,
h->write_waker = NULL;
}
- while(1) {
+ *done = FALSE;
+ do {
hyper_task_return_type t;
task = hyper_executor_poll(h->exec);
if(!task) {
@@ -393,152 +401,141 @@ CURLcode Curl_hyper_stream(struct Curl_easy *data,
switch(code) {
case HYPERE_ABORTED_BY_CALLBACK:
result = CURLE_OK;
- goto out;
+ break;
case HYPERE_UNEXPECTED_EOF:
if(!data->req.bytecount)
result = CURLE_GOT_NOTHING;
else
result = CURLE_RECV_ERROR;
- goto out;
+ break;
case HYPERE_INVALID_PEER_MESSAGE:
/* bump headerbytecount to avoid the count remaining at zero and
appearing to not having read anything from the peer at all */
data->req.headerbytecount++;
result = CURLE_UNSUPPORTED_PROTOCOL; /* maybe */
- goto out;
+ break;
default:
result = CURLE_RECV_ERROR;
- goto out;
+ break;
}
}
- data->req.done = TRUE;
+ *done = TRUE;
hyper_error_free(hypererr);
break;
}
else if(t == HYPER_TASK_EMPTY) {
void *userdata = hyper_task_userdata(task);
hyper_task_free(task);
- if(userdata == (void *)USERDATA_RESP_BODY) {
+ if((userdata_t)userdata == USERDATA_RESP_BODY) {
/* end of transfer */
- data->req.done = TRUE;
+ *done = TRUE;
infof(data, "hyperstream is done");
- if(!k->bodywritten) {
- /* hyper does not always call the body write callback */
- result = Curl_http_firstwrite(data);
+ if(!k->bodywrites) {
+ /* hyper doesn't always call the body write callback */
+ bool stilldone;
+ result = Curl_http_firstwrite(data, data->conn, &stilldone);
}
break;
}
else {
/* A background task for hyper; ignore */
- DEBUGF(infof(data, "hyper: some background task done"));
continue;
}
}
- else if(t == HYPER_TASK_RESPONSE) {
- resp = hyper_task_value(task);
- hyper_task_free(task);
- *didwhat = KEEP_RECV;
- if(!resp) {
- failf(data, "hyperstream: could not get response");
- result = CURLE_RECV_ERROR;
- goto out;
- }
+ DEBUGASSERT(HYPER_TASK_RESPONSE);
- http_status = hyper_response_status(resp);
- http_version = hyper_response_version(resp);
- reasonp = hyper_response_reason_phrase(resp);
- reason_len = hyper_response_reason_phrase_len(resp);
+ resp = hyper_task_value(task);
+ hyper_task_free(task);
- if(http_status == 417 && Curl_http_exp100_is_selected(data)) {
- infof(data, "Got 417 while waiting for a 100");
- data->state.disableexpect = TRUE;
- data->req.newurl = strdup(data->state.url);
- Curl_req_abort_sending(data);
- }
+ *didwhat = KEEP_RECV;
+ if(!resp) {
+ failf(data, "hyperstream: couldn't get response");
+ return CURLE_RECV_ERROR;
+ }
- result = status_line(data, conn,
- http_status, http_version, reasonp, reason_len);
- if(result)
- goto out;
+ http_status = hyper_response_status(resp);
+ http_version = hyper_response_version(resp);
+ reasonp = hyper_response_reason_phrase(resp);
+ reason_len = hyper_response_reason_phrase_len(resp);
- headers = hyper_response_headers(resp);
- if(!headers) {
- failf(data, "hyperstream: could not get response headers");
- result = CURLE_RECV_ERROR;
- goto out;
- }
+ if(http_status == 417 && data->state.expect100header) {
+ infof(data, "Got 417 while waiting for a 100");
+ data->state.disableexpect = TRUE;
+ data->req.newurl = strdup(data->state.url);
+ Curl_done_sending(data, k);
+ }
- /* the headers are already received */
- hyper_headers_foreach(headers, hyper_each_header, data);
- if(data->state.hresult) {
- result = data->state.hresult;
- goto out;
- }
+ result = status_line(data, conn,
+ http_status, http_version, reasonp, reason_len);
+ if(result)
+ break;
+
+ headers = hyper_response_headers(resp);
+ if(!headers) {
+ failf(data, "hyperstream: couldn't get response headers");
+ result = CURLE_RECV_ERROR;
+ break;
+ }
+
+ /* the headers are already received */
+ hyper_headers_foreach(headers, hyper_each_header, data);
+ if(data->state.hresult) {
+ result = data->state.hresult;
+ break;
+ }
- result = empty_header(data);
- if(result)
- goto out;
+ result = empty_header(data);
+ if(result)
+ break;
- k->deductheadercount =
- (100 <= http_status && 199 >= http_status)?k->headerbytecount:0;
+ k->deductheadercount =
+ (100 <= http_status && 199 >= http_status)?k->headerbytecount:0;
#ifdef USE_WEBSOCKETS
- if(k->upgr101 == UPGR101_WS) {
- if(http_status == 101) {
- /* verify the response */
- result = Curl_ws_accept(data, NULL, 0);
- if(result)
- goto out;
- }
- else {
- failf(data, "Expected 101, got %u", k->httpcode);
- result = CURLE_HTTP_RETURNED_ERROR;
- goto out;
- }
+ if(k->upgr101 == UPGR101_WS) {
+ if(http_status == 101) {
+ /* verify the response */
+ result = Curl_ws_accept(data, NULL, 0);
+ if(result)
+ return result;
}
+ else {
+ failf(data, "Expected 101, got %u", k->httpcode);
+ result = CURLE_HTTP_RETURNED_ERROR;
+ break;
+ }
+ }
#endif
- /* Curl_http_auth_act() checks what authentication methods that are
- * available and decides which one (if any) to use. It will set 'newurl'
- * if an auth method was picked. */
- result = Curl_http_auth_act(data);
- if(result)
- goto out;
-
- resp_body = hyper_response_body(resp);
- if(!resp_body) {
- failf(data, "hyperstream: could not get response body");
- result = CURLE_RECV_ERROR;
- goto out;
- }
- foreach = hyper_body_foreach(resp_body, hyper_body_chunk, data);
- if(!foreach) {
- failf(data, "hyperstream: body foreach failed");
- result = CURLE_OUT_OF_MEMORY;
- goto out;
- }
- hyper_task_set_userdata(foreach, (void *)USERDATA_RESP_BODY);
- if(HYPERE_OK != hyper_executor_push(h->exec, foreach)) {
- failf(data, "Couldn't hyper_executor_push the body-foreach");
- result = CURLE_OUT_OF_MEMORY;
- goto out;
- }
+ /* Curl_http_auth_act() checks what authentication methods that are
+ * available and decides which one (if any) to use. It will set 'newurl'
+ * if an auth method was picked. */
+ result = Curl_http_auth_act(data);
+ if(result)
+ break;
- hyper_response_free(resp);
- resp = NULL;
+ resp_body = hyper_response_body(resp);
+ if(!resp_body) {
+ failf(data, "hyperstream: couldn't get response body");
+ result = CURLE_RECV_ERROR;
+ break;
}
- else {
- DEBUGF(infof(data, "hyper: unhandled tasktype %x", t));
+ foreach = hyper_body_foreach(resp_body, hyper_body_chunk, data);
+ if(!foreach) {
+ failf(data, "hyperstream: body foreach failed");
+ result = CURLE_OUT_OF_MEMORY;
+ break;
+ }
+ hyper_task_set_userdata(foreach, (void *)USERDATA_RESP_BODY);
+ if(HYPERE_OK != hyper_executor_push(h->exec, foreach)) {
+ failf(data, "Couldn't hyper_executor_push the body-foreach");
+ result = CURLE_OUT_OF_MEMORY;
+ break;
}
- } /* while(1) */
-
- if(!result && Curl_xfer_needs_flush(data)) {
- DEBUGF(infof(data, "Curl_hyper_stream(), connection needs flush"));
- result = Curl_xfer_flush(data);
- }
-out:
- DEBUGF(infof(data, "Curl_hyper_stream() -> %d", result));
+ hyper_response_free(resp);
+ resp = NULL;
+ } while(1);
if(resp)
hyper_response_free(resp);
return result;
@@ -654,108 +651,150 @@ static CURLcode request_target(struct Curl_easy *data,
return result;
}
+static int uploadpostfields(void *userdata, hyper_context *ctx,
+ hyper_buf **chunk)
+{
+ struct Curl_easy *data = (struct Curl_easy *)userdata;
+ (void)ctx;
+ if(data->req.exp100 > EXP100_SEND_DATA) {
+ if(data->req.exp100 == EXP100_FAILED)
+ return HYPER_POLL_ERROR;
+
+ /* still waiting confirmation */
+ if(data->hyp.exp100_waker)
+ hyper_waker_free(data->hyp.exp100_waker);
+ data->hyp.exp100_waker = hyper_context_waker(ctx);
+ return HYPER_POLL_PENDING;
+ }
+ if(data->req.upload_done)
+ *chunk = NULL; /* nothing more to deliver */
+ else {
+ /* send everything off in a single go */
+ hyper_buf *copy = hyper_buf_copy(data->set.postfields,
+ (size_t)data->req.p.http->postsize);
+ if(copy)
+ *chunk = copy;
+ else {
+ data->state.hresult = CURLE_OUT_OF_MEMORY;
+ return HYPER_POLL_ERROR;
+ }
+ /* increasing the writebytecount here is a little premature but we
+ don't know exactly when the body is sent */
+ data->req.writebytecount += (size_t)data->req.p.http->postsize;
+ Curl_pgrsSetUploadCounter(data, data->req.writebytecount);
+ data->req.upload_done = TRUE;
+ }
+ return HYPER_POLL_READY;
+}
+
static int uploadstreamed(void *userdata, hyper_context *ctx,
hyper_buf **chunk)
{
size_t fillcount;
struct Curl_easy *data = (struct Curl_easy *)userdata;
+ struct connectdata *conn = (struct connectdata *)data->conn;
CURLcode result;
- char *xfer_ulbuf;
- size_t xfer_ulblen;
- bool eos;
- int rc = HYPER_POLL_ERROR;
(void)ctx;
- result = Curl_multi_xfer_ulbuf_borrow(data, &xfer_ulbuf, &xfer_ulblen);
- if(result)
- goto out;
+ if(data->req.exp100 > EXP100_SEND_DATA) {
+ if(data->req.exp100 == EXP100_FAILED)
+ return HYPER_POLL_ERROR;
- result = Curl_client_read(data, xfer_ulbuf, xfer_ulblen, &fillcount, &eos);
- if(result)
- goto out;
+ /* still waiting confirmation */
+ if(data->hyp.exp100_waker)
+ hyper_waker_free(data->hyp.exp100_waker);
+ data->hyp.exp100_waker = hyper_context_waker(ctx);
+ return HYPER_POLL_PENDING;
+ }
- if(fillcount) {
- hyper_buf *copy = hyper_buf_copy((uint8_t *)xfer_ulbuf, fillcount);
+ if(data->req.upload_chunky && conn->bits.authneg) {
+ fillcount = 0;
+ data->req.upload_chunky = FALSE;
+ result = CURLE_OK;
+ }
+ else {
+ result = Curl_fillreadbuffer(data, data->set.upload_buffer_size,
+ &fillcount);
+ }
+ if(result) {
+ data->state.hresult = result;
+ return HYPER_POLL_ERROR;
+ }
+ if(!fillcount) {
+ if((data->req.keepon & KEEP_SEND_PAUSE) != KEEP_SEND_PAUSE)
+ /* done! */
+ *chunk = NULL;
+ else {
+ /* paused, save a waker */
+ if(data->hyp.send_body_waker)
+ hyper_waker_free(data->hyp.send_body_waker);
+ data->hyp.send_body_waker = hyper_context_waker(ctx);
+ return HYPER_POLL_PENDING;
+ }
+ }
+ else {
+ hyper_buf *copy = hyper_buf_copy((uint8_t *)data->state.ulbuf, fillcount);
if(copy)
*chunk = copy;
else {
- result = CURLE_OUT_OF_MEMORY;
- goto out;
+ data->state.hresult = CURLE_OUT_OF_MEMORY;
+ return HYPER_POLL_ERROR;
}
/* increasing the writebytecount here is a little premature but we
- do not know exactly when the body is sent */
+ don't know exactly when the body is sent */
data->req.writebytecount += fillcount;
- if(eos)
- data->req.eos_read = TRUE;
Curl_pgrsSetUploadCounter(data, data->req.writebytecount);
- rc = HYPER_POLL_READY;
- }
- else if(eos) {
- data->req.eos_read = TRUE;
- *chunk = NULL;
- rc = HYPER_POLL_READY;
- }
- else {
- /* paused, save a waker */
- if(data->hyp.send_body_waker)
- hyper_waker_free(data->hyp.send_body_waker);
- data->hyp.send_body_waker = hyper_context_waker(ctx);
- rc = HYPER_POLL_PENDING;
}
-
- if(!data->req.upload_done && data->req.eos_read) {
- DEBUGF(infof(data, "hyper: uploadstreamed(), upload is done"));
- result = Curl_req_set_upload_done(data);
- }
-
-out:
- Curl_multi_xfer_ulbuf_release(data, xfer_ulbuf);
- data->state.hresult = result;
- DEBUGF(infof(data, "hyper: uploadstreamed() -> %d", result));
- return rc;
+ return HYPER_POLL_READY;
}
/*
- * finalize_request() sets up last headers and optional body settings
+ * bodysend() sets up headers in the outgoing request for an HTTP transfer that
+ * sends a body
*/
-static CURLcode finalize_request(struct Curl_easy *data,
- hyper_headers *headers,
- hyper_request *hyperreq,
- Curl_HttpReq httpreq)
+
+static CURLcode bodysend(struct Curl_easy *data,
+ struct connectdata *conn,
+ hyper_headers *headers,
+ hyper_request *hyperreq,
+ Curl_HttpReq httpreq)
{
+ struct HTTP *http = data->req.p.http;
CURLcode result = CURLE_OK;
struct dynbuf req;
- if((httpreq == HTTPREQ_GET) || (httpreq == HTTPREQ_HEAD)) {
+ if((httpreq == HTTPREQ_GET) || (httpreq == HTTPREQ_HEAD))
Curl_pgrsSetUploadSize(data, 0); /* no request body */
- }
else {
hyper_body *body;
Curl_dyn_init(&req, DYN_HTTP_REQUEST);
- result = Curl_http_req_complete(data, &req, httpreq);
- if(result)
- return result;
+ result = Curl_http_bodysend(data, conn, &req, httpreq);
- /* if the "complete" above did produce more than the closing line,
- parse the added headers */
- if(Curl_dyn_len(&req) != 2 || strcmp(Curl_dyn_ptr(&req), "\r\n")) {
+ if(!result)
result = Curl_hyper_header(data, headers, Curl_dyn_ptr(&req));
- if(result)
- return result;
- }
Curl_dyn_free(&req);
body = hyper_body_new();
hyper_body_set_userdata(body, data);
- hyper_body_set_data_func(body, uploadstreamed);
-
+ if(data->set.postfields)
+ hyper_body_set_data_func(body, uploadpostfields);
+ else {
+ result = Curl_get_upload_buffer(data);
+ if(result) {
+ hyper_body_free(body);
+ return result;
+ }
+ /* init the "upload from here" pointer */
+ data->req.upload_fromhere = data->state.ulbuf;
+ hyper_body_set_data_func(body, uploadstreamed);
+ }
if(HYPERE_OK != hyper_request_set_body(hyperreq, body)) {
/* fail */
result = CURLE_OUT_OF_MEMORY;
}
}
-
- return cr_hyper_add(data);
+ http->sending = HTTPSEND_BODY;
+ return result;
}
static CURLcode cookies(struct Curl_easy *data,
@@ -796,7 +835,7 @@ static void http1xx_cb(void *arg, struct hyper_response *resp)
if(!result) {
headers = hyper_response_headers(resp);
if(!headers) {
- failf(data, "hyperstream: could not get 1xx response headers");
+ failf(data, "hyperstream: couldn't get 1xx response headers");
result = CURLE_RECV_ERROR;
}
}
@@ -843,23 +882,14 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
may be parts of the request that is not yet sent, since we can deal with
the rest of the request in the PERFORM phase. */
*done = TRUE;
- result = Curl_client_start(data);
- if(result)
- goto out;
-
- /* Add collecting of headers written to client. For a new connection,
- * we might have done that already, but reuse
- * or multiplex needs it here as well. */
- result = Curl_headers_init(data);
- if(result)
- goto out;
+ Curl_client_cleanup(data);
infof(data, "Time for the Hyper dance");
memset(h, 0, sizeof(struct hyptransfer));
result = Curl_http_host(data, conn);
if(result)
- goto out;
+ return result;
Curl_http_method(data, conn, &method, &httpreq);
@@ -870,40 +900,36 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
char *pq = NULL;
if(data->state.up.query) {
pq = aprintf("%s?%s", data->state.up.path, data->state.up.query);
- if(!pq) {
- result = CURLE_OUT_OF_MEMORY;
- goto out;
- }
+ if(!pq)
+ return CURLE_OUT_OF_MEMORY;
}
result = Curl_http_output_auth(data, conn, method, httpreq,
(pq ? pq : data->state.up.path), FALSE);
free(pq);
if(result)
- goto out;
+ return result;
}
- result = Curl_http_req_set_reader(data, httpreq, &te);
+ result = Curl_http_resume(data, conn, httpreq);
if(result)
- goto out;
+ return result;
result = Curl_http_range(data, httpreq);
if(result)
- goto out;
+ return result;
result = Curl_http_useragent(data);
if(result)
- goto out;
+ return result;
io = hyper_io_new();
if(!io) {
failf(data, "Couldn't create hyper IO");
result = CURLE_OUT_OF_MEMORY;
- goto out;
+ goto error;
}
/* tell Hyper how to read/write network data */
- h->io_ctx.data = data;
- h->io_ctx.sockindex = FIRSTSOCKET;
- hyper_io_set_userdata(io, &h->io_ctx);
+ hyper_io_set_userdata(io, data);
hyper_io_set_read(io, Curl_hyper_recv);
hyper_io_set_write(io, Curl_hyper_send);
@@ -913,7 +939,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
if(!h->exec) {
failf(data, "Couldn't create hyper executor");
result = CURLE_OUT_OF_MEMORY;
- goto out;
+ goto error;
}
}
@@ -921,12 +947,12 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
if(!options) {
failf(data, "Couldn't create hyper client options");
result = CURLE_OUT_OF_MEMORY;
- goto out;
+ goto error;
}
if(conn->alpn == CURL_HTTP_VERSION_2) {
failf(data, "ALPN protocol h2 not supported with Hyper");
result = CURLE_UNSUPPORTED_PROTOCOL;
- goto out;
+ goto error;
}
hyper_clientconn_options_set_preserve_header_case(options, 1);
hyper_clientconn_options_set_preserve_header_order(options, 1);
@@ -939,7 +965,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
if(!handshake) {
failf(data, "Couldn't create hyper client handshake");
result = CURLE_OUT_OF_MEMORY;
- goto out;
+ goto error;
}
io = NULL;
options = NULL;
@@ -947,7 +973,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
if(HYPERE_OK != hyper_executor_push(h->exec, handshake)) {
failf(data, "Couldn't hyper_executor_push the handshake");
result = CURLE_OUT_OF_MEMORY;
- goto out;
+ goto error;
}
handshake = NULL; /* ownership passed on */
@@ -955,7 +981,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
if(!task) {
failf(data, "Couldn't hyper_executor_poll the handshake");
result = CURLE_OUT_OF_MEMORY;
- goto out;
+ goto error;
}
client = hyper_task_value(task);
@@ -965,7 +991,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
if(!req) {
failf(data, "Couldn't hyper_request_new");
result = CURLE_OUT_OF_MEMORY;
- goto out;
+ goto error;
}
if(!Curl_use_http_1_1plus(data, conn)) {
@@ -973,57 +999,64 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
HYPER_HTTP_VERSION_1_0)) {
failf(data, "error setting HTTP version");
result = CURLE_OUT_OF_MEMORY;
- goto out;
+ goto error;
+ }
+ }
+ else {
+ if(!data->state.disableexpect) {
+ data->state.expect100header = TRUE;
}
}
if(hyper_request_set_method(req, (uint8_t *)method, strlen(method))) {
failf(data, "error setting method");
result = CURLE_OUT_OF_MEMORY;
- goto out;
+ goto error;
}
result = request_target(data, conn, method, req);
if(result)
- goto out;
+ goto error;
headers = hyper_request_headers(req);
if(!headers) {
failf(data, "hyper_request_headers");
result = CURLE_OUT_OF_MEMORY;
- goto out;
+ goto error;
}
rc = hyper_request_on_informational(req, http1xx_cb, data);
if(rc) {
result = CURLE_OUT_OF_MEMORY;
- goto out;
+ goto error;
}
+ result = Curl_http_body(data, conn, httpreq, &te);
+ if(result)
+ goto error;
+
if(data->state.aptr.host) {
result = Curl_hyper_header(data, headers, data->state.aptr.host);
if(result)
- goto out;
+ goto error;
}
-#ifndef CURL_DISABLE_PROXY
if(data->state.aptr.proxyuserpwd) {
result = Curl_hyper_header(data, headers, data->state.aptr.proxyuserpwd);
if(result)
- goto out;
+ goto error;
}
-#endif
if(data->state.aptr.userpwd) {
result = Curl_hyper_header(data, headers, data->state.aptr.userpwd);
if(result)
- goto out;
+ goto error;
}
if((data->state.use_range && data->state.aptr.rangeline)) {
result = Curl_hyper_header(data, headers, data->state.aptr.rangeline);
if(result)
- goto out;
+ goto error;
}
if(data->set.str[STRING_USERAGENT] &&
@@ -1031,7 +1064,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
data->state.aptr.uagent) {
result = Curl_hyper_header(data, headers, data->state.aptr.uagent);
if(result)
- goto out;
+ goto error;
}
p_accept = Curl_checkheaders(data,
@@ -1039,12 +1072,12 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
if(p_accept) {
result = Curl_hyper_header(data, headers, p_accept);
if(result)
- goto out;
+ goto error;
}
if(te) {
result = Curl_hyper_header(data, headers, te);
if(result)
- goto out;
+ goto error;
}
#ifndef CURL_DISABLE_ALTSVC
@@ -1053,11 +1086,11 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
conn->conn_to_host.name, conn->conn_to_port);
if(!altused) {
result = CURLE_OUT_OF_MEMORY;
- goto out;
+ goto error;
}
result = Curl_hyper_header(data, headers, altused);
if(result)
- goto out;
+ goto error;
free(altused);
}
#endif
@@ -1068,7 +1101,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
!Curl_checkProxyheaders(data, conn, STRCONST("Proxy-Connection"))) {
result = Curl_hyper_header(data, headers, "Proxy-Connection: Keep-Alive");
if(result)
- goto out;
+ goto error;
}
#endif
@@ -1080,17 +1113,17 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
else
result = Curl_hyper_header(data, headers, data->state.aptr.ref);
if(result)
- goto out;
+ goto error;
}
#ifdef HAVE_LIBZ
/* we only consider transfer-encoding magic if libz support is built-in */
result = Curl_transferencode(data);
if(result)
- goto out;
+ goto error;
result = Curl_hyper_header(data, headers, data->state.aptr.te);
if(result)
- goto out;
+ goto error;
#endif
if(!Curl_checkheaders(data, STRCONST("Accept-Encoding")) &&
@@ -1104,33 +1137,33 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
result = Curl_hyper_header(data, headers,
data->state.aptr.accept_encoding);
if(result)
- goto out;
+ goto error;
}
else
Curl_safefree(data->state.aptr.accept_encoding);
result = cookies(data, conn, headers);
if(result)
- goto out;
+ goto error;
if(!result && conn->handler->protocol&(CURLPROTO_WS|CURLPROTO_WSS))
result = Curl_ws_request(data, headers);
result = Curl_add_timecondition(data, headers);
if(result)
- goto out;
+ goto error;
result = Curl_add_custom_headers(data, FALSE, headers);
if(result)
- goto out;
+ goto error;
- result = finalize_request(data, headers, req, httpreq);
+ result = bodysend(data, conn, headers, req, httpreq);
if(result)
- goto out;
+ goto error;
Curl_debug(data, CURLINFO_HEADER_OUT, (char *)"\r\n", 2);
- if(data->req.upload_chunky && data->req.authneg) {
+ if(data->req.upload_chunky && conn->bits.authneg) {
data->req.upload_chunky = TRUE;
}
else {
@@ -1140,14 +1173,14 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
if(!sendtask) {
failf(data, "hyper_clientconn_send");
result = CURLE_OUT_OF_MEMORY;
- goto out;
+ goto error;
}
req = NULL;
if(HYPERE_OK != hyper_executor_push(h->exec, sendtask)) {
failf(data, "Couldn't hyper_executor_push the send");
result = CURLE_OUT_OF_MEMORY;
- goto out;
+ goto error;
}
sendtask = NULL; /* ownership passed on */
@@ -1157,34 +1190,36 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
if((httpreq == HTTPREQ_GET) || (httpreq == HTTPREQ_HEAD)) {
/* HTTP GET/HEAD download */
Curl_pgrsSetUploadSize(data, 0); /* nothing */
- result = Curl_req_set_upload_done(data);
- if(result)
- goto out;
+ Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE, -1);
}
-
- Curl_xfer_setup1(data, CURL_XFER_SENDRECV, -1, TRUE);
conn->datastream = Curl_hyper_stream;
+ if(data->state.expect100header)
+ /* Timeout count starts now since with Hyper we don't know exactly when
+ the full request has been sent. */
+ data->req.start100 = Curl_now();
/* clear userpwd and proxyuserpwd to avoid reusing old credentials
* from reused connections */
Curl_safefree(data->state.aptr.userpwd);
-#ifndef CURL_DISABLE_PROXY
Curl_safefree(data->state.aptr.proxyuserpwd);
-#endif
+ return CURLE_OK;
+error:
+ DEBUGASSERT(result);
+ if(io)
+ hyper_io_free(io);
+
+ if(options)
+ hyper_clientconn_options_free(options);
+
+ if(handshake)
+ hyper_task_free(handshake);
+
+ if(client)
+ hyper_clientconn_free(client);
+
+ if(req)
+ hyper_request_free(req);
-out:
- if(result) {
- if(io)
- hyper_io_free(io);
- if(options)
- hyper_clientconn_options_free(options);
- if(handshake)
- hyper_task_free(handshake);
- if(client)
- hyper_clientconn_free(client);
- if(req)
- hyper_request_free(req);
- }
return result;
}
@@ -1203,52 +1238,10 @@ void Curl_hyper_done(struct Curl_easy *data)
hyper_waker_free(h->write_waker);
h->write_waker = NULL;
}
- if(h->send_body_waker) {
- hyper_waker_free(h->send_body_waker);
- h->send_body_waker = NULL;
- }
-}
-
-static CURLcode cr_hyper_unpause(struct Curl_easy *data,
- struct Curl_creader *reader)
-{
- (void)reader;
- if(data->hyp.send_body_waker) {
- hyper_waker_wake(data->hyp.send_body_waker);
- data->hyp.send_body_waker = NULL;
+ if(h->exp100_waker) {
+ hyper_waker_free(h->exp100_waker);
+ h->exp100_waker = NULL;
}
- return CURLE_OK;
-}
-
-/* Hyper client reader, handling unpausing */
-static const struct Curl_crtype cr_hyper_protocol = {
- "cr-hyper",
- Curl_creader_def_init,
- Curl_creader_def_read,
- Curl_creader_def_close,
- Curl_creader_def_needs_rewind,
- Curl_creader_def_total_length,
- Curl_creader_def_resume_from,
- Curl_creader_def_rewind,
- cr_hyper_unpause,
- Curl_creader_def_is_paused,
- Curl_creader_def_done,
- sizeof(struct Curl_creader)
-};
-
-static CURLcode cr_hyper_add(struct Curl_easy *data)
-{
- struct Curl_creader *reader = NULL;
- CURLcode result;
-
- result = Curl_creader_create(&reader, data, &cr_hyper_protocol,
- CURL_CR_PROTOCOL);
- if(!result)
- result = Curl_creader_add(data, reader);
-
- if(result && reader)
- Curl_creader_free(data, reader);
- return result;
}
#endif /* !defined(CURL_DISABLE_HTTP) && defined(USE_HYPER) */
diff --git a/contrib/libs/curl/lib/c-hyper.h b/contrib/libs/curl/lib/c-hyper.h
index 38a0187c50..44ba69e066 100644
--- a/contrib/libs/curl/lib/c-hyper.h
+++ b/contrib/libs/curl/lib/c-hyper.h
@@ -29,18 +29,13 @@
#error #include <hyper.h>
-struct hyp_io_ctx {
- struct Curl_easy *data;
- int sockindex;
-};
-
/* per-transfer data for the Hyper backend */
struct hyptransfer {
hyper_waker *write_waker;
hyper_waker *read_waker;
const hyper_executor *exec;
+ hyper_waker *exp100_waker;
hyper_waker *send_body_waker;
- struct hyp_io_ctx io_ctx;
};
size_t Curl_hyper_recv(void *userp, hyper_context *ctx,
@@ -50,6 +45,7 @@ size_t Curl_hyper_send(void *userp, hyper_context *ctx,
CURLcode Curl_hyper_stream(struct Curl_easy *data,
struct connectdata *conn,
int *didwhat,
+ bool *done,
int select_res);
CURLcode Curl_hyper_header(struct Curl_easy *data, hyper_headers *headers,
diff --git a/contrib/libs/curl/lib/cf-h1-proxy.c b/contrib/libs/curl/lib/cf-h1-proxy.c
index 44d89f81f0..091b30dc86 100644
--- a/contrib/libs/curl/lib/cf-h1-proxy.c
+++ b/contrib/libs/curl/lib/cf-h1-proxy.c
@@ -65,11 +65,11 @@ typedef enum {
/* struct for HTTP CONNECT tunneling */
struct h1_tunnel_state {
+ struct HTTP CONNECT;
struct dynbuf rcvbuf;
struct dynbuf request_data;
size_t nsent;
size_t headerlines;
- struct Curl_chunker ch;
enum keeponval {
KEEPON_DONE,
KEEPON_CONNECT,
@@ -113,12 +113,18 @@ static CURLcode tunnel_init(struct Curl_cfilter *cf,
struct h1_tunnel_state **pts)
{
struct h1_tunnel_state *ts;
+ CURLcode result;
if(cf->conn->handler->flags & PROTOPT_NOTCPPROXY) {
failf(data, "%s cannot be done over CONNECT", cf->conn->handler->scheme);
return CURLE_UNSUPPORTED_PROTOCOL;
}
+ /* we might need the upload buffer for streaming a partial request */
+ result = Curl_get_upload_buffer(data);
+ if(result)
+ return result;
+
ts = calloc(1, sizeof(*ts));
if(!ts)
return CURLE_OUT_OF_MEMORY;
@@ -127,7 +133,6 @@ static CURLcode tunnel_init(struct Curl_cfilter *cf,
Curl_dyn_init(&ts->rcvbuf, DYN_PROXY_CONNECT_HEADERS);
Curl_dyn_init(&ts->request_data, DYN_HTTP_REQUEST);
- Curl_httpchunk_init(data, &ts->ch, TRUE);
*pts = ts;
connkeep(cf->conn, "HTTP proxy CONNECT");
@@ -141,6 +146,14 @@ static void h1_tunnel_go_state(struct Curl_cfilter *cf,
{
if(ts->tunnel_state == new_state)
return;
+ /* leaving this one */
+ switch(ts->tunnel_state) {
+ case H1_TUNNEL_CONNECT:
+ data->req.ignorebody = FALSE;
+ break;
+ default:
+ break;
+ }
/* entering this one */
switch(new_state) {
case H1_TUNNEL_INIT:
@@ -170,7 +183,7 @@ static void h1_tunnel_go_state(struct Curl_cfilter *cf,
infof(data, "CONNECT phase completed");
data->state.authproxy.done = TRUE;
data->state.authproxy.multipass = FALSE;
- FALLTHROUGH();
+ /* FALLTHROUGH */
case H1_TUNNEL_FAILED:
if(new_state == H1_TUNNEL_FAILED)
CURL_TRC_CF(data, cf, "new tunnel state 'failed'");
@@ -181,8 +194,8 @@ static void h1_tunnel_go_state(struct Curl_cfilter *cf,
data->info.httpcode = 0; /* clear it as it might've been used for the
proxy */
/* If a proxy-authorization header was used for the proxy, then we should
- make sure that it is not accidentally used for the document request
- after we have connected. So let's free and clear it here. */
+ make sure that it isn't accidentally used for the document request
+ after we've connected. So let's free and clear it here. */
Curl_safefree(data->state.aptr.proxyuserpwd);
#ifdef USE_HYPER
data->state.hconnect = FALSE;
@@ -194,24 +207,16 @@ static void h1_tunnel_go_state(struct Curl_cfilter *cf,
static void tunnel_free(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
- if(cf) {
- struct h1_tunnel_state *ts = cf->ctx;
- if(ts) {
- h1_tunnel_go_state(cf, ts, H1_TUNNEL_FAILED, data);
- Curl_dyn_free(&ts->rcvbuf);
- Curl_dyn_free(&ts->request_data);
- Curl_httpchunk_free(data, &ts->ch);
- free(ts);
- cf->ctx = NULL;
- }
+ struct h1_tunnel_state *ts = cf->ctx;
+ if(ts) {
+ h1_tunnel_go_state(cf, ts, H1_TUNNEL_FAILED, data);
+ Curl_dyn_free(&ts->rcvbuf);
+ Curl_dyn_free(&ts->request_data);
+ free(ts);
+ cf->ctx = NULL;
}
}
-static bool tunnel_want_send(struct h1_tunnel_state *ts)
-{
- return (ts->tunnel_state == H1_TUNNEL_CONNECT);
-}
-
#ifndef USE_HYPER
static CURLcode start_CONNECT(struct Curl_cfilter *cf,
struct Curl_easy *data,
@@ -221,8 +226,8 @@ static CURLcode start_CONNECT(struct Curl_cfilter *cf,
int http_minor;
CURLcode result;
- /* This only happens if we have looped here due to authentication
- reasons, and we do not really use the newly cloned URL here
+ /* This only happens if we've looped here due to authentication
+ reasons, and we don't really use the newly cloned URL here
then. Just free() it. */
Curl_safefree(data->req.newurl);
@@ -238,8 +243,6 @@ static CURLcode start_CONNECT(struct Curl_cfilter *cf,
http_minor = (cf->conn->http_proxy.proxytype == CURLPROXY_HTTP_1_0) ? 0 : 1;
result = Curl_h1_req_write_head(req, http_minor, &ts->request_data);
- if(!result)
- result = Curl_creader_set_null(data);
out:
if(result)
@@ -266,7 +269,7 @@ static CURLcode send_CONNECT(struct Curl_cfilter *cf,
blen -= ts->nsent;
buf += ts->nsent;
- nwritten = cf->next->cft->do_send(cf->next, data, buf, blen, FALSE, &result);
+ nwritten = cf->next->cft->do_send(cf->next, data, buf, blen, &result);
if(nwritten < 0) {
if(result == CURLE_AGAIN) {
result = CURLE_OK;
@@ -341,8 +344,8 @@ static CURLcode on_resp_header(struct Curl_cfilter *cf,
STRCONST("chunked"))) {
infof(data, "CONNECT responded chunked");
ts->chunked_encoding = TRUE;
- /* reset our chunky engine */
- Curl_httpchunk_reset(data, &ts->ch, TRUE);
+ /* init our chunky engine */
+ Curl_httpchunk_init(data);
}
}
else if(Curl_compareheader(header,
@@ -368,8 +371,9 @@ static CURLcode recv_CONNECT_resp(struct Curl_cfilter *cf,
{
CURLcode result = CURLE_OK;
struct SingleRequest *k = &data->req;
+ curl_socket_t tunnelsocket = Curl_conn_cf_get_socket(cf, data);
char *linep;
- size_t line_len;
+ size_t perline;
int error, writetype;
#define SELECT_OK 0
@@ -387,7 +391,7 @@ static CURLcode recv_CONNECT_resp(struct Curl_cfilter *cf,
/* Read one byte at a time to avoid a race condition. Wait at most one
second before looping to ensure continuous pgrsUpdates. */
- result = Curl_conn_recv(data, cf->sockindex, &byte, 1, &nread);
+ result = Curl_read(data, tunnelsocket, &byte, 1, &nread);
if(result == CURLE_AGAIN)
/* socket buffer drained, return */
return CURLE_OK;
@@ -421,25 +425,25 @@ static CURLcode recv_CONNECT_resp(struct Curl_cfilter *cf,
if(ts->cl) {
/* A Content-Length based body: simply count down the counter
- and make sure to break out of the loop when we are done! */
+ and make sure to break out of the loop when we're done! */
ts->cl--;
if(ts->cl <= 0) {
ts->keepon = KEEPON_DONE;
break;
}
}
- else if(ts->chunked_encoding) {
+ else {
/* chunked-encoded body, so we need to do the chunked dance
properly to know when the end of the body is reached */
+ CHUNKcode r;
+ CURLcode extra;
size_t consumed = 0;
/* now parse the chunked piece of data so that we can
properly tell when the stream ends */
- result = Curl_httpchunk_read(data, &ts->ch, &byte, 1, &consumed);
- if(result)
- return result;
- if(Curl_httpchunk_is_done(data, &ts->ch)) {
- /* we are done reading chunks! */
+ r = Curl_httpchunk_read(data, &byte, 1, &consumed, &extra);
+ if(r == CHUNKE_STOP) {
+ /* we're done reading chunks! */
infof(data, "chunk reading DONE");
ts->keepon = KEEPON_DONE;
}
@@ -458,23 +462,23 @@ static CURLcode recv_CONNECT_resp(struct Curl_cfilter *cf,
ts->headerlines++;
linep = Curl_dyn_ptr(&ts->rcvbuf);
- line_len = Curl_dyn_len(&ts->rcvbuf); /* amount of bytes in this line */
+ perline = Curl_dyn_len(&ts->rcvbuf); /* amount of bytes in this line */
/* output debug if that is requested */
- Curl_debug(data, CURLINFO_HEADER_IN, linep, line_len);
+ Curl_debug(data, CURLINFO_HEADER_IN, linep, perline);
/* send the header to the callback */
writetype = CLIENTWRITE_HEADER | CLIENTWRITE_CONNECT |
(ts->headerlines == 1 ? CLIENTWRITE_STATUS : 0);
- result = Curl_client_write(data, writetype, linep, line_len);
+ result = Curl_client_write(data, writetype, linep, perline);
if(result)
return result;
- result = Curl_bump_headersize(data, line_len, TRUE);
+ result = Curl_bump_headersize(data, perline, TRUE);
if(result)
return result;
- /* Newlines are CRLF, so the CR is ignored as the line is not
+ /* Newlines are CRLF, so the CR is ignored as the line isn't
really terminated until the LF comes. Treat a following CR
as end-of-headers as well.*/
@@ -489,14 +493,37 @@ static CURLcode recv_CONNECT_resp(struct Curl_cfilter *cf,
ts->keepon = KEEPON_IGNORE;
if(ts->cl) {
- infof(data, "Ignore %" FMT_OFF_T " bytes of response-body", ts->cl);
+ infof(data, "Ignore %" CURL_FORMAT_CURL_OFF_T
+ " bytes of response-body", ts->cl);
}
else if(ts->chunked_encoding) {
+ CHUNKcode r;
+ CURLcode extra;
+ size_t consumed = 0;
+
infof(data, "Ignore chunked response-body");
+
+ /* We set ignorebody true here since the chunked decoder
+ function will acknowledge that. Pay attention so that this is
+ cleared again when this function returns! */
+ k->ignorebody = TRUE;
+
+ if(linep[1] == '\n')
+ /* this can only be a LF if the letter at index 0 was a CR */
+ linep++;
+
+ /* now parse the chunked piece of data so that we can properly
+ tell when the stream ends */
+ r = Curl_httpchunk_read(data, linep + 1, 1, &consumed, &extra);
+ if(r == CHUNKE_STOP) {
+ /* we're done reading chunks! */
+ infof(data, "chunk reading DONE");
+ ts->keepon = KEEPON_DONE;
+ }
}
else {
/* without content-length or chunked encoding, we
- cannot keep the connection alive since the close is
+ can't keep the connection alive since the close is
the end signal so we bail out at once instead */
CURL_TRC_CF(data, cf, "CONNECT: no content-length or chunked");
ts->keepon = KEEPON_DONE;
@@ -516,7 +543,7 @@ static CURLcode recv_CONNECT_resp(struct Curl_cfilter *cf,
return result;
Curl_dyn_reset(&ts->rcvbuf);
- } /* while there is buffer left and loop is requested */
+ } /* while there's buffer left and loop is requested */
if(error)
result = CURLE_RECV_ERROR;
@@ -593,9 +620,7 @@ static CURLcode start_CONNECT(struct Curl_cfilter *cf,
goto error;
}
/* tell Hyper how to read/write network data */
- h->io_ctx.data = data;
- h->io_ctx.sockindex = cf->sockindex;
- hyper_io_set_userdata(io, &h->io_ctx);
+ hyper_io_set_userdata(io, data);
hyper_io_set_read(io, Curl_hyper_recv);
hyper_io_set_write(io, Curl_hyper_send);
conn->sockfd = tunnelsocket;
@@ -664,8 +689,8 @@ static CURLcode start_CONNECT(struct Curl_cfilter *cf,
goto error;
}
- /* This only happens if we have looped here due to authentication
- reasons, and we do not really use the newly cloned URL here
+ /* This only happens if we've looped here due to authentication
+ reasons, and we don't really use the newly cloned URL here
then. Just free() it. */
Curl_safefree(data->req.newurl);
@@ -727,7 +752,7 @@ static CURLcode start_CONNECT(struct Curl_cfilter *cf,
}
if(!Curl_checkProxyheaders(data, conn, STRCONST("User-Agent")) &&
- data->set.str[STRING_USERAGENT] && *data->set.str[STRING_USERAGENT]) {
+ data->set.str[STRING_USERAGENT]) {
struct dynbuf ua;
Curl_dyn_init(&ua, DYN_HTTP_REQUEST);
result = Curl_dyn_addf(&ua, "User-Agent: %s\r\n",
@@ -751,10 +776,6 @@ static CURLcode start_CONNECT(struct Curl_cfilter *cf,
if(result)
goto error;
- result = Curl_creader_set_null(data);
- if(result)
- goto error;
-
sendtask = hyper_clientconn_send(client, req);
if(!sendtask) {
failf(data, "hyper_clientconn_send");
@@ -838,9 +859,9 @@ static CURLcode recv_CONNECT_resp(struct Curl_cfilter *cf,
int didwhat;
(void)ts;
- result = Curl_hyper_stream(data, cf->conn, &didwhat,
+ *done = FALSE;
+ result = Curl_hyper_stream(data, cf->conn, &didwhat, done,
CURL_CSELECT_IN | CURL_CSELECT_OUT);
- *done = data->req.done;
if(result || !*done)
return result;
if(h->exec) {
@@ -891,7 +912,7 @@ static CURLcode H1_CONNECT(struct Curl_cfilter *cf,
if(result)
goto out;
h1_tunnel_go_state(cf, ts, H1_TUNNEL_CONNECT, data);
- FALLTHROUGH();
+ /* FALLTHROUGH */
case H1_TUNNEL_CONNECT:
/* see that the request is completely sent */
@@ -900,7 +921,7 @@ static CURLcode H1_CONNECT(struct Curl_cfilter *cf,
if(result || !done)
goto out;
h1_tunnel_go_state(cf, ts, H1_TUNNEL_RECEIVE, data);
- FALLTHROUGH();
+ /* FALLTHROUGH */
case H1_TUNNEL_RECEIVE:
/* read what is there */
@@ -915,7 +936,7 @@ static CURLcode H1_CONNECT(struct Curl_cfilter *cf,
goto out;
/* got it */
h1_tunnel_go_state(cf, ts, H1_TUNNEL_RESPONSE, data);
- FALLTHROUGH();
+ /* FALLTHROUGH */
case H1_TUNNEL_RESPONSE:
CURL_TRC_CF(data, cf, "CONNECT response");
@@ -924,7 +945,6 @@ static CURLcode H1_CONNECT(struct Curl_cfilter *cf,
* If the other side indicated a connection close, or if someone
* else told us to close this connection, do so now.
*/
- Curl_req_soft_reset(&data->req, data);
if(ts->close_connection || conn->bits.close) {
/* Close this filter and the sub-chain, re-connect the
* sub-chain and continue. Closing this filter will
@@ -953,7 +973,7 @@ static CURLcode H1_CONNECT(struct Curl_cfilter *cf,
DEBUGASSERT(ts->tunnel_state == H1_TUNNEL_RESPONSE);
if(data->info.httpproxycode/100 != 2) {
- /* a non-2xx response and we have no next URL to try. */
+ /* a non-2xx response and we have no next url to try. */
Curl_safefree(data->req.newurl);
/* failure, close this connection to avoid reuse */
streamclose(conn, "proxy CONNECT failure");
@@ -1010,12 +1030,6 @@ out:
*done = (result == CURLE_OK) && tunnel_is_established(cf->ctx);
if(*done) {
cf->connected = TRUE;
- /* The real request will follow the CONNECT, reset request partially */
- Curl_req_soft_reset(&data->req, data);
- Curl_client_reset(data);
- Curl_pgrsSetUploadCounter(data, 0);
- Curl_pgrsSetDownloadCounter(data, 0);
-
tunnel_free(cf, data);
}
return result;
@@ -1032,11 +1046,11 @@ static void cf_h1_proxy_adjust_pollset(struct Curl_cfilter *cf,
* and not waiting on something, we are tunneling. */
curl_socket_t sock = Curl_conn_cf_get_socket(cf, data);
if(ts) {
- /* when we have sent a CONNECT to a proxy, we should rather either
+ /* when we've sent a CONNECT to a proxy, we should rather either
wait for the socket to become readable to be able to get the
- response headers or if we are still sending the request, wait
+ response headers or if we're still sending the request, wait
for write. */
- if(tunnel_want_send(ts))
+ if(ts->CONNECT.sending == HTTPSEND_REQUEST)
Curl_pollset_set_out_only(data, ps, sock);
else
Curl_pollset_set_in_only(data, ps, sock);
@@ -1057,25 +1071,22 @@ static void cf_h1_proxy_close(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
CURL_TRC_CF(data, cf, "close");
- if(cf) {
- cf->connected = FALSE;
- if(cf->ctx) {
- h1_tunnel_go_state(cf, cf->ctx, H1_TUNNEL_INIT, data);
- }
- if(cf->next)
- cf->next->cft->do_close(cf->next, data);
+ cf->connected = FALSE;
+ if(cf->ctx) {
+ h1_tunnel_go_state(cf, cf->ctx, H1_TUNNEL_INIT, data);
}
+ if(cf->next)
+ cf->next->cft->do_close(cf->next, data);
}
struct Curl_cftype Curl_cft_h1_proxy = {
"H1-PROXY",
- CF_TYPE_IP_CONNECT|CF_TYPE_PROXY,
+ CF_TYPE_IP_CONNECT,
0,
cf_h1_proxy_destroy,
cf_h1_proxy_connect,
cf_h1_proxy_close,
- Curl_cf_def_shutdown,
Curl_cf_http_proxy_get_host,
cf_h1_proxy_adjust_pollset,
Curl_cf_def_data_pending,
diff --git a/contrib/libs/curl/lib/cf-h2-proxy.c b/contrib/libs/curl/lib/cf-h2-proxy.c
index 0a60ae47cd..147acdc86f 100644
--- a/contrib/libs/curl/lib/cf-h2-proxy.c
+++ b/contrib/libs/curl/lib/cf-h2-proxy.c
@@ -38,7 +38,6 @@
#include "http2.h"
#include "http_proxy.h"
#include "multiif.h"
-#include "sendf.h"
#include "cf-h2-proxy.h"
/* The last 3 #include files should be in this order */
@@ -73,6 +72,7 @@ struct tunnel_stream {
char *authority;
int32_t stream_id;
uint32_t error;
+ size_t upload_blocked_len;
h2_tunnel_state state;
BIT(has_final_response);
BIT(closed);
@@ -155,14 +155,14 @@ static void h2_tunnel_go_state(struct Curl_cfilter *cf,
infof(data, "CONNECT phase completed");
data->state.authproxy.done = TRUE;
data->state.authproxy.multipass = FALSE;
- FALLTHROUGH();
+ /* FALLTHROUGH */
case H2_TUNNEL_FAILED:
if(new_state == H2_TUNNEL_FAILED)
CURL_TRC_CF(data, cf, "[%d] new tunnel state 'failed'", ts->stream_id);
ts->state = new_state;
/* If a proxy-authorization header was used for the proxy, then we should
- make sure that it is not accidentally used for the document request
- after we have connected. So let's free and clear it here. */
+ make sure that it isn't accidentally used for the document request
+ after we've connected. So let's free and clear it here. */
Curl_safefree(data->state.aptr.proxyuserpwd);
break;
}
@@ -180,8 +180,7 @@ struct cf_h2_proxy_ctx {
int32_t goaway_error;
int32_t last_stream_id;
BIT(conn_closed);
- BIT(rcvd_goaway);
- BIT(sent_goaway);
+ BIT(goaway);
BIT(nw_out_blocked);
};
@@ -216,18 +215,16 @@ static void drain_tunnel(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct tunnel_stream *tunnel)
{
- struct cf_h2_proxy_ctx *ctx = cf->ctx;
unsigned char bits;
(void)cf;
bits = CURL_CSELECT_IN;
- if(!tunnel->closed && !tunnel->reset &&
- !Curl_bufq_is_empty(&ctx->tunnel.sendbuf))
+ if(!tunnel->closed && !tunnel->reset && tunnel->upload_blocked_len)
bits |= CURL_CSELECT_OUT;
- if(data->state.select_bits != bits) {
- CURL_TRC_CF(data, cf, "[%d] DRAIN select_bits=%x",
+ if(data->state.dselect_bits != bits) {
+ CURL_TRC_CF(data, cf, "[%d] DRAIN dselect_bits=%x",
tunnel->stream_id, bits);
- data->state.select_bits = bits;
+ data->state.dselect_bits = bits;
Curl_expire(data, 0, EXPIRE_RUN_NOW);
}
}
@@ -261,7 +258,7 @@ static ssize_t proxy_h2_nw_out_writer(void *writer_ctx,
if(cf) {
struct Curl_easy *data = CF_DATA_CURRENT(cf);
nwritten = Curl_conn_cf_send(cf->next, data, (const char *)buf, buflen,
- FALSE, err);
+ err);
CURL_TRC_CF(data, cf, "[0] nw_out_writer(len=%zu) -> %zd, %d",
buflen, nwritten, *err);
}
@@ -696,7 +693,7 @@ static int proxy_h2_on_frame_recv(nghttp2_session *session,
}
break;
case NGHTTP2_GOAWAY:
- ctx->rcvd_goaway = TRUE;
+ ctx->goaway = TRUE;
break;
default:
break;
@@ -959,9 +956,6 @@ static CURLcode submit_CONNECT(struct Curl_cfilter *cf,
result = Curl_http_proxy_create_CONNECT(&req, cf, data, 2);
if(result)
goto out;
- result = Curl_creader_set_null(data);
- if(result)
- goto out;
infof(data, "Establish HTTP/2 proxy tunnel to %s", req->authority);
@@ -1039,7 +1033,7 @@ static CURLcode H2_CONNECT(struct Curl_cfilter *cf,
if(result)
goto out;
h2_tunnel_go_state(cf, ts, H2_TUNNEL_CONNECT, data);
- FALLTHROUGH();
+ /* FALLTHROUGH */
case H2_TUNNEL_CONNECT:
/* see that the request is completely sent */
@@ -1058,7 +1052,7 @@ static CURLcode H2_CONNECT(struct Curl_cfilter *cf,
result = CURLE_OK;
goto out;
}
- FALLTHROUGH();
+ /* FALLTHROUGH */
case H2_TUNNEL_RESPONSE:
DEBUGASSERT(ts->has_final_response);
@@ -1080,7 +1074,7 @@ static CURLcode H2_CONNECT(struct Curl_cfilter *cf,
} while(ts->state == H2_TUNNEL_INIT);
out:
- if((result && (result != CURLE_AGAIN)) || ctx->tunnel.closed)
+ if(result || ctx->tunnel.closed)
h2_tunnel_go_state(cf, ts, H2_TUNNEL_FAILED, data);
return result;
}
@@ -1131,12 +1125,7 @@ static CURLcode cf_h2_proxy_connect(struct Curl_cfilter *cf,
out:
*done = (result == CURLE_OK) && (ts->state == H2_TUNNEL_ESTABLISHED);
- if(*done) {
- cf->connected = TRUE;
- /* The real request will follow the CONNECT, reset request partially */
- Curl_req_soft_reset(&data->req, data);
- Curl_client_reset(data);
- }
+ cf->connected = *done;
CF_DATA_RESTORE(cf, save);
return result;
}
@@ -1168,50 +1157,6 @@ static void cf_h2_proxy_destroy(struct Curl_cfilter *cf,
}
}
-static CURLcode cf_h2_proxy_shutdown(struct Curl_cfilter *cf,
- struct Curl_easy *data, bool *done)
-{
- struct cf_h2_proxy_ctx *ctx = cf->ctx;
- struct cf_call_data save;
- CURLcode result;
- int rv;
-
- if(!cf->connected || !ctx->h2 || cf->shutdown || ctx->conn_closed) {
- *done = TRUE;
- return CURLE_OK;
- }
-
- CF_DATA_SAVE(save, cf, data);
-
- if(!ctx->sent_goaway) {
- rv = nghttp2_submit_goaway(ctx->h2, NGHTTP2_FLAG_NONE,
- 0, 0,
- (const uint8_t *)"shutdown",
- sizeof("shutdown"));
- if(rv) {
- failf(data, "nghttp2_submit_goaway() failed: %s(%d)",
- nghttp2_strerror(rv), rv);
- result = CURLE_SEND_ERROR;
- goto out;
- }
- ctx->sent_goaway = TRUE;
- }
- /* GOAWAY submitted, process egress and ingress until nghttp2 is done. */
- result = CURLE_OK;
- if(nghttp2_session_want_write(ctx->h2))
- result = proxy_h2_progress_egress(cf, data);
- if(!result && nghttp2_session_want_read(ctx->h2))
- result = proxy_h2_progress_ingress(cf, data);
-
- *done = (ctx->conn_closed ||
- (!result && !nghttp2_session_want_write(ctx->h2) &&
- !nghttp2_session_want_read(ctx->h2)));
-out:
- CF_DATA_RESTORE(cf, save);
- cf->shutdown = (result || *done);
- return result;
-}
-
static bool cf_h2_proxy_data_pending(struct Curl_cfilter *cf,
const struct Curl_easy *data)
{
@@ -1228,20 +1173,12 @@ static void cf_h2_proxy_adjust_pollset(struct Curl_cfilter *cf,
struct easy_pollset *ps)
{
struct cf_h2_proxy_ctx *ctx = cf->ctx;
- struct cf_call_data save;
curl_socket_t sock = Curl_conn_cf_get_socket(cf, data);
bool want_recv, want_send;
- if(!cf->connected && ctx->h2) {
- want_send = nghttp2_session_want_write(ctx->h2) ||
- !Curl_bufq_is_empty(&ctx->outbufq) ||
- !Curl_bufq_is_empty(&ctx->tunnel.sendbuf);
- want_recv = nghttp2_session_want_read(ctx->h2);
- }
- else
- Curl_pollset_check(data, ps, sock, &want_recv, &want_send);
-
+ Curl_pollset_check(data, ps, sock, &want_recv, &want_send);
if(ctx->h2 && (want_recv || want_send)) {
+ struct cf_call_data save;
bool c_exhaust, s_exhaust;
CF_DATA_SAVE(save, cf, data);
@@ -1251,25 +1188,9 @@ static void cf_h2_proxy_adjust_pollset(struct Curl_cfilter *cf,
ctx->h2, ctx->tunnel.stream_id);
want_recv = (want_recv || c_exhaust || s_exhaust);
want_send = (!s_exhaust && want_send) ||
- (!c_exhaust && nghttp2_session_want_write(ctx->h2)) ||
- !Curl_bufq_is_empty(&ctx->outbufq) ||
- !Curl_bufq_is_empty(&ctx->tunnel.sendbuf);
+ (!c_exhaust && nghttp2_session_want_write(ctx->h2));
Curl_pollset_set(data, ps, sock, want_recv, want_send);
- CURL_TRC_CF(data, cf, "adjust_pollset, want_recv=%d want_send=%d",
- want_recv, want_send);
- CF_DATA_RESTORE(cf, save);
- }
- else if(ctx->sent_goaway && !cf->shutdown) {
- /* shutdown in progress */
- CF_DATA_SAVE(save, cf, data);
- want_send = nghttp2_session_want_write(ctx->h2) ||
- !Curl_bufq_is_empty(&ctx->outbufq) ||
- !Curl_bufq_is_empty(&ctx->tunnel.sendbuf);
- want_recv = nghttp2_session_want_read(ctx->h2);
- Curl_pollset_set(data, ps, sock, want_recv, want_send);
- CURL_TRC_CF(data, cf, "adjust_pollset, want_recv=%d want_send=%d",
- want_recv, want_send);
CF_DATA_RESTORE(cf, save);
}
}
@@ -1284,7 +1205,7 @@ static ssize_t h2_handle_tunnel_close(struct Curl_cfilter *cf,
if(ctx->tunnel.error == NGHTTP2_REFUSED_STREAM) {
CURL_TRC_CF(data, cf, "[%d] REFUSED_STREAM, try again on a new "
"connection", ctx->tunnel.stream_id);
- connclose(cf->conn, "REFUSED_STREAM"); /* do not use this anymore */
+ connclose(cf->conn, "REFUSED_STREAM"); /* don't use this anymore */
*err = CURLE_RECV_ERROR; /* trigger Curl_retry_request() later */
return -1;
}
@@ -1329,8 +1250,7 @@ static ssize_t tunnel_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
}
else if(ctx->tunnel.reset ||
(ctx->conn_closed && Curl_bufq_is_empty(&ctx->inbufq)) ||
- (ctx->rcvd_goaway &&
- ctx->last_stream_id < ctx->tunnel.stream_id)) {
+ (ctx->goaway && ctx->last_stream_id < ctx->tunnel.stream_id)) {
*err = CURLE_RECV_ERROR;
nread = -1;
}
@@ -1376,7 +1296,16 @@ static ssize_t cf_h2_proxy_recv(struct Curl_cfilter *cf,
}
result = proxy_h2_progress_egress(cf, data);
- if(result && (result != CURLE_AGAIN)) {
+ if(result == CURLE_AGAIN) {
+ /* pending data to send, need to be called again. Ideally, we'd
+ * monitor the socket for POLLOUT, but we might not be in SENDING
+ * transfer state any longer and are unable to make this happen.
+ */
+ CURL_TRC_CF(data, cf, "[%d] egress blocked, DRAIN",
+ ctx->tunnel.stream_id);
+ drain_tunnel(cf, data, &ctx->tunnel);
+ }
+ else if(result) {
*err = result;
nread = -1;
}
@@ -1396,16 +1325,15 @@ out:
static ssize_t cf_h2_proxy_send(struct Curl_cfilter *cf,
struct Curl_easy *data,
- const void *buf, size_t len, bool eos,
- CURLcode *err)
+ const void *buf, size_t len, CURLcode *err)
{
struct cf_h2_proxy_ctx *ctx = cf->ctx;
struct cf_call_data save;
int rv;
ssize_t nwritten;
CURLcode result;
+ int blocked = 0;
- (void)eos; /* TODO, maybe useful for blocks? */
if(ctx->tunnel.state != H2_TUNNEL_ESTABLISHED) {
*err = CURLE_SEND_ERROR;
return -1;
@@ -1417,10 +1345,29 @@ static ssize_t cf_h2_proxy_send(struct Curl_cfilter *cf,
*err = CURLE_SEND_ERROR;
goto out;
}
+ else if(ctx->tunnel.upload_blocked_len) {
+ /* the data in `buf` has already been submitted or added to the
+ * buffers, but have been EAGAINed on the last invocation. */
+ DEBUGASSERT(len >= ctx->tunnel.upload_blocked_len);
+ if(len < ctx->tunnel.upload_blocked_len) {
+ /* Did we get called again with a smaller `len`? This should not
+ * happen. We are not prepared to handle that. */
+ failf(data, "HTTP/2 proxy, send again with decreased length");
+ *err = CURLE_HTTP2;
+ nwritten = -1;
+ goto out;
+ }
+ nwritten = (ssize_t)ctx->tunnel.upload_blocked_len;
+ ctx->tunnel.upload_blocked_len = 0;
+ *err = CURLE_OK;
+ }
else {
nwritten = Curl_bufq_write(&ctx->tunnel.sendbuf, buf, len, err);
- if(nwritten < 0 && (*err != CURLE_AGAIN))
- goto out;
+ if(nwritten < 0) {
+ if(*err != CURLE_AGAIN)
+ goto out;
+ nwritten = 0;
+ }
}
if(!Curl_bufq_is_empty(&ctx->tunnel.sendbuf)) {
@@ -1443,13 +1390,52 @@ static ssize_t cf_h2_proxy_send(struct Curl_cfilter *cf,
/* Call the nghttp2 send loop and flush to write ALL buffered data,
* headers and/or request body completely out to the network */
result = proxy_h2_progress_egress(cf, data);
- if(result && (result != CURLE_AGAIN)) {
+ if(result == CURLE_AGAIN) {
+ blocked = 1;
+ }
+ else if(result) {
*err = result;
nwritten = -1;
goto out;
}
+ else if(!Curl_bufq_is_empty(&ctx->tunnel.sendbuf)) {
+ /* although we wrote everything that nghttp2 wants to send now,
+ * there is data left in our stream send buffer unwritten. This may
+ * be due to the stream's HTTP/2 flow window being exhausted. */
+ blocked = 1;
+ }
+
+ if(blocked) {
+ /* Unable to send all data, due to connection blocked or H2 window
+ * exhaustion. Data is left in our stream buffer, or nghttp2's internal
+ * frame buffer or our network out buffer. */
+ size_t rwin = nghttp2_session_get_stream_remote_window_size(
+ ctx->h2, ctx->tunnel.stream_id);
+ if(rwin == 0) {
+ /* H2 flow window exhaustion.
+ * FIXME: there is no way to HOLD all transfers that use this
+ * proxy connection AND to UNHOLD all of them again when the
+ * window increases.
+ * We *could* iterate over all data on this conn maybe? */
+ CURL_TRC_CF(data, cf, "[%d] remote flow "
+ "window is exhausted", ctx->tunnel.stream_id);
+ }
- if(proxy_h2_should_close_session(ctx)) {
+ /* Whatever the cause, we need to return CURL_EAGAIN for this call.
+ * We have unwritten state that needs us being invoked again and EAGAIN
+ * is the only way to ensure that. */
+ ctx->tunnel.upload_blocked_len = nwritten;
+ CURL_TRC_CF(data, cf, "[%d] cf_send(len=%zu) BLOCK: win %u/%zu "
+ "blocked_len=%zu",
+ ctx->tunnel.stream_id, len,
+ nghttp2_session_get_remote_window_size(ctx->h2), rwin,
+ nwritten);
+ drain_tunnel(cf, data, &ctx->tunnel);
+ *err = CURLE_AGAIN;
+ nwritten = -1;
+ goto out;
+ }
+ else if(proxy_h2_should_close_session(ctx)) {
/* nghttp2 thinks this session is done. If the stream has not been
* closed, this is an error state for out transfer */
if(ctx->tunnel.closed) {
@@ -1482,38 +1468,6 @@ out:
return nwritten;
}
-static CURLcode cf_h2_proxy_flush(struct Curl_cfilter *cf,
- struct Curl_easy *data)
-{
- struct cf_h2_proxy_ctx *ctx = cf->ctx;
- struct cf_call_data save;
- CURLcode result = CURLE_OK;
-
- CF_DATA_SAVE(save, cf, data);
- if(!Curl_bufq_is_empty(&ctx->tunnel.sendbuf)) {
- /* resume the potentially suspended tunnel */
- int rv = nghttp2_session_resume_data(ctx->h2, ctx->tunnel.stream_id);
- if(nghttp2_is_fatal(rv)) {
- result = CURLE_SEND_ERROR;
- goto out;
- }
- }
-
- result = proxy_h2_progress_egress(cf, data);
-
-out:
- CURL_TRC_CF(data, cf, "[%d] flush -> %d, "
- "h2 windows %d-%d (stream-conn), buffers %zu-%zu (stream-conn)",
- ctx->tunnel.stream_id, result,
- nghttp2_session_get_stream_remote_window_size(
- ctx->h2, ctx->tunnel.stream_id),
- nghttp2_session_get_remote_window_size(ctx->h2),
- Curl_bufq_len(&ctx->tunnel.sendbuf),
- Curl_bufq_len(&ctx->outbufq));
- CF_DATA_RESTORE(cf, save);
- return result;
-}
-
static bool proxy_h2_connisalive(struct Curl_cfilter *cf,
struct Curl_easy *data,
bool *input_pending)
@@ -1526,8 +1480,8 @@ static bool proxy_h2_connisalive(struct Curl_cfilter *cf,
return FALSE;
if(*input_pending) {
- /* This happens before we have sent off a request and the connection is
- not in use by any other transfer, there should not be any data here,
+ /* This happens before we've sent off a request and the connection is
+ not in use by any other transfer, there shouldn't be any data here,
only "protocol frames" */
CURLcode result;
ssize_t nread = -1;
@@ -1567,69 +1521,22 @@ static bool cf_h2_proxy_is_alive(struct Curl_cfilter *cf,
return result;
}
-static CURLcode cf_h2_proxy_query(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- int query, int *pres1, void *pres2)
-{
- struct cf_h2_proxy_ctx *ctx = cf->ctx;
-
- switch(query) {
- case CF_QUERY_NEED_FLUSH: {
- if(!Curl_bufq_is_empty(&ctx->outbufq) ||
- !Curl_bufq_is_empty(&ctx->tunnel.sendbuf)) {
- CURL_TRC_CF(data, cf, "needs flush");
- *pres1 = TRUE;
- return CURLE_OK;
- }
- break;
- }
- default:
- break;
- }
- return cf->next?
- cf->next->cft->query(cf->next, data, query, pres1, pres2) :
- CURLE_UNKNOWN_OPTION;
-}
-
-static CURLcode cf_h2_proxy_cntrl(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- int event, int arg1, void *arg2)
-{
- CURLcode result = CURLE_OK;
- struct cf_call_data save;
-
- (void)arg1;
- (void)arg2;
-
- switch(event) {
- case CF_CTRL_FLUSH:
- CF_DATA_SAVE(save, cf, data);
- result = cf_h2_proxy_flush(cf, data);
- CF_DATA_RESTORE(cf, save);
- break;
- default:
- break;
- }
- return result;
-}
-
struct Curl_cftype Curl_cft_h2_proxy = {
"H2-PROXY",
- CF_TYPE_IP_CONNECT|CF_TYPE_PROXY,
+ CF_TYPE_IP_CONNECT,
CURL_LOG_LVL_NONE,
cf_h2_proxy_destroy,
cf_h2_proxy_connect,
cf_h2_proxy_close,
- cf_h2_proxy_shutdown,
Curl_cf_http_proxy_get_host,
cf_h2_proxy_adjust_pollset,
cf_h2_proxy_data_pending,
cf_h2_proxy_send,
cf_h2_proxy_recv,
- cf_h2_proxy_cntrl,
+ Curl_cf_def_cntrl,
cf_h2_proxy_is_alive,
Curl_cf_def_conn_keep_alive,
- cf_h2_proxy_query,
+ Curl_cf_def_query,
};
CURLcode Curl_cf_h2_proxy_insert_after(struct Curl_cfilter *cf,
diff --git a/contrib/libs/curl/lib/cf-haproxy.c b/contrib/libs/curl/lib/cf-haproxy.c
index 0fc7625c44..1ca43937bf 100644
--- a/contrib/libs/curl/lib/cf-haproxy.c
+++ b/contrib/libs/curl/lib/cf-haproxy.c
@@ -70,9 +70,8 @@ static CURLcode cf_haproxy_date_out_set(struct Curl_cfilter*cf,
{
struct cf_haproxy_ctx *ctx = cf->ctx;
CURLcode result;
+ const char *tcp_version;
const char *client_ip;
- struct ip_quadruple ipquad;
- int is_ipv6;
DEBUGASSERT(ctx);
DEBUGASSERT(ctx->state == HAPROXY_INIT);
@@ -82,20 +81,19 @@ static CURLcode cf_haproxy_date_out_set(struct Curl_cfilter*cf,
result = Curl_dyn_addn(&ctx->data_out, STRCONST("PROXY UNKNOWN\r\n"));
else {
#endif /* USE_UNIX_SOCKETS */
- result = Curl_conn_cf_get_ip_info(cf->next, data, &is_ipv6, &ipquad);
- if(result)
- return result;
-
/* Emit the correct prefix for IPv6 */
+ tcp_version = cf->conn->bits.ipv6 ? "TCP6" : "TCP4";
if(data->set.str[STRING_HAPROXY_CLIENT_IP])
client_ip = data->set.str[STRING_HAPROXY_CLIENT_IP];
else
- client_ip = ipquad.local_ip;
+ client_ip = data->info.conn_local_ip;
result = Curl_dyn_addf(&ctx->data_out, "PROXY %s %s %s %i %i\r\n",
- is_ipv6? "TCP6" : "TCP4",
- client_ip, ipquad.remote_ip,
- ipquad.local_port, ipquad.remote_port);
+ tcp_version,
+ client_ip,
+ data->info.conn_primary_ip,
+ data->info.conn_local_port,
+ data->info.conn_primary_port);
#ifdef USE_UNIX_SOCKETS
}
@@ -127,28 +125,23 @@ static CURLcode cf_haproxy_connect(struct Curl_cfilter *cf,
if(result)
goto out;
ctx->state = HAPROXY_SEND;
- FALLTHROUGH();
+ /* FALLTHROUGH */
case HAPROXY_SEND:
len = Curl_dyn_len(&ctx->data_out);
if(len > 0) {
- ssize_t nwritten;
- nwritten = Curl_conn_cf_send(cf->next, data,
- Curl_dyn_ptr(&ctx->data_out), len, FALSE,
- &result);
- if(nwritten < 0) {
- if(result != CURLE_AGAIN)
- goto out;
- result = CURLE_OK;
- nwritten = 0;
- }
- Curl_dyn_tail(&ctx->data_out, len - (size_t)nwritten);
+ ssize_t written = Curl_conn_send(data, cf->sockindex,
+ Curl_dyn_ptr(&ctx->data_out),
+ len, &result);
+ if(written < 0)
+ goto out;
+ Curl_dyn_tail(&ctx->data_out, len - (size_t)written);
if(Curl_dyn_len(&ctx->data_out) > 0) {
result = CURLE_OK;
goto out;
}
}
ctx->state = HAPROXY_DONE;
- FALLTHROUGH();
+ /* FALLTHROUGH */
default:
Curl_dyn_free(&ctx->data_out);
break;
@@ -191,12 +184,11 @@ static void cf_haproxy_adjust_pollset(struct Curl_cfilter *cf,
struct Curl_cftype Curl_cft_haproxy = {
"HAPROXY",
- CF_TYPE_PROXY,
+ 0,
0,
cf_haproxy_destroy,
cf_haproxy_connect,
cf_haproxy_close,
- Curl_cf_def_shutdown,
Curl_cf_def_get_host,
cf_haproxy_adjust_pollset,
Curl_cf_def_data_pending,
diff --git a/contrib/libs/curl/lib/cf-https-connect.c b/contrib/libs/curl/lib/cf-https-connect.c
index bc71598720..b4f33c8e02 100644
--- a/contrib/libs/curl/lib/cf-https-connect.c
+++ b/contrib/libs/curl/lib/cf-https-connect.c
@@ -55,8 +55,7 @@ struct cf_hc_baller {
CURLcode result;
struct curltime started;
int reply_ms;
- BIT(enabled);
- BIT(shutdown);
+ bool enabled;
};
static void cf_hc_baller_reset(struct cf_hc_baller *b,
@@ -96,21 +95,6 @@ static bool cf_hc_baller_data_pending(struct cf_hc_baller *b,
return b->cf && !b->result && b->cf->cft->has_data_pending(b->cf, data);
}
-static bool cf_hc_baller_needs_flush(struct cf_hc_baller *b,
- struct Curl_easy *data)
-{
- return b->cf && !b->result && Curl_conn_cf_needs_flush(b->cf, data);
-}
-
-static CURLcode cf_hc_baller_cntrl(struct cf_hc_baller *b,
- struct Curl_easy *data,
- int event, int arg1, void *arg2)
-{
- if(b->cf && !b->result)
- return Curl_conn_cf_cntrl(b->cf, data, FALSE, event, arg1, arg2);
- return CURLE_OK;
-}
-
struct cf_hc_ctx {
cf_hc_state state;
const struct Curl_dns_entry *remotehost;
@@ -118,8 +102,8 @@ struct cf_hc_ctx {
CURLcode result; /* overall result */
struct cf_hc_baller h3_baller;
struct cf_hc_baller h21_baller;
- unsigned int soft_eyeballs_timeout_ms;
- unsigned int hard_eyeballs_timeout_ms;
+ int soft_eyeballs_timeout_ms;
+ int hard_eyeballs_timeout_ms;
};
static void cf_hc_baller_init(struct cf_hc_baller *b,
@@ -189,6 +173,7 @@ static CURLcode baller_connected(struct Curl_cfilter *cf,
switch(cf->conn->alpn) {
case CURL_HTTP_VERSION_3:
+ infof(data, "using HTTP/3");
break;
case CURL_HTTP_VERSION_2:
#ifdef USE_NGHTTP2
@@ -201,12 +186,16 @@ static CURLcode baller_connected(struct Curl_cfilter *cf,
return result;
}
#endif
+ infof(data, "using HTTP/2");
break;
default:
+ infof(data, "using HTTP/1.x");
break;
}
ctx->state = CF_HC_SUCCESS;
cf->connected = TRUE;
+ Curl_conn_cf_cntrl(cf->next, data, TRUE,
+ CF_CTRL_CONN_INFO_UPDATE, 0, NULL);
return result;
}
@@ -277,7 +266,7 @@ static CURLcode cf_hc_connect(struct Curl_cfilter *cf,
cf_hc_baller_init(&ctx->h21_baller, cf, data, "h21",
cf->conn->transport);
ctx->state = CF_HC_CONNECT;
- FALLTHROUGH();
+ /* FALLTHROUGH */
case CF_HC_CONNECT:
if(cf_hc_baller_is_active(&ctx->h3_baller)) {
@@ -333,49 +322,6 @@ out:
return result;
}
-static CURLcode cf_hc_shutdown(struct Curl_cfilter *cf,
- struct Curl_easy *data, bool *done)
-{
- struct cf_hc_ctx *ctx = cf->ctx;
- struct cf_hc_baller *ballers[2];
- size_t i;
- CURLcode result = CURLE_OK;
-
- DEBUGASSERT(data);
- if(cf->connected) {
- *done = TRUE;
- return CURLE_OK;
- }
-
- /* shutdown all ballers that have not done so already. If one fails,
- * continue shutting down others until all are shutdown. */
- ballers[0] = &ctx->h3_baller;
- ballers[1] = &ctx->h21_baller;
- for(i = 0; i < sizeof(ballers)/sizeof(ballers[0]); i++) {
- struct cf_hc_baller *b = ballers[i];
- bool bdone = FALSE;
- if(!cf_hc_baller_is_active(b) || b->shutdown)
- continue;
- b->result = b->cf->cft->do_shutdown(b->cf, data, &bdone);
- if(b->result || bdone)
- b->shutdown = TRUE; /* treat a failed shutdown as done */
- }
-
- *done = TRUE;
- for(i = 0; i < sizeof(ballers)/sizeof(ballers[0]); i++) {
- if(ballers[i] && !ballers[i]->shutdown)
- *done = FALSE;
- }
- if(*done) {
- for(i = 0; i < sizeof(ballers)/sizeof(ballers[0]); i++) {
- if(ballers[i] && ballers[i]->result)
- result = ballers[i]->result;
- }
- }
- CURL_TRC_CF(data, cf, "shutdown -> %d, done=%d", result, *done);
- return result;
-}
-
static void cf_hc_adjust_pollset(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct easy_pollset *ps)
@@ -438,8 +384,6 @@ static CURLcode cf_hc_query(struct Curl_cfilter *cf,
struct Curl_easy *data,
int query, int *pres1, void *pres2)
{
- struct cf_hc_ctx *ctx = cf->ctx;
-
if(!cf->connected) {
switch(query) {
case CF_QUERY_TIMER_CONNECT: {
@@ -452,14 +396,6 @@ static CURLcode cf_hc_query(struct Curl_cfilter *cf,
*when = cf_get_max_baller_time(cf, data, CF_QUERY_TIMER_APPCONNECT);
return CURLE_OK;
}
- case CF_QUERY_NEED_FLUSH: {
- if(cf_hc_baller_needs_flush(&ctx->h3_baller, data)
- || cf_hc_baller_needs_flush(&ctx->h21_baller, data)) {
- *pres1 = TRUE;
- return CURLE_OK;
- }
- break;
- }
default:
break;
}
@@ -469,23 +405,6 @@ static CURLcode cf_hc_query(struct Curl_cfilter *cf,
CURLE_UNKNOWN_OPTION;
}
-static CURLcode cf_hc_cntrl(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- int event, int arg1, void *arg2)
-{
- struct cf_hc_ctx *ctx = cf->ctx;
- CURLcode result = CURLE_OK;
-
- if(!cf->connected) {
- result = cf_hc_baller_cntrl(&ctx->h3_baller, data, event, arg1, arg2);
- if(!result || (result == CURLE_AGAIN))
- result = cf_hc_baller_cntrl(&ctx->h21_baller, data, event, arg1, arg2);
- if(result == CURLE_AGAIN)
- result = CURLE_OK;
- }
- return result;
-}
-
static void cf_hc_close(struct Curl_cfilter *cf, struct Curl_easy *data)
{
CURL_TRC_CF(data, cf, "close");
@@ -515,13 +434,12 @@ struct Curl_cftype Curl_cft_http_connect = {
cf_hc_destroy,
cf_hc_connect,
cf_hc_close,
- cf_hc_shutdown,
Curl_cf_def_get_host,
cf_hc_adjust_pollset,
cf_hc_data_pending,
Curl_cf_def_send,
Curl_cf_def_recv,
- cf_hc_cntrl,
+ Curl_cf_def_cntrl,
Curl_cf_def_conn_is_alive,
Curl_cf_def_conn_keep_alive,
cf_hc_query,
@@ -592,7 +510,7 @@ CURLcode Curl_cf_https_setup(struct Curl_easy *data,
if(data->state.httpwant == CURL_HTTP_VERSION_3ONLY) {
result = Curl_conn_may_http3(data, conn);
- if(result) /* cannot do it */
+ if(result) /* can't do it */
goto out;
try_h3 = TRUE;
try_h21 = FALSE;
diff --git a/contrib/libs/curl/lib/cf-socket.c b/contrib/libs/curl/lib/cf-socket.c
index e4d6a5b86d..d86dfd7b72 100644
--- a/contrib/libs/curl/lib/cf-socket.c
+++ b/contrib/libs/curl/lib/cf-socket.c
@@ -35,9 +35,6 @@
#elif defined(HAVE_NETINET_TCP_H)
#include <netinet/tcp.h>
#endif
-#ifdef HAVE_NETINET_UDP_H
-#include <netinet/udp.h>
-#endif
#ifdef HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>
#endif
@@ -56,11 +53,6 @@
#include <inet.h>
#endif
-#ifdef __DragonFly__
-/* Required for __DragonFly_version */
-#include <sys/param.h>
-#endif
-
#include "urldata.h"
#include "bufq.h"
#include "sendf.h"
@@ -81,7 +73,6 @@
#include "multihandle.h"
#include "rand.h"
#include "share.h"
-#include "strdup.h"
#include "version_win32.h"
/* The last 3 #include files should be in this order */
@@ -90,7 +81,7 @@
#include "memdebug.h"
-#if defined(USE_IPV6) && defined(IPV6_V6ONLY) && defined(_WIN32)
+#if defined(ENABLE_IPV6) && defined(IPV6_V6ONLY) && defined(_WIN32)
/* It makes support for IPv4-mapped IPv6 addresses.
* Linux kernel, NetBSD, FreeBSD and Darwin: default is off;
* Windows Vista and later: default is on;
@@ -124,7 +115,7 @@ static void tcpnodelay(struct Curl_easy *data, curl_socket_t sockfd)
}
#ifdef SO_NOSIGPIPE
-/* The preferred method on macOS (10.2 and later) to prevent SIGPIPEs when
+/* The preferred method on Mac OS X (10.2 and later) to prevent SIGPIPEs when
sending data to a dead peer (instead of relying on the 4th argument to send
being MSG_NOSIGNAL). Possibly also existing and in use on other BSD
systems? */
@@ -146,24 +137,14 @@ static void nosigpipe(struct Curl_easy *data,
#define nosigpipe(x,y) Curl_nop_stmt
#endif
-#if defined(USE_WINSOCK) && \
- defined(TCP_KEEPIDLE) && defined(TCP_KEEPINTVL) && defined(TCP_KEEPCNT)
-/* Win 10, v 1709 (10.0.16299) and later can use SetSockOpt TCP_KEEP____
- * so should use seconds */
-#define CURL_WINSOCK_KEEP_SSO
-#define KEEPALIVE_FACTOR(x)
-#elif defined(USE_WINSOCK) || \
- (defined(__sun) && !defined(TCP_KEEPIDLE)) || \
- (defined(__DragonFly__) && __DragonFly_version < 500702) || \
- (defined(_WIN32) && !defined(TCP_KEEPIDLE))
-/* Solaris < 11.4, DragonFlyBSD < 500702 and Windows < 10.0.16299
- * use millisecond units. */
+#if defined(__DragonFly__) || defined(HAVE_WINSOCK2_H)
+/* DragonFlyBSD and Windows use millisecond units */
#define KEEPALIVE_FACTOR(x) (x *= 1000)
#else
#define KEEPALIVE_FACTOR(x)
#endif
-#if defined(USE_WINSOCK) && !defined(SIO_KEEPALIVE_VALS)
+#if defined(HAVE_WINSOCK2_H) && !defined(SIO_KEEPALIVE_VALS)
#define SIO_KEEPALIVE_VALS _WSAIOW(IOC_VENDOR,4)
struct tcp_keepalive {
@@ -182,82 +163,39 @@ tcpkeepalive(struct Curl_easy *data,
/* only set IDLE and INTVL if setting KEEPALIVE is successful */
if(setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE,
(void *)&optval, sizeof(optval)) < 0) {
- infof(data, "Failed to set SO_KEEPALIVE on fd "
- "%" FMT_SOCKET_T ": errno %d",
- sockfd, SOCKERRNO);
+ infof(data, "Failed to set SO_KEEPALIVE on fd %d", sockfd);
}
else {
-#if defined(SIO_KEEPALIVE_VALS) /* Windows */
-/* Windows 10, version 1709 (10.0.16299) and later versions */
-#if defined(CURL_WINSOCK_KEEP_SSO)
- optval = curlx_sltosi(data->set.tcp_keepidle);
- KEEPALIVE_FACTOR(optval);
- if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPIDLE,
- (const char *)&optval, sizeof(optval)) < 0) {
- infof(data, "Failed to set TCP_KEEPIDLE on fd "
- "%" FMT_SOCKET_T ": errno %d",
- sockfd, SOCKERRNO);
- }
- optval = curlx_sltosi(data->set.tcp_keepintvl);
- KEEPALIVE_FACTOR(optval);
- if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPINTVL,
- (const char *)&optval, sizeof(optval)) < 0) {
- infof(data, "Failed to set TCP_KEEPINTVL on fd "
- "%" FMT_SOCKET_T ": errno %d",
- sockfd, SOCKERRNO);
- }
- optval = curlx_sltosi(data->set.tcp_keepcnt);
- if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPCNT,
- (const char *)&optval, sizeof(optval)) < 0) {
- infof(data, "Failed to set TCP_KEEPCNT on fd "
- "%" FMT_SOCKET_T ": errno %d",
- sockfd, SOCKERRNO);
- }
-#else /* Windows < 10.0.16299 */
+#if defined(SIO_KEEPALIVE_VALS)
struct tcp_keepalive vals;
DWORD dummy;
vals.onoff = 1;
optval = curlx_sltosi(data->set.tcp_keepidle);
KEEPALIVE_FACTOR(optval);
- vals.keepalivetime = (u_long)optval;
+ vals.keepalivetime = optval;
optval = curlx_sltosi(data->set.tcp_keepintvl);
KEEPALIVE_FACTOR(optval);
- vals.keepaliveinterval = (u_long)optval;
+ vals.keepaliveinterval = optval;
if(WSAIoctl(sockfd, SIO_KEEPALIVE_VALS, (LPVOID) &vals, sizeof(vals),
NULL, 0, &dummy, NULL, NULL) != 0) {
- infof(data, "Failed to set SIO_KEEPALIVE_VALS on fd "
- "%" FMT_SOCKET_T ": errno %d", sockfd, SOCKERRNO);
+ infof(data, "Failed to set SIO_KEEPALIVE_VALS on fd %d: %d",
+ (int)sockfd, WSAGetLastError());
}
-#endif
-#else /* !Windows */
+#else
#ifdef TCP_KEEPIDLE
optval = curlx_sltosi(data->set.tcp_keepidle);
KEEPALIVE_FACTOR(optval);
if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPIDLE,
(void *)&optval, sizeof(optval)) < 0) {
- infof(data, "Failed to set TCP_KEEPIDLE on fd "
- "%" FMT_SOCKET_T ": errno %d",
- sockfd, SOCKERRNO);
+ infof(data, "Failed to set TCP_KEEPIDLE on fd %d", sockfd);
}
#elif defined(TCP_KEEPALIVE)
- /* macOS style */
+ /* Mac OS X style */
optval = curlx_sltosi(data->set.tcp_keepidle);
KEEPALIVE_FACTOR(optval);
if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPALIVE,
(void *)&optval, sizeof(optval)) < 0) {
- infof(data, "Failed to set TCP_KEEPALIVE on fd "
- "%" FMT_SOCKET_T ": errno %d",
- sockfd, SOCKERRNO);
- }
-#elif defined(TCP_KEEPALIVE_THRESHOLD)
- /* Solaris <11.4 style */
- optval = curlx_sltosi(data->set.tcp_keepidle);
- KEEPALIVE_FACTOR(optval);
- if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPALIVE_THRESHOLD,
- (void *)&optval, sizeof(optval)) < 0) {
- infof(data, "Failed to set TCP_KEEPALIVE_THRESHOLD on fd "
- "%" FMT_SOCKET_T ": errno %d",
- sockfd, SOCKERRNO);
+ infof(data, "Failed to set TCP_KEEPALIVE on fd %d", sockfd);
}
#endif
#ifdef TCP_KEEPINTVL
@@ -265,37 +203,7 @@ tcpkeepalive(struct Curl_easy *data,
KEEPALIVE_FACTOR(optval);
if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPINTVL,
(void *)&optval, sizeof(optval)) < 0) {
- infof(data, "Failed to set TCP_KEEPINTVL on fd "
- "%" FMT_SOCKET_T ": errno %d",
- sockfd, SOCKERRNO);
- }
-#elif defined(TCP_KEEPALIVE_ABORT_THRESHOLD)
- /* Solaris <11.4 style */
- /* TCP_KEEPALIVE_ABORT_THRESHOLD should equal to
- * TCP_KEEPCNT * TCP_KEEPINTVL on other platforms.
- * The default value of TCP_KEEPCNT is 9 on Linux,
- * 8 on *BSD/macOS, 5 or 10 on Windows. We use the
- * default config for Solaris <11.4 because there is
- * no default value for TCP_KEEPCNT on Solaris 11.4.
- *
- * Note that the consequent probes will not be sent
- * at equal intervals on Solaris, but will be sent
- * using the exponential backoff algorithm. */
- optval = curlx_sltosi(data->set.tcp_keepcnt) *
- curlx_sltosi(data->set.tcp_keepintvl);
- KEEPALIVE_FACTOR(optval);
- if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPALIVE_ABORT_THRESHOLD,
- (void *)&optval, sizeof(optval)) < 0) {
- infof(data, "Failed to set TCP_KEEPALIVE_ABORT_THRESHOLD on fd "
- "%" FMT_SOCKET_T ": errno %d", sockfd, SOCKERRNO);
- }
-#endif
-#ifdef TCP_KEEPCNT
- optval = curlx_sltosi(data->set.tcp_keepcnt);
- if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPCNT,
- (void *)&optval, sizeof(optval)) < 0) {
- infof(data, "Failed to set TCP_KEEPCNT on fd "
- "%" FMT_SOCKET_T ": errno %d", sockfd, SOCKERRNO);
+ infof(data, "Failed to set TCP_KEEPINTVL on fd %d", sockfd);
}
#endif
#endif
@@ -332,7 +240,7 @@ void Curl_sock_assign_addr(struct Curl_sockaddr_ex *dest,
dest->protocol = IPPROTO_UDP;
break;
}
- dest->addrlen = (unsigned int)ai->ai_addrlen;
+ dest->addrlen = ai->ai_addrlen;
if(dest->addrlen > sizeof(struct Curl_sockaddr_storage))
dest->addrlen = sizeof(struct Curl_sockaddr_storage);
@@ -370,7 +278,7 @@ static CURLcode socket_open(struct Curl_easy *data,
/* no socket, no connection */
return CURLE_COULDNT_CONNECT;
-#if defined(USE_IPV6) && defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID)
+#if defined(ENABLE_IPV6) && defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID)
if(data->conn->scope_id && (addr->family == AF_INET6)) {
struct sockaddr_in6 * const sa6 = (void *)&addr->sa_addr;
sa6->sin6_scope_id = data->conn->scope_id;
@@ -397,7 +305,7 @@ CURLcode Curl_socket_open(struct Curl_easy *data,
struct Curl_sockaddr_ex dummy;
if(!addr)
- /* if the caller does not want info back, use a local temp copy */
+ /* if the caller doesn't want info back, use a local temp copy */
addr = &dummy;
Curl_sock_assign_addr(addr, ai, transport);
@@ -407,9 +315,6 @@ CURLcode Curl_socket_open(struct Curl_easy *data,
static int socket_close(struct Curl_easy *data, struct connectdata *conn,
int use_callback, curl_socket_t sock)
{
- if(CURL_SOCKET_BAD == sock)
- return 0;
-
if(use_callback && conn && conn->fclosesocket) {
int rc;
Curl_multi_closed(data, sock);
@@ -449,14 +354,14 @@ int Curl_socket_close(struct Curl_easy *data, struct connectdata *conn,
Buffer Size
The problem described in this knowledge-base is applied only to pre-Vista
- Windows. Following function trying to detect OS version and skips
+ Windows. Following function trying to detect OS version and skips
SO_SNDBUF adjustment for Windows Vista and above.
*/
#define DETECT_OS_NONE 0
#define DETECT_OS_PREVISTA 1
#define DETECT_OS_VISTA_OR_LATER 2
-void Curl_sndbuf_init(curl_socket_t sockfd)
+void Curl_sndbufset(curl_socket_t sockfd)
{
int val = CURL_MAX_WRITE_SIZE + 32;
int curval = 0;
@@ -481,88 +386,7 @@ void Curl_sndbuf_init(curl_socket_t sockfd)
setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (const char *)&val, sizeof(val));
}
-#endif /* USE_WINSOCK */
-
-/*
- * Curl_parse_interface()
- *
- * This is used to parse interface argument in the following formats.
- * In all the examples, `host` can be an IP address or a hostname.
- *
- * <iface_or_host> - can be either an interface name or a host.
- * if!<iface> - interface name.
- * host!<host> - hostname.
- * ifhost!<iface>!<host> - interface name and hostname.
- *
- * Parameters:
- *
- * input [in] - input string.
- * len [in] - length of the input string.
- * dev [in/out] - address where a pointer to newly allocated memory
- * holding the interface-or-host will be stored upon
- * completion.
- * iface [in/out] - address where a pointer to newly allocated memory
- * holding the interface will be stored upon completion.
- * host [in/out] - address where a pointer to newly allocated memory
- * holding the host will be stored upon completion.
- *
- * Returns CURLE_OK on success.
- */
-CURLcode Curl_parse_interface(const char *input,
- char **dev, char **iface, char **host)
-{
- static const char if_prefix[] = "if!";
- static const char host_prefix[] = "host!";
- static const char if_host_prefix[] = "ifhost!";
- size_t len;
-
- DEBUGASSERT(dev);
- DEBUGASSERT(iface);
- DEBUGASSERT(host);
-
- len = strlen(input);
- if(len > 512)
- return CURLE_BAD_FUNCTION_ARGUMENT;
-
- if(!strncmp(if_prefix, input, strlen(if_prefix))) {
- input += strlen(if_prefix);
- if(!*input)
- return CURLE_BAD_FUNCTION_ARGUMENT;
- *iface = Curl_memdup0(input, len - strlen(if_prefix));
- return *iface ? CURLE_OK : CURLE_OUT_OF_MEMORY;
- }
- else if(!strncmp(host_prefix, input, strlen(host_prefix))) {
- input += strlen(host_prefix);
- if(!*input)
- return CURLE_BAD_FUNCTION_ARGUMENT;
- *host = Curl_memdup0(input, len - strlen(host_prefix));
- return *host ? CURLE_OK : CURLE_OUT_OF_MEMORY;
- }
- else if(!strncmp(if_host_prefix, input, strlen(if_host_prefix))) {
- const char *host_part;
- input += strlen(if_host_prefix);
- len -= strlen(if_host_prefix);
- host_part = memchr(input, '!', len);
- if(!host_part || !*(host_part + 1))
- return CURLE_BAD_FUNCTION_ARGUMENT;
- *iface = Curl_memdup0(input, host_part - input);
- if(!*iface)
- return CURLE_OUT_OF_MEMORY;
- ++host_part;
- *host = Curl_memdup0(host_part, len - (host_part - input));
- if(!*host) {
- free(*iface);
- *iface = NULL;
- return CURLE_OUT_OF_MEMORY;
- }
- return CURLE_OK;
- }
-
- if(!*input)
- return CURLE_BAD_FUNCTION_ARGUMENT;
- *dev = Curl_memdup0(input, len);
- return *dev ? CURLE_OK : CURLE_OUT_OF_MEMORY;
-}
+#endif
#ifndef CURL_DISABLE_BINDLOCAL
static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
@@ -572,7 +396,7 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
struct sockaddr *sock = (struct sockaddr *)&sa; /* bind to this address */
curl_socklen_t sizeof_sa = 0; /* size of the data sock points to */
struct sockaddr_in *si4 = (struct sockaddr_in *)&sa;
-#ifdef USE_IPV6
+#ifdef ENABLE_IPV6
struct sockaddr_in6 *si6 = (struct sockaddr_in6 *)&sa;
#endif
@@ -582,92 +406,94 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
/* how many port numbers to try to bind to, increasing one at a time */
int portnum = data->set.localportrange;
const char *dev = data->set.str[STRING_DEVICE];
- const char *iface_input = data->set.str[STRING_INTERFACE];
- const char *host_input = data->set.str[STRING_BINDHOST];
- const char *iface = iface_input ? iface_input : dev;
- const char *host = host_input ? host_input : dev;
int error;
#ifdef IP_BIND_ADDRESS_NO_PORT
int on = 1;
#endif
-#ifndef USE_IPV6
+#ifndef ENABLE_IPV6
(void)scope;
#endif
/*************************************************************
* Select device to bind socket to
*************************************************************/
- if(!iface && !host && !port)
+ if(!dev && !port)
/* no local kind of binding was requested */
return CURLE_OK;
memset(&sa, 0, sizeof(struct Curl_sockaddr_storage));
- if(iface && (strlen(iface)<255) ) {
+ if(dev && (strlen(dev)<255) ) {
char myhost[256] = "";
int done = 0; /* -1 for error, 1 for address found */
- if2ip_result_t if2ip_result = IF2IP_NOT_FOUND;
+ bool is_interface = FALSE;
+ bool is_host = FALSE;
+ static const char *if_prefix = "if!";
+ static const char *host_prefix = "host!";
+
+ if(strncmp(if_prefix, dev, strlen(if_prefix)) == 0) {
+ dev += strlen(if_prefix);
+ is_interface = TRUE;
+ }
+ else if(strncmp(host_prefix, dev, strlen(host_prefix)) == 0) {
+ dev += strlen(host_prefix);
+ is_host = TRUE;
+ }
/* interface */
+ if(!is_host) {
#ifdef SO_BINDTODEVICE
- /*
- * This binds the local socket to a particular interface. This will
- * force even requests to other local interfaces to go out the external
- * interface. Only bind to the interface when specified as interface,
- * not just as a hostname or ip address.
- *
- * The interface might be a VRF, eg: vrf-blue, which means it cannot be
- * converted to an IP address and would fail Curl_if2ip. Simply try to
- * use it straight away.
- */
- if(setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE,
- iface, (curl_socklen_t)strlen(iface) + 1) == 0) {
- /* This is often "errno 1, error: Operation not permitted" if you are
- * not running as root or another suitable privileged user. If it
- * succeeds it means the parameter was a valid interface and not an IP
- * address. Return immediately.
- */
- if(!host_input) {
- infof(data, "socket successfully bound to interface '%s'", iface);
+ /*
+ * This binds the local socket to a particular interface. This will
+ * force even requests to other local interfaces to go out the external
+ * interface. Only bind to the interface when specified as interface,
+ * not just as a hostname or ip address.
+ *
+ * The interface might be a VRF, eg: vrf-blue, which means it cannot be
+ * converted to an IP address and would fail Curl_if2ip. Simply try to
+ * use it straight away.
+ */
+ if(setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE,
+ dev, (curl_socklen_t)strlen(dev) + 1) == 0) {
+ /* This is often "errno 1, error: Operation not permitted" if you're
+ * not running as root or another suitable privileged user. If it
+ * succeeds it means the parameter was a valid interface and not an IP
+ * address. Return immediately.
+ */
+ infof(data, "socket successfully bound to interface '%s'", dev);
return CURLE_OK;
}
- }
#endif
- if(!host_input) {
- /* Discover IP from input device, then bind to it */
- if2ip_result = Curl_if2ip(af,
-#ifdef USE_IPV6
- scope, conn->scope_id,
+
+ switch(Curl_if2ip(af,
+#ifdef ENABLE_IPV6
+ scope, conn->scope_id,
#endif
- iface, myhost, sizeof(myhost));
- }
- switch(if2ip_result) {
- case IF2IP_NOT_FOUND:
- if(iface_input && !host_input) {
- /* Do not fall back to treating it as a hostname */
- char buffer[STRERROR_LEN];
- data->state.os_errno = error = SOCKERRNO;
- failf(data, "Couldn't bind to interface '%s' with errno %d: %s",
- iface, error, Curl_strerror(error, buffer, sizeof(buffer)));
- return CURLE_INTERFACE_FAILED;
- }
- break;
- case IF2IP_AF_NOT_SUPPORTED:
- /* Signal the caller to try another address family if available */
- return CURLE_UNSUPPORTED_PROTOCOL;
- case IF2IP_FOUND:
- /*
- * We now have the numerical IP address in the 'myhost' buffer
- */
- host = myhost;
- infof(data, "Local Interface %s is ip %s using address family %i",
- iface, host, af);
- done = 1;
- break;
+ dev, myhost, sizeof(myhost))) {
+ case IF2IP_NOT_FOUND:
+ if(is_interface) {
+ /* Do not fall back to treating it as a host name */
+ failf(data, "Couldn't bind to interface '%s'", dev);
+ return CURLE_INTERFACE_FAILED;
+ }
+ break;
+ case IF2IP_AF_NOT_SUPPORTED:
+ /* Signal the caller to try another address family if available */
+ return CURLE_UNSUPPORTED_PROTOCOL;
+ case IF2IP_FOUND:
+ is_interface = TRUE;
+ /*
+ * We now have the numerical IP address in the 'myhost' buffer
+ */
+ infof(data, "Local Interface %s is ip %s using address family %i",
+ dev, myhost, af);
+ done = 1;
+ break;
+ }
}
- if(!iface_input || host_input) {
+ if(!is_interface) {
/*
- * This was not an interface, resolve the name as a hostname
+ * This was not an interface, resolve the name as a host name
* or IP number
*
* Temporarily force name resolution to use only the address type
@@ -679,24 +505,23 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
if(af == AF_INET)
conn->ip_version = CURL_IPRESOLVE_V4;
-#ifdef USE_IPV6
+#ifdef ENABLE_IPV6
else if(af == AF_INET6)
conn->ip_version = CURL_IPRESOLVE_V6;
#endif
- rc = Curl_resolv(data, host, 80, FALSE, &h);
+ rc = Curl_resolv(data, dev, 80, FALSE, &h);
if(rc == CURLRESOLV_PENDING)
(void)Curl_resolver_wait_resolv(data, &h);
conn->ip_version = ipver;
if(h) {
- int h_af = h->addr->ai_family;
/* convert the resolved address, sizeof myhost >= INET_ADDRSTRLEN */
Curl_printable_address(h->addr, myhost, sizeof(myhost));
infof(data, "Name '%s' family %i resolved to '%s' family %i",
- host, af, myhost, h_af);
- Curl_resolv_unlink(data, &h); /* this will NULL, potential free h */
- if(af != h_af) {
+ dev, af, myhost, h->addr->ai_family);
+ Curl_resolv_unlock(data, h);
+ if(af != h->addr->ai_family) {
/* bad IP version combo, signal the caller to try another address
family if available */
return CURLE_UNSUPPORTED_PROTOCOL;
@@ -706,14 +531,14 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
else {
/*
* provided dev was no interface (or interfaces are not supported
- * e.g. Solaris) no ip address and no domain we fail here
+ * e.g. solaris) no ip address and no domain we fail here
*/
done = -1;
}
}
if(done > 0) {
-#ifdef USE_IPV6
+#ifdef ENABLE_IPV6
/* IPv6 address */
if(af == AF_INET6) {
#ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
@@ -728,7 +553,7 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
if(scope_ptr) {
/* The "myhost" string either comes from Curl_if2ip or from
Curl_printable_address. The latter returns only numeric scope
- IDs and the former returns none at all. So the scope ID, if
+ IDs and the former returns none at all. So the scope ID, if
present, is known to be numeric */
unsigned long scope_id = strtoul(scope_ptr, NULL, 10);
if(scope_id > UINT_MAX)
@@ -755,17 +580,14 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
/* errorbuf is set false so failf will overwrite any message already in
the error buffer, so the user receives this error message instead of a
generic resolve error. */
- char buffer[STRERROR_LEN];
data->state.errorbuf = FALSE;
- data->state.os_errno = error = SOCKERRNO;
- failf(data, "Couldn't bind to '%s' with errno %d: %s",
- host, error, Curl_strerror(error, buffer, sizeof(buffer)));
+ failf(data, "Couldn't bind to '%s'", dev);
return CURLE_INTERFACE_FAILED;
}
}
else {
/* no device was given, prepare sa to match af's needs */
-#ifdef USE_IPV6
+#ifdef ENABLE_IPV6
if(af == AF_INET6) {
si6->sin6_family = AF_INET6;
si6->sin6_port = htons(port);
@@ -785,6 +607,16 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
for(;;) {
if(bind(sockfd, sock, sizeof_sa) >= 0) {
/* we succeeded to bind */
+ struct Curl_sockaddr_storage add;
+ curl_socklen_t size = sizeof(add);
+ memset(&add, 0, sizeof(struct Curl_sockaddr_storage));
+ if(getsockname(sockfd, (struct sockaddr *) &add, &size) < 0) {
+ char buffer[STRERROR_LEN];
+ data->state.os_errno = error = SOCKERRNO;
+ failf(data, "getsockname() failed with errno %d: %s",
+ error, Curl_strerror(error, buffer, sizeof(buffer)));
+ return CURLE_INTERFACE_FAILED;
+ }
infof(data, "Local port: %hu", port);
conn->bits.bound = TRUE;
return CURLE_OK;
@@ -798,7 +630,7 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
/* We reuse/clobber the port variable here below */
if(sock->sa_family == AF_INET)
si4->sin_port = ntohs(port);
-#ifdef USE_IPV6
+#ifdef ENABLE_IPV6
else
si6->sin6_port = ntohs(port);
#endif
@@ -836,8 +668,8 @@ static bool verifyconnect(curl_socket_t sockfd, int *error)
* Gisle Vanem could reproduce the former problems with this function, but
* could avoid them by adding this SleepEx() call below:
*
- * "I do not have Rational Quantify, but the hint from his post was
- * ntdll::NtRemoveIoCompletion(). I would assume the SleepEx (or maybe
+ * "I don't have Rational Quantify, but the hint from his post was
+ * ntdll::NtRemoveIoCompletion(). So I'd assume the SleepEx (or maybe
* just Sleep(0) would be enough?) would release whatever
* mutex/critical-section the ntdll call is waiting on.
*
@@ -855,14 +687,14 @@ static bool verifyconnect(curl_socket_t sockfd, int *error)
if(0 != getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void *)&err, &errSize))
err = SOCKERRNO;
#ifdef _WIN32_WCE
- /* Old Windows CE versions do not support SO_ERROR */
+ /* Old WinCE versions don't support SO_ERROR */
if(WSAENOPROTOOPT == err) {
SET_SOCKERRNO(0);
err = 0;
}
#endif
#if defined(EBADIOCTL) && defined(__minix)
- /* Minix 3.1.x does not support getsockopt on UDP sockets */
+ /* Minix 3.1.x doesn't support getsockopt on UDP sockets */
if(EBADIOCTL == err) {
SET_SOCKERRNO(0);
err = 0;
@@ -872,7 +704,7 @@ static bool verifyconnect(curl_socket_t sockfd, int *error)
/* we are connected, awesome! */
rc = TRUE;
else
- /* This was not a successful connect */
+ /* This wasn't a successful connect */
rc = FALSE;
if(error)
*error = err;
@@ -934,14 +766,14 @@ struct cf_socket_ctx {
int transport;
struct Curl_sockaddr_ex addr; /* address to connect to */
curl_socket_t sock; /* current attempt socket */
- struct ip_quadruple ip; /* The IP quadruple 2x(addr+port) */
+ struct bufq recvbuf; /* used when `buffer_recv` is set */
+ char r_ip[MAX_IPADR_LEN]; /* remote IP as string */
+ int r_port; /* remote port number */
+ char l_ip[MAX_IPADR_LEN]; /* local IP as string */
+ int l_port; /* local port number */
struct curltime started_at; /* when socket was created */
struct curltime connected_at; /* when socket connected/got first byte */
struct curltime first_byte_at; /* when first byte was recvd */
-#ifdef USE_WINSOCK
- struct curltime last_sndbuf_query_at; /* when SO_SNDBUF last queried */
- ULONG sndbuf_size; /* the last set SO_SNDBUF size */
-#endif
int error; /* errno of last failure or 0 */
#ifdef DEBUGBUILD
int wblock_percent; /* percent of writes doing EAGAIN */
@@ -950,10 +782,9 @@ struct cf_socket_ctx {
size_t recv_max; /* max enforced read size */
#endif
BIT(got_first_byte); /* if first byte was received */
- BIT(listening); /* socket is listening */
BIT(accepted); /* socket was accepted, not connected */
- BIT(sock_connected); /* socket is "connected", e.g. in UDP */
BIT(active);
+ BIT(buffer_recv);
};
static void cf_socket_ctx_init(struct cf_socket_ctx *ctx,
@@ -964,6 +795,7 @@ static void cf_socket_ctx_init(struct cf_socket_ctx *ctx,
ctx->sock = CURL_SOCKET_BAD;
ctx->transport = transport;
Curl_sock_assign_addr(&ctx->addr, ai, transport);
+ Curl_bufq_init(&ctx->recvbuf, NW_RECV_CHUNK_SIZE, NW_RECV_CHUNKS);
#ifdef DEBUGBUILD
{
char *p = getenv("CURL_DBG_SOCK_WBLOCK");
@@ -994,19 +826,71 @@ static void cf_socket_ctx_init(struct cf_socket_ctx *ctx,
#endif
}
+struct reader_ctx {
+ struct Curl_cfilter *cf;
+ struct Curl_easy *data;
+};
+
+static ssize_t nw_in_read(void *reader_ctx,
+ unsigned char *buf, size_t len,
+ CURLcode *err)
+{
+ struct reader_ctx *rctx = reader_ctx;
+ struct cf_socket_ctx *ctx = rctx->cf->ctx;
+ ssize_t nread;
+
+ *err = CURLE_OK;
+ nread = sread(ctx->sock, buf, len);
+
+ if(-1 == nread) {
+ int sockerr = SOCKERRNO;
+
+ if(
+#ifdef WSAEWOULDBLOCK
+ /* This is how Windows does it */
+ (WSAEWOULDBLOCK == sockerr)
+#else
+ /* errno may be EWOULDBLOCK or on some systems EAGAIN when it returned
+ due to its inability to send off data without blocking. We therefore
+ treat both error codes the same here */
+ (EWOULDBLOCK == sockerr) || (EAGAIN == sockerr) || (EINTR == sockerr)
+#endif
+ ) {
+ /* this is just a case of EWOULDBLOCK */
+ *err = CURLE_AGAIN;
+ nread = -1;
+ }
+ else {
+ char buffer[STRERROR_LEN];
+
+ failf(rctx->data, "Recv failure: %s",
+ Curl_strerror(sockerr, buffer, sizeof(buffer)));
+ rctx->data->state.os_errno = sockerr;
+ *err = CURLE_RECV_ERROR;
+ nread = -1;
+ }
+ }
+ CURL_TRC_CF(rctx->data, rctx->cf, "nw_in_read(len=%zu) -> %d, err=%d",
+ len, (int)nread, *err);
+ return nread;
+}
+
static void cf_socket_close(struct Curl_cfilter *cf, struct Curl_easy *data)
{
struct cf_socket_ctx *ctx = cf->ctx;
if(ctx && CURL_SOCKET_BAD != ctx->sock) {
- CURL_TRC_CF(data, cf, "cf_socket_close(%" FMT_SOCKET_T ")", ctx->sock);
+ CURL_TRC_CF(data, cf, "cf_socket_close(%" CURL_FORMAT_SOCKET_T
+ ")", ctx->sock);
if(ctx->sock == cf->conn->sock[cf->sockindex])
cf->conn->sock[cf->sockindex] = CURL_SOCKET_BAD;
socket_close(data, cf->conn, !ctx->accepted, ctx->sock);
ctx->sock = CURL_SOCKET_BAD;
if(ctx->active && cf->sockindex == FIRSTSOCKET)
cf->conn->remote_addr = NULL;
+ Curl_bufq_reset(&ctx->recvbuf);
ctx->active = FALSE;
+ ctx->buffer_recv = FALSE;
memset(&ctx->started_at, 0, sizeof(ctx->started_at));
memset(&ctx->connected_at, 0, sizeof(ctx->connected_at));
}
@@ -1014,34 +898,13 @@ static void cf_socket_close(struct Curl_cfilter *cf, struct Curl_easy *data)
cf->connected = FALSE;
}
-static CURLcode cf_socket_shutdown(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- bool *done)
-{
- if(cf->connected) {
- struct cf_socket_ctx *ctx = cf->ctx;
-
- CURL_TRC_CF(data, cf, "cf_socket_shutdown(%" FMT_SOCKET_T ")", ctx->sock);
- /* On TCP, and when the socket looks well and non-blocking mode
- * can be enabled, receive dangling bytes before close to avoid
- * entering RST states unnecessarily. */
- if(ctx->sock != CURL_SOCKET_BAD &&
- ctx->transport == TRNSPRT_TCP &&
- (curlx_nonblock(ctx->sock, TRUE) >= 0)) {
- unsigned char buf[1024];
- (void)sread(ctx->sock, buf, sizeof(buf));
- }
- }
- *done = TRUE;
- return CURLE_OK;
-}
-
static void cf_socket_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
{
struct cf_socket_ctx *ctx = cf->ctx;
cf_socket_close(cf, data);
CURL_TRC_CF(data, cf, "destroy");
+ Curl_bufq_free(&ctx->recvbuf);
free(ctx);
cf->ctx = NULL;
}
@@ -1052,8 +915,7 @@ static CURLcode set_local_ip(struct Curl_cfilter *cf,
struct cf_socket_ctx *ctx = cf->ctx;
#ifdef HAVE_GETSOCKNAME
- if((ctx->sock != CURL_SOCKET_BAD) &&
- !(data->conn->handler->protocol & CURLPROTO_TFTP)) {
+ if(!(data->conn->handler->protocol & CURLPROTO_TFTP)) {
/* TFTP does not connect, so it cannot get the IP like this */
char buffer[STRERROR_LEN];
@@ -1068,7 +930,7 @@ static CURLcode set_local_ip(struct Curl_cfilter *cf,
return CURLE_FAILED_INIT;
}
if(!Curl_addr2string((struct sockaddr*)&ssloc, slen,
- ctx->ip.local_ip, &ctx->ip.local_port)) {
+ ctx->l_ip, &ctx->l_port)) {
failf(data, "ssloc inet_ntop() failed with errno %d: %s",
errno, Curl_strerror(errno, buffer, sizeof(buffer)));
return CURLE_FAILED_INIT;
@@ -1076,8 +938,8 @@ static CURLcode set_local_ip(struct Curl_cfilter *cf,
}
#else
(void)data;
- ctx->ip.local_ip[0] = 0;
- ctx->ip.local_port = -1;
+ ctx->l_ip[0] = 0;
+ ctx->l_port = -1;
#endif
return CURLE_OK;
}
@@ -1088,8 +950,8 @@ static CURLcode set_remote_ip(struct Curl_cfilter *cf,
struct cf_socket_ctx *ctx = cf->ctx;
/* store remote address and port used in this connection attempt */
- if(!Curl_addr2string(&ctx->addr.sa_addr, (curl_socklen_t)ctx->addr.addrlen,
- ctx->ip.remote_ip, &ctx->ip.remote_port)) {
+ if(!Curl_addr2string(&ctx->addr.sa_addr, ctx->addr.addrlen,
+ ctx->r_ip, &ctx->r_port)) {
char buffer[STRERROR_LEN];
ctx->error = errno;
@@ -1113,20 +975,7 @@ static CURLcode cf_socket_open(struct Curl_cfilter *cf,
(void)data;
DEBUGASSERT(ctx->sock == CURL_SOCKET_BAD);
ctx->started_at = Curl_now();
-#ifdef SOCK_NONBLOCK
- /* Do not tuck SOCK_NONBLOCK into socktype when opensocket callback is set
- * because we would not know how socketype is about to be used in the
- * callback, SOCK_NONBLOCK might get factored out before calling socket().
- */
- if(!data->set.fopensocket)
- ctx->addr.socktype |= SOCK_NONBLOCK;
-#endif
result = socket_open(data, &ctx->addr, &ctx->sock);
-#ifdef SOCK_NONBLOCK
- /* Restore the socktype after the socket is created. */
- if(!data->set.fopensocket)
- ctx->addr.socktype &= ~SOCK_NONBLOCK;
-#endif
if(result)
goto out;
@@ -1134,16 +983,22 @@ static CURLcode cf_socket_open(struct Curl_cfilter *cf,
if(result)
goto out;
-#ifdef USE_IPV6
- if(ctx->addr.family == AF_INET6) {
- set_ipv6_v6only(ctx->sock, 0);
- infof(data, " Trying [%s]:%d...", ctx->ip.remote_ip, ctx->ip.remote_port);
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+ {
+ const char *ipmsg;
+#ifdef ENABLE_IPV6
+ if(ctx->addr.family == AF_INET6) {
+ set_ipv6_v6only(ctx->sock, 0);
+ ipmsg = " Trying [%s]:%d...";
+ }
+ else
+#endif
+ ipmsg = " Trying %s:%d...";
+ infof(data, ipmsg, ctx->r_ip, ctx->r_port);
}
- else
#endif
- infof(data, " Trying %s:%d...", ctx->ip.remote_ip, ctx->ip.remote_port);
-#ifdef USE_IPV6
+#ifdef ENABLE_IPV6
is_tcp = (ctx->addr.family == AF_INET
|| ctx->addr.family == AF_INET6) &&
ctx->addr.socktype == SOCK_STREAM;
@@ -1156,7 +1011,7 @@ static CURLcode cf_socket_open(struct Curl_cfilter *cf,
nosigpipe(data, ctx->sock);
- Curl_sndbuf_init(ctx->sock);
+ Curl_sndbufset(ctx->sock);
if(is_tcp && data->set.tcp_keepalive)
tcpkeepalive(data, ctx->sock);
@@ -1180,7 +1035,7 @@ static CURLcode cf_socket_open(struct Curl_cfilter *cf,
#ifndef CURL_DISABLE_BINDLOCAL
/* possibly bind the local end to an IP, interface or port */
if(ctx->addr.family == AF_INET
-#ifdef USE_IPV6
+#ifdef ENABLE_IPV6
|| ctx->addr.family == AF_INET6
#endif
) {
@@ -1197,28 +1052,9 @@ static CURLcode cf_socket_open(struct Curl_cfilter *cf,
}
#endif
-#ifndef SOCK_NONBLOCK
- /* Set socket non-blocking, must be a non-blocking socket for
- * a non-blocking connect. */
- error = curlx_nonblock(ctx->sock, TRUE);
- if(error < 0) {
- result = CURLE_UNSUPPORTED_PROTOCOL;
- ctx->error = SOCKERRNO;
- goto out;
- }
-#else
- if(data->set.fopensocket) {
- /* Set socket non-blocking, must be a non-blocking socket for
- * a non-blocking connect. */
- error = curlx_nonblock(ctx->sock, TRUE);
- if(error < 0) {
- result = CURLE_UNSUPPORTED_PROTOCOL;
- ctx->error = SOCKERRNO;
- goto out;
- }
- }
-#endif
- ctx->sock_connected = (ctx->addr.socktype != SOCK_DGRAM);
+ /* set socket non-blocking */
+ (void)curlx_nonblock(ctx->sock, TRUE);
+
out:
if(result) {
if(ctx->sock != CURL_SOCKET_BAD) {
@@ -1231,7 +1067,7 @@ out:
ctx->connected_at = Curl_now();
cf->connected = TRUE;
}
- CURL_TRC_CF(data, cf, "cf_socket_open() -> %d, fd=%" FMT_SOCKET_T,
+ CURL_TRC_CF(data, cf, "cf_socket_open() -> %d, fd=%" CURL_FORMAT_SOCKET_T,
result, ctx->sock);
return result;
}
@@ -1273,8 +1109,8 @@ static int do_connect(struct Curl_cfilter *cf, struct Curl_easy *data,
#elif defined(TCP_FASTOPEN_CONNECT) /* Linux >= 4.11 */
if(setsockopt(ctx->sock, IPPROTO_TCP, TCP_FASTOPEN_CONNECT,
(void *)&optval, sizeof(optval)) < 0)
- infof(data, "Failed to enable TCP Fast Open on fd %" FMT_SOCKET_T,
- ctx->sock);
+ infof(data, "Failed to enable TCP Fast Open on fd %"
+ CURL_FORMAT_SOCKET_T, ctx->sock);
rc = connect(ctx->sock, &ctx->addr.sa_addr, ctx->addr.addrlen);
#elif defined(MSG_FASTOPEN) /* old Linux */
@@ -1285,8 +1121,7 @@ static int do_connect(struct Curl_cfilter *cf, struct Curl_easy *data,
#endif
}
else {
- rc = connect(ctx->sock, &ctx->addr.sa_addr,
- (curl_socklen_t)ctx->addr.addrlen);
+ rc = connect(ctx->sock, &ctx->addr.sa_addr, ctx->addr.addrlen);
}
return rc;
}
@@ -1327,9 +1162,9 @@ static CURLcode cf_tcp_connect(struct Curl_cfilter *cf,
error = SOCKERRNO;
set_local_ip(cf, data);
CURL_TRC_CF(data, cf, "local address %s port %d...",
- ctx->ip.local_ip, ctx->ip.local_port);
+ ctx->l_ip, ctx->l_port);
if(-1 == rc) {
- result = socket_connect_result(data, ctx->ip.remote_ip, error);
+ result = socket_connect_result(data, ctx->r_ip, error);
goto out;
}
}
@@ -1374,8 +1209,7 @@ out:
{
char buffer[STRERROR_LEN];
infof(data, "connect to %s port %u from %s port %d failed: %s",
- ctx->ip.remote_ip, ctx->ip.remote_port,
- ctx->ip.local_ip, ctx->ip.local_port,
+ ctx->r_ip, ctx->r_port, ctx->l_ip, ctx->l_port,
Curl_strerror(ctx->error, buffer, sizeof(buffer)));
}
#endif
@@ -1395,11 +1229,10 @@ static void cf_socket_get_host(struct Curl_cfilter *cf,
const char **pdisplay_host,
int *pport)
{
- struct cf_socket_ctx *ctx = cf->ctx;
(void)data;
*phost = cf->conn->host.name;
*pdisplay_host = cf->conn->host.dispname;
- *pport = ctx->ip.remote_port;
+ *pport = cf->conn->port;
}
static void cf_socket_adjust_pollset(struct Curl_cfilter *cf,
@@ -1409,25 +1242,11 @@ static void cf_socket_adjust_pollset(struct Curl_cfilter *cf,
struct cf_socket_ctx *ctx = cf->ctx;
if(ctx->sock != CURL_SOCKET_BAD) {
- /* A listening socket filter needs to be connected before the accept
- * for some weird FTP interaction. This should be rewritten, so that
- * FTP no longer does the socket checks and accept calls and delegates
- * all that to the filter. TODO. */
- if(ctx->listening) {
- Curl_pollset_set_in_only(data, ps, ctx->sock);
- CURL_TRC_CF(data, cf, "adjust_pollset, listening, POLLIN fd=%"
- FMT_SOCKET_T, ctx->sock);
- }
- else if(!cf->connected) {
+ if(!cf->connected)
Curl_pollset_set_out_only(data, ps, ctx->sock);
- CURL_TRC_CF(data, cf, "adjust_pollset, !connected, POLLOUT fd=%"
- FMT_SOCKET_T, ctx->sock);
- }
- else if(!ctx->active) {
+ else if(CURL_WANT_RECV(data))
Curl_pollset_add_in(data, ps, ctx->sock);
- CURL_TRC_CF(data, cf, "adjust_pollset, !active, POLLIN fd=%"
- FMT_SOCKET_T, ctx->sock);
- }
+ CURL_TRC_CF(data, cf, "adjust_pollset -> %d socks", ps->num);
}
}
@@ -1438,46 +1257,21 @@ static bool cf_socket_data_pending(struct Curl_cfilter *cf,
int readable;
(void)data;
+ if(!Curl_bufq_is_empty(&ctx->recvbuf))
+ return TRUE;
+
readable = SOCKET_READABLE(ctx->sock, 0);
return (readable > 0 && (readable & CURL_CSELECT_IN));
}
-#ifdef USE_WINSOCK
-
-#ifndef SIO_IDEAL_SEND_BACKLOG_QUERY
-#define SIO_IDEAL_SEND_BACKLOG_QUERY 0x4004747B
-#endif
-
-static void win_update_sndbuf_size(struct cf_socket_ctx *ctx)
-{
- ULONG ideal;
- DWORD ideallen;
- struct curltime n = Curl_now();
-
- if(Curl_timediff(n, ctx->last_sndbuf_query_at) > 1000) {
- if(!WSAIoctl(ctx->sock, SIO_IDEAL_SEND_BACKLOG_QUERY, 0, 0,
- &ideal, sizeof(ideal), &ideallen, 0, 0) &&
- ideal != ctx->sndbuf_size &&
- !setsockopt(ctx->sock, SOL_SOCKET, SO_SNDBUF,
- (const char *)&ideal, sizeof(ideal))) {
- ctx->sndbuf_size = ideal;
- }
- ctx->last_sndbuf_query_at = n;
- }
-}
-
-#endif /* USE_WINSOCK */
-
static ssize_t cf_socket_send(struct Curl_cfilter *cf, struct Curl_easy *data,
- const void *buf, size_t len, bool eos,
- CURLcode *err)
+ const void *buf, size_t len, CURLcode *err)
{
struct cf_socket_ctx *ctx = cf->ctx;
curl_socket_t fdsave;
ssize_t nwritten;
size_t orig_len = len;
- (void)eos; /* unused */
*err = CURLE_OK;
fdsave = cf->conn->sock[cf->sockindex];
cf->conn->sock[cf->sockindex] = ctx->sock;
@@ -1485,8 +1279,8 @@ static ssize_t cf_socket_send(struct Curl_cfilter *cf, struct Curl_easy *data,
#ifdef DEBUGBUILD
/* simulate network blocking/partial writes */
if(ctx->wblock_percent > 0) {
- unsigned char c = 0;
- Curl_rand_bytes(data, FALSE, &c, 1);
+ unsigned char c;
+ Curl_rand(data, &c, 1);
if(c >= ((100-ctx->wblock_percent)*256/100)) {
CURL_TRC_CF(data, cf, "send(len=%zu) SIMULATE EWOULDBLOCK", orig_len);
*err = CURLE_AGAIN;
@@ -1542,11 +1336,6 @@ static ssize_t cf_socket_send(struct Curl_cfilter *cf, struct Curl_easy *data,
}
}
-#if defined(USE_WINSOCK)
- if(!*err)
- win_update_sndbuf_size(ctx);
-#endif
-
CURL_TRC_CF(data, cf, "send(len=%zu) -> %d, err=%d",
orig_len, (int)nwritten, *err);
cf->conn->sock[cf->sockindex] = fdsave;
@@ -1557,19 +1346,25 @@ static ssize_t cf_socket_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
char *buf, size_t len, CURLcode *err)
{
struct cf_socket_ctx *ctx = cf->ctx;
+ curl_socket_t fdsave;
ssize_t nread;
*err = CURLE_OK;
+ fdsave = cf->conn->sock[cf->sockindex];
+ cf->conn->sock[cf->sockindex] = ctx->sock;
+
#ifdef DEBUGBUILD
/* simulate network blocking/partial reads */
if(cf->cft != &Curl_cft_udp && ctx->rblock_percent > 0) {
- unsigned char c = 0;
+ unsigned char c;
Curl_rand(data, &c, 1);
if(c >= ((100-ctx->rblock_percent)*256/100)) {
CURL_TRC_CF(data, cf, "recv(len=%zu) SIMULATE EWOULDBLOCK", len);
*err = CURLE_AGAIN;
- return -1;
+ nread = -1;
+ cf->conn->sock[cf->sockindex] = fdsave;
+ return nread;
}
}
if(cf->cft != &Curl_cft_udp && ctx->recv_max && ctx->recv_max < len) {
@@ -1580,55 +1375,90 @@ static ssize_t cf_socket_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
}
#endif
- *err = CURLE_OK;
- nread = sread(ctx->sock, buf, len);
-
- if(-1 == nread) {
- int sockerr = SOCKERRNO;
-
- if(
-#ifdef WSAEWOULDBLOCK
- /* This is how Windows does it */
- (WSAEWOULDBLOCK == sockerr)
-#else
- /* errno may be EWOULDBLOCK or on some systems EAGAIN when it returned
- due to its inability to send off data without blocking. We therefore
- treat both error codes the same here */
- (EWOULDBLOCK == sockerr) || (EAGAIN == sockerr) || (EINTR == sockerr)
-#endif
- ) {
- /* this is just a case of EWOULDBLOCK */
- *err = CURLE_AGAIN;
+ if(ctx->buffer_recv && !Curl_bufq_is_empty(&ctx->recvbuf)) {
+ CURL_TRC_CF(data, cf, "recv from buffer");
+ nread = Curl_bufq_read(&ctx->recvbuf, (unsigned char *)buf, len, err);
+ }
+ else {
+ struct reader_ctx rctx;
+
+ rctx.cf = cf;
+ rctx.data = data;
+
+ /* "small" reads may trigger filling our buffer, "large" reads
+ * are probably not worth the additional copy */
+ if(ctx->buffer_recv && len < NW_SMALL_READS) {
+ ssize_t nwritten;
+ nwritten = Curl_bufq_slurp(&ctx->recvbuf, nw_in_read, &rctx, err);
+ if(nwritten < 0 && !Curl_bufq_is_empty(&ctx->recvbuf)) {
+ /* we have a partial read with an error. need to deliver
+ * what we got, return the error later. */
+ CURL_TRC_CF(data, cf, "partial read: empty buffer first");
+ nread = Curl_bufq_read(&ctx->recvbuf, (unsigned char *)buf, len, err);
+ }
+ else if(nwritten < 0) {
+ nread = -1;
+ goto out;
+ }
+ else if(nwritten == 0) {
+ /* eof */
+ *err = CURLE_OK;
+ nread = 0;
+ }
+ else {
+ CURL_TRC_CF(data, cf, "buffered %zd additional bytes", nwritten);
+ nread = Curl_bufq_read(&ctx->recvbuf, (unsigned char *)buf, len, err);
+ }
}
else {
- char buffer[STRERROR_LEN];
-
- failf(data, "Recv failure: %s",
- Curl_strerror(sockerr, buffer, sizeof(buffer)));
- data->state.os_errno = sockerr;
- *err = CURLE_RECV_ERROR;
+ nread = nw_in_read(&rctx, (unsigned char *)buf, len, err);
}
}
+out:
CURL_TRC_CF(data, cf, "recv(len=%zu) -> %d, err=%d", len, (int)nread,
*err);
if(nread > 0 && !ctx->got_first_byte) {
ctx->first_byte_at = Curl_now();
ctx->got_first_byte = TRUE;
}
+ cf->conn->sock[cf->sockindex] = fdsave;
return nread;
}
-static void cf_socket_update_data(struct Curl_cfilter *cf,
- struct Curl_easy *data)
+static void conn_set_primary_ip(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
- /* Update the IP info held in the transfer, if we have that. */
- if(cf->connected && (cf->sockindex == FIRSTSOCKET)) {
- struct cf_socket_ctx *ctx = cf->ctx;
- data->info.primary = ctx->ip;
- /* not sure if this is redundant... */
- data->info.conn_remote_port = cf->conn->remote_port;
+#ifdef HAVE_GETPEERNAME
+ struct cf_socket_ctx *ctx = cf->ctx;
+ if(!(data->conn->handler->protocol & CURLPROTO_TFTP)) {
+ /* TFTP does not connect the endpoint: getpeername() failed with errno
+ 107: Transport endpoint is not connected */
+
+ char buffer[STRERROR_LEN];
+ struct Curl_sockaddr_storage ssrem;
+ curl_socklen_t plen;
+ int port;
+
+ plen = sizeof(ssrem);
+ memset(&ssrem, 0, plen);
+ if(getpeername(ctx->sock, (struct sockaddr*) &ssrem, &plen)) {
+ int error = SOCKERRNO;
+ failf(data, "getpeername() failed with errno %d: %s",
+ error, Curl_strerror(error, buffer, sizeof(buffer)));
+ return;
+ }
+ if(!Curl_addr2string((struct sockaddr*)&ssrem, plen,
+ cf->conn->primary_ip, &port)) {
+ failf(data, "ssrem inet_ntop() failed with errno %d: %s",
+ errno, Curl_strerror(errno, buffer, sizeof(buffer)));
+ return;
+ }
}
+#else
+ cf->conn->primary_ip[0] = 0;
+ (void)data;
+#endif
}
static void cf_socket_active(struct Curl_cfilter *cf, struct Curl_easy *data)
@@ -1637,16 +1467,20 @@ static void cf_socket_active(struct Curl_cfilter *cf, struct Curl_easy *data)
/* use this socket from now on */
cf->conn->sock[cf->sockindex] = ctx->sock;
- set_local_ip(cf, data);
+ /* the first socket info gets set at conn and data */
if(cf->sockindex == FIRSTSOCKET) {
- cf->conn->primary = ctx->ip;
cf->conn->remote_addr = &ctx->addr;
- #ifdef USE_IPV6
+ #ifdef ENABLE_IPV6
cf->conn->bits.ipv6 = (ctx->addr.family == AF_INET6)? TRUE : FALSE;
#endif
- }
- else {
- cf->conn->secondary = ctx->ip;
+ conn_set_primary_ip(cf, data);
+ set_local_ip(cf, data);
+ Curl_persistconninfo(data, cf->conn, ctx->l_ip, ctx->l_port);
+ /* buffering is currently disabled by default because we have stalls
+ * in parallel transfers where not all buffered data is consumed and no
+ * socket events happen.
+ */
+ ctx->buffer_recv = FALSE;
}
ctx->active = TRUE;
}
@@ -1662,10 +1496,9 @@ static CURLcode cf_socket_cntrl(struct Curl_cfilter *cf,
switch(event) {
case CF_CTRL_CONN_INFO_UPDATE:
cf_socket_active(cf, data);
- cf_socket_update_data(cf, data);
break;
case CF_CTRL_DATA_SETUP:
- cf_socket_update_data(cf, data);
+ Curl_persistconninfo(data, cf->conn, ctx->l_ip, ctx->l_port);
break;
case CF_CTRL_FORGET_SOCKET:
ctx->sock = CURL_SOCKET_BAD;
@@ -1741,21 +1574,13 @@ static CURLcode cf_socket_query(struct Curl_cfilter *cf,
*when = ctx->first_byte_at;
break;
}
- FALLTHROUGH();
+ /* FALLTHROUGH */
default:
*when = ctx->connected_at;
break;
}
return CURLE_OK;
}
- case CF_QUERY_IP_INFO:
-#ifdef USE_IPV6
- *pres1 = (ctx->addr.family == AF_INET6)? TRUE : FALSE;
-#else
- *pres1 = FALSE;
-#endif
- *(struct ip_quadruple *)pres2 = ctx->ip;
- return CURLE_OK;
default:
break;
}
@@ -1771,7 +1596,6 @@ struct Curl_cftype Curl_cft_tcp = {
cf_socket_destroy,
cf_tcp_connect,
cf_socket_close,
- cf_socket_shutdown,
cf_socket_get_host,
cf_socket_adjust_pollset,
cf_socket_data_pending,
@@ -1816,35 +1640,25 @@ out:
}
static CURLcode cf_udp_setup_quic(struct Curl_cfilter *cf,
- struct Curl_easy *data)
+ struct Curl_easy *data)
{
struct cf_socket_ctx *ctx = cf->ctx;
int rc;
- int one = 1;
-
- (void)one;
/* QUIC needs a connected socket, nonblocking */
DEBUGASSERT(ctx->sock != CURL_SOCKET_BAD);
- rc = connect(ctx->sock, &ctx->addr.sa_addr,
- (curl_socklen_t)ctx->addr.addrlen);
+ rc = connect(ctx->sock, &ctx->addr.sa_addr, ctx->addr.addrlen);
if(-1 == rc) {
- return socket_connect_result(data, ctx->ip.remote_ip, SOCKERRNO);
+ return socket_connect_result(data, ctx->r_ip, SOCKERRNO);
}
- ctx->sock_connected = TRUE;
set_local_ip(cf, data);
- CURL_TRC_CF(data, cf, "%s socket %" FMT_SOCKET_T
+ CURL_TRC_CF(data, cf, "%s socket %" CURL_FORMAT_SOCKET_T
" connected: [%s:%d] -> [%s:%d]",
(ctx->transport == TRNSPRT_QUIC)? "QUIC" : "UDP",
- ctx->sock, ctx->ip.local_ip, ctx->ip.local_port,
- ctx->ip.remote_ip, ctx->ip.remote_port);
+ ctx->sock, ctx->l_ip, ctx->l_port, ctx->r_ip, ctx->r_port);
- /* Currently, cf->ctx->sock is always non-blocking because the only
- * caller to cf_udp_setup_quic() is cf_udp_connect() that passes the
- * non-blocking socket created by cf_socket_open() to it. Thus, we
- * do not need to call curlx_nonblock() in cf_udp_setup_quic() anymore.
- */
+ (void)curlx_nonblock(ctx->sock, TRUE);
switch(ctx->addr.family) {
#if defined(__linux__) && defined(IP_MTU_DISCOVER)
case AF_INET: {
@@ -1863,14 +1677,6 @@ static CURLcode cf_udp_setup_quic(struct Curl_cfilter *cf,
}
#endif
}
-
-#if defined(__linux__) && defined(UDP_GRO) && \
- (defined(HAVE_SENDMMSG) || defined(HAVE_SENDMSG)) && \
- ((defined(USE_NGTCP2) && defined(USE_NGHTTP3)) || defined(USE_QUICHE))
- (void)setsockopt(ctx->sock, IPPROTO_UDP, UDP_GRO, &one,
- (socklen_t)sizeof(one));
-#endif
-
return CURLE_OK;
}
@@ -1899,12 +1705,12 @@ static CURLcode cf_udp_connect(struct Curl_cfilter *cf,
if(result)
goto out;
CURL_TRC_CF(data, cf, "cf_udp_connect(), opened socket=%"
- FMT_SOCKET_T " (%s:%d)",
- ctx->sock, ctx->ip.local_ip, ctx->ip.local_port);
+ CURL_FORMAT_SOCKET_T " (%s:%d)",
+ ctx->sock, ctx->l_ip, ctx->l_port);
}
else {
CURL_TRC_CF(data, cf, "cf_udp_connect(), opened socket=%"
- FMT_SOCKET_T " (unconnected)", ctx->sock);
+ CURL_FORMAT_SOCKET_T " (unconnected)", ctx->sock);
}
*done = TRUE;
cf->connected = TRUE;
@@ -1920,7 +1726,6 @@ struct Curl_cftype Curl_cft_udp = {
cf_socket_destroy,
cf_udp_connect,
cf_socket_close,
- cf_socket_shutdown,
cf_socket_get_host,
cf_socket_adjust_pollset,
cf_socket_data_pending,
@@ -1972,7 +1777,6 @@ struct Curl_cftype Curl_cft_unix = {
cf_socket_destroy,
cf_tcp_connect,
cf_socket_close,
- cf_socket_shutdown,
cf_socket_get_host,
cf_socket_adjust_pollset,
cf_socket_data_pending,
@@ -2037,7 +1841,6 @@ struct Curl_cftype Curl_cft_tcp_accept = {
cf_socket_destroy,
cf_tcp_accept_connect,
cf_socket_close,
- cf_socket_shutdown,
cf_socket_get_host, /* TODO: not accurate */
cf_socket_adjust_pollset,
cf_socket_data_pending,
@@ -2068,7 +1871,6 @@ CURLcode Curl_conn_tcp_listen_set(struct Curl_easy *data,
}
ctx->transport = conn->transport;
ctx->sock = *s;
- ctx->listening = TRUE;
ctx->accepted = FALSE;
result = Curl_cf_create(&cf, &Curl_cft_tcp_accept, ctx);
if(result)
@@ -2080,8 +1882,8 @@ CURLcode Curl_conn_tcp_listen_set(struct Curl_easy *data,
ctx->active = TRUE;
ctx->connected_at = Curl_now();
cf->connected = TRUE;
- CURL_TRC_CF(data, cf, "Curl_conn_tcp_listen_set(%" FMT_SOCKET_T ")",
- ctx->sock);
+ CURL_TRC_CF(data, cf, "Curl_conn_tcp_listen_set(%"
+ CURL_FORMAT_SOCKET_T ")", ctx->sock);
out:
if(result) {
@@ -2100,8 +1902,8 @@ static void set_accepted_remote_ip(struct Curl_cfilter *cf,
struct Curl_sockaddr_storage ssrem;
curl_socklen_t plen;
- ctx->ip.remote_ip[0] = 0;
- ctx->ip.remote_port = 0;
+ ctx->r_ip[0] = 0;
+ ctx->r_port = 0;
plen = sizeof(ssrem);
memset(&ssrem, 0, plen);
if(getpeername(ctx->sock, (struct sockaddr*) &ssrem, &plen)) {
@@ -2111,14 +1913,14 @@ static void set_accepted_remote_ip(struct Curl_cfilter *cf,
return;
}
if(!Curl_addr2string((struct sockaddr*)&ssrem, plen,
- ctx->ip.remote_ip, &ctx->ip.remote_port)) {
+ ctx->r_ip, &ctx->r_port)) {
failf(data, "ssrem inet_ntop() failed with errno %d: %s",
errno, Curl_strerror(errno, buffer, sizeof(buffer)));
return;
}
#else
- ctx->ip.remote_ip[0] = 0;
- ctx->ip.remote_port = 0;
+ ctx->r_ip[0] = 0;
+ ctx->r_port = 0;
(void)data;
#endif
}
@@ -2135,10 +1937,8 @@ CURLcode Curl_conn_tcp_accepted_set(struct Curl_easy *data,
return CURLE_FAILED_INIT;
ctx = cf->ctx;
- DEBUGASSERT(ctx->listening);
/* discard the listen socket */
socket_close(data, conn, TRUE, ctx->sock);
- ctx->listening = FALSE;
ctx->sock = *s;
conn->sock[sockindex] = ctx->sock;
set_accepted_remote_ip(cf, data);
@@ -2147,9 +1947,9 @@ CURLcode Curl_conn_tcp_accepted_set(struct Curl_easy *data,
ctx->accepted = TRUE;
ctx->connected_at = Curl_now();
cf->connected = TRUE;
- CURL_TRC_CF(data, cf, "accepted_set(sock=%" FMT_SOCKET_T
+ CURL_TRC_CF(data, cf, "accepted_set(sock=%" CURL_FORMAT_SOCKET_T
", remote=%s port=%d)",
- ctx->sock, ctx->ip.remote_ip, ctx->ip.remote_port);
+ ctx->sock, ctx->r_ip, ctx->r_port);
return CURLE_OK;
}
@@ -2169,9 +1969,9 @@ CURLcode Curl_cf_socket_peek(struct Curl_cfilter *cf,
struct Curl_easy *data,
curl_socket_t *psock,
const struct Curl_sockaddr_ex **paddr,
- struct ip_quadruple *pip)
+ const char **pr_ip_str, int *pr_port,
+ const char **pl_ip_str, int *pl_port)
{
- (void)data;
if(cf_is_socket(cf) && cf->ctx) {
struct cf_socket_ctx *ctx = cf->ctx;
@@ -2179,8 +1979,17 @@ CURLcode Curl_cf_socket_peek(struct Curl_cfilter *cf,
*psock = ctx->sock;
if(paddr)
*paddr = &ctx->addr;
- if(pip)
- *pip = ctx->ip;
+ if(pr_ip_str)
+ *pr_ip_str = ctx->r_ip;
+ if(pr_port)
+ *pr_port = ctx->r_port;
+ if(pl_port ||pl_ip_str) {
+ set_local_ip(cf, data);
+ if(pl_ip_str)
+ *pl_ip_str = ctx->l_ip;
+ if(pl_port)
+ *pl_port = ctx->l_port;
+ }
return CURLE_OK;
}
return CURLE_FAILED_INIT;
diff --git a/contrib/libs/curl/lib/cf-socket.h b/contrib/libs/curl/lib/cf-socket.h
index 35225f153c..1d40df737f 100644
--- a/contrib/libs/curl/lib/cf-socket.h
+++ b/contrib/libs/curl/lib/cf-socket.h
@@ -33,7 +33,23 @@ struct Curl_cfilter;
struct Curl_easy;
struct connectdata;
struct Curl_sockaddr_ex;
-struct ip_quadruple;
+
+#ifndef SIZEOF_CURL_SOCKET_T
+/* configure and cmake check and set the define */
+# ifdef _WIN64
+# define SIZEOF_CURL_SOCKET_T 8
+# else
+/* default guess */
+# define SIZEOF_CURL_SOCKET_T 4
+# endif
+#endif
+
+#if SIZEOF_CURL_SOCKET_T < 8
+# define CURL_FORMAT_SOCKET_T "d"
+#else
+# define CURL_FORMAT_SOCKET_T "qd"
+#endif
+
/*
* The Curl_sockaddr_ex structure is basically libcurl's external API
@@ -54,11 +70,6 @@ struct Curl_sockaddr_ex {
};
#define sa_addr _sa_ex_u.addr
-/*
- * Parse interface option, and return the interface name and the host part.
-*/
-CURLcode Curl_parse_interface(const char *input,
- char **dev, char **iface, char **host);
/*
* Create a socket based on info from 'conn' and 'ai'.
@@ -86,9 +97,9 @@ int Curl_socket_close(struct Curl_easy *data, struct connectdata *conn,
Buffer Size
*/
-void Curl_sndbuf_init(curl_socket_t sockfd);
+void Curl_sndbufset(curl_socket_t sockfd);
#else
-#define Curl_sndbuf_init(y) Curl_nop_stmt
+#define Curl_sndbufset(y) Curl_nop_stmt
#endif
/**
@@ -159,14 +170,18 @@ CURLcode Curl_conn_tcp_accepted_set(struct Curl_easy *data,
* The filter owns all returned values.
* @param psock pointer to hold socket descriptor or NULL
* @param paddr pointer to hold addr reference or NULL
- * @param pip pointer to get IP quadruple or NULL
+ * @param pr_ip_str pointer to hold remote addr as string or NULL
+ * @param pr_port pointer to hold remote port number or NULL
+ * @param pl_ip_str pointer to hold local addr as string or NULL
+ * @param pl_port pointer to hold local port number or NULL
* Returns error if the filter is of invalid type.
*/
CURLcode Curl_cf_socket_peek(struct Curl_cfilter *cf,
struct Curl_easy *data,
curl_socket_t *psock,
const struct Curl_sockaddr_ex **paddr,
- struct ip_quadruple *pip);
+ const char **pr_ip_str, int *pr_port,
+ const char **pl_ip_str, int *pl_port);
extern struct Curl_cftype Curl_cft_tcp;
extern struct Curl_cftype Curl_cft_udp;
diff --git a/contrib/libs/curl/lib/cfilters.c b/contrib/libs/curl/lib/cfilters.c
index 3d7da0c69c..e78ecd71de 100644
--- a/contrib/libs/curl/lib/cfilters.c
+++ b/contrib/libs/curl/lib/cfilters.c
@@ -45,10 +45,7 @@
#define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
#endif
-static void cf_cntrl_update_info(struct Curl_easy *data,
- struct connectdata *conn);
-
-#ifdef UNITTESTS
+#ifdef DEBUGBUILD
/* used by unit2600.c */
void Curl_cf_def_close(struct Curl_cfilter *cf, struct Curl_easy *data)
{
@@ -58,15 +55,6 @@ void Curl_cf_def_close(struct Curl_cfilter *cf, struct Curl_easy *data)
}
#endif
-CURLcode Curl_cf_def_shutdown(struct Curl_cfilter *cf,
- struct Curl_easy *data, bool *done)
-{
- (void)cf;
- (void)data;
- *done = TRUE;
- return CURLE_OK;
-}
-
static void conn_report_connect_stats(struct Curl_easy *data,
struct connectdata *conn);
@@ -79,7 +67,7 @@ void Curl_cf_def_get_host(struct Curl_cfilter *cf, struct Curl_easy *data,
else {
*phost = cf->conn->host.name;
*pdisplay_host = cf->conn->host.dispname;
- *pport = cf->conn->primary.remote_port;
+ *pport = cf->conn->port;
}
}
@@ -101,11 +89,10 @@ bool Curl_cf_def_data_pending(struct Curl_cfilter *cf,
}
ssize_t Curl_cf_def_send(struct Curl_cfilter *cf, struct Curl_easy *data,
- const void *buf, size_t len, bool eos,
- CURLcode *err)
+ const void *buf, size_t len, CURLcode *err)
{
return cf->next?
- cf->next->cft->do_send(cf->next, data, buf, len, eos, err) :
+ cf->next->cft->do_send(cf->next, data, buf, len, err) :
CURLE_RECV_ERROR;
}
@@ -179,104 +166,40 @@ void Curl_conn_close(struct Curl_easy *data, int index)
if(cf) {
cf->cft->do_close(cf, data);
}
- Curl_shutdown_clear(data, index);
}
-CURLcode Curl_conn_shutdown(struct Curl_easy *data, int sockindex, bool *done)
-{
- struct Curl_cfilter *cf;
- CURLcode result = CURLE_OK;
- timediff_t timeout_ms;
- struct curltime now;
-
- DEBUGASSERT(data->conn);
- /* Get the first connected filter that is not shut down already. */
- cf = data->conn->cfilter[sockindex];
- while(cf && (!cf->connected || cf->shutdown))
- cf = cf->next;
-
- if(!cf) {
- *done = TRUE;
- return CURLE_OK;
- }
-
- *done = FALSE;
- now = Curl_now();
- if(!Curl_shutdown_started(data, sockindex)) {
- DEBUGF(infof(data, "shutdown start on%s connection",
- sockindex? " secondary" : ""));
- Curl_shutdown_start(data, sockindex, &now);
- }
- else {
- timeout_ms = Curl_shutdown_timeleft(data->conn, sockindex, &now);
- if(timeout_ms < 0) {
- failf(data, "SSL shutdown timeout");
- return CURLE_OPERATION_TIMEDOUT;
- }
- }
-
- while(cf) {
- if(!cf->shutdown) {
- bool cfdone = FALSE;
- result = cf->cft->do_shutdown(cf, data, &cfdone);
- if(result) {
- CURL_TRC_CF(data, cf, "shut down failed with %d", result);
- return result;
- }
- else if(!cfdone) {
- CURL_TRC_CF(data, cf, "shut down not done yet");
- return CURLE_OK;
- }
- CURL_TRC_CF(data, cf, "shut down successfully");
- cf->shutdown = TRUE;
- }
- cf = cf->next;
- }
- *done = (!result);
- return result;
-}
-
-ssize_t Curl_cf_recv(struct Curl_easy *data, int num, char *buf,
- size_t len, CURLcode *code)
+ssize_t Curl_conn_recv(struct Curl_easy *data, int num, char *buf,
+ size_t len, CURLcode *code)
{
struct Curl_cfilter *cf;
DEBUGASSERT(data);
DEBUGASSERT(data->conn);
- *code = CURLE_OK;
cf = data->conn->cfilter[num];
while(cf && !cf->connected) {
cf = cf->next;
}
if(cf) {
- ssize_t nread = cf->cft->do_recv(cf, data, buf, len, code);
- DEBUGASSERT(nread >= 0 || *code);
- DEBUGASSERT(nread < 0 || !*code);
- return nread;
+ return cf->cft->do_recv(cf, data, buf, len, code);
}
failf(data, "recv: no filter connected");
*code = CURLE_FAILED_INIT;
return -1;
}
-ssize_t Curl_cf_send(struct Curl_easy *data, int num,
- const void *mem, size_t len, bool eos,
- CURLcode *code)
+ssize_t Curl_conn_send(struct Curl_easy *data, int num,
+ const void *mem, size_t len, CURLcode *code)
{
struct Curl_cfilter *cf;
DEBUGASSERT(data);
DEBUGASSERT(data->conn);
- *code = CURLE_OK;
cf = data->conn->cfilter[num];
while(cf && !cf->connected) {
cf = cf->next;
}
if(cf) {
- ssize_t nwritten = cf->cft->do_send(cf, data, mem, len, eos, code);
- DEBUGASSERT(nwritten >= 0 || *code);
- DEBUGASSERT(nwritten < 0 || !*code || !len);
- return nwritten;
+ return cf->cft->do_send(cf, data, mem, len, code);
}
failf(data, "send: no filter connected");
DEBUGASSERT(0);
@@ -384,11 +307,10 @@ void Curl_conn_cf_close(struct Curl_cfilter *cf, struct Curl_easy *data)
}
ssize_t Curl_conn_cf_send(struct Curl_cfilter *cf, struct Curl_easy *data,
- const void *buf, size_t len, bool eos,
- CURLcode *err)
+ const void *buf, size_t len, CURLcode *err)
{
if(cf)
- return cf->cft->do_send(cf, data, buf, len, eos, err);
+ return cf->cft->do_send(cf, data, buf, len, err);
*err = CURLE_SEND_ERROR;
return -1;
}
@@ -415,29 +337,16 @@ CURLcode Curl_conn_connect(struct Curl_easy *data,
cf = data->conn->cfilter[sockindex];
DEBUGASSERT(cf);
- if(!cf) {
- *done = FALSE;
+ if(!cf)
return CURLE_FAILED_INIT;
- }
*done = cf->connected;
if(!*done) {
- if(Curl_conn_needs_flush(data, sockindex)) {
- DEBUGF(infof(data, "Curl_conn_connect(index=%d), flush", sockindex));
- result = Curl_conn_flush(data, sockindex);
- if(result && (result != CURLE_AGAIN))
- return result;
- }
-
result = cf->cft->do_connect(cf, data, blocking, done);
if(!result && *done) {
- /* Now that the complete filter chain is connected, let all filters
- * persist information at the connection. E.g. cf-socket sets the
- * socket and ip related information. */
- cf_cntrl_update_info(data, data->conn);
+ Curl_conn_ev_update_info(data, data->conn);
conn_report_connect_stats(data, data->conn);
data->conn->keepalive = Curl_now();
- Curl_verboseconnect(data, data->conn, sockindex);
}
else if(result) {
conn_report_connect_stats(data, data->conn);
@@ -518,21 +427,6 @@ bool Curl_conn_data_pending(struct Curl_easy *data, int sockindex)
return FALSE;
}
-bool Curl_conn_cf_needs_flush(struct Curl_cfilter *cf,
- struct Curl_easy *data)
-{
- CURLcode result;
- int pending = FALSE;
- result = cf? cf->cft->query(cf, data, CF_QUERY_NEED_FLUSH,
- &pending, NULL) : CURLE_UNKNOWN_OPTION;
- return (result || pending == FALSE)? FALSE : TRUE;
-}
-
-bool Curl_conn_needs_flush(struct Curl_easy *data, int sockindex)
-{
- return Curl_conn_cf_needs_flush(data->conn->cfilter[sockindex], data);
-}
-
void Curl_conn_cf_adjust_pollset(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct easy_pollset *ps)
@@ -540,9 +434,6 @@ void Curl_conn_cf_adjust_pollset(struct Curl_cfilter *cf,
/* Get the lowest not-connected filter, if there are any */
while(cf && !cf->connected && cf->next && !cf->next->connected)
cf = cf->next;
- /* Skip all filters that have already shut down */
- while(cf && cf->shutdown)
- cf = cf->next;
/* From there on, give all filters a chance to adjust the pollset.
* Lower filters are called later, so they may override */
while(cf) {
@@ -563,42 +454,6 @@ void Curl_conn_adjust_pollset(struct Curl_easy *data,
}
}
-int Curl_conn_cf_poll(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- timediff_t timeout_ms)
-{
- struct easy_pollset ps;
- struct pollfd pfds[MAX_SOCKSPEREASYHANDLE];
- unsigned int i, npfds = 0;
-
- DEBUGASSERT(cf);
- DEBUGASSERT(data);
- DEBUGASSERT(data->conn);
- memset(&ps, 0, sizeof(ps));
- memset(pfds, 0, sizeof(pfds));
-
- Curl_conn_cf_adjust_pollset(cf, data, &ps);
- DEBUGASSERT(ps.num <= MAX_SOCKSPEREASYHANDLE);
- for(i = 0; i < ps.num; ++i) {
- short events = 0;
- if(ps.actions[i] & CURL_POLL_IN) {
- events |= POLLIN;
- }
- if(ps.actions[i] & CURL_POLL_OUT) {
- events |= POLLOUT;
- }
- if(events) {
- pfds[npfds].fd = ps.sockets[i];
- pfds[npfds].events = events;
- ++npfds;
- }
- }
-
- if(!npfds)
- DEBUGF(infof(data, "no sockets to poll!"));
- return Curl_poll(pfds, npfds, timeout_ms);
-}
-
void Curl_conn_get_host(struct Curl_easy *data, int sockindex,
const char **phost, const char **pdisplay_host,
int *pport)
@@ -659,15 +514,6 @@ curl_socket_t Curl_conn_cf_get_socket(struct Curl_cfilter *cf,
return CURL_SOCKET_BAD;
}
-CURLcode Curl_conn_cf_get_ip_info(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- int *is_ipv6, struct ip_quadruple *ipquad)
-{
- if(cf)
- return cf->cft->query(cf, data, CF_QUERY_IP_INFO, is_ipv6, ipquad);
- return CURLE_UNKNOWN_OPTION;
-}
-
curl_socket_t Curl_conn_get_socket(struct Curl_easy *data, int sockindex)
{
struct Curl_cfilter *cf;
@@ -734,16 +580,9 @@ CURLcode Curl_conn_ev_data_idle(struct Curl_easy *data)
CF_CTRL_DATA_IDLE, 0, NULL);
}
-
-CURLcode Curl_conn_flush(struct Curl_easy *data, int sockindex)
-{
- return Curl_conn_cf_cntrl(data->conn->cfilter[sockindex], data, FALSE,
- CF_CTRL_FLUSH, 0, NULL);
-}
-
/**
* Notify connection filters that the transfer represented by `data`
- * is done with sending data (e.g. has uploaded everything).
+ * is donw with sending data (e.g. has uploaded everything).
*/
void Curl_conn_ev_data_done_send(struct Curl_easy *data)
{
@@ -765,8 +604,8 @@ CURLcode Curl_conn_ev_data_pause(struct Curl_easy *data, bool do_pause)
CF_CTRL_DATA_PAUSE, do_pause, NULL);
}
-static void cf_cntrl_update_info(struct Curl_easy *data,
- struct connectdata *conn)
+void Curl_conn_ev_update_info(struct Curl_easy *data,
+ struct connectdata *conn)
{
cf_cntrl_all(conn, data, TRUE, CF_CTRL_CONN_INFO_UPDATE, 0, NULL);
}
@@ -823,75 +662,6 @@ size_t Curl_conn_get_max_concurrent(struct Curl_easy *data,
return (result || n <= 0)? 1 : (size_t)n;
}
-int Curl_conn_get_stream_error(struct Curl_easy *data,
- struct connectdata *conn,
- int sockindex)
-{
- CURLcode result;
- int n = 0;
-
- struct Curl_cfilter *cf = conn->cfilter[sockindex];
- result = cf? cf->cft->query(cf, data, CF_QUERY_STREAM_ERROR,
- &n, NULL) : CURLE_UNKNOWN_OPTION;
- return (result || n < 0)? 0 : n;
-}
-
-int Curl_conn_sockindex(struct Curl_easy *data, curl_socket_t sockfd)
-{
- if(data && data->conn &&
- sockfd != CURL_SOCKET_BAD && sockfd == data->conn->sock[SECONDARYSOCKET])
- return SECONDARYSOCKET;
- return FIRSTSOCKET;
-}
-
-CURLcode Curl_conn_recv(struct Curl_easy *data, int sockindex,
- char *buf, size_t blen, ssize_t *n)
-{
- CURLcode result = CURLE_OK;
- ssize_t nread;
-
- DEBUGASSERT(data->conn);
- nread = data->conn->recv[sockindex](data, sockindex, buf, blen, &result);
- DEBUGASSERT(nread >= 0 || result);
- DEBUGASSERT(nread < 0 || !result);
- *n = (nread >= 0)? (size_t)nread : 0;
- return result;
-}
-
-CURLcode Curl_conn_send(struct Curl_easy *data, int sockindex,
- const void *buf, size_t blen, bool eos,
- size_t *pnwritten)
-{
- size_t write_len = blen;
- ssize_t nwritten;
- CURLcode result = CURLE_OK;
- struct connectdata *conn;
-
- DEBUGASSERT(sockindex >= 0 && sockindex < 2);
- DEBUGASSERT(pnwritten);
- DEBUGASSERT(data);
- DEBUGASSERT(data->conn);
- conn = data->conn;
-#ifdef DEBUGBUILD
- {
- /* Allow debug builds to override this logic to force short sends
- */
- char *p = getenv("CURL_SMALLSENDS");
- if(p) {
- size_t altsize = (size_t)strtoul(p, NULL, 10);
- if(altsize)
- write_len = CURLMIN(write_len, altsize);
- }
- }
-#endif
- if(write_len != blen)
- eos = FALSE;
- nwritten = conn->send[sockindex](data, sockindex, buf, write_len, eos,
- &result);
- DEBUGASSERT((nwritten >= 0) || result);
- *pnwritten = (nwritten < 0)? 0 : (size_t)nwritten;
- return result;
-}
void Curl_pollset_reset(struct Curl_easy *data,
struct easy_pollset *ps)
@@ -990,11 +760,25 @@ static void ps_add(struct Curl_easy *data, struct easy_pollset *ps,
void Curl_pollset_add_socks(struct Curl_easy *data,
struct easy_pollset *ps,
int (*get_socks_cb)(struct Curl_easy *data,
+ struct connectdata *conn,
curl_socket_t *socks))
{
curl_socket_t socks[MAX_SOCKSPEREASYHANDLE];
int bitmap;
+ DEBUGASSERT(data->conn);
+ bitmap = get_socks_cb(data, data->conn, socks);
+ ps_add(data, ps, bitmap, socks);
+}
+
+void Curl_pollset_add_socks2(struct Curl_easy *data,
+ struct easy_pollset *ps,
+ int (*get_socks_cb)(struct Curl_easy *data,
+ curl_socket_t *socks))
+{
+ curl_socket_t socks[MAX_SOCKSPEREASYHANDLE];
+ int bitmap;
+
bitmap = get_socks_cb(data, socks);
ps_add(data, ps, bitmap, socks);
}
diff --git a/contrib/libs/curl/lib/cfilters.h b/contrib/libs/curl/lib/cfilters.h
index af696f52a5..09a3f162ac 100644
--- a/contrib/libs/curl/lib/cfilters.h
+++ b/contrib/libs/curl/lib/cfilters.h
@@ -24,13 +24,11 @@
*
***************************************************************************/
-#include "timediff.h"
struct Curl_cfilter;
struct Curl_easy;
struct Curl_dns_entry;
struct connectdata;
-struct ip_quadruple;
/* Callback to destroy resources held by this filter instance.
* Implementations MUST NOT chain calls to cf->next.
@@ -38,17 +36,9 @@ struct ip_quadruple;
typedef void Curl_cft_destroy_this(struct Curl_cfilter *cf,
struct Curl_easy *data);
-/* Callback to close the connection immediately. */
typedef void Curl_cft_close(struct Curl_cfilter *cf,
struct Curl_easy *data);
-/* Callback to close the connection filter gracefully, non-blocking.
- * Implementations MUST NOT chain calls to cf->next.
- */
-typedef CURLcode Curl_cft_shutdown(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- bool *done);
-
typedef CURLcode Curl_cft_connect(struct Curl_cfilter *cf,
struct Curl_easy *data,
bool blocking, bool *done);
@@ -86,10 +76,10 @@ struct easy_pollset;
* the pollset. Filters, whose filter "below" is not connected, should
* also do no adjustments.
*
- * Examples: a TLS handshake, while ongoing, might remove POLL_IN when it
- * needs to write, or vice versa. An HTTP/2 filter might remove POLL_OUT when
- * a stream window is exhausted and a WINDOW_UPDATE needs to be received first
- * and add instead POLL_IN.
+ * Examples: a TLS handshake, while ongoing, might remove POLL_IN
+ * when it needs to write, or vice versa. A HTTP/2 filter might remove
+ * POLL_OUT when a stream window is exhausted and a WINDOW_UPDATE needs
+ * to be received first and add instead POLL_IN.
*
* @param cf the filter to ask
* @param data the easy handle the pollset is about
@@ -106,7 +96,6 @@ typedef ssize_t Curl_cft_send(struct Curl_cfilter *cf,
struct Curl_easy *data, /* transfer */
const void *buf, /* data to write */
size_t len, /* amount to write */
- bool eos, /* last chunk */
CURLcode *err); /* error to return */
typedef ssize_t Curl_cft_recv(struct Curl_cfilter *cf,
@@ -142,7 +131,6 @@ typedef CURLcode Curl_cft_conn_keep_alive(struct Curl_cfilter *cf,
/* update conn info at connection and data */
#define CF_CTRL_CONN_INFO_UPDATE (256+0) /* 0 NULL ignored */
#define CF_CTRL_FORGET_SOCKET (256+1) /* 0 NULL ignored */
-#define CF_CTRL_FLUSH (256+2) /* 0 NULL first fail */
/**
* Handle event/control for the filter.
@@ -165,9 +153,6 @@ typedef CURLcode Curl_cft_cntrl(struct Curl_cfilter *cf,
* were received.
* -1 if not determined yet.
* - CF_QUERY_SOCKET: the socket used by the filter chain
- * - CF_QUERY_NEED_FLUSH: TRUE iff any of the filters have unsent data
- * - CF_QUERY_IP_INFO: res1 says if connection used IPv6, res2 is the
- * ip quadruple
*/
/* query res1 res2 */
#define CF_QUERY_MAX_CONCURRENT 1 /* number - */
@@ -175,9 +160,6 @@ typedef CURLcode Curl_cft_cntrl(struct Curl_cfilter *cf,
#define CF_QUERY_SOCKET 3 /* - curl_socket_t */
#define CF_QUERY_TIMER_CONNECT 4 /* - struct curltime */
#define CF_QUERY_TIMER_APPCONNECT 5 /* - struct curltime */
-#define CF_QUERY_STREAM_ERROR 6 /* error code - */
-#define CF_QUERY_NEED_FLUSH 7 /* TRUE/FALSE - */
-#define CF_QUERY_IP_INFO 8 /* TRUE/FALSE struct ip_quadruple */
/**
* Query the cfilter for properties. Filters ignorant of a query will
@@ -196,12 +178,10 @@ typedef CURLcode Curl_cft_query(struct Curl_cfilter *cf,
* connection, etc.
* CF_TYPE_SSL: provide SSL/TLS
* CF_TYPE_MULTIPLEX: provides multiplexing of easy handles
- * CF_TYPE_PROXY provides proxying
*/
#define CF_TYPE_IP_CONNECT (1 << 0)
#define CF_TYPE_SSL (1 << 1)
#define CF_TYPE_MULTIPLEX (1 << 2)
-#define CF_TYPE_PROXY (1 << 3)
/* A connection filter type, e.g. specific implementation. */
struct Curl_cftype {
@@ -211,7 +191,6 @@ struct Curl_cftype {
Curl_cft_destroy_this *destroy; /* destroy resources of this cf */
Curl_cft_connect *do_connect; /* establish connection */
Curl_cft_close *do_close; /* close conn */
- Curl_cft_shutdown *do_shutdown; /* shutdown conn */
Curl_cft_get_host *get_host; /* host filter talks to */
Curl_cft_adjust_pollset *adjust_pollset; /* adjust transfer poll set */
Curl_cft_data_pending *has_data_pending;/* conn has data pending */
@@ -231,7 +210,6 @@ struct Curl_cfilter {
struct connectdata *conn; /* the connection this filter belongs to */
int sockindex; /* the index the filter is installed at */
BIT(connected); /* != 0 iff this filter is connected */
- BIT(shutdown); /* != 0 iff this filter has shut down */
};
/* Default implementations for the type functions, implementing nop. */
@@ -249,8 +227,7 @@ void Curl_cf_def_adjust_pollset(struct Curl_cfilter *cf,
bool Curl_cf_def_data_pending(struct Curl_cfilter *cf,
const struct Curl_easy *data);
ssize_t Curl_cf_def_send(struct Curl_cfilter *cf, struct Curl_easy *data,
- const void *buf, size_t len, bool eos,
- CURLcode *err);
+ const void *buf, size_t len, CURLcode *err);
ssize_t Curl_cf_def_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
char *buf, size_t len, CURLcode *err);
CURLcode Curl_cf_def_cntrl(struct Curl_cfilter *cf,
@@ -264,8 +241,6 @@ CURLcode Curl_cf_def_conn_keep_alive(struct Curl_cfilter *cf,
CURLcode Curl_cf_def_query(struct Curl_cfilter *cf,
struct Curl_easy *data,
int query, int *pres1, void *pres2);
-CURLcode Curl_cf_def_shutdown(struct Curl_cfilter *cf,
- struct Curl_easy *data, bool *done);
/**
* Create a new filter instance, unattached to the filter chain.
@@ -326,8 +301,7 @@ CURLcode Curl_conn_cf_connect(struct Curl_cfilter *cf,
bool blocking, bool *done);
void Curl_conn_cf_close(struct Curl_cfilter *cf, struct Curl_easy *data);
ssize_t Curl_conn_cf_send(struct Curl_cfilter *cf, struct Curl_easy *data,
- const void *buf, size_t len, bool eos,
- CURLcode *err);
+ const void *buf, size_t len, CURLcode *err);
ssize_t Curl_conn_cf_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
char *buf, size_t len, CURLcode *err);
CURLcode Curl_conn_cf_cntrl(struct Curl_cfilter *cf,
@@ -348,12 +322,6 @@ bool Curl_conn_cf_is_ssl(struct Curl_cfilter *cf);
curl_socket_t Curl_conn_cf_get_socket(struct Curl_cfilter *cf,
struct Curl_easy *data);
-CURLcode Curl_conn_cf_get_ip_info(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- int *is_ipv6, struct ip_quadruple *ipquad);
-
-bool Curl_conn_cf_needs_flush(struct Curl_cfilter *cf,
- struct Curl_easy *data);
#define CURL_CF_SSL_DEFAULT -1
#define CURL_CF_SSL_DISABLE 0
@@ -401,13 +369,6 @@ bool Curl_conn_is_multiplex(struct connectdata *conn, int sockindex);
void Curl_conn_close(struct Curl_easy *data, int sockindex);
/**
- * Shutdown the connection at `sockindex` non-blocking, using timeout
- * from `data->set.shutdowntimeout`, default DEFAULT_SHUTDOWN_TIMEOUT_MS.
- * Will return CURLE_OK and *done == FALSE if not finished.
- */
-CURLcode Curl_conn_shutdown(struct Curl_easy *data, int sockindex, bool *done);
-
-/**
* Return if data is pending in some connection filter at chain
* `sockindex` for connection `data->conn`.
*/
@@ -415,17 +376,6 @@ bool Curl_conn_data_pending(struct Curl_easy *data,
int sockindex);
/**
- * Return TRUE if any of the connection filters at chain `sockindex`
- * have data still to send.
- */
-bool Curl_conn_needs_flush(struct Curl_easy *data, int sockindex);
-
-/**
- * Flush any pending data on the connection filters at chain `sockindex`.
- */
-CURLcode Curl_conn_flush(struct Curl_easy *data, int sockindex);
-
-/**
* Return the socket used on data's connection for the index.
* Returns CURL_SOCKET_BAD if not available.
*/
@@ -450,22 +400,13 @@ void Curl_conn_adjust_pollset(struct Curl_easy *data,
struct easy_pollset *ps);
/**
- * Curl_poll() the filter chain at `cf` with timeout `timeout_ms`.
- * Returns 0 on timeout, negative on error or number of sockets
- * with requested poll events.
- */
-int Curl_conn_cf_poll(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- timediff_t timeout_ms);
-
-/**
* Receive data through the filter chain at `sockindex` for connection
* `data->conn`. Copy at most `len` bytes into `buf`. Return the
- * actual number of bytes copied or a negative value on error.
+ * actuel number of bytes copied or a negative value on error.
* The error code is placed into `*code`.
*/
-ssize_t Curl_cf_recv(struct Curl_easy *data, int sockindex, char *buf,
- size_t len, CURLcode *code);
+ssize_t Curl_conn_recv(struct Curl_easy *data, int sockindex, char *buf,
+ size_t len, CURLcode *code);
/**
* Send `len` bytes of data from `buf` through the filter chain `sockindex`
@@ -473,8 +414,8 @@ ssize_t Curl_cf_recv(struct Curl_easy *data, int sockindex, char *buf,
* or a negative value on error.
* The error code is placed into `*code`.
*/
-ssize_t Curl_cf_send(struct Curl_easy *data, int sockindex,
- const void *buf, size_t len, bool eos, CURLcode *code);
+ssize_t Curl_conn_send(struct Curl_easy *data, int sockindex,
+ const void *buf, size_t len, CURLcode *code);
/**
* The easy handle `data` is being attached to `conn`. This does
@@ -508,7 +449,7 @@ CURLcode Curl_conn_ev_data_idle(struct Curl_easy *data);
/**
* Notify connection filters that the transfer represented by `data`
- * is done with sending data (e.g. has uploaded everything).
+ * is donw with sending data (e.g. has uploaded everything).
*/
void Curl_conn_ev_data_done_send(struct Curl_easy *data);
@@ -524,6 +465,12 @@ void Curl_conn_ev_data_done(struct Curl_easy *data, bool premature);
CURLcode Curl_conn_ev_data_pause(struct Curl_easy *data, bool do_pause);
/**
+ * Inform connection filters to update their info in `conn`.
+ */
+void Curl_conn_ev_update_info(struct Curl_easy *data,
+ struct connectdata *conn);
+
+/**
* Check if FIRSTSOCKET's cfilter chain deems connection alive.
*/
bool Curl_conn_is_alive(struct Curl_easy *data, struct connectdata *conn,
@@ -536,9 +483,7 @@ CURLcode Curl_conn_keep_alive(struct Curl_easy *data,
struct connectdata *conn,
int sockindex);
-#ifdef UNITTESTS
void Curl_cf_def_close(struct Curl_cfilter *cf, struct Curl_easy *data);
-#endif
void Curl_conn_get_host(struct Curl_easy *data, int sockindex,
const char **phost, const char **pdisplay_host,
int *pport);
@@ -551,36 +496,6 @@ size_t Curl_conn_get_max_concurrent(struct Curl_easy *data,
struct connectdata *conn,
int sockindex);
-/**
- * Get the underlying error code for a transfer stream or 0 if not known.
- */
-int Curl_conn_get_stream_error(struct Curl_easy *data,
- struct connectdata *conn,
- int sockindex);
-
-/**
- * Get the index of the given socket in the connection's sockets.
- * Useful in calling `Curl_conn_send()/Curl_conn_recv()` with the
- * correct socket index.
- */
-int Curl_conn_sockindex(struct Curl_easy *data, curl_socket_t sockfd);
-
-/*
- * Receive data on the connection, using FIRSTSOCKET/SECONDARYSOCKET.
- * Will return CURLE_AGAIN iff blocked on receiving.
- */
-CURLcode Curl_conn_recv(struct Curl_easy *data, int sockindex,
- char *buf, size_t buffersize,
- ssize_t *pnread);
-
-/*
- * Send data on the connection, using FIRSTSOCKET/SECONDARYSOCKET.
- * Will return CURLE_AGAIN iff blocked on sending.
- */
-CURLcode Curl_conn_send(struct Curl_easy *data, int sockindex,
- const void *buf, size_t blen, bool eos,
- size_t *pnwritten);
-
void Curl_pollset_reset(struct Curl_easy *data,
struct easy_pollset *ps);
@@ -615,7 +530,12 @@ void Curl_pollset_set(struct Curl_easy *data,
void Curl_pollset_add_socks(struct Curl_easy *data,
struct easy_pollset *ps,
int (*get_socks_cb)(struct Curl_easy *data,
+ struct connectdata *conn,
curl_socket_t *socks));
+void Curl_pollset_add_socks2(struct Curl_easy *data,
+ struct easy_pollset *ps,
+ int (*get_socks_cb)(struct Curl_easy *data,
+ curl_socket_t *socks));
/**
* Check if the pollset, as is, wants to read and/or write regarding
diff --git a/contrib/libs/curl/lib/conncache.c b/contrib/libs/curl/lib/conncache.c
index 8f477827cc..66f18ecb85 100644
--- a/contrib/libs/curl/lib/conncache.c
+++ b/contrib/libs/curl/lib/conncache.c
@@ -29,17 +29,13 @@
#include "urldata.h"
#include "url.h"
-#include "cfilters.h"
#include "progress.h"
#include "multiif.h"
#include "sendf.h"
#include "conncache.h"
-#include "http_negotiate.h"
-#include "http_ntlm.h"
#include "share.h"
#include "sigpipe.h"
#include "connect.h"
-#include "select.h"
#include "strcase.h"
/* The last 3 #include files should be in this order */
@@ -47,242 +43,168 @@
#include "curl_memory.h"
#include "memdebug.h"
+#define HASHKEY_SIZE 128
-#define CPOOL_IS_LOCKED(c) ((c) && (c)->locked)
-
-#define CPOOL_LOCK(c) \
- do { \
- if((c)) { \
- if(CURL_SHARE_KEEP_CONNECT((c)->share)) \
- Curl_share_lock(((c)->idata), CURL_LOCK_DATA_CONNECT, \
- CURL_LOCK_ACCESS_SINGLE); \
- DEBUGASSERT(!(c)->locked); \
- (c)->locked = TRUE; \
- } \
- } while(0)
-
-#define CPOOL_UNLOCK(c) \
- do { \
- if((c)) { \
- DEBUGASSERT((c)->locked); \
- (c)->locked = FALSE; \
- if(CURL_SHARE_KEEP_CONNECT((c)->share)) \
- Curl_share_unlock((c)->idata, CURL_LOCK_DATA_CONNECT); \
- } \
- } while(0)
-
-
-/* A list of connections to the same destinationn. */
-struct cpool_bundle {
- struct Curl_llist conns; /* connections in the bundle */
- size_t dest_len; /* total length of destination, including NUL */
- char *dest[1]; /* destination of bundle, allocated to keep dest_len bytes */
-};
-
-
-static void cpool_discard_conn(struct cpool *cpool,
- struct Curl_easy *data,
- struct connectdata *conn,
- bool aborted);
-static void cpool_close_and_destroy(struct cpool *cpool,
- struct connectdata *conn,
- struct Curl_easy *data,
- bool do_shutdown);
-static void cpool_run_conn_shutdown(struct Curl_easy *data,
- struct connectdata *conn,
- bool *done);
-static void cpool_run_conn_shutdown_handler(struct Curl_easy *data,
- struct connectdata *conn);
-static CURLMcode cpool_update_shutdown_ev(struct Curl_multi *multi,
- struct Curl_easy *data,
- struct connectdata *conn);
-static void cpool_shutdown_all(struct cpool *cpool,
- struct Curl_easy *data, int timeout_ms);
-static void cpool_close_and_destroy_all(struct cpool *cpool);
-static struct connectdata *cpool_get_oldest_idle(struct cpool *cpool);
-
-static struct cpool_bundle *cpool_bundle_create(const char *dest,
- size_t dest_len)
+static CURLcode bundle_create(struct connectbundle **bundlep)
{
- struct cpool_bundle *bundle;
- bundle = calloc(1, sizeof(*bundle) + dest_len);
- if(!bundle)
- return NULL;
- Curl_llist_init(&bundle->conns, NULL);
- bundle->dest_len = dest_len;
- memcpy(bundle->dest, dest, dest_len);
- return bundle;
+ DEBUGASSERT(*bundlep == NULL);
+ *bundlep = malloc(sizeof(struct connectbundle));
+ if(!*bundlep)
+ return CURLE_OUT_OF_MEMORY;
+
+ (*bundlep)->num_connections = 0;
+ (*bundlep)->multiuse = BUNDLE_UNKNOWN;
+
+ Curl_llist_init(&(*bundlep)->conn_list, NULL);
+ return CURLE_OK;
}
-static void cpool_bundle_destroy(struct cpool_bundle *bundle)
+static void bundle_destroy(struct connectbundle *bundle)
{
- DEBUGASSERT(!Curl_llist_count(&bundle->conns));
free(bundle);
}
/* Add a connection to a bundle */
-static void cpool_bundle_add(struct cpool_bundle *bundle,
- struct connectdata *conn)
+static void bundle_add_conn(struct connectbundle *bundle,
+ struct connectdata *conn)
{
- DEBUGASSERT(!Curl_node_llist(&conn->cpool_node));
- Curl_llist_append(&bundle->conns, conn, &conn->cpool_node);
- conn->bits.in_cpool = TRUE;
+ Curl_llist_insert_next(&bundle->conn_list, bundle->conn_list.tail, conn,
+ &conn->bundle_node);
+ conn->bundle = bundle;
+ bundle->num_connections++;
}
/* Remove a connection from a bundle */
-static void cpool_bundle_remove(struct cpool_bundle *bundle,
- struct connectdata *conn)
+static int bundle_remove_conn(struct connectbundle *bundle,
+ struct connectdata *conn)
{
- (void)bundle;
- DEBUGASSERT(Curl_node_llist(&conn->cpool_node) == &bundle->conns);
- Curl_node_remove(&conn->cpool_node);
- conn->bits.in_cpool = FALSE;
-}
+ struct Curl_llist_element *curr;
-static void cpool_bundle_free_entry(void *freethis)
-{
- cpool_bundle_destroy((struct cpool_bundle *)freethis);
+ curr = bundle->conn_list.head;
+ while(curr) {
+ if(curr->ptr == conn) {
+ Curl_llist_remove(&bundle->conn_list, curr, NULL);
+ bundle->num_connections--;
+ conn->bundle = NULL;
+ return 1; /* we removed a handle */
+ }
+ curr = curr->next;
+ }
+ DEBUGASSERT(0);
+ return 0;
}
-int Curl_cpool_init(struct cpool *cpool,
- Curl_cpool_disconnect_cb *disconnect_cb,
- struct Curl_multi *multi,
- struct Curl_share *share,
- size_t size)
+static void free_bundle_hash_entry(void *freethis)
{
- DEBUGASSERT(!!multi != !!share); /* either one */
- Curl_hash_init(&cpool->dest2bundle, size, Curl_hash_str,
- Curl_str_key_compare, cpool_bundle_free_entry);
- Curl_llist_init(&cpool->shutdowns, NULL);
+ struct connectbundle *b = (struct connectbundle *) freethis;
- DEBUGASSERT(disconnect_cb);
- if(!disconnect_cb)
- return 1;
+ bundle_destroy(b);
+}
+int Curl_conncache_init(struct conncache *connc, int size)
+{
/* allocate a new easy handle to use when closing cached connections */
- cpool->idata = curl_easy_init();
- if(!cpool->idata)
+ connc->closure_handle = curl_easy_init();
+ if(!connc->closure_handle)
return 1; /* bad */
- cpool->idata->state.internal = true;
- /* TODO: this is quirky. We need an internal handle for certain
- * operations, but we do not add it to the multi (if there is one).
- * But we give it the multi so that socket event operations can work.
- * Probably better to have an internal handle owned by the multi that
- * can be used for cpool operations. */
- cpool->idata->multi = multi;
- #ifdef DEBUGBUILD
- if(getenv("CURL_DEBUG"))
- cpool->idata->set.verbose = true;
-#endif
+ connc->closure_handle->state.internal = true;
- cpool->disconnect_cb = disconnect_cb;
- cpool->idata->multi = cpool->multi = multi;
- cpool->idata->share = cpool->share = share;
+ Curl_hash_init(&connc->hash, size, Curl_hash_str,
+ Curl_str_key_compare, free_bundle_hash_entry);
+ connc->closure_handle->state.conn_cache = connc;
return 0; /* good */
}
-void Curl_cpool_destroy(struct cpool *cpool)
+void Curl_conncache_destroy(struct conncache *connc)
{
- if(cpool) {
- if(cpool->idata) {
- cpool_close_and_destroy_all(cpool);
- /* The internal closure handle is special and we need to
- * disconnect it from multi/share before closing it down. */
- cpool->idata->multi = NULL;
- cpool->idata->share = NULL;
- Curl_close(&cpool->idata);
- }
- Curl_hash_destroy(&cpool->dest2bundle);
- cpool->multi = NULL;
- }
+ if(connc)
+ Curl_hash_destroy(&connc->hash);
}
-static struct cpool *cpool_get_instance(struct Curl_easy *data)
+/* creates a key to find a bundle for this connection */
+static void hashkey(struct connectdata *conn, char *buf, size_t len)
{
- if(data) {
- if(CURL_SHARE_KEEP_CONNECT(data->share))
- return &data->share->cpool;
- else if(data->multi_easy)
- return &data->multi_easy->cpool;
- else if(data->multi)
- return &data->multi->cpool;
+ const char *hostname;
+ long port = conn->remote_port;
+ DEBUGASSERT(len >= HASHKEY_SIZE);
+#ifndef CURL_DISABLE_PROXY
+ if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) {
+ hostname = conn->http_proxy.host.name;
+ port = conn->port;
}
- return NULL;
-}
+ else
+#endif
+ if(conn->bits.conn_to_host)
+ hostname = conn->conn_to_host.name;
+ else
+ hostname = conn->host.name;
-void Curl_cpool_xfer_init(struct Curl_easy *data)
-{
- struct cpool *cpool = cpool_get_instance(data);
-
- DEBUGASSERT(cpool);
- if(cpool) {
- CPOOL_LOCK(cpool);
- /* the identifier inside the connection cache */
- data->id = cpool->next_easy_id++;
- if(cpool->next_easy_id <= 0)
- cpool->next_easy_id = 0;
- data->state.lastconnect_id = -1;
-
- /* The closure handle only ever has default timeouts set. To improve the
- state somewhat we clone the timeouts from each added handle so that the
- closure handle always has the same timeouts as the most recently added
- easy handle. */
- cpool->idata->set.timeout = data->set.timeout;
- cpool->idata->set.server_response_timeout =
- data->set.server_response_timeout;
- cpool->idata->set.no_signal = data->set.no_signal;
-
- CPOOL_UNLOCK(cpool);
- }
- else {
- /* We should not get here, but in a non-debug build, do something */
- data->id = 0;
- data->state.lastconnect_id = -1;
- }
+ /* put the numbers first so that the hostname gets cut off if too long */
+#ifdef ENABLE_IPV6
+ msnprintf(buf, len, "%u/%ld/%s", conn->scope_id, port, hostname);
+#else
+ msnprintf(buf, len, "%ld/%s", port, hostname);
+#endif
+ Curl_strntolower(buf, buf, len);
}
-static struct cpool_bundle *cpool_find_bundle(struct cpool *cpool,
- struct connectdata *conn)
+/* Returns number of connections currently held in the connection cache.
+ Locks/unlocks the cache itself!
+*/
+size_t Curl_conncache_size(struct Curl_easy *data)
{
- return Curl_hash_pick(&cpool->dest2bundle,
- conn->destination, conn->destination_len);
+ size_t num;
+ CONNCACHE_LOCK(data);
+ num = data->state.conn_cache->num_conn;
+ CONNCACHE_UNLOCK(data);
+ return num;
}
-static struct cpool_bundle *
-cpool_add_bundle(struct cpool *cpool, struct connectdata *conn)
-{
- struct cpool_bundle *bundle;
+/* Look up the bundle with all the connections to the same host this
+ connectdata struct is setup to use.
- bundle = cpool_bundle_create(conn->destination, conn->destination_len);
- if(!bundle)
- return NULL;
-
- if(!Curl_hash_add(&cpool->dest2bundle,
- bundle->dest, bundle->dest_len, bundle)) {
- cpool_bundle_destroy(bundle);
- return NULL;
+ **NOTE**: When it returns, it holds the connection cache lock! */
+struct connectbundle *
+Curl_conncache_find_bundle(struct Curl_easy *data,
+ struct connectdata *conn,
+ struct conncache *connc)
+{
+ struct connectbundle *bundle = NULL;
+ CONNCACHE_LOCK(data);
+ if(connc) {
+ char key[HASHKEY_SIZE];
+ hashkey(conn, key, sizeof(key));
+ bundle = Curl_hash_pick(&connc->hash, key, strlen(key));
}
+
return bundle;
}
-static void cpool_remove_bundle(struct cpool *cpool,
- struct cpool_bundle *bundle)
+static void *conncache_add_bundle(struct conncache *connc,
+ char *key,
+ struct connectbundle *bundle)
+{
+ return Curl_hash_add(&connc->hash, key, strlen(key), bundle);
+}
+
+static void conncache_remove_bundle(struct conncache *connc,
+ struct connectbundle *bundle)
{
struct Curl_hash_iterator iter;
struct Curl_hash_element *he;
- if(!cpool)
+ if(!connc)
return;
- Curl_hash_start_iterate(&cpool->dest2bundle, &iter);
+ Curl_hash_start_iterate(&connc->hash, &iter);
he = Curl_hash_next_element(&iter);
while(he) {
if(he->ptr == bundle) {
/* The bundle is destroyed by the hash destructor function,
free_bundle_hash_entry() */
- Curl_hash_delete(&cpool->dest2bundle, he->key, he->key_len);
+ Curl_hash_delete(&connc->hash, he->key, he->key_len);
return;
}
@@ -290,252 +212,227 @@ static void cpool_remove_bundle(struct cpool *cpool,
}
}
-static struct connectdata *
-cpool_bundle_get_oldest_idle(struct cpool_bundle *bundle);
-
-int Curl_cpool_check_limits(struct Curl_easy *data,
- struct connectdata *conn)
+CURLcode Curl_conncache_add_conn(struct Curl_easy *data)
{
- struct cpool *cpool = cpool_get_instance(data);
- struct cpool_bundle *bundle;
- size_t dest_limit = 0;
- size_t total_limit = 0;
- int result = CPOOL_LIMIT_OK;
-
- if(!cpool)
- return CPOOL_LIMIT_OK;
-
- if(data && data->multi) {
- dest_limit = data->multi->max_host_connections;
- total_limit = data->multi->max_total_connections;
- }
+ CURLcode result = CURLE_OK;
+ struct connectbundle *bundle = NULL;
+ struct connectdata *conn = data->conn;
+ struct conncache *connc = data->state.conn_cache;
+ DEBUGASSERT(conn);
- if(!dest_limit && !total_limit)
- return CPOOL_LIMIT_OK;
-
- CPOOL_LOCK(cpool);
- if(dest_limit) {
- bundle = cpool_find_bundle(cpool, conn);
- while(bundle && (Curl_llist_count(&bundle->conns) >= dest_limit)) {
- struct connectdata *oldest_idle = NULL;
- /* The bundle is full. Extract the oldest connection that may
- * be removed now, if there is one. */
- oldest_idle = cpool_bundle_get_oldest_idle(bundle);
- if(!oldest_idle)
- break;
- /* disconnect the old conn and continue */
- DEBUGF(infof(data, "Discarding connection #%"
- FMT_OFF_T " from %zu to reach destination "
- "limit of %zu", oldest_idle->connection_id,
- Curl_llist_count(&bundle->conns), dest_limit));
- Curl_cpool_disconnect(data, oldest_idle, FALSE);
- }
- if(bundle && (Curl_llist_count(&bundle->conns) >= dest_limit)) {
- result = CPOOL_LIMIT_DEST;
- goto out;
- }
- }
+ /* *find_bundle() locks the connection cache */
+ bundle = Curl_conncache_find_bundle(data, conn, data->state.conn_cache);
+ if(!bundle) {
+ char key[HASHKEY_SIZE];
- if(total_limit) {
- while(cpool->num_conn >= total_limit) {
- struct connectdata *oldest_idle = cpool_get_oldest_idle(cpool);
- if(!oldest_idle)
- break;
- /* disconnect the old conn and continue */
- DEBUGF(infof(data, "Discarding connection #%"
- FMT_OFF_T " from %zu to reach total "
- "limit of %zu",
- oldest_idle->connection_id, cpool->num_conn, total_limit));
- Curl_cpool_disconnect(data, oldest_idle, FALSE);
- }
- if(cpool->num_conn >= total_limit) {
- result = CPOOL_LIMIT_TOTAL;
- goto out;
+ result = bundle_create(&bundle);
+ if(result) {
+ goto unlock;
}
- }
-out:
- CPOOL_UNLOCK(cpool);
- return result;
-}
+ hashkey(conn, key, sizeof(key));
-CURLcode Curl_cpool_add_conn(struct Curl_easy *data,
- struct connectdata *conn)
-{
- CURLcode result = CURLE_OK;
- struct cpool_bundle *bundle = NULL;
- struct cpool *cpool = cpool_get_instance(data);
- DEBUGASSERT(conn);
-
- DEBUGASSERT(cpool);
- if(!cpool)
- return CURLE_FAILED_INIT;
-
- CPOOL_LOCK(cpool);
- bundle = cpool_find_bundle(cpool, conn);
- if(!bundle) {
- bundle = cpool_add_bundle(cpool, conn);
- if(!bundle) {
+ if(!conncache_add_bundle(data->state.conn_cache, key, bundle)) {
+ bundle_destroy(bundle);
result = CURLE_OUT_OF_MEMORY;
- goto out;
+ goto unlock;
}
}
- cpool_bundle_add(bundle, conn);
- conn->connection_id = cpool->next_connection_id++;
- cpool->num_conn++;
- DEBUGF(infof(data, "Added connection %" FMT_OFF_T ". "
+ bundle_add_conn(bundle, conn);
+ conn->connection_id = connc->next_connection_id++;
+ connc->num_conn++;
+
+ DEBUGF(infof(data, "Added connection %" CURL_FORMAT_CURL_OFF_T ". "
"The cache now contains %zu members",
- conn->connection_id, cpool->num_conn));
-out:
- CPOOL_UNLOCK(cpool);
+ conn->connection_id, connc->num_conn));
+
+unlock:
+ CONNCACHE_UNLOCK(data);
return result;
}
-static void cpool_remove_conn(struct cpool *cpool,
- struct connectdata *conn)
+/*
+ * Removes the connectdata object from the connection cache, but the transfer
+ * still owns this connection.
+ *
+ * Pass TRUE/FALSE in the 'lock' argument depending on if the parent function
+ * already holds the lock or not.
+ */
+void Curl_conncache_remove_conn(struct Curl_easy *data,
+ struct connectdata *conn, bool lock)
{
- struct Curl_llist *list = Curl_node_llist(&conn->cpool_node);
- DEBUGASSERT(cpool);
- if(list) {
- /* The connection is certainly in the pool, but where? */
- struct cpool_bundle *bundle = cpool_find_bundle(cpool, conn);
- if(bundle && (list == &bundle->conns)) {
- cpool_bundle_remove(bundle, conn);
- if(!Curl_llist_count(&bundle->conns))
- cpool_remove_bundle(cpool, bundle);
- conn->bits.in_cpool = FALSE;
- cpool->num_conn--;
+ struct connectbundle *bundle = conn->bundle;
+ struct conncache *connc = data->state.conn_cache;
+
+ /* The bundle pointer can be NULL, since this function can be called
+ due to a failed connection attempt, before being added to a bundle */
+ if(bundle) {
+ if(lock) {
+ CONNCACHE_LOCK(data);
+ }
+ bundle_remove_conn(bundle, conn);
+ if(bundle->num_connections == 0)
+ conncache_remove_bundle(connc, bundle);
+ conn->bundle = NULL; /* removed from it */
+ if(connc) {
+ connc->num_conn--;
+ DEBUGF(infof(data, "The cache now contains %zu members",
+ connc->num_conn));
}
- else {
- /* Not in a bundle, already in the shutdown list? */
- DEBUGASSERT(list == &cpool->shutdowns);
+ if(lock) {
+ CONNCACHE_UNLOCK(data);
}
}
}
-/* This function iterates the entire connection pool and calls the function
+/* This function iterates the entire connection cache and calls the function
func() with the connection pointer as the first argument and the supplied
'param' argument as the other.
- The cpool lock is still held when the callback is called. It needs it,
+ The conncache lock is still held when the callback is called. It needs it,
so that it can safely continue traversing the lists once the callback
returns.
- Returns TRUE if the loop was aborted due to the callback's return code.
+ Returns 1 if the loop was aborted due to the callback's return code.
Return 0 from func() to continue the loop, return 1 to abort it.
*/
-static bool cpool_foreach(struct Curl_easy *data,
- struct cpool *cpool,
- void *param,
- int (*func)(struct Curl_easy *data,
- struct connectdata *conn, void *param))
+bool Curl_conncache_foreach(struct Curl_easy *data,
+ struct conncache *connc,
+ void *param,
+ int (*func)(struct Curl_easy *data,
+ struct connectdata *conn, void *param))
{
struct Curl_hash_iterator iter;
+ struct Curl_llist_element *curr;
struct Curl_hash_element *he;
- if(!cpool)
+ if(!connc)
return FALSE;
- Curl_hash_start_iterate(&cpool->dest2bundle, &iter);
+ CONNCACHE_LOCK(data);
+ Curl_hash_start_iterate(&connc->hash, &iter);
he = Curl_hash_next_element(&iter);
while(he) {
- struct Curl_llist_node *curr;
- struct cpool_bundle *bundle = he->ptr;
+ struct connectbundle *bundle;
+
+ bundle = he->ptr;
he = Curl_hash_next_element(&iter);
- curr = Curl_llist_head(&bundle->conns);
+ curr = bundle->conn_list.head;
while(curr) {
/* Yes, we need to update curr before calling func(), because func()
might decide to remove the connection */
- struct connectdata *conn = Curl_node_elem(curr);
- curr = Curl_node_next(curr);
+ struct connectdata *conn = curr->ptr;
+ curr = curr->next;
if(1 == func(data, conn, param)) {
+ CONNCACHE_UNLOCK(data);
return TRUE;
}
}
}
+ CONNCACHE_UNLOCK(data);
return FALSE;
}
-/* Return a live connection in the pool or NULL. */
-static struct connectdata *cpool_get_live_conn(struct cpool *cpool)
+/* Return the first connection found in the cache. Used when closing all
+ connections.
+
+ NOTE: no locking is done here as this is presumably only done when cleaning
+ up a cache!
+*/
+static struct connectdata *
+conncache_find_first_connection(struct conncache *connc)
{
struct Curl_hash_iterator iter;
struct Curl_hash_element *he;
- struct cpool_bundle *bundle;
- struct Curl_llist_node *conn_node;
+ struct connectbundle *bundle;
+
+ Curl_hash_start_iterate(&connc->hash, &iter);
- Curl_hash_start_iterate(&cpool->dest2bundle, &iter);
- for(he = Curl_hash_next_element(&iter); he;
- he = Curl_hash_next_element(&iter)) {
+ he = Curl_hash_next_element(&iter);
+ while(he) {
+ struct Curl_llist_element *curr;
bundle = he->ptr;
- conn_node = Curl_llist_head(&bundle->conns);
- if(conn_node)
- return Curl_node_elem(conn_node);
+
+ curr = bundle->conn_list.head;
+ if(curr) {
+ return curr->ptr;
+ }
+
+ he = Curl_hash_next_element(&iter);
}
+
return NULL;
}
/*
- * A connection (already in the pool) has become idle. Do any
- * cleanups in regard to the pool's limits.
+ * Give ownership of a connection back to the connection cache. Might
+ * disconnect the oldest existing in there to make space.
*
- * Return TRUE if idle connection kept in pool, FALSE if closed.
+ * Return TRUE if stored, FALSE if closed.
*/
-bool Curl_cpool_conn_now_idle(struct Curl_easy *data,
- struct connectdata *conn)
+bool Curl_conncache_return_conn(struct Curl_easy *data,
+ struct connectdata *conn)
{
unsigned int maxconnects = !data->multi->maxconnects ?
data->multi->num_easy * 4: data->multi->maxconnects;
- struct connectdata *oldest_idle = NULL;
- struct cpool *cpool = cpool_get_instance(data);
- bool kept = TRUE;
+ struct connectdata *conn_candidate = NULL;
conn->lastused = Curl_now(); /* it was used up until now */
- if(cpool && maxconnects) {
- /* may be called form a callback already under lock */
- bool do_lock = !CPOOL_IS_LOCKED(cpool);
- if(do_lock)
- CPOOL_LOCK(cpool);
- if(cpool->num_conn > maxconnects) {
- infof(data, "Connection pool is full, closing the oldest one");
-
- oldest_idle = cpool_get_oldest_idle(cpool);
- kept = (oldest_idle != conn);
- if(oldest_idle) {
- Curl_cpool_disconnect(cpool->idata, oldest_idle, FALSE);
- }
+ if(maxconnects && Curl_conncache_size(data) > maxconnects) {
+ infof(data, "Connection cache is full, closing the oldest one");
+
+ conn_candidate = Curl_conncache_extract_oldest(data);
+ if(conn_candidate) {
+ /* Use the closure handle for this disconnect so that anything that
+ happens during the disconnect is not stored and associated with the
+ 'data' handle which already just finished a transfer and it is
+ important that details from this (unrelated) disconnect does not
+ taint meta-data in the data handle. */
+ struct conncache *connc = data->state.conn_cache;
+ connc->closure_handle->state.buffer = data->state.buffer;
+ connc->closure_handle->set.buffer_size = data->set.buffer_size;
+ Curl_disconnect(connc->closure_handle, conn_candidate,
+ /* dead_connection */ FALSE);
}
- if(do_lock)
- CPOOL_UNLOCK(cpool);
}
- return kept;
+ return (conn_candidate == conn) ? FALSE : TRUE;
+
}
/*
* This function finds the connection in the connection bundle that has been
* unused for the longest time.
+ *
+ * Does not lock the connection cache!
+ *
+ * Returns the pointer to the oldest idle connection, or NULL if none was
+ * found.
*/
-static struct connectdata *
-cpool_bundle_get_oldest_idle(struct cpool_bundle *bundle)
+struct connectdata *
+Curl_conncache_extract_bundle(struct Curl_easy *data,
+ struct connectbundle *bundle)
{
- struct Curl_llist_node *curr;
+ struct Curl_llist_element *curr;
timediff_t highscore = -1;
timediff_t score;
struct curltime now;
- struct connectdata *oldest_idle = NULL;
+ struct connectdata *conn_candidate = NULL;
struct connectdata *conn;
+ (void)data;
+
now = Curl_now();
- curr = Curl_llist_head(&bundle->conns);
+
+ curr = bundle->conn_list.head;
while(curr) {
- conn = Curl_node_elem(curr);
+ conn = curr->ptr;
if(!CONN_INUSE(conn)) {
/* Set higher score for the age passed since the connection was used */
@@ -543,836 +440,145 @@ cpool_bundle_get_oldest_idle(struct cpool_bundle *bundle)
if(score > highscore) {
highscore = score;
- oldest_idle = conn;
+ conn_candidate = conn;
}
}
- curr = Curl_node_next(curr);
+ curr = curr->next;
+ }
+ if(conn_candidate) {
+ /* remove it to prevent another thread from nicking it */
+ bundle_remove_conn(bundle, conn_candidate);
+ data->state.conn_cache->num_conn--;
+ DEBUGF(infof(data, "The cache now contains %zu members",
+ data->state.conn_cache->num_conn));
}
- return oldest_idle;
+
+ return conn_candidate;
}
-static struct connectdata *cpool_get_oldest_idle(struct cpool *cpool)
+/*
+ * This function finds the connection in the connection cache that has been
+ * unused for the longest time and extracts that from the bundle.
+ *
+ * Returns the pointer to the connection, or NULL if none was found.
+ */
+struct connectdata *
+Curl_conncache_extract_oldest(struct Curl_easy *data)
{
+ struct conncache *connc = data->state.conn_cache;
struct Curl_hash_iterator iter;
- struct Curl_llist_node *curr;
+ struct Curl_llist_element *curr;
struct Curl_hash_element *he;
- struct connectdata *oldest_idle = NULL;
- struct cpool_bundle *bundle;
- struct curltime now;
timediff_t highscore =- 1;
timediff_t score;
+ struct curltime now;
+ struct connectdata *conn_candidate = NULL;
+ struct connectbundle *bundle;
+ struct connectbundle *bundle_candidate = NULL;
now = Curl_now();
- Curl_hash_start_iterate(&cpool->dest2bundle, &iter);
- for(he = Curl_hash_next_element(&iter); he;
- he = Curl_hash_next_element(&iter)) {
- struct connectdata *conn;
- bundle = he->ptr;
-
- for(curr = Curl_llist_head(&bundle->conns); curr;
- curr = Curl_node_next(curr)) {
- conn = Curl_node_elem(curr);
- if(CONN_INUSE(conn) || conn->bits.close || conn->connect_only)
- continue;
- /* Set higher score for the age passed since the connection was used */
- score = Curl_timediff(now, conn->lastused);
- if(score > highscore) {
- highscore = score;
- oldest_idle = conn;
- }
- }
- }
- return oldest_idle;
-}
+ CONNCACHE_LOCK(data);
+ Curl_hash_start_iterate(&connc->hash, &iter);
-bool Curl_cpool_find(struct Curl_easy *data,
- const char *destination, size_t dest_len,
- Curl_cpool_conn_match_cb *conn_cb,
- Curl_cpool_done_match_cb *done_cb,
- void *userdata)
-{
- struct cpool *cpool = cpool_get_instance(data);
- struct cpool_bundle *bundle;
- bool result = FALSE;
+ he = Curl_hash_next_element(&iter);
+ while(he) {
+ struct connectdata *conn;
- DEBUGASSERT(cpool);
- DEBUGASSERT(conn_cb);
- if(!cpool)
- return FALSE;
+ bundle = he->ptr;
- CPOOL_LOCK(cpool);
- bundle = Curl_hash_pick(&cpool->dest2bundle, (void *)destination, dest_len);
- if(bundle) {
- struct Curl_llist_node *curr = Curl_llist_head(&bundle->conns);
+ curr = bundle->conn_list.head;
while(curr) {
- struct connectdata *conn = Curl_node_elem(curr);
- /* Get next node now. callback might discard current */
- curr = Curl_node_next(curr);
-
- if(conn_cb(conn, userdata)) {
- result = TRUE;
- break;
+ conn = curr->ptr;
+
+ if(!CONN_INUSE(conn) && !conn->bits.close &&
+ !conn->connect_only) {
+ /* Set higher score for the age passed since the connection was used */
+ score = Curl_timediff(now, conn->lastused);
+
+ if(score > highscore) {
+ highscore = score;
+ conn_candidate = conn;
+ bundle_candidate = bundle;
+ }
}
+ curr = curr->next;
}
- }
- if(done_cb) {
- result = done_cb(result, userdata);
+ he = Curl_hash_next_element(&iter);
}
- CPOOL_UNLOCK(cpool);
- return result;
-}
-
-static void cpool_shutdown_discard_all(struct cpool *cpool)
-{
- struct Curl_llist_node *e = Curl_llist_head(&cpool->shutdowns);
- struct connectdata *conn;
-
- if(!e)
- return;
-
- DEBUGF(infof(cpool->idata, "cpool_shutdown_discard_all"));
- while(e) {
- conn = Curl_node_elem(e);
- Curl_node_remove(e);
- DEBUGF(infof(cpool->idata, "discard connection #%" FMT_OFF_T,
- conn->connection_id));
- cpool_close_and_destroy(cpool, conn, NULL, FALSE);
- e = Curl_llist_head(&cpool->shutdowns);
+ if(conn_candidate) {
+ /* remove it to prevent another thread from nicking it */
+ bundle_remove_conn(bundle_candidate, conn_candidate);
+ connc->num_conn--;
+ DEBUGF(infof(data, "The cache now contains %zu members",
+ connc->num_conn));
}
+ CONNCACHE_UNLOCK(data);
+
+ return conn_candidate;
}
-static void cpool_close_and_destroy_all(struct cpool *cpool)
+void Curl_conncache_close_all_connections(struct conncache *connc)
{
struct connectdata *conn;
- int timeout_ms = 0;
+ char buffer[READBUFFER_MIN + 1];
SIGPIPE_VARIABLE(pipe_st);
+ if(!connc->closure_handle)
+ return;
+ connc->closure_handle->state.buffer = buffer;
+ connc->closure_handle->set.buffer_size = READBUFFER_MIN;
- DEBUGASSERT(cpool);
- /* Move all connections to the shutdown list */
- sigpipe_init(&pipe_st);
- CPOOL_LOCK(cpool);
- conn = cpool_get_live_conn(cpool);
+ conn = conncache_find_first_connection(connc);
while(conn) {
- cpool_remove_conn(cpool, conn);
- sigpipe_apply(cpool->idata, &pipe_st);
+ sigpipe_ignore(connc->closure_handle, &pipe_st);
+ /* This will remove the connection from the cache */
connclose(conn, "kill all");
- cpool_discard_conn(cpool, cpool->idata, conn, FALSE);
-
- conn = cpool_get_live_conn(cpool);
- }
- CPOOL_UNLOCK(cpool);
-
- /* Just for testing, run graceful shutdown */
-#ifdef DEBUGBUILD
- {
- char *p = getenv("CURL_GRACEFUL_SHUTDOWN");
- if(p) {
- long l = strtol(p, NULL, 10);
- if(l > 0 && l < INT_MAX)
- timeout_ms = (int)l;
- }
- }
-#endif
- sigpipe_apply(cpool->idata, &pipe_st);
- cpool_shutdown_all(cpool, cpool->idata, timeout_ms);
-
- /* discard all connections in the shutdown list */
- cpool_shutdown_discard_all(cpool);
-
- Curl_hostcache_clean(cpool->idata, cpool->idata->dns.hostcache);
- sigpipe_restore(&pipe_st);
-}
-
-
-static void cpool_shutdown_destroy_oldest(struct cpool *cpool)
-{
- struct Curl_llist_node *e;
- struct connectdata *conn;
-
- e = Curl_llist_head(&cpool->shutdowns);
- if(e) {
- SIGPIPE_VARIABLE(pipe_st);
- conn = Curl_node_elem(e);
- Curl_node_remove(e);
- sigpipe_init(&pipe_st);
- sigpipe_apply(cpool->idata, &pipe_st);
- cpool_close_and_destroy(cpool, conn, NULL, FALSE);
+ Curl_conncache_remove_conn(connc->closure_handle, conn, TRUE);
+ Curl_disconnect(connc->closure_handle, conn, FALSE);
sigpipe_restore(&pipe_st);
- }
-}
-
-static void cpool_discard_conn(struct cpool *cpool,
- struct Curl_easy *data,
- struct connectdata *conn,
- bool aborted)
-{
- bool done = FALSE;
-
- DEBUGASSERT(data);
- DEBUGASSERT(cpool);
- DEBUGASSERT(!conn->bits.in_cpool);
-
- /*
- * If this connection is not marked to force-close, leave it open if there
- * are other users of it
- */
- if(CONN_INUSE(conn) && !aborted) {
- DEBUGF(infof(data, "[CCACHE] not discarding #%" FMT_OFF_T
- " still in use by %zu transfers", conn->connection_id,
- CONN_INUSE(conn)));
- return;
- }
- /* treat the connection as aborted in CONNECT_ONLY situations, we do
- * not know what the APP did with it. */
- if(conn->connect_only)
- aborted = TRUE;
- conn->bits.aborted = aborted;
-
- /* We do not shutdown dead connections. The term 'dead' can be misleading
- * here, as we also mark errored connections/transfers as 'dead'.
- * If we do a shutdown for an aborted transfer, the server might think
- * it was successful otherwise (for example an ftps: upload). This is
- * not what we want. */
- if(aborted)
- done = TRUE;
- if(!done) {
- /* Attempt to shutdown the connection right away. */
- Curl_attach_connection(data, conn);
- cpool_run_conn_shutdown(data, conn, &done);
- DEBUGF(infof(data, "[CCACHE] shutdown #%" FMT_OFF_T ", done=%d",
- conn->connection_id, done));
- Curl_detach_connection(data);
- }
-
- if(done) {
- cpool_close_and_destroy(cpool, conn, data, FALSE);
- return;
+ conn = conncache_find_first_connection(connc);
}
- /* Add the connection to our shutdown list for non-blocking shutdown
- * during multi processing. */
- if(data->multi && data->multi->max_shutdown_connections > 0 &&
- (data->multi->max_shutdown_connections >=
- (long)Curl_llist_count(&cpool->shutdowns))) {
- DEBUGF(infof(data, "[CCACHE] discarding oldest shutdown connection "
- "due to limit of %ld",
- data->multi->max_shutdown_connections));
- cpool_shutdown_destroy_oldest(cpool);
- }
-
- if(data->multi && data->multi->socket_cb) {
- DEBUGASSERT(cpool == &data->multi->cpool);
- /* Start with an empty shutdown pollset, so out internal closure handle
- * is added to the sockets. */
- memset(&conn->shutdown_poll, 0, sizeof(conn->shutdown_poll));
- if(cpool_update_shutdown_ev(data->multi, cpool->idata, conn)) {
- DEBUGF(infof(data, "[CCACHE] update events for shutdown failed, "
- "discarding #%" FMT_OFF_T,
- conn->connection_id));
- cpool_close_and_destroy(cpool, conn, data, FALSE);
- return;
- }
- }
-
- Curl_llist_append(&cpool->shutdowns, conn, &conn->cpool_node);
- DEBUGF(infof(data, "[CCACHE] added #%" FMT_OFF_T
- " to shutdown list of length %zu", conn->connection_id,
- Curl_llist_count(&cpool->shutdowns)));
-}
-
-void Curl_cpool_disconnect(struct Curl_easy *data,
- struct connectdata *conn,
- bool aborted)
-{
- struct cpool *cpool = cpool_get_instance(data);
- bool do_lock;
-
- DEBUGASSERT(cpool);
- DEBUGASSERT(data && !data->conn);
- if(!cpool)
- return;
-
- /* If this connection is not marked to force-close, leave it open if there
- * are other users of it */
- if(CONN_INUSE(conn) && !aborted) {
- DEBUGASSERT(0); /* does this ever happen? */
- DEBUGF(infof(data, "Curl_disconnect when inuse: %zu", CONN_INUSE(conn)));
- return;
- }
-
- /* This method may be called while we are under lock, e.g. from a
- * user callback in find. */
- do_lock = !CPOOL_IS_LOCKED(cpool);
- if(do_lock)
- CPOOL_LOCK(cpool);
-
- if(conn->bits.in_cpool) {
- cpool_remove_conn(cpool, conn);
- DEBUGASSERT(!conn->bits.in_cpool);
- }
-
- /* Run the callback to let it clean up anything it wants to. */
- aborted = cpool->disconnect_cb(data, conn, aborted);
-
- if(data->multi) {
- /* Add it to the multi's cpool for shutdown handling */
- infof(data, "%s connection #%" FMT_OFF_T,
- aborted? "closing" : "shutting down", conn->connection_id);
- cpool_discard_conn(&data->multi->cpool, data, conn, aborted);
- }
- else {
- /* No multi available. Make a best-effort shutdown + close */
- infof(data, "closing connection #%" FMT_OFF_T, conn->connection_id);
- cpool_close_and_destroy(NULL, conn, data, !aborted);
- }
-
- if(do_lock)
- CPOOL_UNLOCK(cpool);
-}
-
-static void cpool_run_conn_shutdown_handler(struct Curl_easy *data,
- struct connectdata *conn)
-{
- if(!conn->bits.shutdown_handler) {
- if(conn->dns_entry)
- Curl_resolv_unlink(data, &conn->dns_entry);
+ connc->closure_handle->state.buffer = NULL;
+ sigpipe_ignore(connc->closure_handle, &pipe_st);
- /* Cleanup NTLM connection-related data */
- Curl_http_auth_cleanup_ntlm(conn);
-
- /* Cleanup NEGOTIATE connection-related data */
- Curl_http_auth_cleanup_negotiate(conn);
-
- if(conn->handler && conn->handler->disconnect) {
- /* This is set if protocol-specific cleanups should be made */
- DEBUGF(infof(data, "connection #%" FMT_OFF_T
- ", shutdown protocol handler (aborted=%d)",
- conn->connection_id, conn->bits.aborted));
-
- conn->handler->disconnect(data, conn, conn->bits.aborted);
- }
-
- /* possible left-overs from the async name resolvers */
- Curl_resolver_cancel(data);
-
- conn->bits.shutdown_handler = TRUE;
- }
-}
-
-static void cpool_run_conn_shutdown(struct Curl_easy *data,
- struct connectdata *conn,
- bool *done)
-{
- CURLcode r1, r2;
- bool done1, done2;
-
- /* We expect to be attached when called */
- DEBUGASSERT(data->conn == conn);
-
- cpool_run_conn_shutdown_handler(data, conn);
-
- if(conn->bits.shutdown_filters) {
- *done = TRUE;
- return;
- }
-
- if(!conn->connect_only && Curl_conn_is_connected(conn, FIRSTSOCKET))
- r1 = Curl_conn_shutdown(data, FIRSTSOCKET, &done1);
- else {
- r1 = CURLE_OK;
- done1 = TRUE;
- }
-
- if(!conn->connect_only && Curl_conn_is_connected(conn, SECONDARYSOCKET))
- r2 = Curl_conn_shutdown(data, SECONDARYSOCKET, &done2);
- else {
- r2 = CURLE_OK;
- done2 = TRUE;
- }
-
- /* we are done when any failed or both report success */
- *done = (r1 || r2 || (done1 && done2));
- if(*done)
- conn->bits.shutdown_filters = TRUE;
-}
-
-static CURLcode cpool_add_pollfds(struct cpool *cpool,
- struct curl_pollfds *cpfds)
-{
- CURLcode result = CURLE_OK;
-
- if(Curl_llist_head(&cpool->shutdowns)) {
- struct Curl_llist_node *e;
- struct easy_pollset ps;
- struct connectdata *conn;
-
- for(e = Curl_llist_head(&cpool->shutdowns); e;
- e = Curl_node_next(e)) {
- conn = Curl_node_elem(e);
- memset(&ps, 0, sizeof(ps));
- Curl_attach_connection(cpool->idata, conn);
- Curl_conn_adjust_pollset(cpool->idata, &ps);
- Curl_detach_connection(cpool->idata);
-
- result = Curl_pollfds_add_ps(cpfds, &ps);
- if(result) {
- Curl_pollfds_cleanup(cpfds);
- goto out;
- }
- }
- }
-out:
- return result;
-}
-
-CURLcode Curl_cpool_add_pollfds(struct cpool *cpool,
- struct curl_pollfds *cpfds)
-{
- CURLcode result;
- CPOOL_LOCK(cpool);
- result = cpool_add_pollfds(cpool, cpfds);
- CPOOL_UNLOCK(cpool);
- return result;
-}
-
-CURLcode Curl_cpool_add_waitfds(struct cpool *cpool,
- struct curl_waitfds *cwfds)
-{
- CURLcode result = CURLE_OK;
-
- CPOOL_LOCK(cpool);
- if(Curl_llist_head(&cpool->shutdowns)) {
- struct Curl_llist_node *e;
- struct easy_pollset ps;
- struct connectdata *conn;
-
- for(e = Curl_llist_head(&cpool->shutdowns); e;
- e = Curl_node_next(e)) {
- conn = Curl_node_elem(e);
- memset(&ps, 0, sizeof(ps));
- Curl_attach_connection(cpool->idata, conn);
- Curl_conn_adjust_pollset(cpool->idata, &ps);
- Curl_detach_connection(cpool->idata);
-
- result = Curl_waitfds_add_ps(cwfds, &ps);
- if(result)
- goto out;
- }
- }
-out:
- CPOOL_UNLOCK(cpool);
- return result;
-}
-
-static void cpool_perform(struct cpool *cpool)
-{
- struct Curl_easy *data = cpool->idata;
- struct Curl_llist_node *e = Curl_llist_head(&cpool->shutdowns);
- struct Curl_llist_node *enext;
- struct connectdata *conn;
- struct curltime *nowp = NULL;
- struct curltime now;
- timediff_t next_from_now_ms = 0, ms;
- bool done;
-
- if(!e)
- return;
-
- DEBUGASSERT(data);
- DEBUGF(infof(data, "[CCACHE] perform, %zu connections being shutdown",
- Curl_llist_count(&cpool->shutdowns)));
- while(e) {
- enext = Curl_node_next(e);
- conn = Curl_node_elem(e);
- Curl_attach_connection(data, conn);
- cpool_run_conn_shutdown(data, conn, &done);
- DEBUGF(infof(data, "[CCACHE] shutdown #%" FMT_OFF_T ", done=%d",
- conn->connection_id, done));
- Curl_detach_connection(data);
- if(done) {
- Curl_node_remove(e);
- cpool_close_and_destroy(cpool, conn, NULL, FALSE);
- }
- else {
- /* Not done, when does this connection time out? */
- if(!nowp) {
- now = Curl_now();
- nowp = &now;
- }
- ms = Curl_conn_shutdown_timeleft(conn, nowp);
- if(ms && ms < next_from_now_ms)
- next_from_now_ms = ms;
- }
- e = enext;
- }
-
- if(next_from_now_ms)
- Curl_expire(data, next_from_now_ms, EXPIRE_RUN_NOW);
-}
-
-void Curl_cpool_multi_perform(struct Curl_multi *multi)
-{
- CPOOL_LOCK(&multi->cpool);
- cpool_perform(&multi->cpool);
- CPOOL_UNLOCK(&multi->cpool);
-}
-
-
-/*
- * Close and destroy the connection. Run the shutdown sequence once,
- * of so requested.
- */
-static void cpool_close_and_destroy(struct cpool *cpool,
- struct connectdata *conn,
- struct Curl_easy *data,
- bool do_shutdown)
-{
- bool done;
-
- /* there must be a connection to close */
- DEBUGASSERT(conn);
- /* it must be removed from the connection pool */
- DEBUGASSERT(!conn->bits.in_cpool);
- /* there must be an associated transfer */
- DEBUGASSERT(data || cpool);
- if(!data)
- data = cpool->idata;
-
- /* the transfer must be detached from the connection */
- DEBUGASSERT(data && !data->conn);
-
- Curl_attach_connection(data, conn);
-
- cpool_run_conn_shutdown_handler(data, conn);
- if(do_shutdown) {
- /* Make a last attempt to shutdown handlers and filters, if
- * not done so already. */
- cpool_run_conn_shutdown(data, conn, &done);
- }
-
- if(cpool)
- DEBUGF(infof(data, "[CCACHE] closing #%" FMT_OFF_T,
- conn->connection_id));
- else
- DEBUGF(infof(data, "closing connection #%" FMT_OFF_T,
- conn->connection_id));
- Curl_conn_close(data, SECONDARYSOCKET);
- Curl_conn_close(data, FIRSTSOCKET);
- Curl_detach_connection(data);
-
- Curl_conn_free(data, conn);
-}
-
-
-static CURLMcode cpool_update_shutdown_ev(struct Curl_multi *multi,
- struct Curl_easy *data,
- struct connectdata *conn)
-{
- struct easy_pollset ps;
- CURLMcode mresult;
-
- DEBUGASSERT(data);
- DEBUGASSERT(multi);
- DEBUGASSERT(multi->socket_cb);
-
- memset(&ps, 0, sizeof(ps));
- Curl_attach_connection(data, conn);
- Curl_conn_adjust_pollset(data, &ps);
- Curl_detach_connection(data);
-
- mresult = Curl_multi_pollset_ev(multi, data, &ps, &conn->shutdown_poll);
-
- if(!mresult) /* Remember for next time */
- memcpy(&conn->shutdown_poll, &ps, sizeof(ps));
- return mresult;
-}
-
-void Curl_cpool_multi_socket(struct Curl_multi *multi,
- curl_socket_t s, int ev_bitmask)
-{
- struct cpool *cpool = &multi->cpool;
- struct Curl_easy *data = cpool->idata;
- struct Curl_llist_node *e;
- struct connectdata *conn;
- bool done;
-
- (void)ev_bitmask;
- DEBUGASSERT(multi->socket_cb);
- CPOOL_LOCK(cpool);
- e = Curl_llist_head(&cpool->shutdowns);
- while(e) {
- conn = Curl_node_elem(e);
- if(s == conn->sock[FIRSTSOCKET] || s == conn->sock[SECONDARYSOCKET]) {
- Curl_attach_connection(data, conn);
- cpool_run_conn_shutdown(data, conn, &done);
- DEBUGF(infof(data, "[CCACHE] shutdown #%" FMT_OFF_T ", done=%d",
- conn->connection_id, done));
- Curl_detach_connection(data);
- if(done || cpool_update_shutdown_ev(multi, data, conn)) {
- Curl_node_remove(e);
- cpool_close_and_destroy(cpool, conn, NULL, FALSE);
- }
- break;
- }
- e = Curl_node_next(e);
- }
- CPOOL_UNLOCK(cpool);
-}
-
-#define NUM_POLLS_ON_STACK 10
-
-static CURLcode cpool_shutdown_wait(struct cpool *cpool, int timeout_ms)
-{
- struct pollfd a_few_on_stack[NUM_POLLS_ON_STACK];
- struct curl_pollfds cpfds;
- CURLcode result;
-
- Curl_pollfds_init(&cpfds, a_few_on_stack, NUM_POLLS_ON_STACK);
-
- result = cpool_add_pollfds(cpool, &cpfds);
- if(result)
- goto out;
-
- Curl_poll(cpfds.pfds, cpfds.n, CURLMIN(timeout_ms, 1000));
-
-out:
- Curl_pollfds_cleanup(&cpfds);
- return result;
-}
-
-static void cpool_shutdown_all(struct cpool *cpool,
- struct Curl_easy *data, int timeout_ms)
-{
- struct connectdata *conn;
- struct curltime started = Curl_now();
-
- if(!data)
- return;
- (void)data;
-
- DEBUGF(infof(data, "cpool shutdown all"));
-
- /* Move all connections into the shutdown queue */
- for(conn = cpool_get_live_conn(cpool); conn;
- conn = cpool_get_live_conn(cpool)) {
- /* Move conn from live set to shutdown or destroy right away */
- DEBUGF(infof(data, "moving connection #%" FMT_OFF_T
- " to shutdown queue", conn->connection_id));
- cpool_remove_conn(cpool, conn);
- cpool_discard_conn(cpool, data, conn, FALSE);
- }
-
- while(Curl_llist_head(&cpool->shutdowns)) {
- timediff_t timespent;
- int remain_ms;
-
- cpool_perform(cpool);
-
- if(!Curl_llist_head(&cpool->shutdowns)) {
- DEBUGF(infof(data, "cpool shutdown ok"));
- break;
- }
-
- /* wait for activity, timeout or "nothing" */
- timespent = Curl_timediff(Curl_now(), started);
- if(timespent >= (timediff_t)timeout_ms) {
- DEBUGF(infof(data, "cpool shutdown %s",
- (timeout_ms > 0)? "timeout" : "best effort done"));
- break;
- }
-
- remain_ms = timeout_ms - (int)timespent;
- if(cpool_shutdown_wait(cpool, remain_ms)) {
- DEBUGF(infof(data, "cpool shutdown all, abort"));
- break;
- }
- }
-
- /* Due to errors/timeout, we might come here without being done. */
- cpool_shutdown_discard_all(cpool);
-}
-
-struct cpool_reaper_ctx {
- struct curltime now;
-};
-
-static int cpool_reap_dead_cb(struct Curl_easy *data,
- struct connectdata *conn, void *param)
-{
- struct cpool_reaper_ctx *rctx = param;
- if(Curl_conn_seems_dead(conn, data, &rctx->now)) {
- /* stop the iteration here, pass back the connection that was pruned */
- Curl_cpool_disconnect(data, conn, FALSE);
- return 1;
- }
- return 0; /* continue iteration */
-}
-
-/*
- * This function scans the data's connection pool for half-open/dead
- * connections, closes and removes them.
- * The cleanup is done at most once per second.
- *
- * When called, this transfer has no connection attached.
- */
-void Curl_cpool_prune_dead(struct Curl_easy *data)
-{
- struct cpool *cpool = cpool_get_instance(data);
- struct cpool_reaper_ctx rctx;
- timediff_t elapsed;
-
- if(!cpool)
- return;
-
- rctx.now = Curl_now();
- CPOOL_LOCK(cpool);
- elapsed = Curl_timediff(rctx.now, cpool->last_cleanup);
-
- if(elapsed >= 1000L) {
- while(cpool_foreach(data, cpool, &rctx, cpool_reap_dead_cb))
- ;
- cpool->last_cleanup = rctx.now;
- }
- CPOOL_UNLOCK(cpool);
-}
-
-static int conn_upkeep(struct Curl_easy *data,
- struct connectdata *conn,
- void *param)
-{
- struct curltime *now = param;
- /* TODO, shall we reap connections that return an error here? */
- Curl_conn_upkeep(data, conn, now);
- return 0; /* continue iteration */
-}
-
-CURLcode Curl_cpool_upkeep(void *data)
-{
- struct cpool *cpool = cpool_get_instance(data);
- struct curltime now = Curl_now();
-
- if(!cpool)
- return CURLE_OK;
-
- CPOOL_LOCK(cpool);
- cpool_foreach(data, cpool, &now, conn_upkeep);
- CPOOL_UNLOCK(cpool);
- return CURLE_OK;
-}
-
-struct cpool_find_ctx {
- curl_off_t id;
- struct connectdata *conn;
-};
-
-static int cpool_find_conn(struct Curl_easy *data,
- struct connectdata *conn, void *param)
-{
- struct cpool_find_ctx *fctx = param;
- (void)data;
- if(conn->connection_id == fctx->id) {
- fctx->conn = conn;
- return 1;
- }
- return 0;
-}
-
-struct connectdata *Curl_cpool_get_conn(struct Curl_easy *data,
- curl_off_t conn_id)
-{
- struct cpool *cpool = cpool_get_instance(data);
- struct cpool_find_ctx fctx;
-
- if(!cpool)
- return NULL;
- fctx.id = conn_id;
- fctx.conn = NULL;
- CPOOL_LOCK(cpool);
- cpool_foreach(cpool->idata, cpool, &fctx, cpool_find_conn);
- CPOOL_UNLOCK(cpool);
- return fctx.conn;
-}
-
-struct cpool_do_conn_ctx {
- curl_off_t id;
- Curl_cpool_conn_do_cb *cb;
- void *cbdata;
-};
-
-static int cpool_do_conn(struct Curl_easy *data,
- struct connectdata *conn, void *param)
-{
- struct cpool_do_conn_ctx *dctx = param;
- (void)data;
- if(conn->connection_id == dctx->id) {
- dctx->cb(conn, data, dctx->cbdata);
- return 1;
- }
- return 0;
-}
-
-void Curl_cpool_do_by_id(struct Curl_easy *data, curl_off_t conn_id,
- Curl_cpool_conn_do_cb *cb, void *cbdata)
-{
- struct cpool *cpool = cpool_get_instance(data);
- struct cpool_do_conn_ctx dctx;
-
- if(!cpool)
- return;
- dctx.id = conn_id;
- dctx.cb = cb;
- dctx.cbdata = cbdata;
- CPOOL_LOCK(cpool);
- cpool_foreach(data, cpool, &dctx, cpool_do_conn);
- CPOOL_UNLOCK(cpool);
-}
-
-void Curl_cpool_do_locked(struct Curl_easy *data,
- struct connectdata *conn,
- Curl_cpool_conn_do_cb *cb, void *cbdata)
-{
- struct cpool *cpool = cpool_get_instance(data);
- if(cpool) {
- CPOOL_LOCK(cpool);
- cb(conn, data, cbdata);
- CPOOL_UNLOCK(cpool);
- }
- else
- cb(conn, data, cbdata);
+ Curl_hostcache_clean(connc->closure_handle,
+ connc->closure_handle->dns.hostcache);
+ Curl_close(&connc->closure_handle);
+ sigpipe_restore(&pipe_st);
}
#if 0
-/* Useful for debugging the connection pool */
-void Curl_cpool_print(struct cpool *cpool)
+/* Useful for debugging the connection cache */
+void Curl_conncache_print(struct conncache *connc)
{
struct Curl_hash_iterator iter;
- struct Curl_llist_node *curr;
+ struct Curl_llist_element *curr;
struct Curl_hash_element *he;
- if(!cpool)
+ if(!connc)
return;
fprintf(stderr, "=Bundle cache=\n");
- Curl_hash_start_iterate(cpool->dest2bundle, &iter);
+ Curl_hash_start_iterate(connc->hash, &iter);
he = Curl_hash_next_element(&iter);
while(he) {
- struct cpool_bundle *bundle;
+ struct connectbundle *bundle;
struct connectdata *conn;
bundle = he->ptr;
fprintf(stderr, "%s -", he->key);
- curr = Curl_llist_head(bundle->conns);
+ curr = bundle->conn_list->head;
while(curr) {
- conn = Curl_node_elem(curr);
+ conn = curr->ptr;
- fprintf(stderr, " [%p %d]", (void *)conn, conn->refcount);
- curr = Curl_node_next(curr);
+ fprintf(stderr, " [%p %d]", (void *)conn, conn->inuse);
+ curr = curr->next;
}
fprintf(stderr, "\n");
diff --git a/contrib/libs/curl/lib/conncache.h b/contrib/libs/curl/lib/conncache.h
index a379ee747d..c60f8449ee 100644
--- a/contrib/libs/curl/lib/conncache.h
+++ b/contrib/libs/curl/lib/conncache.h
@@ -25,177 +25,98 @@
*
***************************************************************************/
+/*
+ * All accesses to struct fields and changing of data in the connection cache
+ * and connectbundles must be done with the conncache LOCKED. The cache might
+ * be shared.
+ */
+
#include <curl/curl.h>
#include "timeval.h"
struct connectdata;
-struct Curl_easy;
-struct curl_pollfds;
-struct curl_waitfds;
-struct Curl_multi;
-struct Curl_share;
-/**
- * Callback invoked when disconnecting connections.
- * @param data transfer last handling the connection, not attached
- * @param conn the connection to discard
- * @param aborted if the connection is being aborted
- * @return if the connection is being aborted, e.g. should NOT perform
- * a shutdown and just close.
- **/
-typedef bool Curl_cpool_disconnect_cb(struct Curl_easy *data,
- struct connectdata *conn,
- bool aborted);
-
-struct cpool {
- /* the pooled connections, bundled per destination */
- struct Curl_hash dest2bundle;
+struct conncache {
+ struct Curl_hash hash;
size_t num_conn;
curl_off_t next_connection_id;
curl_off_t next_easy_id;
struct curltime last_cleanup;
- struct Curl_llist shutdowns; /* The connections being shut down */
- struct Curl_easy *idata; /* internal handle used for discard */
- struct Curl_multi *multi; /* != NULL iff pool belongs to multi */
- struct Curl_share *share; /* != NULL iff pool belongs to share */
- Curl_cpool_disconnect_cb *disconnect_cb;
- BIT(locked);
+ /* handle used for closing cached connections */
+ struct Curl_easy *closure_handle;
};
-/* Init the pool, pass multi only if pool is owned by it.
- * returns 1 on error, 0 is fine.
- */
-int Curl_cpool_init(struct cpool *cpool,
- Curl_cpool_disconnect_cb *disconnect_cb,
- struct Curl_multi *multi,
- struct Curl_share *share,
- size_t size);
-
-/* Destroy all connections and free all members */
-void Curl_cpool_destroy(struct cpool *connc);
-
-/* Init the transfer to be used within its connection pool.
- * Assigns `data->id`. */
-void Curl_cpool_xfer_init(struct Curl_easy *data);
-
-/**
- * Get the connection with the given id from the transfer's pool.
- */
-struct connectdata *Curl_cpool_get_conn(struct Curl_easy *data,
- curl_off_t conn_id);
-
-CURLcode Curl_cpool_add_conn(struct Curl_easy *data,
- struct connectdata *conn) WARN_UNUSED_RESULT;
-
-/**
- * Return if the pool has reached its configured limits for adding
- * the given connection. Will try to discard the oldest, idle
- * connections to make space.
- */
-#define CPOOL_LIMIT_OK 0
-#define CPOOL_LIMIT_DEST 1
-#define CPOOL_LIMIT_TOTAL 2
-int Curl_cpool_check_limits(struct Curl_easy *data,
- struct connectdata *conn);
-
-/* Return of conn is suitable. If so, stops iteration. */
-typedef bool Curl_cpool_conn_match_cb(struct connectdata *conn,
- void *userdata);
-
-/* Act on the result of the find, may override it. */
-typedef bool Curl_cpool_done_match_cb(bool result, void *userdata);
-
-/**
- * Find a connection in the pool matching `destination`.
- * All callbacks are invoked while the pool's lock is held.
- * @param data current transfer
- * @param destination match agaonst `conn->destination` in pool
- * @param dest_len destination length, including terminating NUL
- * @param conn_cb must be present, called for each connection in the
- * bundle until it returns TRUE
- * @param result_cb if not NULL, is called at the end with the result
- * of the `conn_cb` or FALSE if never called.
- * @return combined result of last conn_db and result_cb or FALSE if no
- connections were present.
- */
-bool Curl_cpool_find(struct Curl_easy *data,
- const char *destination, size_t dest_len,
- Curl_cpool_conn_match_cb *conn_cb,
- Curl_cpool_done_match_cb *done_cb,
- void *userdata);
-
-/*
- * A connection (already in the pool) is now idle. Do any
- * cleanups in regard to the pool's limits.
- *
- * Return TRUE if idle connection kept in pool, FALSE if closed.
- */
-bool Curl_cpool_conn_now_idle(struct Curl_easy *data,
- struct connectdata *conn);
-
-/**
- * Remove the connection from the pool and tear it down.
- * If `aborted` is FALSE, the connection will be shut down first
- * before closing and destroying it.
- * If the shutdown is not immediately complete, the connection
- * will be placed into the pool's shutdown queue.
- */
-void Curl_cpool_disconnect(struct Curl_easy *data,
- struct connectdata *conn,
- bool aborted);
-
-/**
- * This function scans the data's connection pool for half-open/dead
- * connections, closes and removes them.
- * The cleanup is done at most once per second.
- *
- * When called, this transfer has no connection attached.
- */
-void Curl_cpool_prune_dead(struct Curl_easy *data);
-
-/**
- * Perform upkeep actions on connections in the transfer's pool.
- */
-CURLcode Curl_cpool_upkeep(void *data);
-
-typedef void Curl_cpool_conn_do_cb(struct connectdata *conn,
- struct Curl_easy *data,
- void *cbdata);
-
-/**
- * Invoke the callback on the pool's connection with the
- * given connection id (if it exists).
- */
-void Curl_cpool_do_by_id(struct Curl_easy *data,
- curl_off_t conn_id,
- Curl_cpool_conn_do_cb *cb, void *cbdata);
-
-/**
- * Invoked the callback for the given data + connection under the
- * connection pool's lock.
- * The callback is always invoked, even if the transfer has no connection
- * pool associated.
- */
-void Curl_cpool_do_locked(struct Curl_easy *data,
- struct connectdata *conn,
- Curl_cpool_conn_do_cb *cb, void *cbdata);
-
-/**
- * Add sockets and POLLIN/OUT flags for connections handled by the pool.
- */
-CURLcode Curl_cpool_add_pollfds(struct cpool *connc,
- struct curl_pollfds *cpfds);
-CURLcode Curl_cpool_add_waitfds(struct cpool *connc,
- struct curl_waitfds *cwfds);
-
-/**
- * Perform maintenance on connections in the pool. Specifically,
- * progress the shutdown of connections in the queue.
- */
-void Curl_cpool_multi_perform(struct Curl_multi *multi);
-
-void Curl_cpool_multi_socket(struct Curl_multi *multi,
- curl_socket_t s, int ev_bitmask);
+#define BUNDLE_NO_MULTIUSE -1
+#define BUNDLE_UNKNOWN 0 /* initial value */
+#define BUNDLE_MULTIPLEX 2
+
+#ifdef CURLDEBUG
+/* the debug versions of these macros make extra certain that the lock is
+ never doubly locked or unlocked */
+#define CONNCACHE_LOCK(x) \
+ do { \
+ if((x)->share) { \
+ Curl_share_lock((x), CURL_LOCK_DATA_CONNECT, \
+ CURL_LOCK_ACCESS_SINGLE); \
+ DEBUGASSERT(!(x)->state.conncache_lock); \
+ (x)->state.conncache_lock = TRUE; \
+ } \
+ } while(0)
+
+#define CONNCACHE_UNLOCK(x) \
+ do { \
+ if((x)->share) { \
+ DEBUGASSERT((x)->state.conncache_lock); \
+ (x)->state.conncache_lock = FALSE; \
+ Curl_share_unlock((x), CURL_LOCK_DATA_CONNECT); \
+ } \
+ } while(0)
+#else
+#define CONNCACHE_LOCK(x) if((x)->share) \
+ Curl_share_lock((x), CURL_LOCK_DATA_CONNECT, CURL_LOCK_ACCESS_SINGLE)
+#define CONNCACHE_UNLOCK(x) if((x)->share) \
+ Curl_share_unlock((x), CURL_LOCK_DATA_CONNECT)
+#endif
+
+struct connectbundle {
+ int multiuse; /* supports multi-use */
+ size_t num_connections; /* Number of connections in the bundle */
+ struct Curl_llist conn_list; /* The connectdata members of the bundle */
+};
+/* returns 1 on error, 0 is fine */
+int Curl_conncache_init(struct conncache *, int size);
+void Curl_conncache_destroy(struct conncache *connc);
+
+/* return the correct bundle, to a host or a proxy */
+struct connectbundle *Curl_conncache_find_bundle(struct Curl_easy *data,
+ struct connectdata *conn,
+ struct conncache *connc);
+/* returns number of connections currently held in the connection cache */
+size_t Curl_conncache_size(struct Curl_easy *data);
+
+bool Curl_conncache_return_conn(struct Curl_easy *data,
+ struct connectdata *conn);
+CURLcode Curl_conncache_add_conn(struct Curl_easy *data) WARN_UNUSED_RESULT;
+void Curl_conncache_remove_conn(struct Curl_easy *data,
+ struct connectdata *conn,
+ bool lock);
+bool Curl_conncache_foreach(struct Curl_easy *data,
+ struct conncache *connc,
+ void *param,
+ int (*func)(struct Curl_easy *data,
+ struct connectdata *conn,
+ void *param));
+
+struct connectdata *
+Curl_conncache_find_first_connection(struct conncache *connc);
+
+struct connectdata *
+Curl_conncache_extract_bundle(struct Curl_easy *data,
+ struct connectbundle *bundle);
+struct connectdata *
+Curl_conncache_extract_oldest(struct Curl_easy *data);
+void Curl_conncache_close_all_connections(struct conncache *connc);
+void Curl_conncache_print(struct conncache *connc);
#endif /* HEADER_CURL_CONNCACHE_H */
diff --git a/contrib/libs/curl/lib/connect.c b/contrib/libs/curl/lib/connect.c
index 923f37ac3b..ec5ab71d49 100644
--- a/contrib/libs/curl/lib/connect.c
+++ b/contrib/libs/curl/lib/connect.c
@@ -90,20 +90,28 @@
/*
* Curl_timeleft() returns the amount of milliseconds left allowed for the
- * transfer/connection. If the value is 0, there is no timeout (ie there is
+ * transfer/connection. If the value is 0, there's no timeout (ie there's
* infinite time left). If the value is negative, the timeout time has already
* elapsed.
- * @param data the transfer to check on
- * @param nowp timestamp to use for calculation, NULL to use Curl_now()
- * @param duringconnect TRUE iff connect timeout is also taken into account.
+ *
+ * If 'nowp' is non-NULL, it points to the current time.
+ * 'duringconnect' is FALSE if not during a connect, as then of course the
+ * connect timeout is not taken into account!
+ *
* @unittest: 1303
*/
+
+#define TIMEOUT_CONNECT 1
+#define TIMEOUT_MAXTIME 2
+
timediff_t Curl_timeleft(struct Curl_easy *data,
struct curltime *nowp,
bool duringconnect)
{
- timediff_t timeleft_ms = 0;
- timediff_t ctimeleft_ms = 0;
+ unsigned int timeout_set = 0;
+ timediff_t connect_timeout_ms = 0;
+ timediff_t maxtime_timeout_ms = 0;
+ timediff_t timeout_ms = 0;
struct curltime now;
/* The duration of a connect and the total transfer are calculated from two
@@ -111,101 +119,61 @@ timediff_t Curl_timeleft(struct Curl_easy *data,
before the connect timeout expires and we must acknowledge whichever
timeout that is reached first. The total timeout is set per entire
operation, while the connect timeout is set per connect. */
- if(data->set.timeout <= 0 && !duringconnect)
- return 0; /* no timeout in place or checked, return "no limit" */
-
- if(!nowp) {
- now = Curl_now();
- nowp = &now;
- }
if(data->set.timeout > 0) {
- timeleft_ms = data->set.timeout -
- Curl_timediff(*nowp, data->progress.t_startop);
- if(!timeleft_ms)
- timeleft_ms = -1; /* 0 is "no limit", fake 1 ms expiry */
- if(!duringconnect)
- return timeleft_ms; /* no connect check, this is it */
+ timeout_set = TIMEOUT_MAXTIME;
+ maxtime_timeout_ms = data->set.timeout;
}
-
if(duringconnect) {
- timediff_t ctimeout_ms = (data->set.connecttimeout > 0) ?
+ timeout_set |= TIMEOUT_CONNECT;
+ connect_timeout_ms = (data->set.connecttimeout > 0) ?
data->set.connecttimeout : DEFAULT_CONNECT_TIMEOUT;
- ctimeleft_ms = ctimeout_ms -
- Curl_timediff(*nowp, data->progress.t_startsingle);
- if(!ctimeleft_ms)
- ctimeleft_ms = -1; /* 0 is "no limit", fake 1 ms expiry */
- if(!timeleft_ms)
- return ctimeleft_ms; /* no general timeout, this is it */
}
- /* return minimal time left or max amount already expired */
- return (ctimeleft_ms < timeleft_ms)? ctimeleft_ms : timeleft_ms;
-}
-
-void Curl_shutdown_start(struct Curl_easy *data, int sockindex,
- struct curltime *nowp)
-{
- struct curltime now;
+ if(!timeout_set)
+ /* no timeout */
+ return 0;
- DEBUGASSERT(data->conn);
if(!nowp) {
now = Curl_now();
nowp = &now;
}
- data->conn->shutdown.start[sockindex] = *nowp;
- data->conn->shutdown.timeout_ms = (data->set.shutdowntimeout > 0) ?
- data->set.shutdowntimeout : DEFAULT_SHUTDOWN_TIMEOUT_MS;
-}
-
-timediff_t Curl_shutdown_timeleft(struct connectdata *conn, int sockindex,
- struct curltime *nowp)
-{
- struct curltime now;
- timediff_t left_ms;
- if(!conn->shutdown.start[sockindex].tv_sec || !conn->shutdown.timeout_ms)
- return 0; /* not started or no limits */
-
- if(!nowp) {
- now = Curl_now();
- nowp = &now;
+ if(timeout_set & TIMEOUT_MAXTIME) {
+ maxtime_timeout_ms -= Curl_timediff(*nowp, data->progress.t_startop);
+ timeout_ms = maxtime_timeout_ms;
}
- left_ms = conn->shutdown.timeout_ms -
- Curl_timediff(*nowp, conn->shutdown.start[sockindex]);
- return left_ms? left_ms : -1;
-}
-timediff_t Curl_conn_shutdown_timeleft(struct connectdata *conn,
- struct curltime *nowp)
-{
- timediff_t left_ms = 0, ms;
- struct curltime now;
- int i;
+ if(timeout_set & TIMEOUT_CONNECT) {
+ connect_timeout_ms -= Curl_timediff(*nowp, data->progress.t_startsingle);
- for(i = 0; conn->shutdown.timeout_ms && (i < 2); ++i) {
- if(!conn->shutdown.start[i].tv_sec)
- continue;
- if(!nowp) {
- now = Curl_now();
- nowp = &now;
- }
- ms = Curl_shutdown_timeleft(conn, i, nowp);
- if(ms && (!left_ms || ms < left_ms))
- left_ms = ms;
+ if(!(timeout_set & TIMEOUT_MAXTIME) ||
+ (connect_timeout_ms < maxtime_timeout_ms))
+ timeout_ms = connect_timeout_ms;
}
- return left_ms;
-}
-void Curl_shutdown_clear(struct Curl_easy *data, int sockindex)
-{
- struct curltime *pt = &data->conn->shutdown.start[sockindex];
- memset(pt, 0, sizeof(*pt));
+ if(!timeout_ms)
+ /* avoid returning 0 as that means no timeout! */
+ return -1;
+
+ return timeout_ms;
}
-bool Curl_shutdown_started(struct Curl_easy *data, int sockindex)
+/* Copies connection info into the transfer handle to make it available when
+ the transfer handle is no longer associated with the connection. */
+void Curl_persistconninfo(struct Curl_easy *data, struct connectdata *conn,
+ char *local_ip, int local_port)
{
- struct curltime *pt = &data->conn->shutdown.start[sockindex];
- return (pt->tv_sec > 0) || (pt->tv_usec > 0);
+ memcpy(data->info.conn_primary_ip, conn->primary_ip, MAX_IPADR_LEN);
+ if(local_ip && local_ip[0])
+ memcpy(data->info.conn_local_ip, local_ip, MAX_IPADR_LEN);
+ else
+ data->info.conn_local_ip[0] = 0;
+ data->info.conn_scheme = conn->handler->scheme;
+ /* conn_protocol can only provide "old" protocols */
+ data->info.conn_protocol = (conn->handler->protocol) & CURLPROTO_MASK;
+ data->info.conn_primary_port = conn->port;
+ data->info.conn_remote_port = conn->remote_port;
+ data->info.conn_local_port = local_port;
}
static const struct Curl_addrinfo *
@@ -236,7 +204,7 @@ bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen,
char *addr, int *port)
{
struct sockaddr_in *si = NULL;
-#ifdef USE_IPV6
+#ifdef ENABLE_IPV6
struct sockaddr_in6 *si6 = NULL;
#endif
#if (defined(HAVE_SYS_UN_H) || defined(WIN32_SOCKADDR_UN)) && defined(AF_UNIX)
@@ -255,7 +223,7 @@ bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen,
return TRUE;
}
break;
-#ifdef USE_IPV6
+#ifdef ENABLE_IPV6
case AF_INET6:
si6 = (struct sockaddr_in6 *)(void *) sa;
if(Curl_inet_ntop(sa->sa_family, &si6->sin6_addr,
@@ -287,6 +255,23 @@ bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen,
return FALSE;
}
+struct connfind {
+ curl_off_t id_tofind;
+ struct connectdata *found;
+};
+
+static int conn_is_conn(struct Curl_easy *data,
+ struct connectdata *conn, void *param)
+{
+ struct connfind *f = (struct connfind *)param;
+ (void)data;
+ if(conn->connection_id == f->id_tofind) {
+ f->found = conn;
+ return 1;
+ }
+ return 0;
+}
+
/*
* Used to extract socket and connectdata struct for the most recent
* transfer on the given Curl_easy.
@@ -303,19 +288,30 @@ curl_socket_t Curl_getconnectinfo(struct Curl_easy *data,
* - that is associated with a multi handle, and whose connection
* was detached with CURLOPT_CONNECT_ONLY
*/
- if(data->state.lastconnect_id != -1) {
- struct connectdata *conn;
-
- conn = Curl_cpool_get_conn(data, data->state.lastconnect_id);
- if(!conn) {
+ if((data->state.lastconnect_id != -1) && (data->multi_easy || data->multi)) {
+ struct connectdata *c;
+ struct connfind find;
+ find.id_tofind = data->state.lastconnect_id;
+ find.found = NULL;
+
+ Curl_conncache_foreach(data,
+ data->share && (data->share->specifier
+ & (1<< CURL_LOCK_DATA_CONNECT))?
+ &data->share->conn_cache:
+ data->multi_easy?
+ &data->multi_easy->conn_cache:
+ &data->multi->conn_cache, &find, conn_is_conn);
+
+ if(!find.found) {
data->state.lastconnect_id = -1;
return CURL_SOCKET_BAD;
}
+ c = find.found;
if(connp)
/* only store this if the caller cares for it */
- *connp = conn;
- return conn->sock[FIRSTSOCKET];
+ *connp = c;
+ return c->sock[FIRSTSOCKET];
}
return CURL_SOCKET_BAD;
}
@@ -330,7 +326,7 @@ void Curl_conncontrol(struct connectdata *conn,
#endif
)
{
- /* close if a connection, or a stream that is not multiplexed. */
+ /* close if a connection, or a stream that isn't multiplexed. */
/* This function will be called both before and after this connection is
associated with a transfer. */
bool closeit, is_multiplex;
@@ -371,7 +367,6 @@ struct eyeballer {
BIT(has_started); /* attempts have started */
BIT(is_done); /* out of addresses/time */
BIT(connected); /* cf has connected */
- BIT(shutdown); /* cf has shutdown */
BIT(inconclusive); /* connect was not a hard failure, we
* might talk to a restarting server */
};
@@ -410,12 +405,12 @@ static CURLcode eyeballer_new(struct eyeballer **pballer,
struct eyeballer *baller;
*pballer = NULL;
- baller = calloc(1, sizeof(*baller));
+ baller = calloc(1, sizeof(*baller) + 1000);
if(!baller)
return CURLE_OUT_OF_MEMORY;
baller->name = ((ai_family == AF_INET)? "ipv4" : (
-#ifdef USE_IPV6
+#ifdef ENABLE_IPV6
(ai_family == AF_INET6)? "ipv6" :
#endif
"ip"));
@@ -478,7 +473,7 @@ static void baller_initiate(struct Curl_cfilter *cf,
CURLcode result;
- /* Do not close a previous cfilter yet to ensure that the next IP's
+ /* Don't close a previous cfilter yet to ensure that the next IP's
socket gets a different file descriptor, which can prevent bugs when
the curl_multi_socket_action interface is used with certain select()
replacements such as kqueue. */
@@ -547,11 +542,9 @@ static CURLcode baller_start_next(struct Curl_cfilter *cf,
{
if(cf->sockindex == FIRSTSOCKET) {
baller_next_addr(baller);
- /* If we get inconclusive answers from the server(s), we start
- * again until this whole thing times out. This allows us to
- * connect to servers that are gracefully restarting and the
- * packet routing to the new instance has not happened yet (e.g. QUIC). */
- if(!baller->addr && baller->inconclusive)
+ /* If we get inconclusive answers from the server(s), we make
+ * a second iteration over the address list */
+ if(!baller->addr && baller->inconclusive && !baller->rewinded)
baller_rewind(baller);
baller_start(cf, data, baller, timeoutms);
}
@@ -583,7 +576,7 @@ static CURLcode baller_connect(struct Curl_cfilter *cf,
baller->is_done = TRUE;
}
else if(Curl_timediff(*now, baller->started) >= baller->timeoutms) {
- infof(data, "%s connect timeout after %" FMT_TIMEDIFF_T
+ infof(data, "%s connect timeout after %" CURL_FORMAT_TIMEDIFF_T
"ms, move on!", baller->name, baller->timeoutms);
#if defined(ETIMEDOUT)
baller->error = ETIMEDOUT;
@@ -674,7 +667,7 @@ evaluate:
/* Nothing connected, check the time before we might
* start new ballers or return ok. */
if((ongoing || not_started) && Curl_timeleft(data, &now, TRUE) < 0) {
- failf(data, "Connection timeout after %" FMT_OFF_T " ms",
+ failf(data, "Connection timeout after %" CURL_FORMAT_CURL_OFF_T " ms",
Curl_timediff(now, data->progress.t_startsingle));
return CURLE_OPERATION_TIMEDOUT;
}
@@ -697,7 +690,8 @@ evaluate:
CURL_TRC_CF(data, cf, "%s done", baller->name);
}
else {
- CURL_TRC_CF(data, cf, "%s starting (timeout=%" FMT_TIMEDIFF_T "ms)",
+ CURL_TRC_CF(data, cf, "%s starting (timeout=%"
+ CURL_FORMAT_TIMEDIFF_T "ms)",
baller->name, baller->timeoutms);
++ongoing;
++added;
@@ -742,8 +736,8 @@ evaluate:
hostname = conn->host.name;
failf(data, "Failed to connect to %s port %u after "
- "%" FMT_TIMEDIFF_T " ms: %s",
- hostname, conn->primary.remote_port,
+ "%" CURL_FORMAT_TIMEDIFF_T " ms: %s",
+ hostname, conn->port,
Curl_timediff(now, data->progress.t_startsingle),
curl_easy_strerror(result));
@@ -759,7 +753,7 @@ evaluate:
}
/*
- * Connect to the given host with timeout, proxy or remote does not matter.
+ * Connect to the given host with timeout, proxy or remote doesn't matter.
* There might be more than one IP address to try out.
*/
static CURLcode start_connect(struct Curl_cfilter *cf,
@@ -769,9 +763,9 @@ static CURLcode start_connect(struct Curl_cfilter *cf,
struct cf_he_ctx *ctx = cf->ctx;
struct connectdata *conn = cf->conn;
CURLcode result = CURLE_COULDNT_CONNECT;
- int ai_family0 = 0, ai_family1 = 0;
+ int ai_family0, ai_family1;
timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
- const struct Curl_addrinfo *addr0 = NULL, *addr1 = NULL;
+ const struct Curl_addrinfo *addr0, *addr1;
if(timeout_ms < 0) {
/* a precaution, no need to continue if time already is up */
@@ -790,33 +784,33 @@ static CURLcode start_connect(struct Curl_cfilter *cf,
* the 2 connect attempt ballers to try different families, if possible.
*
*/
- if(conn->ip_version == CURL_IPRESOLVE_V6) {
-#ifdef USE_IPV6
- ai_family0 = AF_INET6;
- addr0 = addr_first_match(remotehost->addr, ai_family0);
+ if(conn->ip_version == CURL_IPRESOLVE_WHATEVER) {
+ /* any IP version is allowed */
+ ai_family0 = remotehost->addr?
+ remotehost->addr->ai_family : 0;
+#ifdef ENABLE_IPV6
+ ai_family1 = ai_family0 == AF_INET6 ?
+ AF_INET : AF_INET6;
+#else
+ ai_family1 = AF_UNSPEC;
#endif
}
- else if(conn->ip_version == CURL_IPRESOLVE_V4) {
- ai_family0 = AF_INET;
- addr0 = addr_first_match(remotehost->addr, ai_family0);
- }
else {
- /* no user preference, we try ipv6 always first when available */
-#ifdef USE_IPV6
- ai_family0 = AF_INET6;
- addr0 = addr_first_match(remotehost->addr, ai_family0);
+ /* only one IP version is allowed */
+ ai_family0 = (conn->ip_version == CURL_IPRESOLVE_V4) ?
+ AF_INET :
+#ifdef ENABLE_IPV6
+ AF_INET6;
+#else
+ AF_UNSPEC;
#endif
- /* next candidate is ipv4 */
- ai_family1 = AF_INET;
- addr1 = addr_first_match(remotehost->addr, ai_family1);
- /* no ip address families, probably AF_UNIX or something, use the
- * address family given to us */
- if(!addr1 && !addr0 && remotehost->addr) {
- ai_family0 = remotehost->addr->ai_family;
- addr0 = addr_first_match(remotehost->addr, ai_family0);
- }
+ ai_family1 = AF_UNSPEC;
}
+ /* Get the first address in the list that matches the family,
+ * this might give NULL, if we do not have any matches. */
+ addr0 = addr_first_match(remotehost->addr, ai_family0);
+ addr1 = addr_first_match(remotehost->addr, ai_family1);
if(!addr0 && addr1) {
/* switch around, so a single baller always uses addr0 */
addr0 = addr1;
@@ -835,7 +829,8 @@ static CURLcode start_connect(struct Curl_cfilter *cf,
timeout_ms, EXPIRE_DNS_PER_NAME);
if(result)
return result;
- CURL_TRC_CF(data, cf, "created %s (timeout %" FMT_TIMEDIFF_T "ms)",
+ CURL_TRC_CF(data, cf, "created %s (timeout %"
+ CURL_FORMAT_TIMEDIFF_T "ms)",
ctx->baller[0]->name, ctx->baller[0]->timeoutms);
if(addr1) {
/* second one gets a delayed start */
@@ -846,7 +841,8 @@ static CURLcode start_connect(struct Curl_cfilter *cf,
timeout_ms, EXPIRE_DNS_PER_NAME2);
if(result)
return result;
- CURL_TRC_CF(data, cf, "created %s (timeout %" FMT_TIMEDIFF_T "ms)",
+ CURL_TRC_CF(data, cf, "created %s (timeout %"
+ CURL_FORMAT_TIMEDIFF_T "ms)",
ctx->baller[1]->name, ctx->baller[1]->timeoutms);
Curl_expire(data, data->set.happy_eyeballs_timeout,
EXPIRE_HAPPY_EYEBALLS);
@@ -870,46 +866,6 @@ static void cf_he_ctx_clear(struct Curl_cfilter *cf, struct Curl_easy *data)
ctx->winner = NULL;
}
-static CURLcode cf_he_shutdown(struct Curl_cfilter *cf,
- struct Curl_easy *data, bool *done)
-{
- struct cf_he_ctx *ctx = cf->ctx;
- size_t i;
- CURLcode result = CURLE_OK;
-
- DEBUGASSERT(data);
- if(cf->connected) {
- *done = TRUE;
- return CURLE_OK;
- }
-
- /* shutdown all ballers that have not done so already. If one fails,
- * continue shutting down others until all are shutdown. */
- for(i = 0; i < ARRAYSIZE(ctx->baller); i++) {
- struct eyeballer *baller = ctx->baller[i];
- bool bdone = FALSE;
- if(!baller || !baller->cf || baller->shutdown)
- continue;
- baller->result = baller->cf->cft->do_shutdown(baller->cf, data, &bdone);
- if(baller->result || bdone)
- baller->shutdown = TRUE; /* treat a failed shutdown as done */
- }
-
- *done = TRUE;
- for(i = 0; i < ARRAYSIZE(ctx->baller); i++) {
- if(ctx->baller[i] && !ctx->baller[i]->shutdown)
- *done = FALSE;
- }
- if(*done) {
- for(i = 0; i < ARRAYSIZE(ctx->baller); i++) {
- if(ctx->baller[i] && ctx->baller[i]->result)
- result = ctx->baller[i]->result;
- }
- }
- CURL_TRC_CF(data, cf, "shutdown -> %d, done=%d", result, *done);
- return result;
-}
-
static void cf_he_adjust_pollset(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct easy_pollset *ps)
@@ -952,7 +908,7 @@ static CURLcode cf_he_connect(struct Curl_cfilter *cf,
if(result)
return result;
ctx->state = SCFST_WAITING;
- FALLTHROUGH();
+ /* FALLTHROUGH */
case SCFST_WAITING:
result = is_connected(cf, data, done);
if(!result && *done) {
@@ -966,20 +922,12 @@ static CURLcode cf_he_connect(struct Curl_cfilter *cf,
cf->next = ctx->winner->cf;
ctx->winner->cf = NULL;
cf_he_ctx_clear(cf, data);
+ Curl_conn_cf_cntrl(cf->next, data, TRUE,
+ CF_CTRL_CONN_INFO_UPDATE, 0, NULL);
if(cf->conn->handler->protocol & PROTO_FAMILY_SSH)
- Curl_pgrsTime(data, TIMER_APPCONNECT); /* we are connected already */
- if(Curl_trc_cf_is_verbose(cf, data)) {
- struct ip_quadruple ipquad;
- int is_ipv6;
- if(!Curl_conn_cf_get_ip_info(cf->next, data, &is_ipv6, &ipquad)) {
- const char *host, *disphost;
- int port;
- cf->next->cft->get_host(cf->next, data, &host, &disphost, &port);
- CURL_TRC_CF(data, cf, "Connected to %s (%s) port %u",
- disphost, ipquad.remote_ip, ipquad.remote_port);
- }
- }
+ Curl_pgrsTime(data, TIMER_APPCONNECT); /* we're connected already */
+ Curl_verboseconnect(data, cf->conn);
data->info.numconnects++; /* to track the # of connections made */
}
break;
@@ -1113,7 +1061,6 @@ struct Curl_cftype Curl_cft_happy_eyeballs = {
cf_he_destroy,
cf_he_connect,
cf_he_close,
- cf_he_shutdown,
Curl_cf_def_get_host,
cf_he_adjust_pollset,
cf_he_data_pending,
@@ -1174,12 +1121,12 @@ struct transport_provider {
};
static
-#ifndef UNITTESTS
+#ifndef DEBUGBUILD
const
#endif
struct transport_provider transport_providers[] = {
{ TRNSPRT_TCP, Curl_cf_tcp_create },
-#ifdef USE_HTTP3
+#ifdef ENABLE_QUIC
{ TRNSPRT_QUIC, Curl_cf_quic_create },
#endif
#ifndef CURL_DISABLE_TFTP
@@ -1378,7 +1325,6 @@ struct Curl_cftype Curl_cft_setup = {
cf_setup_destroy,
cf_setup_connect,
cf_setup_close,
- Curl_cf_def_shutdown,
Curl_cf_def_get_host,
Curl_cf_def_adjust_pollset,
Curl_cf_def_data_pending,
@@ -1441,7 +1387,7 @@ out:
return result;
}
-#ifdef UNITTESTS
+#ifdef DEBUGBUILD
/* used by unit2600.c */
void Curl_debug_set_transport_provider(int transport,
cf_ip_connect_create *cf_create)
@@ -1454,7 +1400,7 @@ void Curl_debug_set_transport_provider(int transport,
}
}
}
-#endif /* UNITTESTS */
+#endif /* DEBUGBUILD */
CURLcode Curl_cf_setup_insert_after(struct Curl_cfilter *cf_at,
struct Curl_easy *data,
diff --git a/contrib/libs/curl/lib/connect.h b/contrib/libs/curl/lib/connect.h
index 160db9420f..58264bdba4 100644
--- a/contrib/libs/curl/lib/connect.h
+++ b/contrib/libs/curl/lib/connect.h
@@ -30,9 +30,8 @@
#include "timeval.h"
struct Curl_dns_entry;
-struct ip_quadruple;
-/* generic function that returns how much time there is left to run, according
+/* generic function that returns how much time there's left to run, according
to the timeouts set */
timediff_t Curl_timeleft(struct Curl_easy *data,
struct curltime *nowp,
@@ -40,26 +39,6 @@ timediff_t Curl_timeleft(struct Curl_easy *data,
#define DEFAULT_CONNECT_TIMEOUT 300000 /* milliseconds == five minutes */
-#define DEFAULT_SHUTDOWN_TIMEOUT_MS (2 * 1000)
-
-void Curl_shutdown_start(struct Curl_easy *data, int sockindex,
- struct curltime *nowp);
-
-/* return how much time there is left to shutdown the connection at
- * sockindex. Returns 0 if there is no limit or shutdown has not started. */
-timediff_t Curl_shutdown_timeleft(struct connectdata *conn, int sockindex,
- struct curltime *nowp);
-
-/* return how much time there is left to shutdown the connection.
- * Returns 0 if there is no limit or shutdown has not started. */
-timediff_t Curl_conn_shutdown_timeleft(struct connectdata *conn,
- struct curltime *nowp);
-
-void Curl_shutdown_clear(struct Curl_easy *data, int sockindex);
-
-/* TRUE iff shutdown has been started */
-bool Curl_shutdown_started(struct Curl_easy *data, int sockindex);
-
/*
* Used to extract socket and connectdata struct for the most recent
* transfer on the given Curl_easy.
@@ -72,6 +51,9 @@ curl_socket_t Curl_getconnectinfo(struct Curl_easy *data,
bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen,
char *addr, int *port);
+void Curl_persistconninfo(struct Curl_easy *data, struct connectdata *conn,
+ char *local_ip, int local_port);
+
/*
* Curl_conncontrol() marks the end of a connection/stream. The 'closeit'
* argument specifies if it is the end of a connection or a stream.
@@ -142,7 +124,7 @@ CURLcode Curl_conn_setup(struct Curl_easy *data,
extern struct Curl_cftype Curl_cft_happy_eyeballs;
extern struct Curl_cftype Curl_cft_setup;
-#ifdef UNITTESTS
+#ifdef DEBUGBUILD
void Curl_debug_set_transport_provider(int transport,
cf_ip_connect_create *cf_create);
#endif
diff --git a/contrib/libs/curl/lib/content_encoding.c b/contrib/libs/curl/lib/content_encoding.c
index c0b97f1f7d..4167d4d684 100644
--- a/contrib/libs/curl/lib/content_encoding.c
+++ b/contrib/libs/curl/lib/content_encoding.c
@@ -79,10 +79,10 @@
#define GZIP_MAGIC_1 0x8b
/* gzip flag byte */
-#define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */
+#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */
#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
-#define ORIG_NAME 0x08 /* bit 3 set: original filename present */
+#define ORIG_NAME 0x08 /* bit 3 set: original file name present */
#define COMMENT 0x10 /* bit 4 set: file comment present */
#define RESERVED 0xE0 /* bits 5..7: reserved */
@@ -192,7 +192,7 @@ static CURLcode inflate_stream(struct Curl_easy *data,
zp->zlib_init != ZLIB_GZIP_INFLATING)
return exit_zlib(data, z, &zp->zlib_init, CURLE_WRITE_ERROR);
- /* Dynamically allocate a buffer for decompression because it is uncommonly
+ /* Dynamically allocate a buffer for decompression because it's uncommonly
large to hold on the stack */
decomp = malloc(DSIZ);
if(!decomp)
@@ -246,7 +246,7 @@ static CURLcode inflate_stream(struct Curl_easy *data,
to fix and continue anyway */
if(zp->zlib_init == ZLIB_INIT) {
/* Do not use inflateReset2(): only available since zlib 1.2.3.4. */
- (void) inflateEnd(z); /* do not care about the return code */
+ (void) inflateEnd(z); /* don't care about the return code */
if(inflateInit2(z, -MAX_WBITS) == Z_OK) {
z->next_in = orig_in;
z->avail_in = nread;
@@ -266,7 +266,7 @@ static CURLcode inflate_stream(struct Curl_easy *data,
}
free(decomp);
- /* We are about to leave this call so the `nread' data bytes will not be seen
+ /* We're about to leave this call so the `nread' data bytes won't be seen
again. If we are in a state that would wrongly allow restart in raw mode
at the next call, assume output has already started. */
if(nread && zp->zlib_init == ZLIB_INIT)
@@ -300,7 +300,7 @@ static CURLcode deflate_do_write(struct Curl_easy *data,
struct zlib_writer *zp = (struct zlib_writer *) writer;
z_stream *z = &zp->z; /* zlib state structure */
- if(!(type & CLIENTWRITE_BODY) || !nbytes)
+ if(!(type & CLIENTWRITE_BODY))
return Curl_cwriter_write(data, writer->next, type, buf, nbytes);
/* Set the compressed input when this function is called */
@@ -365,14 +365,11 @@ static CURLcode gzip_do_init(struct Curl_easy *data,
#ifdef OLD_ZLIB_SUPPORT
/* Skip over the gzip header */
-typedef enum {
+static enum {
GZIP_OK,
GZIP_BAD,
GZIP_UNDERFLOW
-} gzip_status;
-
-static gzip_status check_gzip_header(unsigned char const *data, ssize_t len,
- ssize_t *headerlen)
+} check_gzip_header(unsigned char const *data, ssize_t len, ssize_t *headerlen)
{
int method, flags;
const ssize_t totallen = len;
@@ -388,7 +385,7 @@ static gzip_status check_gzip_header(unsigned char const *data, ssize_t len,
flags = data[3];
if(method != Z_DEFLATED || (flags & RESERVED) != 0) {
- /* cannot handle this compression method or unknown flag */
+ /* Can't handle this compression method or unknown flag */
return GZIP_BAD;
}
@@ -412,7 +409,7 @@ static gzip_status check_gzip_header(unsigned char const *data, ssize_t len,
}
if(flags & ORIG_NAME) {
- /* Skip over NUL-terminated filename */
+ /* Skip over NUL-terminated file name */
while(len && *data) {
--len;
++data;
@@ -457,7 +454,7 @@ static CURLcode gzip_do_write(struct Curl_easy *data,
struct zlib_writer *zp = (struct zlib_writer *) writer;
z_stream *z = &zp->z; /* zlib state structure */
- if(!(type & CLIENTWRITE_BODY) || !nbytes)
+ if(!(type & CLIENTWRITE_BODY))
return Curl_cwriter_write(data, writer->next, type, buf, nbytes);
if(zp->zlib_init == ZLIB_INIT_GZIP) {
@@ -474,10 +471,10 @@ static CURLcode gzip_do_write(struct Curl_easy *data,
return exit_zlib(data, z, &zp->zlib_init, CURLE_WRITE_ERROR);
#else
- /* This next mess is to get around the potential case where there is not
- * enough data passed in to skip over the gzip header. If that happens, we
- * malloc a block and copy what we have then wait for the next call. If
- * there still is not enough (this is definitely a worst-case scenario), we
+ /* This next mess is to get around the potential case where there isn't
+ * enough data passed in to skip over the gzip header. If that happens, we
+ * malloc a block and copy what we have then wait for the next call. If
+ * there still isn't enough (this is definitely a worst-case scenario), we
* make the block bigger, copy the next part in and keep waiting.
*
* This is only required with zlib versions < 1.2.0.4 as newer versions
@@ -499,11 +496,11 @@ static CURLcode gzip_do_write(struct Curl_easy *data,
break;
case GZIP_UNDERFLOW:
- /* We need more data so we can find the end of the gzip header. it is
+ /* We need more data so we can find the end of the gzip header. It's
* possible that the memory block we malloc here will never be freed if
- * the transfer abruptly aborts after this point. Since it is unlikely
+ * the transfer abruptly aborts after this point. Since it's unlikely
* that circumstances will be right for this code path to be followed in
- * the first place, and it is even more unlikely for a transfer to fail
+ * the first place, and it's even more unlikely for a transfer to fail
* immediately afterwards, it should seldom be a problem.
*/
z->avail_in = (uInt) nbytes;
@@ -513,7 +510,7 @@ static CURLcode gzip_do_write(struct Curl_easy *data,
}
memcpy(z->next_in, buf, z->avail_in);
zp->zlib_init = ZLIB_GZIP_HEADER; /* Need more gzip header data state */
- /* We do not have any data to inflate yet */
+ /* We don't have any data to inflate yet */
return CURLE_OK;
case GZIP_BAD:
@@ -536,18 +533,18 @@ static CURLcode gzip_do_write(struct Curl_easy *data,
/* Append the new block of data to the previous one */
memcpy(z->next_in + z->avail_in - nbytes, buf, nbytes);
- switch(check_gzip_header(z->next_in, (ssize_t)z->avail_in, &hlen)) {
+ switch(check_gzip_header(z->next_in, z->avail_in, &hlen)) {
case GZIP_OK:
/* This is the zlib stream data */
free(z->next_in);
- /* Do not point into the malloced block since we just freed it */
+ /* Don't point into the malloced block since we just freed it */
z->next_in = (Bytef *) buf + hlen + nbytes - z->avail_in;
- z->avail_in = z->avail_in - (uInt)hlen;
+ z->avail_in = (uInt) (z->avail_in - hlen);
zp->zlib_init = ZLIB_GZIP_INFLATING; /* Inflating stream state */
break;
case GZIP_UNDERFLOW:
- /* We still do not have any data to inflate! */
+ /* We still don't have any data to inflate! */
return CURLE_OK;
case GZIP_BAD:
@@ -572,11 +569,11 @@ static CURLcode gzip_do_write(struct Curl_easy *data,
}
if(z->avail_in == 0) {
- /* We do not have any data to inflate; wait until next time */
+ /* We don't have any data to inflate; wait until next time */
return CURLE_OK;
}
- /* We have parsed the header, now uncompress the data */
+ /* We've parsed the header, now uncompress the data */
return inflate_stream(data, writer, type, ZLIB_GZIP_INFLATING);
#endif
}
@@ -669,7 +666,7 @@ static CURLcode brotli_do_write(struct Curl_easy *data,
CURLcode result = CURLE_OK;
BrotliDecoderResult r = BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT;
- if(!(type & CLIENTWRITE_BODY) || !nbytes)
+ if(!(type & CLIENTWRITE_BODY))
return Curl_cwriter_write(data, writer->next, type, buf, nbytes);
if(!bp->br)
@@ -762,7 +759,7 @@ static CURLcode zstd_do_write(struct Curl_easy *data,
ZSTD_outBuffer out;
size_t errorCode;
- if(!(type & CLIENTWRITE_BODY) || !nbytes)
+ if(!(type & CLIENTWRITE_BODY))
return Curl_cwriter_write(data, writer->next, type, buf, nbytes);
if(!zp->decomp) {
@@ -835,8 +832,8 @@ static const struct Curl_cwtype identity_encoding = {
};
-/* supported general content decoders. */
-static const struct Curl_cwtype * const general_unencoders[] = {
+/* supported content encodings table. */
+static const struct Curl_cwtype * const encodings[] = {
&identity_encoding,
#ifdef HAVE_LIBZ
&deflate_encoding,
@@ -851,13 +848,6 @@ static const struct Curl_cwtype * const general_unencoders[] = {
NULL
};
-/* supported content decoders only for transfer encodings */
-static const struct Curl_cwtype * const transfer_unencoders[] = {
-#ifndef CURL_DISABLE_HTTP
- &Curl_httpchunk_unencoder,
-#endif
- NULL
-};
/* Provide a list of comma-separated names of supported encodings.
*/
@@ -871,7 +861,7 @@ void Curl_all_content_encodings(char *buf, size_t blen)
DEBUGASSERT(blen);
buf[0] = 0;
- for(cep = general_unencoders; *cep; cep++) {
+ for(cep = encodings; *cep; cep++) {
ce = *cep;
if(!strcasecompare(ce->name, CONTENT_ENCODING_DEFAULT))
len += strlen(ce->name) + 2;
@@ -883,7 +873,7 @@ void Curl_all_content_encodings(char *buf, size_t blen)
}
else if(blen > len) {
char *p = buf;
- for(cep = general_unencoders; *cep; cep++) {
+ for(cep = encodings; *cep; cep++) {
ce = *cep;
if(!strcasecompare(ce->name, CONTENT_ENCODING_DEFAULT)) {
strcpy(p, ce->name);
@@ -909,18 +899,18 @@ static CURLcode error_do_write(struct Curl_easy *data,
struct Curl_cwriter *writer, int type,
const char *buf, size_t nbytes)
{
+ char all[256];
+ (void)Curl_all_content_encodings(all, sizeof(all));
+
(void) writer;
(void) buf;
(void) nbytes;
- if(!(type & CLIENTWRITE_BODY) || !nbytes)
+ if(!(type & CLIENTWRITE_BODY))
return Curl_cwriter_write(data, writer->next, type, buf, nbytes);
- else {
- char all[256];
- (void)Curl_all_content_encodings(all, sizeof(all));
- failf(data, "Unrecognized content encoding type. "
- "libcurl understands %s content encodings.", all);
- }
+
+ failf(data, "Unrecognized content encoding type. "
+ "libcurl understands %s content encodings.", all);
return CURLE_BAD_CONTENT_ENCODING;
}
@@ -941,23 +931,12 @@ static const struct Curl_cwtype error_writer = {
};
/* Find the content encoding by name. */
-static const struct Curl_cwtype *find_unencode_writer(const char *name,
- size_t len,
- Curl_cwriter_phase phase)
+static const struct Curl_cwtype *find_encoding(const char *name,
+ size_t len)
{
const struct Curl_cwtype * const *cep;
- if(phase == CURL_CW_TRANSFER_DECODE) {
- for(cep = transfer_unencoders; *cep; cep++) {
- const struct Curl_cwtype *ce = *cep;
- if((strncasecompare(name, ce->name, len) && !ce->name[len]) ||
- (ce->alias && strncasecompare(name, ce->alias, len)
- && !ce->alias[len]))
- return ce;
- }
- }
- /* look among the general decoders */
- for(cep = general_unencoders; *cep; cep++) {
+ for(cep = encodings; *cep; cep++) {
const struct Curl_cwtype *ce = *cep;
if((strncasecompare(name, ce->name, len) && !ce->name[len]) ||
(ce->alias && strncasecompare(name, ce->alias, len) && !ce->alias[len]))
@@ -966,11 +945,12 @@ static const struct Curl_cwtype *find_unencode_writer(const char *name,
return NULL;
}
-/* Setup the unencoding stack from the Content-Encoding header value.
+/* Set-up the unencoding stack from the Content-Encoding header value.
* See RFC 7231 section 3.1.2.2. */
CURLcode Curl_build_unencoding_stack(struct Curl_easy *data,
const char *enclist, int is_transfer)
{
+ struct SingleRequest *k = &data->req;
Curl_cwriter_phase phase = is_transfer?
CURL_CW_TRANSFER_DECODE:CURL_CW_CONTENT_DECODE;
CURLcode result;
@@ -978,7 +958,6 @@ CURLcode Curl_build_unencoding_stack(struct Curl_easy *data,
do {
const char *name;
size_t namelen;
- bool is_chunked = FALSE;
/* Parse a single encoding name. */
while(ISBLANK(*enclist) || *enclist == ',')
@@ -990,21 +969,18 @@ CURLcode Curl_build_unencoding_stack(struct Curl_easy *data,
if(!ISSPACE(*enclist))
namelen = enclist - name + 1;
- if(namelen) {
+ /* Special case: chunked encoding is handled at the reader level. */
+ if(is_transfer && namelen == 7 && strncasecompare(name, "chunked", 7)) {
+ k->chunk = TRUE; /* chunks coming our way. */
+ Curl_httpchunk_init(data); /* init our chunky engine. */
+ }
+ else if(namelen) {
const struct Curl_cwtype *cwt;
struct Curl_cwriter *writer;
- CURL_TRC_WRITE(data, "looking for %s decoder: %.*s",
- is_transfer? "transfer" : "content", (int)namelen, name);
- is_chunked = (is_transfer && (namelen == 7) &&
- strncasecompare(name, "chunked", 7));
- /* if we skip the decoding in this phase, do not look further.
- * Exception is "chunked" transfer-encoding which always must happen */
- if((is_transfer && !data->set.http_transfer_encoding && !is_chunked) ||
+ if((is_transfer && !data->set.http_transfer_encoding) ||
(!is_transfer && data->set.http_ce_skip)) {
/* not requested, ignore */
- CURL_TRC_WRITE(data, "decoder not requested, ignored: %.*s",
- (int)namelen, name);
return CURLE_OK;
}
@@ -1014,39 +990,11 @@ CURLcode Curl_build_unencoding_stack(struct Curl_easy *data,
return CURLE_BAD_CONTENT_ENCODING;
}
- cwt = find_unencode_writer(name, namelen, phase);
- if(cwt && is_chunked && Curl_cwriter_get_by_type(data, cwt)) {
- /* A 'chunked' transfer encoding has already been added.
- * Ignore duplicates. See #13451.
- * Also RFC 9112, ch. 6.1:
- * "A sender MUST NOT apply the chunked transfer coding more than
- * once to a message body."
- */
- CURL_TRC_WRITE(data, "ignoring duplicate 'chunked' decoder");
- return CURLE_OK;
- }
-
- if(is_transfer && !is_chunked &&
- Curl_cwriter_get_by_name(data, "chunked")) {
- /* RFC 9112, ch. 6.1:
- * "If any transfer coding other than chunked is applied to a
- * response's content, the sender MUST either apply chunked as the
- * final transfer coding or terminate the message by closing the
- * connection."
- * "chunked" must be the last added to be the first in its phase,
- * reject this.
- */
- failf(data, "Reject response due to 'chunked' not being the last "
- "Transfer-Encoding");
- return CURLE_BAD_CONTENT_ENCODING;
- }
-
+ cwt = find_encoding(name, namelen);
if(!cwt)
cwt = &error_writer; /* Defer error at use. */
result = Curl_cwriter_create(&writer, data, cwt, phase);
- CURL_TRC_WRITE(data, "added %s decoder %s -> %d",
- is_transfer? "transfer" : "content", cwt->name, result);
if(result)
return result;
diff --git a/contrib/libs/curl/lib/cookie.c b/contrib/libs/curl/lib/cookie.c
index 95ca4a100e..9095cea3e9 100644
--- a/contrib/libs/curl/lib/cookie.c
+++ b/contrib/libs/curl/lib/cookie.c
@@ -61,7 +61,7 @@ struct Cookies *Curl_cookie_getlist(struct CookieInfo *cookie,
boolean informs the cookie if a secure connection is achieved or
not.
- It shall only return cookies that have not expired.
+ It shall only return cookies that haven't expired.
Example set of cookies:
@@ -150,7 +150,7 @@ static bool cookie_tailmatch(const char *cookie_domain,
}
/*
- * matching cookie path and URL path
+ * matching cookie path and url path
* RFC6265 5.1.4 Paths and Path-Match
*/
static bool pathmatch(const char *cookie_path, const char *request_uri)
@@ -262,9 +262,8 @@ static size_t cookie_hash_domain(const char *domain, const size_t len)
size_t h = 5381;
while(domain < end) {
- size_t j = (size_t)Curl_raw_toupper(*domain++);
h += h << 5;
- h ^= j;
+ h ^= Curl_raw_toupper(*domain++);
}
return (h % COOKIE_HASH_SIZE);
@@ -366,7 +365,7 @@ static void strstore(char **str, const char *newstr, size_t len)
DEBUGASSERT(newstr);
DEBUGASSERT(str);
free(*str);
- *str = Curl_memdup0(newstr, len);
+ *str = Curl_strndup(newstr, len);
}
/*
@@ -374,7 +373,7 @@ static void strstore(char **str, const char *newstr, size_t len)
*
* Remove expired cookies from the hash by inspecting the expires timestamp on
* each cookie in the hash, freeing and deleting any where the timestamp is in
- * the past. If the cookiejar has recorded the next timestamp at which one or
+ * the past. If the cookiejar has recorded the next timestamp at which one or
* more cookies expire, then processing will exit early in case this timestamp
* is in the future.
*/
@@ -386,11 +385,11 @@ static void remove_expired(struct CookieInfo *cookies)
/*
* If the earliest expiration timestamp in the jar is in the future we can
- * skip scanning the whole jar and instead exit early as there will not be
- * any cookies to evict. If we need to evict however, reset the
- * next_expiration counter in order to track the next one. In case the
- * recorded first expiration is the max offset, then perform the safe
- * fallback of checking all cookies.
+ * skip scanning the whole jar and instead exit early as there won't be any
+ * cookies to evict. If we need to evict however, reset the next_expiration
+ * counter in order to track the next one. In case the recorded first
+ * expiration is the max offset, then perform the safe fallback of checking
+ * all cookies.
*/
if(now < cookies->next_expiration &&
cookies->next_expiration != CURL_OFF_T_MAX)
@@ -415,7 +414,7 @@ static void remove_expired(struct CookieInfo *cookies)
}
else {
/*
- * If this cookie has an expiration timestamp earlier than what we have
+ * If this cookie has an expiration timestamp earlier than what we've
* seen so far then record it for the next round of expirations.
*/
if(co->expires && co->expires < cookies->next_expiration)
@@ -427,7 +426,6 @@ static void remove_expired(struct CookieInfo *cookies)
}
}
-#ifndef USE_LIBPSL
/* Make sure domain contains a dot or is localhost. */
static bool bad_domain(const char *domain, size_t len)
{
@@ -445,7 +443,6 @@ static bool bad_domain(const char *domain, size_t len)
}
return TRUE;
}
-#endif
/*
RFC 6265 section 4.1.1 says a server should accept this range:
@@ -474,7 +471,7 @@ static int invalid_octets(const char *p)
* Curl_cookie_add
*
* Add a single cookie line to the cookie keeping object. Be aware that
- * sometimes we get an IP-only hostname, and that might also be a numerical
+ * sometimes we get an IP-only host name, and that might also be a numerical
* IPv6 address.
*
* Returns NULL on out of memory or invalid cookie. This is suboptimal,
@@ -510,7 +507,7 @@ Curl_cookie_add(struct Curl_easy *data,
/* First, alloc and init a new struct for it */
co = calloc(1, sizeof(struct Cookie));
if(!co)
- return NULL; /* bail out if we are this low on memory */
+ return NULL; /* bail out if we're this low on memory */
if(httpheader) {
/* This line was read off an HTTP-header */
@@ -648,7 +645,7 @@ Curl_cookie_add(struct Curl_easy *data,
else if((nlen == 8) && strncasecompare("httponly", namep, 8))
co->httponly = TRUE;
else if(sep)
- /* there was a '=' so we are not done parsing this field */
+ /* there was a '=' so we're not done parsing this field */
done = FALSE;
}
if(done)
@@ -682,9 +679,9 @@ Curl_cookie_add(struct Curl_easy *data,
#ifndef USE_LIBPSL
/*
- * Without PSL we do not know when the incoming cookie is set on a
+ * Without PSL we don't know when the incoming cookie is set on a
* TLD or otherwise "protected" suffix. To reduce risk, we require a
- * dot OR the exact hostname being "localhost".
+ * dot OR the exact host name being "localhost".
*/
if(bad_domain(valuep, vlen))
domain = ":";
@@ -722,10 +719,10 @@ Curl_cookie_add(struct Curl_easy *data,
/*
* Defined in RFC2109:
*
- * Optional. The Max-Age attribute defines the lifetime of the
- * cookie, in seconds. The delta-seconds value is a decimal non-
- * negative integer. After delta-seconds seconds elapse, the
- * client should discard the cookie. A value of zero means the
+ * Optional. The Max-Age attribute defines the lifetime of the
+ * cookie, in seconds. The delta-seconds value is a decimal non-
+ * negative integer. After delta-seconds seconds elapse, the
+ * client should discard the cookie. A value of zero means the
* cookie should be discarded immediately.
*/
CURLofft offt;
@@ -781,7 +778,7 @@ Curl_cookie_add(struct Curl_easy *data,
}
/*
- * Else, this is the second (or more) name we do not know about!
+ * Else, this is the second (or more) name we don't know about!
*/
}
else {
@@ -807,7 +804,7 @@ Curl_cookie_add(struct Curl_easy *data,
if(!badcookie && !co->path && path) {
/*
- * No path was given in the header line, set the default. Note that the
+ * No path was given in the header line, set the default. Note that the
* passed-in path to this function MAY have a '?' and following part that
* MUST NOT be stored as part of the path.
*/
@@ -824,8 +821,10 @@ Curl_cookie_add(struct Curl_easy *data,
endslash = memrchr(path, '/', (queryp - path));
if(endslash) {
size_t pathlen = (endslash-path + 1); /* include end slash */
- co->path = Curl_memdup0(path, pathlen);
+ co->path = malloc(pathlen + 1); /* one extra for the zero byte */
if(co->path) {
+ memcpy(co->path, path, pathlen);
+ co->path[pathlen] = 0; /* null-terminate */
co->spath = sanitize_cookie_path(co->path);
if(!co->spath)
badcookie = TRUE; /* out of memory bad */
@@ -836,7 +835,7 @@ Curl_cookie_add(struct Curl_easy *data,
}
/*
- * If we did not get a cookie name, or a bad one, the this is an illegal
+ * If we didn't get a cookie name, or a bad one, the this is an illegal
* line so bail out.
*/
if(badcookie || !co->name) {
@@ -869,7 +868,7 @@ Curl_cookie_add(struct Curl_easy *data,
}
if(lineptr[0]=='#') {
- /* do not even try the comments */
+ /* don't even try the comments */
free(co);
return NULL;
}
@@ -887,8 +886,7 @@ Curl_cookie_add(struct Curl_easy *data,
* Now loop through the fields and init the struct we already have
* allocated
*/
- fields = 0;
- for(ptr = firstptr; ptr && !badcookie;
+ for(ptr = firstptr, fields = 0; ptr && !badcookie;
ptr = strtok_r(NULL, "\t", &tok_buf), fields++) {
switch(fields) {
case 0:
@@ -909,7 +907,7 @@ Curl_cookie_add(struct Curl_easy *data,
case 2:
/* The file format allows the path field to remain not filled in */
if(strcmp("TRUE", ptr) && strcmp("FALSE", ptr)) {
- /* only if the path does not look like a boolean option! */
+ /* only if the path doesn't look like a boolean option! */
co->path = strdup(ptr);
if(!co->path)
badcookie = TRUE;
@@ -921,7 +919,7 @@ Curl_cookie_add(struct Curl_easy *data,
}
break;
}
- /* this does not look like a path, make one up! */
+ /* this doesn't look like a path, make one up! */
co->path = strdup("/");
if(!co->path)
badcookie = TRUE;
@@ -929,7 +927,7 @@ Curl_cookie_add(struct Curl_easy *data,
if(!co->spath)
badcookie = TRUE;
fields++; /* add a field and fall down to secure */
- FALLTHROUGH();
+ /* FALLTHROUGH */
case 3:
co->secure = FALSE;
if(strcasecompare(ptr, "TRUE")) {
@@ -1004,7 +1002,7 @@ Curl_cookie_add(struct Curl_easy *data,
if(!c->running && /* read from a file */
c->newsession && /* clean session cookies */
- !co->expires) { /* this is a session cookie since it does not expire! */
+ !co->expires) { /* this is a session cookie since it doesn't expire! */
freecookie(co);
return NULL;
}
@@ -1025,11 +1023,9 @@ Curl_cookie_add(struct Curl_easy *data,
#ifdef USE_LIBPSL
/*
* Check if the domain is a Public Suffix and if yes, ignore the cookie. We
- * must also check that the data handle is not NULL since the psl code will
+ * must also check that the data handle isn't NULL since the psl code will
* dereference it.
*/
- DEBUGF(infof(data, "PSL check set-cookie '%s' for domain=%s in %s",
- co->name, co->domain, domain));
if(data && (domain && co->domain && !Curl_host_is_ipnum(co->domain))) {
bool acceptable = FALSE;
char lcase[256];
@@ -1046,7 +1042,7 @@ Curl_cookie_add(struct Curl_easy *data,
Curl_psl_release(data);
}
else
- infof(data, "libpsl problem, rejecting cookie for satety");
+ acceptable = !bad_domain(domain, strlen(domain));
}
if(!acceptable) {
@@ -1056,9 +1052,6 @@ Curl_cookie_add(struct Curl_easy *data,
return NULL;
}
}
-#else
- DEBUGF(infof(data, "NO PSL to check set-cookie '%s' for domain=%s in %s",
- co->name, co->domain, domain));
#endif
/* A non-secure cookie may not overlay an existing secure cookie. */
@@ -1130,10 +1123,10 @@ Curl_cookie_add(struct Curl_easy *data,
if(replace_old && !co->livecookie && clist->livecookie) {
/*
- * Both cookies matched fine, except that the already present cookie
- * is "live", which means it was set from a header, while the new one
- * was read from a file and thus is not "live". "live" cookies are
- * preferred so the new cookie is freed.
+ * Both cookies matched fine, except that the already present cookie is
+ * "live", which means it was set from a header, while the new one was
+ * read from a file and thus isn't "live". "live" cookies are preferred
+ * so the new cookie is freed.
*/
freecookie(co);
return NULL;
@@ -1170,7 +1163,7 @@ Curl_cookie_add(struct Curl_easy *data,
if(c->running)
/* Only show this when NOT reading the cookies from a file */
infof(data, "%s cookie %s=\"%s\" for domain %s, path %s, "
- "expire %" FMT_OFF_T,
+ "expire %" CURL_FORMAT_CURL_OFF_T,
replace_old?"Replaced":"Added", co->name, co->value,
co->domain, co->path, co->expires);
@@ -1184,7 +1177,7 @@ Curl_cookie_add(struct Curl_easy *data,
}
/*
- * Now that we have added a new cookie to the jar, update the expiration
+ * Now that we've added a new cookie to the jar, update the expiration
* tracker in case it is the next one to expire.
*/
if(co->expires && (co->expires < c->next_expiration))
@@ -1214,15 +1207,16 @@ struct CookieInfo *Curl_cookie_init(struct Curl_easy *data,
bool newsession)
{
struct CookieInfo *c;
+ char *line = NULL;
FILE *handle = NULL;
if(!inc) {
- /* we did not get a struct, create one */
+ /* we didn't get a struct, create one */
c = calloc(1, sizeof(struct CookieInfo));
if(!c)
return NULL; /* failed to get memory */
/*
- * Initialize the next_expiration time to signal that we do not have enough
+ * Initialize the next_expiration time to signal that we don't have enough
* information yet.
*/
c->next_expiration = CURL_OFF_T_MAX;
@@ -1235,7 +1229,7 @@ struct CookieInfo *Curl_cookie_init(struct Curl_easy *data,
if(data) {
FILE *fp = NULL;
- if(file && *file) {
+ if(file) {
if(!strcmp(file, "-"))
fp = stdin;
else {
@@ -1249,14 +1243,16 @@ struct CookieInfo *Curl_cookie_init(struct Curl_easy *data,
c->running = FALSE; /* this is not running, this is init */
if(fp) {
- struct dynbuf buf;
- Curl_dyn_init(&buf, MAX_COOKIE_LINE);
- while(Curl_get_line(&buf, fp)) {
- char *lineptr = Curl_dyn_ptr(&buf);
+
+ line = malloc(MAX_COOKIE_LINE);
+ if(!line)
+ goto fail;
+ while(Curl_get_line(line, MAX_COOKIE_LINE, fp)) {
+ char *lineptr = line;
bool headerline = FALSE;
- if(checkprefix("Set-Cookie:", lineptr)) {
+ if(checkprefix("Set-Cookie:", line)) {
/* This is a cookie line, get it! */
- lineptr += 11;
+ lineptr = &line[11];
headerline = TRUE;
while(*lineptr && ISBLANK(*lineptr))
lineptr++;
@@ -1264,7 +1260,7 @@ struct CookieInfo *Curl_cookie_init(struct Curl_easy *data,
Curl_cookie_add(data, c, headerline, TRUE, lineptr, NULL, NULL, TRUE);
}
- Curl_dyn_free(&buf); /* free the line buffer */
+ free(line); /* free the line buffer */
/*
* Remove expired cookies from the hash. We must make sure to run this
@@ -1277,9 +1273,21 @@ struct CookieInfo *Curl_cookie_init(struct Curl_easy *data,
}
data->state.cookie_engine = TRUE;
}
- c->running = TRUE; /* now, we are running */
+ c->running = TRUE; /* now, we're running */
return c;
+
+fail:
+ free(line);
+ /*
+ * Only clean up if we allocated it here, as the original could still be in
+ * use by a share handle.
+ */
+ if(!inc)
+ Curl_cookie_cleanup(c);
+ if(handle)
+ fclose(handle);
+ return NULL; /* out of memory */
}
/*
@@ -1373,7 +1381,7 @@ fail:
* should send to the server if used now. The secure boolean informs the cookie
* if a secure connection is achieved or not.
*
- * It shall only return cookies that have not expired.
+ * It shall only return cookies that haven't expired.
*/
struct Cookie *Curl_cookie_getlist(struct Curl_easy *data,
struct CookieInfo *c,
@@ -1399,7 +1407,7 @@ struct Cookie *Curl_cookie_getlist(struct Curl_easy *data,
co = c->cookies[myhash];
while(co) {
- /* if the cookie requires we are secure we must only continue if we are! */
+ /* if the cookie requires we're secure we must only continue if we are! */
if(co->secure?secure:TRUE) {
/* now check if the domain is correct */
@@ -1589,7 +1597,7 @@ static char *get_netscape_format(const struct Cookie *co)
"%s\t" /* tailmatch */
"%s\t" /* path */
"%s\t" /* secure */
- "%" FMT_OFF_T "\t" /* expires */
+ "%" CURL_FORMAT_CURL_OFF_T "\t" /* expires */
"%s\t" /* name */
"%s", /* value */
co->httponly?"#HttpOnly_":"",
@@ -1611,7 +1619,7 @@ static char *get_netscape_format(const struct Cookie *co)
* cookie_output()
*
* Writes all internally known cookies to the specified file. Specify
- * "-" as filename to write to stdout.
+ * "-" as file name to write to stdout.
*
* The function returns non-zero on write failure.
*/
diff --git a/contrib/libs/curl/lib/cookie.h b/contrib/libs/curl/lib/cookie.h
index 838d74d82f..012dd892c9 100644
--- a/contrib/libs/curl/lib/cookie.h
+++ b/contrib/libs/curl/lib/cookie.h
@@ -75,7 +75,7 @@ struct CookieInfo {
/** Limits for INCOMING cookies **/
-/* The longest we allow a line to be when reading a cookie from an HTTP header
+/* The longest we allow a line to be when reading a cookie from a HTTP header
or from a cookie jar */
#define MAX_COOKIE_LINE 5000
diff --git a/contrib/libs/curl/lib/curl_addrinfo.c b/contrib/libs/curl/lib/curl_addrinfo.c
index 834b39c8ed..8d1b20c13b 100644
--- a/contrib/libs/curl/lib/curl_addrinfo.c
+++ b/contrib/libs/curl/lib/curl_addrinfo.c
@@ -95,7 +95,7 @@ Curl_freeaddrinfo(struct Curl_addrinfo *cahead)
* the only difference that instead of returning a linked list of
* addrinfo structs this one returns a linked list of Curl_addrinfo
* ones. The memory allocated by this function *MUST* be free'd with
- * Curl_freeaddrinfo(). For each successful call to this function
+ * Curl_freeaddrinfo(). For each successful call to this function
* there must be an associated call later to Curl_freeaddrinfo().
*
* There should be no single call to system's getaddrinfo() in the
@@ -130,7 +130,7 @@ Curl_getaddrinfo_ex(const char *nodename,
/* settle family-specific sockaddr structure size. */
if(ai->ai_family == AF_INET)
ss_size = sizeof(struct sockaddr_in);
-#ifdef USE_IPV6
+#ifdef ENABLE_IPV6
else if(ai->ai_family == AF_INET6)
ss_size = sizeof(struct sockaddr_in6);
#endif
@@ -221,7 +221,7 @@ Curl_getaddrinfo_ex(const char *nodename,
* stack, but usable also for IPv4, all hosts and environments.
*
* The memory allocated by this function *MUST* be free'd later on calling
- * Curl_freeaddrinfo(). For each successful call to this function there
+ * Curl_freeaddrinfo(). For each successful call to this function there
* must be an associated call later to Curl_freeaddrinfo().
*
* Curl_addrinfo defined in "lib/curl_addrinfo.h"
@@ -259,7 +259,7 @@ Curl_he2ai(const struct hostent *he, int port)
struct Curl_addrinfo *prevai = NULL;
struct Curl_addrinfo *firstai = NULL;
struct sockaddr_in *addr;
-#ifdef USE_IPV6
+#ifdef ENABLE_IPV6
struct sockaddr_in6 *addr6;
#endif
CURLcode result = CURLE_OK;
@@ -275,7 +275,7 @@ Curl_he2ai(const struct hostent *he, int port)
for(i = 0; (curr = he->h_addr_list[i]) != NULL; i++) {
size_t ss_size;
size_t namelen = strlen(he->h_name) + 1; /* include null-terminator */
-#ifdef USE_IPV6
+#ifdef ENABLE_IPV6
if(he->h_addrtype == AF_INET6)
ss_size = sizeof(struct sockaddr_in6);
else
@@ -317,24 +317,16 @@ Curl_he2ai(const struct hostent *he, int port)
addr = (void *)ai->ai_addr; /* storage area for this info */
memcpy(&addr->sin_addr, curr, sizeof(struct in_addr));
-#ifdef __MINGW32__
- addr->sin_family = (short)(he->h_addrtype);
-#else
addr->sin_family = (CURL_SA_FAMILY_T)(he->h_addrtype);
-#endif
addr->sin_port = htons((unsigned short)port);
break;
-#ifdef USE_IPV6
+#ifdef ENABLE_IPV6
case AF_INET6:
addr6 = (void *)ai->ai_addr; /* storage area for this info */
memcpy(&addr6->sin6_addr, curr, sizeof(struct in6_addr));
-#ifdef __MINGW32__
- addr6->sin6_family = (short)(he->h_addrtype);
-#else
addr6->sin6_family = (CURL_SA_FAMILY_T)(he->h_addrtype);
-#endif
addr6->sin6_port = htons((unsigned short)port);
break;
#endif
@@ -356,7 +348,7 @@ struct namebuff {
struct hostent hostentry;
union {
struct in_addr ina4;
-#ifdef USE_IPV6
+#ifdef ENABLE_IPV6
struct in6_addr ina6;
#endif
} addrentry;
@@ -367,7 +359,7 @@ struct namebuff {
/*
* Curl_ip2addr()
*
- * This function takes an Internet address, in binary form, as input parameter
+ * This function takes an internet address, in binary form, as input parameter
* along with its address family and the string version of the address, and it
* returns a Curl_addrinfo chain filled in correctly with information for the
* given address/host
@@ -409,7 +401,7 @@ Curl_ip2addr(int af, const void *inaddr, const char *hostname, int port)
addrentry = (void *)&buf->addrentry.ina4;
memcpy(addrentry, inaddr, sizeof(struct in_addr));
break;
-#ifdef USE_IPV6
+#ifdef ENABLE_IPV6
case AF_INET6:
addrsize = sizeof(struct in6_addr);
addrentry = (void *)&buf->addrentry.ina6;
@@ -455,7 +447,7 @@ struct Curl_addrinfo *Curl_str2addr(char *address, int port)
if(Curl_inet_pton(AF_INET, address, &in) > 0)
/* This is a dotted IP address 123.123.123.123-style */
return Curl_ip2addr(AF_INET, &in, address, port);
-#ifdef USE_IPV6
+#ifdef ENABLE_IPV6
{
struct in6_addr in6;
if(Curl_inet_pton(AF_INET6, address, &in6) > 0)
@@ -519,7 +511,7 @@ struct Curl_addrinfo *Curl_unix2addr(const char *path, bool *longpath,
*
* This is strictly for memory tracing and are using the same style as the
* family otherwise present in memdebug.c. I put these ones here since they
- * require a bunch of structs I did not want to include in memdebug.c
+ * require a bunch of structs I didn't want to include in memdebug.c
*/
void
@@ -543,7 +535,7 @@ curl_dbg_freeaddrinfo(struct addrinfo *freethis,
*
* This is strictly for memory tracing and are using the same style as the
* family otherwise present in memdebug.c. I put these ones here since they
- * require a bunch of structs I did not want to include in memdebug.c
+ * require a bunch of structs I didn't want to include in memdebug.c
*/
int
@@ -571,14 +563,14 @@ curl_dbg_getaddrinfo(const char *hostname,
#if defined(HAVE_GETADDRINFO) && defined(USE_RESOLVE_ON_IPS)
/*
- * Work-arounds the sin6_port is always zero bug on iOS 9.3.2 and macOS
+ * Work-arounds the sin6_port is always zero bug on iOS 9.3.2 and Mac OS X
* 10.11.5.
*/
void Curl_addrinfo_set_port(struct Curl_addrinfo *addrinfo, int port)
{
struct Curl_addrinfo *ca;
struct sockaddr_in *addr;
-#ifdef USE_IPV6
+#ifdef ENABLE_IPV6
struct sockaddr_in6 *addr6;
#endif
for(ca = addrinfo; ca != NULL; ca = ca->ai_next) {
@@ -588,7 +580,7 @@ void Curl_addrinfo_set_port(struct Curl_addrinfo *addrinfo, int port)
addr->sin_port = htons((unsigned short)port);
break;
-#ifdef USE_IPV6
+#ifdef ENABLE_IPV6
case AF_INET6:
addr6 = (void *)ca->ai_addr; /* storage area for this info */
addr6->sin6_port = htons((unsigned short)port);
diff --git a/contrib/libs/curl/lib/curl_addrinfo.h b/contrib/libs/curl/lib/curl_addrinfo.h
index 9ceac997da..c757c49c5c 100644
--- a/contrib/libs/curl/lib/curl_addrinfo.h
+++ b/contrib/libs/curl/lib/curl_addrinfo.h
@@ -44,9 +44,9 @@
/*
* Curl_addrinfo is our internal struct definition that we use to allow
- * consistent internal handling of this data. We use this even when the system
- * provides an addrinfo structure definition. We use this for all sorts of
- * IPv4 and IPV6 builds.
+ * consistent internal handling of this data. We use this even when the
+ * system provides an addrinfo structure definition. And we use this for
+ * all sorts of IPv4 and IPV6 builds.
*/
struct Curl_addrinfo {
diff --git a/contrib/libs/curl/lib/curl_config-linux.h b/contrib/libs/curl/lib/curl_config-linux.h
index 966b408892..22debd1fcd 100644
--- a/contrib/libs/curl/lib/curl_config-linux.h
+++ b/contrib/libs/curl/lib/curl_config-linux.h
@@ -1,16 +1,13 @@
/* lib/curl_config.h. Generated from curl_config.h.in by configure. */
/* lib/curl_config.h.in. Generated from configure.ac by autoheader. */
-/* Ignore c-ares deprecation warnings */
-#define CARES_NO_DEPRECATED 1
-
/* to enable curl debug memory tracking */
/* #undef CURLDEBUG */
/* Location of default ca bundle */
#define CURL_CA_BUNDLE "/etc/ssl/certs/ca-certificates.crt"
-/* define "1" to use built-in CA store of SSL library */
+/* define "1" to use built in CA store of SSL library */
#define CURL_CA_FALLBACK 1
/* Location of default ca path */
@@ -121,9 +118,6 @@
/* to disable RTSP */
/* #undef CURL_DISABLE_RTSP */
-/* disable SHA-512/256 hash algorithm */
-/* #undef CURL_DISABLE_SHA512_256 */
-
/* disable DNS shuffling */
/* #undef CURL_DISABLE_SHUFFLE_DNS */
@@ -157,6 +151,9 @@
/* enable debug build options */
/* #undef DEBUGBUILD */
+/* Define if you want to enable IPv6 support */
+#define ENABLE_IPV6 1
+
/* Define to the type of arg 2 for gethostname. */
#define GETHOSTNAME_TYPE_ARG2 size_t
@@ -213,18 +210,12 @@
/* "Set if getpwuid_r() declaration is missing" */
/* #undef HAVE_DECL_GETPWUID_R_MISSING */
-/* if you have <dirent.h> */
-#define HAVE_DIRENT_H 1
-
/* Define to 1 if you have the <dlfcn.h> header file. */
#define HAVE_DLFCN_H 1
/* Define to 1 if you have the <err.h> header file. */
/* #undef HAVE_ERR_H */
-/* Define to 1 if you have the `eventfd' function. */
-#define HAVE_EVENTFD 1
-
/* Define to 1 if you have the fcntl function. */
#define HAVE_FCNTL 1
@@ -333,6 +324,12 @@
/* if you have GNU GSS */
/* #undef HAVE_GSSGNU */
+/* if you have Heimdal */
+/* #undef HAVE_GSSHEIMDAL */
+
+/* if you have MIT Kerberos */
+/* #undef HAVE_GSSMIT */
+
/* Define to 1 if you have the <hyper.h> header file. */
/* #undef HAVE_HYPER_H */
@@ -406,10 +403,7 @@
/* Define to 1 if you have the `idn2' library (-lidn2). */
/* #undef HAVE_LIBIDN2 */
-/* Define to 1 if you have the <libpsl.h> header file. */
-/* #undef HAVE_LIBPSL_H */
-
-/* Define to 1 if using LibreSSL. */
+/* Define to 1 if using libressl. */
/* #undef HAVE_LIBRESSL */
/* Define to 1 if you have the <librtmp/rtmp.h> header file. */
@@ -488,8 +482,8 @@
*/
/* #undef HAVE_OLD_GSSMIT */
-/* if you have opendir */
-#define HAVE_OPENDIR 1
+/* Define to 1 if using OpenSSL 3 or later. */
+#define HAVE_OPENSSL3 1
/* Define to 1 if you have the <openssl/crypto.h> header file. */
#define HAVE_OPENSSL_CRYPTO_H 1
@@ -600,8 +594,8 @@
/* Define to 1 if you have the <socket.h> header file. */
/* #undef HAVE_SOCKET_H */
-/* Define to 1 if you have the `SSL_ech_set1_echconfig' function. */
-/* #undef HAVE_SSL_ECH_SET1_ECHCONFIG */
+/* Define to 1 if you have the `SSL_get_ech_status' function. */
+/* #undef HAVE_SSL_GET_ECH_STATUS */
/* Define to 1 if you have the <ssl.h> header file. */
/* #undef HAVE_SSL_H */
@@ -609,13 +603,6 @@
/* Define to 1 if you have the `SSL_set0_wbio' function. */
#define HAVE_SSL_SET0_WBIO 1
-/* Define to 1 if you have the `SSL_set1_ech_config_list' function. */
-/* #undef HAVE_SSL_SET1_ECH_CONFIG_LIST */
-
-/* Define to 1 if you have the `SSL_set_quic_use_legacy_codepoint' function.
- */
-/* #undef HAVE_SSL_SET_QUIC_USE_LEGACY_CODEPOINT */
-
/* Define to 1 if you have the <stdatomic.h> header file. */
#define HAVE_STDATOMIC_H 1
@@ -670,9 +657,6 @@
/* Define to 1 if suseconds_t is an available type. */
#define HAVE_SUSECONDS_T 1
-/* Define to 1 if you have the <sys/eventfd.h> header file. */
-#define HAVE_SYS_EVENTFD_H 1
-
/* Define to 1 if you have the <sys/filio.h> header file. */
/* #undef HAVE_SYS_FILIO_H */
@@ -727,9 +711,6 @@
/* Define this if time_t is unsigned */
/* #undef HAVE_TIME_T_UNSIGNED */
-/* Define to 1 if you have the <unicode/uidna.h> header file. */
-/* #undef HAVE_UNICODE_UIDNA_H */
-
/* Define to 1 if you have the <unistd.h> header file. */
#define HAVE_UNISTD_H 1
@@ -742,15 +723,15 @@
/* Define to 1 if you have the <utime.h> header file. */
#define HAVE_UTIME_H 1
-/* Define to 1 if you have the <uv.h> header file. */
-/* #undef HAVE_UV_H */
+/* Define to 1 if you have the windows.h header file. */
+/* #undef HAVE_WINDOWS_H */
+
+/* Define to 1 if you have the winsock2.h header file. */
+/* #undef HAVE_WINSOCK2_H */
/* Define to 1 if you have the <wolfssh/ssh.h> header file. */
/* #undef HAVE_WOLFSSH_SSH_H */
-/* Define to 1 if you have the `wolfSSL_CTX_GenerateEchConfig' function. */
-/* #undef HAVE_WOLFSSL_CTX_GENERATEECHCONFIG */
-
/* if you have wolfSSL_DES_ecb_encrypt */
/* #undef HAVE_WOLFSSL_DES_ECB_ENCRYPT */
@@ -766,6 +747,9 @@
/* Define this symbol if your OS supports changing the contents of argv */
#define HAVE_WRITABLE_ARGV 1
+/* Define to 1 if you have the ws2tcpip.h header file. */
+/* #undef HAVE_WS2TCPIP_H */
+
/* Define to 1 if you have the <x509.h> header file. */
/* #undef HAVE_X509_H */
@@ -790,6 +774,12 @@
/* Define to 1 if _THREAD_SAFE preprocessor symbol must be defined. */
/* #undef NEED_THREAD_SAFE */
+/* Define to enable NTLM delegation to winbind's ntlm_auth helper. */
+/* #undef NTLM_WB_ENABLED */
+
+/* Define absolute filename for winbind's ntlm_auth helper. */
+/* #undef NTLM_WB_FILE */
+
/* cpu-machine-OS */
#define OS "x86_64-pc-linux-gnu"
@@ -814,6 +804,9 @@
/* Define to the version of this package. */
#define PACKAGE_VERSION "-"
+/* a suitable file to read random data from */
+#define RANDOM_FILE "/dev/urandom"
+
/* Size of curl_off_t in number of bytes */
#define SIZEOF_CURL_OFF_T 8
@@ -850,9 +843,6 @@
/* if AmiSSL is in use */
/* #undef USE_AMISSL */
-/* if AppleIDN */
-/* #undef USE_APPLE_IDN */
-
/* Define to enable c-ares support */
#define USE_ARES 1
@@ -868,29 +858,23 @@
/* GSASL support enabled */
/* #undef USE_GSASL */
-/* force HTTPS RR support for ECH */
-/* #undef USE_HTTPSRR */
-
/* if hyper is in use */
/* #undef USE_HYPER */
-/* Define if you want to enable IPv6 support */
-#define USE_IPV6 1
-
-/* if libpsl is in use */
+/* PSL support enabled */
/* #undef USE_LIBPSL */
/* if librtmp is in use */
/* #undef USE_LIBRTMP */
-/* if libssh is in use */
+/* if libSSH is in use */
/* #undef USE_LIBSSH */
-/* if libssh2 is in use */
+/* if libSSH2 is in use */
/* #undef USE_LIBSSH2 */
-/* if libuv is in use */
-/* #undef USE_LIBUV */
+/* If you want to build curl with the built-in manual */
+/* #undef USE_MANUAL */
/* if mbedTLS is enabled */
/* #undef USE_MBEDTLS */
@@ -907,9 +891,6 @@
/* if ngtcp2 is in use */
/* #undef USE_NGTCP2 */
-/* if ngtcp2_crypto_boringssl is in use */
-/* #undef USE_NGTCP2_CRYPTO_BORINGSSL */
-
/* if ngtcp2_crypto_gnutls is in use */
/* #undef USE_NGTCP2_CRYPTO_GNUTLS */
@@ -919,25 +900,16 @@
/* if ngtcp2_crypto_wolfssl is in use */
/* #undef USE_NGTCP2_CRYPTO_WOLFSSL */
-/* if ngtcp2 + nghttp3 is in use */
-/* #undef USE_NGTCP2_H3 */
-
/* Use OpenLDAP-specific code */
/* #undef USE_OPENLDAP */
/* if OpenSSL is in use */
#define USE_OPENSSL 1
-/* if openssl quic + nghttp3 is in use */
-/* #undef USE_OPENSSL_H3 */
-
-/* if openssl QUIC is in use */
-/* #undef USE_OPENSSL_QUIC */
-
/* if quiche is in use */
/* #undef USE_QUICHE */
-/* if Rustls is enabled */
+/* if rustls is enabled */
/* #undef USE_RUSTLS */
/* to enable Windows native SSL/TLS support */
@@ -958,7 +930,7 @@
/* Use Unix domain sockets */
#define USE_UNIX_SOCKETS 1
-/* enable WebSockets support */
+/* enable websockets support */
/* #undef USE_WEBSOCKETS */
/* Define to 1 if you are building a Windows target with crypto API support.
@@ -1008,6 +980,12 @@
/* Type to use in place of in_addr_t when system does not provide it. */
/* #undef in_addr_t */
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+ calls it, or to nothing if 'inline' is not supported under any name. */
+#ifndef __cplusplus
+/* #undef inline */
+#endif
+
/* Define to `unsigned int' if <sys/types.h> does not define. */
/* #undef size_t */
diff --git a/contrib/libs/curl/lib/curl_des.c b/contrib/libs/curl/lib/curl_des.c
index 15836f58b9..b77763f268 100644
--- a/contrib/libs/curl/lib/curl_des.c
+++ b/contrib/libs/curl/lib/curl_des.c
@@ -24,10 +24,10 @@
#include "curl_setup.h"
-#if defined(USE_CURL_NTLM_CORE) && \
- (defined(USE_GNUTLS) || \
- defined(USE_SECTRANSP) || \
- defined(USE_OS400CRYPTO) || \
+#if defined(USE_CURL_NTLM_CORE) && !defined(USE_WOLFSSL) && \
+ (defined(USE_GNUTLS) || \
+ defined(USE_SECTRANSP) || \
+ defined(USE_OS400CRYPTO) || \
defined(USE_WIN32_CRYPTO))
#include "curl_des.h"
@@ -36,7 +36,7 @@
* Curl_des_set_odd_parity()
*
* This is used to apply odd parity to the given byte array. It is typically
- * used by when a cryptography engine does not have its own version.
+ * used by when a cryptography engines doesn't have it's own version.
*
* The function is a port of the Java based oddParity() function over at:
*
diff --git a/contrib/libs/curl/lib/curl_des.h b/contrib/libs/curl/lib/curl_des.h
index 2dd498da24..66525ab436 100644
--- a/contrib/libs/curl/lib/curl_des.h
+++ b/contrib/libs/curl/lib/curl_des.h
@@ -26,10 +26,10 @@
#include "curl_setup.h"
-#if defined(USE_CURL_NTLM_CORE) && \
- (defined(USE_GNUTLS) || \
- defined(USE_SECTRANSP) || \
- defined(USE_OS400CRYPTO) || \
+#if defined(USE_CURL_NTLM_CORE) && !defined(USE_WOLFSSL) && \
+ (defined(USE_GNUTLS) || \
+ defined(USE_SECTRANSP) || \
+ defined(USE_OS400CRYPTO) || \
defined(USE_WIN32_CRYPTO))
/* Applies odd parity to the given byte array */
diff --git a/contrib/libs/curl/lib/curl_endian.c b/contrib/libs/curl/lib/curl_endian.c
index d982e31269..11c662a4c7 100644
--- a/contrib/libs/curl/lib/curl_endian.c
+++ b/contrib/libs/curl/lib/curl_endian.c
@@ -30,7 +30,7 @@
* Curl_read16_le()
*
* This function converts a 16-bit integer from the little endian format, as
- * used in the incoming package to whatever endian format we are using
+ * used in the incoming package to whatever endian format we're using
* natively.
*
* Parameters:
@@ -49,7 +49,7 @@ unsigned short Curl_read16_le(const unsigned char *buf)
* Curl_read32_le()
*
* This function converts a 32-bit integer from the little endian format, as
- * used in the incoming package to whatever endian format we are using
+ * used in the incoming package to whatever endian format we're using
* natively.
*
* Parameters:
@@ -68,7 +68,7 @@ unsigned int Curl_read32_le(const unsigned char *buf)
* Curl_read16_be()
*
* This function converts a 16-bit integer from the big endian format, as
- * used in the incoming package to whatever endian format we are using
+ * used in the incoming package to whatever endian format we're using
* natively.
*
* Parameters:
diff --git a/contrib/libs/curl/lib/curl_fnmatch.c b/contrib/libs/curl/lib/curl_fnmatch.c
index ab848e8ffe..5f9ca4f1be 100644
--- a/contrib/libs/curl/lib/curl_fnmatch.c
+++ b/contrib/libs/curl/lib/curl_fnmatch.c
@@ -80,7 +80,7 @@ static int parsekeyword(unsigned char **pattern, unsigned char *charset)
unsigned char *p = *pattern;
bool found = FALSE;
for(i = 0; !found; i++) {
- char c = (char)*p++;
+ char c = *p++;
if(i >= KEYLEN)
return SETCHARSET_FAIL;
switch(state) {
diff --git a/contrib/libs/curl/lib/curl_fnmatch.h b/contrib/libs/curl/lib/curl_fnmatch.h
index b8c2a4353c..595646ff0d 100644
--- a/contrib/libs/curl/lib/curl_fnmatch.h
+++ b/contrib/libs/curl/lib/curl_fnmatch.h
@@ -31,7 +31,7 @@
/* default pattern matching function
* =================================
* Implemented with recursive backtracking, if you want to use Curl_fnmatch,
- * please note that there is not implemented UTF/Unicode support.
+ * please note that there is not implemented UTF/UNICODE support.
*
* Implemented features:
* '?' notation, does not match UTF characters
diff --git a/contrib/libs/curl/lib/curl_get_line.c b/contrib/libs/curl/lib/curl_get_line.c
index 100207331d..686abe7511 100644
--- a/contrib/libs/curl/lib/curl_get_line.c
+++ b/contrib/libs/curl/lib/curl_get_line.c
@@ -33,16 +33,14 @@
#include "memdebug.h"
/*
- * Curl_get_line() makes sure to only return complete whole lines that end
- * newlines.
+ * Curl_get_line() makes sure to only return complete whole lines that fit in
+ * 'len' bytes and end with a newline.
*/
-int Curl_get_line(struct dynbuf *buf, FILE *input)
+char *Curl_get_line(char *buf, int len, FILE *input)
{
- CURLcode result;
- char buffer[128];
- Curl_dyn_reset(buf);
+ bool partial = FALSE;
while(1) {
- char *b = fgets(buffer, sizeof(buffer), input);
+ char *b = fgets(buf, len, input);
if(b) {
size_t rlen = strlen(b);
@@ -50,28 +48,39 @@ int Curl_get_line(struct dynbuf *buf, FILE *input)
if(!rlen)
break;
- result = Curl_dyn_addn(buf, b, rlen);
- if(result)
- /* too long line or out of memory */
- return 0; /* error */
-
- else if(b[rlen-1] == '\n')
- /* end of the line */
- return 1; /* all good */
-
+ if(b[rlen-1] == '\n') {
+ /* b is \n terminated */
+ if(partial) {
+ partial = FALSE;
+ continue;
+ }
+ return b;
+ }
else if(feof(input)) {
- /* append a newline */
- result = Curl_dyn_addn(buf, "\n", 1);
- if(result)
- /* too long line or out of memory */
- return 0; /* error */
- return 1; /* all good */
+ if(partial)
+ /* Line is already too large to return, ignore rest */
+ break;
+
+ if(rlen + 1 < (size_t) len) {
+ /* b is EOF terminated, insert missing \n */
+ b[rlen] = '\n';
+ b[rlen + 1] = '\0';
+ return b;
+ }
+ else
+ /* Maximum buffersize reached + EOF
+ * This line is impossible to add a \n to so we'll ignore it
+ */
+ break;
}
+ else
+ /* Maximum buffersize reached */
+ partial = TRUE;
}
else
break;
}
- return 0;
+ return NULL;
}
#endif /* if not disabled */
diff --git a/contrib/libs/curl/lib/curl_get_line.h b/contrib/libs/curl/lib/curl_get_line.h
index 7907cde880..0ff32c5c2c 100644
--- a/contrib/libs/curl/lib/curl_get_line.h
+++ b/contrib/libs/curl/lib/curl_get_line.h
@@ -24,9 +24,8 @@
*
***************************************************************************/
-#include "dynbuf.h"
-
-/* Curl_get_line() returns complete lines that end with a newline. */
-int Curl_get_line(struct dynbuf *buf, FILE *input);
+/* get_line() makes sure to only return complete whole lines that fit in 'len'
+ * bytes and end with a newline. */
+char *Curl_get_line(char *buf, int len, FILE *input);
#endif /* HEADER_CURL_GET_LINE_H */
diff --git a/contrib/libs/curl/lib/curl_gethostname.c b/contrib/libs/curl/lib/curl_gethostname.c
index 617a8ad52f..706b2e6892 100644
--- a/contrib/libs/curl/lib/curl_gethostname.c
+++ b/contrib/libs/curl/lib/curl_gethostname.c
@@ -28,17 +28,26 @@
/*
* Curl_gethostname() is a wrapper around gethostname() which allows
- * overriding the hostname that the function would normally return.
+ * overriding the host name that the function would normally return.
* This capability is used by the test suite to verify exact matching
* of NTLM authentication, which exercises libcurl's MD4 and DES code
* as well as by the SMTP module when a hostname is not provided.
*
- * For libcurl debug enabled builds hostname overriding takes place
+ * For libcurl debug enabled builds host name overriding takes place
* when environment variable CURL_GETHOSTNAME is set, using the value
- * held by the variable to override returned hostname.
+ * held by the variable to override returned host name.
*
* Note: The function always returns the un-qualified hostname rather
* than being provider dependent.
+ *
+ * For libcurl shared library release builds the test suite preloads
+ * another shared library named libhostname using the LD_PRELOAD
+ * mechanism which intercepts, and might override, the gethostname()
+ * function call. In this case a given platform must support the
+ * LD_PRELOAD mechanism and additionally have environment variable
+ * CURL_GETHOSTNAME set in order to override the returned host name.
+ *
+ * For libcurl static library release builds no overriding takes place.
*/
int Curl_gethostname(char * const name, GETHOSTNAME_TYPE_ARG2 namelen)
@@ -56,13 +65,10 @@ int Curl_gethostname(char * const name, GETHOSTNAME_TYPE_ARG2 namelen)
#ifdef DEBUGBUILD
- /* Override hostname when environment variable CURL_GETHOSTNAME is set */
+ /* Override host name when environment variable CURL_GETHOSTNAME is set */
const char *force_hostname = getenv("CURL_GETHOSTNAME");
if(force_hostname) {
- if(strlen(force_hostname) < (size_t)namelen)
- strcpy(name, force_hostname);
- else
- return 1; /* can't do it */
+ strncpy(name, force_hostname, namelen);
err = 0;
}
else {
@@ -72,6 +78,9 @@ int Curl_gethostname(char * const name, GETHOSTNAME_TYPE_ARG2 namelen)
#else /* DEBUGBUILD */
+ /* The call to system's gethostname() might get intercepted by the
+ libhostname library when libcurl is built as a non-debug shared
+ library when running the test suite. */
name[0] = '\0';
err = gethostname(name, namelen);
diff --git a/contrib/libs/curl/lib/curl_memrchr.c b/contrib/libs/curl/lib/curl_memrchr.c
index c6d55f1042..3f3dc6de16 100644
--- a/contrib/libs/curl/lib/curl_memrchr.c
+++ b/contrib/libs/curl/lib/curl_memrchr.c
@@ -33,9 +33,6 @@
#include "memdebug.h"
#ifndef HAVE_MEMRCHR
-#if (!defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)) || \
- defined(USE_OPENSSL) || \
- defined(USE_SCHANNEL)
/*
* Curl_memrchr()
@@ -64,5 +61,4 @@ Curl_memrchr(const void *s, int c, size_t n)
return NULL;
}
-#endif
#endif /* HAVE_MEMRCHR */
diff --git a/contrib/libs/curl/lib/curl_memrchr.h b/contrib/libs/curl/lib/curl_memrchr.h
index 67a21ef361..45bb38c68e 100644
--- a/contrib/libs/curl/lib/curl_memrchr.h
+++ b/contrib/libs/curl/lib/curl_memrchr.h
@@ -34,15 +34,11 @@
#endif
#else /* HAVE_MEMRCHR */
-#if (!defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)) || \
- defined(USE_OPENSSL) || \
- defined(USE_SCHANNEL)
void *Curl_memrchr(const void *s, int c, size_t n);
#define memrchr(x,y,z) Curl_memrchr((x),(y),(z))
-#endif
#endif /* HAVE_MEMRCHR */
#endif /* HEADER_CURL_MEMRCHR_H */
diff --git a/contrib/libs/curl/lib/curl_multibyte.c b/contrib/libs/curl/lib/curl_multibyte.c
index 86ac74ff4b..ff21098563 100644
--- a/contrib/libs/curl/lib/curl_multibyte.c
+++ b/contrib/libs/curl/lib/curl_multibyte.c
@@ -159,4 +159,21 @@ int curlx_win32_stat(const char *path, struct_stat *buffer)
#endif
}
+int curlx_win32_access(const char *path, int mode)
+{
+#if defined(_UNICODE)
+ int result = -1;
+ wchar_t *path_w = curlx_convert_UTF8_to_wchar(path);
+ if(path_w) {
+ result = _waccess(path_w, mode);
+ curlx_unicodefree(path_w);
+ }
+ else
+ errno = EINVAL;
+ return result;
+#else
+ return _access(path, mode);
+#endif
+}
+
#endif /* USE_WIN32_LARGE_FILES || USE_WIN32_SMALL_FILES */
diff --git a/contrib/libs/curl/lib/curl_multibyte.h b/contrib/libs/curl/lib/curl_multibyte.h
index dec384e2fe..8b9ac719e5 100644
--- a/contrib/libs/curl/lib/curl_multibyte.h
+++ b/contrib/libs/curl/lib/curl_multibyte.h
@@ -39,20 +39,19 @@ char *curlx_convert_wchar_to_UTF8(const wchar_t *str_w);
* Macros curlx_convert_UTF8_to_tchar(), curlx_convert_tchar_to_UTF8()
* and curlx_unicodefree() main purpose is to minimize the number of
* preprocessor conditional directives needed by code using these
- * to differentiate Unicode from non-Unicode builds.
+ * to differentiate UNICODE from non-UNICODE builds.
*
- * In the case of a non-Unicode build the tchar strings are char strings that
+ * In the case of a non-UNICODE build the tchar strings are char strings that
* are duplicated via strdup and remain in whatever the passed in encoding is,
* which is assumed to be UTF-8 but may be other encoding. Therefore the
- * significance of the conversion functions is primarily for Unicode builds.
+ * significance of the conversion functions is primarily for UNICODE builds.
*
* Allocated memory should be free'd with curlx_unicodefree().
*
* Note: Because these are curlx functions their memory usage is not tracked
- * by the curl memory tracker memdebug. you will notice that curlx
- * function-like macros call free and strdup in parentheses, eg (strdup)(ptr),
- * and that is to ensure that the curl memdebug override macros do not replace
- * them.
+ * by the curl memory tracker memdebug. You'll notice that curlx function-like
+ * macros call free and strdup in parentheses, eg (strdup)(ptr), and that's to
+ * ensure that the curl memdebug override macros do not replace them.
*/
#if defined(UNICODE) && defined(_WIN32)
diff --git a/contrib/libs/curl/lib/curl_ntlm_core.c b/contrib/libs/curl/lib/curl_ntlm_core.c
index 34fa128483..b5e8e16e15 100644
--- a/contrib/libs/curl/lib/curl_ntlm_core.c
+++ b/contrib/libs/curl/lib/curl_ntlm_core.c
@@ -57,14 +57,9 @@
#if !defined(OPENSSL_NO_DES) && !defined(OPENSSL_NO_DEPRECATED_3_0)
#define USE_OPENSSL_DES
#endif
-#elif defined(USE_WOLFSSL)
- #error #include <wolfssl/options.h>
- #if !defined(NO_DES3)
- #define USE_OPENSSL_DES
- #endif
#endif
-#if defined(USE_OPENSSL_DES)
+#if defined(USE_OPENSSL_DES) || defined(USE_WOLFSSL)
#if defined(USE_OPENSSL)
# include <openssl/des.h>
@@ -72,6 +67,7 @@
# include <openssl/ssl.h>
# include <openssl/rand.h>
#else
+# error #include <wolfssl/options.h>
# error #include <wolfssl/openssl/des.h>
# error #include <wolfssl/openssl/md5.h>
# error #include <wolfssl/openssl/ssl.h>
@@ -114,7 +110,7 @@
#elif defined(USE_WIN32_CRYPTO)
# include <wincrypt.h>
#else
-# error "cannot compile NTLM support without a crypto library with DES."
+# error "Can't compile NTLM support without a crypto library with DES."
# define CURL_NTLM_NOT_SUPPORTED
#endif
@@ -141,20 +137,20 @@
*/
static void extend_key_56_to_64(const unsigned char *key_56, char *key)
{
- key[0] = (char)key_56[0];
- key[1] = (char)(((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1));
- key[2] = (char)(((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2));
- key[3] = (char)(((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3));
- key[4] = (char)(((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4));
- key[5] = (char)(((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5));
- key[6] = (char)(((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6));
- key[7] = (char) ((key_56[6] << 1) & 0xFF);
+ key[0] = key_56[0];
+ key[1] = (unsigned char)(((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1));
+ key[2] = (unsigned char)(((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2));
+ key[3] = (unsigned char)(((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3));
+ key[4] = (unsigned char)(((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4));
+ key[5] = (unsigned char)(((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5));
+ key[6] = (unsigned char)(((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6));
+ key[7] = (unsigned char) ((key_56[6] << 1) & 0xFF);
}
#endif
-#if defined(USE_OPENSSL_DES)
+#if defined(USE_OPENSSL_DES) || defined(USE_WOLFSSL)
/*
- * Turns a 56-bit key into a 64-bit, odd parity key and sets the key. The
+ * Turns a 56 bit key into the 64 bit, odd parity key and sets the key. The
* key schedule ks is also set.
*/
static void setup_des_key(const unsigned char *key_56,
@@ -162,7 +158,7 @@ static void setup_des_key(const unsigned char *key_56,
{
DES_cblock key;
- /* Expand the 56-bit key to 64 bits */
+ /* Expand the 56-bit key to 64-bits */
extend_key_56_to_64(key_56, (char *) &key);
/* Set the key parity to odd */
@@ -179,7 +175,7 @@ static void setup_des_key(const unsigned char *key_56,
{
char key[8];
- /* Expand the 56-bit key to 64 bits */
+ /* Expand the 56-bit key to 64-bits */
extend_key_56_to_64(key_56, key);
/* Set the key parity to odd */
@@ -197,7 +193,7 @@ static bool encrypt_des(const unsigned char *in, unsigned char *out,
mbedtls_des_context ctx;
char key[8];
- /* Expand the 56-bit key to 64 bits */
+ /* Expand the 56-bit key to 64-bits */
extend_key_56_to_64(key_56, key);
/* Set the key parity to odd */
@@ -218,7 +214,7 @@ static bool encrypt_des(const unsigned char *in, unsigned char *out,
size_t out_len;
CCCryptorStatus err;
- /* Expand the 56-bit key to 64 bits */
+ /* Expand the 56-bit key to 64-bits */
extend_key_56_to_64(key_56, key);
/* Set the key parity to odd */
@@ -244,7 +240,7 @@ static bool encrypt_des(const unsigned char *in, unsigned char *out,
ctl.Func_ID = ENCRYPT_ONLY;
ctl.Data_Len = sizeof(key);
- /* Expand the 56-bit key to 64 bits */
+ /* Expand the 56-bit key to 64-bits */
extend_key_56_to_64(key_56, ctl.Crypto_Key);
/* Set the key parity to odd */
@@ -282,7 +278,7 @@ static bool encrypt_des(const unsigned char *in, unsigned char *out,
blob.hdr.aiKeyAlg = CALG_DES;
blob.len = sizeof(blob.key);
- /* Expand the 56-bit key to 64 bits */
+ /* Expand the 56-bit key to 64-bits */
extend_key_56_to_64(key_56, blob.key);
/* Set the key parity to odd */
@@ -317,7 +313,7 @@ void Curl_ntlm_core_lm_resp(const unsigned char *keys,
const unsigned char *plaintext,
unsigned char *results)
{
-#if defined(USE_OPENSSL_DES)
+#if defined(USE_OPENSSL_DES) || defined(USE_WOLFSSL)
DES_key_schedule ks;
setup_des_key(keys, DESKEY(ks));
@@ -371,7 +367,7 @@ CURLcode Curl_ntlm_core_mk_lm_hash(const char *password,
{
/* Create LanManager hashed password. */
-#if defined(USE_OPENSSL_DES)
+#if defined(USE_OPENSSL_DES) || defined(USE_WOLFSSL)
DES_key_schedule ks;
setup_des_key(pw, DESKEY(ks));
@@ -470,13 +466,13 @@ static void time2filetime(struct ms_filetime *ft, time_t t)
unsigned int r, s;
unsigned int i;
- ft->dwLowDateTime = (unsigned int)t & 0xFFFFFFFF;
+ ft->dwLowDateTime = t & 0xFFFFFFFF;
ft->dwHighDateTime = 0;
# ifndef HAVE_TIME_T_UNSIGNED
/* Extend sign if needed. */
if(ft->dwLowDateTime & 0x80000000)
- ft->dwHighDateTime = ~(unsigned int)0;
+ ft->dwHighDateTime = ~0;
# endif
/* Bias seconds to Jan 1, 1601.
@@ -538,13 +534,13 @@ CURLcode Curl_ntlm_core_mk_ntlmv2_hash(const char *user, size_t userlen,
/*
* Curl_ntlm_core_mk_ntlmv2_resp()
*
- * This creates the NTLMv2 response as set in the NTLM type-3 message.
+ * This creates the NTLMv2 response as set in the ntlm type-3 message.
*
* Parameters:
*
- * ntlmv2hash [in] - The NTLMv2 hash (16 bytes)
+ * ntlmv2hash [in] - The ntlmv2 hash (16 bytes)
* challenge_client [in] - The client nonce (8 bytes)
- * ntlm [in] - The NTLM data struct being used to read TargetInfo
+ * ntlm [in] - The ntlm data struct being used to read TargetInfo
and Server challenge received in the type-2 message
* ntresp [out] - The address where a pointer to newly allocated
* memory holding the NTLMv2 response.
@@ -633,11 +629,11 @@ CURLcode Curl_ntlm_core_mk_ntlmv2_resp(unsigned char *ntlmv2hash,
/*
* Curl_ntlm_core_mk_lmv2_resp()
*
- * This creates the LMv2 response as used in the NTLM type-3 message.
+ * This creates the LMv2 response as used in the ntlm type-3 message.
*
* Parameters:
*
- * ntlmv2hash [in] - The NTLMv2 hash (16 bytes)
+ * ntlmv2hash [in] - The ntlmv2 hash (16 bytes)
* challenge_client [in] - The client nonce (8 bytes)
* challenge_client [in] - The server challenge (8 bytes)
* lmresp [out] - The LMv2 response (24 bytes)
@@ -661,7 +657,7 @@ CURLcode Curl_ntlm_core_mk_lmv2_resp(unsigned char *ntlmv2hash,
if(result)
return result;
- /* Concatenate the HMAC MD5 output with the client nonce */
+ /* Concatenate the HMAC MD5 output with the client nonce */
memcpy(lmresp, hmac_output, 16);
memcpy(lmresp + 16, challenge_client, 8);
diff --git a/contrib/libs/curl/lib/curl_ntlm_core.h b/contrib/libs/curl/lib/curl_ntlm_core.h
index e2e4b1bd43..1a1b503a67 100644
--- a/contrib/libs/curl/lib/curl_ntlm_core.h
+++ b/contrib/libs/curl/lib/curl_ntlm_core.h
@@ -28,6 +28,13 @@
#if defined(USE_CURL_NTLM_CORE)
+#if defined(USE_OPENSSL)
+# include <openssl/ssl.h>
+#elif defined(USE_WOLFSSL)
+# error #include <wolfssl/options.h>
+# error #include <wolfssl/openssl/ssl.h>
+#endif
+
/* Helpers to generate function byte arguments in little endian order */
#define SHORTPAIR(x) ((int)((x) & 0xff)), ((int)(((x) >> 8) & 0xff))
#define LONGQUARTET(x) ((int)((x) & 0xff)), ((int)(((x) >> 8) & 0xff)), \
diff --git a/contrib/libs/curl/lib/curl_ntlm_wb.c b/contrib/libs/curl/lib/curl_ntlm_wb.c
new file mode 100644
index 0000000000..b087a37a3d
--- /dev/null
+++ b/contrib/libs/curl/lib/curl_ntlm_wb.c
@@ -0,0 +1,500 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM) && \
+ defined(NTLM_WB_ENABLED)
+
+/*
+ * NTLM details:
+ *
+ * https://davenport.sourceforge.net/ntlm.html
+ * https://www.innovation.ch/java/ntlm.html
+ */
+
+#define DEBUG_ME 0
+
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+#include <signal.h>
+#ifdef HAVE_PWD_H
+#include <pwd.h>
+#endif
+
+#include "urldata.h"
+#include "sendf.h"
+#include "select.h"
+#include "vauth/ntlm.h"
+#include "curl_ntlm_core.h"
+#include "curl_ntlm_wb.h"
+#include "url.h"
+#include "strerror.h"
+#include "strdup.h"
+#include "strcase.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+#if DEBUG_ME
+# define DEBUG_OUT(x) x
+#else
+# define DEBUG_OUT(x) Curl_nop_stmt
+#endif
+
+/* Portable 'sclose_nolog' used only in child process instead of 'sclose'
+ to avoid fooling the socket leak detector */
+#ifdef HAVE_PIPE
+# define sclose_nolog(x) close((x))
+#elif defined(HAVE_CLOSESOCKET)
+# define sclose_nolog(x) closesocket((x))
+#elif defined(HAVE_CLOSESOCKET_CAMEL)
+# define sclose_nolog(x) CloseSocket((x))
+#else
+# define sclose_nolog(x) close((x))
+#endif
+
+static void ntlm_wb_cleanup(struct ntlmdata *ntlm)
+{
+ if(ntlm->ntlm_auth_hlpr_socket != CURL_SOCKET_BAD) {
+ sclose(ntlm->ntlm_auth_hlpr_socket);
+ ntlm->ntlm_auth_hlpr_socket = CURL_SOCKET_BAD;
+ }
+
+ if(ntlm->ntlm_auth_hlpr_pid) {
+ int i;
+ for(i = 0; i < 4; i++) {
+ pid_t ret = waitpid(ntlm->ntlm_auth_hlpr_pid, NULL, WNOHANG);
+ if(ret == ntlm->ntlm_auth_hlpr_pid || errno == ECHILD)
+ break;
+ switch(i) {
+ case 0:
+ kill(ntlm->ntlm_auth_hlpr_pid, SIGTERM);
+ break;
+ case 1:
+ /* Give the process another moment to shut down cleanly before
+ bringing down the axe */
+ Curl_wait_ms(1);
+ break;
+ case 2:
+ kill(ntlm->ntlm_auth_hlpr_pid, SIGKILL);
+ break;
+ case 3:
+ break;
+ }
+ }
+ ntlm->ntlm_auth_hlpr_pid = 0;
+ }
+
+ Curl_safefree(ntlm->challenge);
+ Curl_safefree(ntlm->response);
+}
+
+static CURLcode ntlm_wb_init(struct Curl_easy *data, struct ntlmdata *ntlm,
+ const char *userp)
+{
+ curl_socket_t sockfds[2];
+ pid_t child_pid;
+ const char *username;
+ char *slash, *domain = NULL;
+ const char *ntlm_auth = NULL;
+ char *ntlm_auth_alloc = NULL;
+#if defined(HAVE_GETPWUID_R) && defined(HAVE_GETEUID)
+ struct passwd pw, *pw_res;
+ char pwbuf[1024];
+#endif
+ char buffer[STRERROR_LEN];
+
+#if defined(CURL_DISABLE_VERBOSE_STRINGS)
+ (void) data;
+#endif
+
+ /* Return if communication with ntlm_auth already set up */
+ if(ntlm->ntlm_auth_hlpr_socket != CURL_SOCKET_BAD ||
+ ntlm->ntlm_auth_hlpr_pid)
+ return CURLE_OK;
+
+ username = userp;
+ /* The real ntlm_auth really doesn't like being invoked with an
+ empty username. It won't make inferences for itself, and expects
+ the client to do so (mostly because it's really designed for
+ servers like squid to use for auth, and client support is an
+ afterthought for it). So try hard to provide a suitable username
+ if we don't already have one. But if we can't, provide the
+ empty one anyway. Perhaps they have an implementation of the
+ ntlm_auth helper which *doesn't* need it so we might as well try */
+ if(!username || !username[0]) {
+ username = getenv("NTLMUSER");
+ if(!username || !username[0])
+ username = getenv("LOGNAME");
+ if(!username || !username[0])
+ username = getenv("USER");
+#if defined(HAVE_GETPWUID_R) && defined(HAVE_GETEUID)
+ if((!username || !username[0]) &&
+ !getpwuid_r(geteuid(), &pw, pwbuf, sizeof(pwbuf), &pw_res) &&
+ pw_res) {
+ username = pw.pw_name;
+ }
+#endif
+ if(!username || !username[0])
+ username = userp;
+ }
+ slash = strpbrk(username, "\\/");
+ if(slash) {
+ domain = strdup(username);
+ if(!domain)
+ return CURLE_OUT_OF_MEMORY;
+ slash = domain + (slash - username);
+ *slash = '\0';
+ username = username + (slash - domain) + 1;
+ }
+
+ /* For testing purposes, when DEBUGBUILD is defined and environment
+ variable CURL_NTLM_WB_FILE is set a fake_ntlm is used to perform
+ NTLM challenge/response which only accepts commands and output
+ strings pre-written in test case definitions */
+#ifdef DEBUGBUILD
+ ntlm_auth_alloc = curl_getenv("CURL_NTLM_WB_FILE");
+ if(ntlm_auth_alloc)
+ ntlm_auth = ntlm_auth_alloc;
+ else
+#endif
+ ntlm_auth = NTLM_WB_FILE;
+
+ if(access(ntlm_auth, X_OK) != 0) {
+ failf(data, "Could not access ntlm_auth: %s errno %d: %s",
+ ntlm_auth, errno, Curl_strerror(errno, buffer, sizeof(buffer)));
+ goto done;
+ }
+
+ if(wakeup_create(sockfds)) {
+ failf(data, "Could not open socket pair. errno %d: %s",
+ errno, Curl_strerror(errno, buffer, sizeof(buffer)));
+ goto done;
+ }
+
+ child_pid = fork();
+ if(child_pid == -1) {
+ wakeup_close(sockfds[0]);
+ wakeup_close(sockfds[1]);
+ failf(data, "Could not fork. errno %d: %s",
+ errno, Curl_strerror(errno, buffer, sizeof(buffer)));
+ goto done;
+ }
+ else if(!child_pid) {
+ /*
+ * child process
+ */
+
+ /* Don't use sclose in the child since it fools the socket leak detector */
+ sclose_nolog(sockfds[0]);
+ if(dup2(sockfds[1], STDIN_FILENO) == -1) {
+ failf(data, "Could not redirect child stdin. errno %d: %s",
+ errno, Curl_strerror(errno, buffer, sizeof(buffer)));
+ exit(1);
+ }
+
+ if(dup2(sockfds[1], STDOUT_FILENO) == -1) {
+ failf(data, "Could not redirect child stdout. errno %d: %s",
+ errno, Curl_strerror(errno, buffer, sizeof(buffer)));
+ exit(1);
+ }
+
+ if(domain)
+ execl(ntlm_auth, ntlm_auth,
+ "--helper-protocol", "ntlmssp-client-1",
+ "--use-cached-creds",
+ "--username", username,
+ "--domain", domain,
+ NULL);
+ else
+ execl(ntlm_auth, ntlm_auth,
+ "--helper-protocol", "ntlmssp-client-1",
+ "--use-cached-creds",
+ "--username", username,
+ NULL);
+
+ sclose_nolog(sockfds[1]);
+ failf(data, "Could not execl(). errno %d: %s",
+ errno, Curl_strerror(errno, buffer, sizeof(buffer)));
+ exit(1);
+ }
+
+ sclose(sockfds[1]);
+ ntlm->ntlm_auth_hlpr_socket = sockfds[0];
+ ntlm->ntlm_auth_hlpr_pid = child_pid;
+ free(domain);
+ free(ntlm_auth_alloc);
+ return CURLE_OK;
+
+done:
+ free(domain);
+ free(ntlm_auth_alloc);
+ return CURLE_REMOTE_ACCESS_DENIED;
+}
+
+/* if larger than this, something is seriously wrong */
+#define MAX_NTLM_WB_RESPONSE 100000
+
+static CURLcode ntlm_wb_response(struct Curl_easy *data, struct ntlmdata *ntlm,
+ const char *input, curlntlm state)
+{
+ size_t len_in = strlen(input), len_out = 0;
+ struct dynbuf b;
+ char *ptr = NULL;
+ unsigned char *buf = (unsigned char *)data->state.buffer;
+ Curl_dyn_init(&b, MAX_NTLM_WB_RESPONSE);
+
+ while(len_in > 0) {
+ ssize_t written = wakeup_write(ntlm->ntlm_auth_hlpr_socket, input, len_in);
+ if(written == -1) {
+ /* Interrupted by a signal, retry it */
+ if(errno == EINTR)
+ continue;
+ /* write failed if other errors happen */
+ goto done;
+ }
+ input += written;
+ len_in -= written;
+ }
+ /* Read one line */
+ while(1) {
+ ssize_t size =
+ wakeup_read(ntlm->ntlm_auth_hlpr_socket, buf, data->set.buffer_size);
+ if(size == -1) {
+ if(errno == EINTR)
+ continue;
+ goto done;
+ }
+ else if(size == 0)
+ goto done;
+
+ if(Curl_dyn_addn(&b, buf, size))
+ goto done;
+
+ len_out = Curl_dyn_len(&b);
+ ptr = Curl_dyn_ptr(&b);
+ if(len_out && ptr[len_out - 1] == '\n') {
+ ptr[len_out - 1] = '\0';
+ break; /* done! */
+ }
+ /* loop */
+ }
+
+ /* Samba/winbind installed but not configured */
+ if(state == NTLMSTATE_TYPE1 &&
+ len_out == 3 &&
+ ptr[0] == 'P' && ptr[1] == 'W')
+ goto done;
+ /* invalid response */
+ if(len_out < 4)
+ goto done;
+ if(state == NTLMSTATE_TYPE1 &&
+ (ptr[0]!='Y' || ptr[1]!='R' || ptr[2]!=' '))
+ goto done;
+ if(state == NTLMSTATE_TYPE2 &&
+ (ptr[0]!='K' || ptr[1]!='K' || ptr[2]!=' ') &&
+ (ptr[0]!='A' || ptr[1]!='F' || ptr[2]!=' '))
+ goto done;
+
+ ntlm->response = strdup(ptr + 3);
+ Curl_dyn_free(&b);
+ if(!ntlm->response)
+ return CURLE_OUT_OF_MEMORY;
+ return CURLE_OK;
+done:
+ Curl_dyn_free(&b);
+ return CURLE_REMOTE_ACCESS_DENIED;
+}
+
+CURLcode Curl_input_ntlm_wb(struct Curl_easy *data,
+ struct connectdata *conn,
+ bool proxy,
+ const char *header)
+{
+ struct ntlmdata *ntlm = proxy ? &conn->proxyntlm : &conn->ntlm;
+ curlntlm *state = proxy ? &conn->proxy_ntlm_state : &conn->http_ntlm_state;
+
+ (void) data; /* In case it gets unused by nop log macros. */
+
+ if(!checkprefix("NTLM", header))
+ return CURLE_BAD_CONTENT_ENCODING;
+
+ header += strlen("NTLM");
+ while(*header && ISSPACE(*header))
+ header++;
+
+ if(*header) {
+ ntlm->challenge = strdup(header);
+ if(!ntlm->challenge)
+ return CURLE_OUT_OF_MEMORY;
+
+ *state = NTLMSTATE_TYPE2; /* We got a type-2 message */
+ }
+ else {
+ if(*state == NTLMSTATE_LAST) {
+ infof(data, "NTLM auth restarted");
+ Curl_http_auth_cleanup_ntlm_wb(conn);
+ }
+ else if(*state == NTLMSTATE_TYPE3) {
+ infof(data, "NTLM handshake rejected");
+ Curl_http_auth_cleanup_ntlm_wb(conn);
+ *state = NTLMSTATE_NONE;
+ return CURLE_REMOTE_ACCESS_DENIED;
+ }
+ else if(*state >= NTLMSTATE_TYPE1) {
+ infof(data, "NTLM handshake failure (internal error)");
+ return CURLE_REMOTE_ACCESS_DENIED;
+ }
+
+ *state = NTLMSTATE_TYPE1; /* We should send away a type-1 */
+ }
+
+ return CURLE_OK;
+}
+
+/*
+ * This is for creating ntlm header output by delegating challenge/response
+ * to Samba's winbind daemon helper ntlm_auth.
+ */
+CURLcode Curl_output_ntlm_wb(struct Curl_easy *data, struct connectdata *conn,
+ bool proxy)
+{
+ /* point to the address of the pointer that holds the string to send to the
+ server, which is for a plain host or for an HTTP proxy */
+ char **allocuserpwd;
+ /* point to the name and password for this */
+ const char *userp;
+ struct ntlmdata *ntlm;
+ curlntlm *state;
+ struct auth *authp;
+
+ CURLcode res = CURLE_OK;
+
+ DEBUGASSERT(conn);
+ DEBUGASSERT(data);
+
+ if(proxy) {
+#ifndef CURL_DISABLE_PROXY
+ allocuserpwd = &data->state.aptr.proxyuserpwd;
+ userp = conn->http_proxy.user;
+ ntlm = &conn->proxyntlm;
+ state = &conn->proxy_ntlm_state;
+ authp = &data->state.authproxy;
+#else
+ return CURLE_NOT_BUILT_IN;
+#endif
+ }
+ else {
+ allocuserpwd = &data->state.aptr.userpwd;
+ userp = conn->user;
+ ntlm = &conn->ntlm;
+ state = &conn->http_ntlm_state;
+ authp = &data->state.authhost;
+ }
+ authp->done = FALSE;
+
+ /* not set means empty */
+ if(!userp)
+ userp = "";
+
+ switch(*state) {
+ case NTLMSTATE_TYPE1:
+ default:
+ /* Use Samba's 'winbind' daemon to support NTLM authentication,
+ * by delegating the NTLM challenge/response protocol to a helper
+ * in ntlm_auth.
+ * https://web.archive.org/web/20190925164737
+ * /devel.squid-cache.org/ntlm/squid_helper_protocol.html
+ * https://www.samba.org/samba/docs/man/manpages-3/winbindd.8.html
+ * https://www.samba.org/samba/docs/man/manpages-3/ntlm_auth.1.html
+ * Preprocessor symbol 'NTLM_WB_ENABLED' is defined when this
+ * feature is enabled and 'NTLM_WB_FILE' symbol holds absolute
+ * filename of ntlm_auth helper.
+ * If NTLM authentication using winbind fails, go back to original
+ * request handling process.
+ */
+ /* Create communication with ntlm_auth */
+ res = ntlm_wb_init(data, ntlm, userp);
+ if(res)
+ return res;
+ res = ntlm_wb_response(data, ntlm, "YR\n", *state);
+ if(res)
+ return res;
+
+ free(*allocuserpwd);
+ *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n",
+ proxy ? "Proxy-" : "",
+ ntlm->response);
+ DEBUG_OUT(fprintf(stderr, "**** Header %s\n ", *allocuserpwd));
+ Curl_safefree(ntlm->response);
+ if(!*allocuserpwd)
+ return CURLE_OUT_OF_MEMORY;
+ break;
+
+ case NTLMSTATE_TYPE2: {
+ char *input = aprintf("TT %s\n", ntlm->challenge);
+ if(!input)
+ return CURLE_OUT_OF_MEMORY;
+ res = ntlm_wb_response(data, ntlm, input, *state);
+ free(input);
+ if(res)
+ return res;
+
+ free(*allocuserpwd);
+ *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n",
+ proxy ? "Proxy-" : "",
+ ntlm->response);
+ DEBUG_OUT(fprintf(stderr, "**** %s\n ", *allocuserpwd));
+ *state = NTLMSTATE_TYPE3; /* we sent a type-3 */
+ authp->done = TRUE;
+ Curl_http_auth_cleanup_ntlm_wb(conn);
+ if(!*allocuserpwd)
+ return CURLE_OUT_OF_MEMORY;
+ break;
+ }
+ case NTLMSTATE_TYPE3:
+ /* connection is already authenticated,
+ * don't send a header in future requests */
+ *state = NTLMSTATE_LAST;
+ /* FALLTHROUGH */
+ case NTLMSTATE_LAST:
+ Curl_safefree(*allocuserpwd);
+ authp->done = TRUE;
+ break;
+ }
+
+ return CURLE_OK;
+}
+
+void Curl_http_auth_cleanup_ntlm_wb(struct connectdata *conn)
+{
+ ntlm_wb_cleanup(&conn->ntlm);
+ ntlm_wb_cleanup(&conn->proxyntlm);
+}
+
+#endif /* !CURL_DISABLE_HTTP && USE_NTLM && NTLM_WB_ENABLED */
diff --git a/contrib/libs/curl/lib/cw-out.h b/contrib/libs/curl/lib/curl_ntlm_wb.h
index ca4c2e435d..37704c0fe0 100644
--- a/contrib/libs/curl/lib/cw-out.h
+++ b/contrib/libs/curl/lib/curl_ntlm_wb.h
@@ -1,5 +1,5 @@
-#ifndef HEADER_CURL_CW_OUT_H
-#define HEADER_CURL_CW_OUT_H
+#ifndef HEADER_CURL_NTLM_WB_H
+#define HEADER_CURL_NTLM_WB_H
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
@@ -26,28 +26,20 @@
#include "curl_setup.h"
-#include "sendf.h"
+#if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM) && \
+ defined(NTLM_WB_ENABLED)
-/**
- * The client writer type "cw-out" that does the actual writing to
- * the client callbacks. Intended to be the last installed in the
- * client writer stack of a transfer.
- */
-extern struct Curl_cwtype Curl_cwt_out;
+/* this is for ntlm header input */
+CURLcode Curl_input_ntlm_wb(struct Curl_easy *data,
+ struct connectdata *conn, bool proxy,
+ const char *header);
-/**
- * Return TRUE iff 'cw-out' client write has paused data.
- */
-bool Curl_cw_out_is_paused(struct Curl_easy *data);
+/* this is for creating ntlm header output */
+CURLcode Curl_output_ntlm_wb(struct Curl_easy *data, struct connectdata *conn,
+ bool proxy);
-/**
- * Flush any buffered date to the client, chunk collation still applies.
- */
-CURLcode Curl_cw_out_unpause(struct Curl_easy *data);
+void Curl_http_auth_cleanup_ntlm_wb(struct connectdata *conn);
-/**
- * Mark EndOfStream reached and flush ALL data to the client.
- */
-CURLcode Curl_cw_out_done(struct Curl_easy *data);
+#endif /* !CURL_DISABLE_HTTP && USE_NTLM && NTLM_WB_ENABLED */
-#endif /* HEADER_CURL_CW_OUT_H */
+#endif /* HEADER_CURL_NTLM_WB_H */
diff --git a/contrib/libs/curl/lib/curl_path.c b/contrib/libs/curl/lib/curl_path.c
index 6babf81d59..2e5e3e7ba8 100644
--- a/contrib/libs/curl/lib/curl_path.c
+++ b/contrib/libs/curl/lib/curl_path.c
@@ -98,8 +98,8 @@ CURLcode Curl_getworkingpath(struct Curl_easy *data,
return CURLE_OK;
}
-/* The original get_pathname() function came from OpenSSH sftp.c version
- 4.6p1. */
+/* The get_pathname() function is being borrowed from OpenSSH sftp.c
+ version 4.6p1. */
/*
* Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
*
@@ -115,37 +115,38 @@ CURLcode Curl_getworkingpath(struct Curl_easy *data,
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-
-#define MAX_PATHLENGTH 65535 /* arbitrary long */
-
-CURLcode Curl_get_pathname(const char **cpp, char **path, const char *homedir)
+CURLcode Curl_get_pathname(const char **cpp, char **path, char *homedir)
{
const char *cp = *cpp, *end;
char quot;
- unsigned int i;
+ unsigned int i, j;
+ size_t fullPathLength, pathLength;
+ bool relativePath = false;
static const char WHITESPACE[] = " \t\r\n";
- struct dynbuf out;
- CURLcode result;
DEBUGASSERT(homedir);
- *path = NULL;
- *cpp = NULL;
- if(!*cp || !homedir)
+ if(!*cp || !homedir) {
+ *cpp = NULL;
+ *path = NULL;
return CURLE_QUOTE_ERROR;
-
- Curl_dyn_init(&out, MAX_PATHLENGTH);
-
+ }
/* Ignore leading whitespace */
cp += strspn(cp, WHITESPACE);
+ /* Allocate enough space for home directory and filename + separator */
+ fullPathLength = strlen(cp) + strlen(homedir) + 2;
+ *path = malloc(fullPathLength);
+ if(!*path)
+ return CURLE_OUT_OF_MEMORY;
/* Check for quoted filenames */
if(*cp == '\"' || *cp == '\'') {
quot = *cp++;
/* Search for terminating quote, unescape some chars */
- for(i = 0; i <= strlen(cp); i++) {
+ for(i = j = 0; i <= strlen(cp); i++) {
if(cp[i] == quot) { /* Found quote */
i++;
+ (*path)[j] = '\0';
break;
}
if(cp[i] == '\0') { /* End of string */
@@ -158,45 +159,40 @@ CURLcode Curl_get_pathname(const char **cpp, char **path, const char *homedir)
goto fail;
}
}
- result = Curl_dyn_addn(&out, &cp[i], 1);
- if(result)
- return result;
+ (*path)[j++] = cp[i];
}
- if(!Curl_dyn_len(&out))
+ if(j == 0) {
goto fail;
-
- /* return pointer to second parameter if it exists */
- *cpp = &cp[i] + strspn(&cp[i], WHITESPACE);
+ }
+ *cpp = cp + i + strspn(cp + i, WHITESPACE);
}
else {
/* Read to end of filename - either to whitespace or terminator */
end = strpbrk(cp, WHITESPACE);
if(!end)
end = strchr(cp, '\0');
-
/* return pointer to second parameter if it exists */
*cpp = end + strspn(end, WHITESPACE);
-
+ pathLength = 0;
+ relativePath = (cp[0] == '/' && cp[1] == '~' && cp[2] == '/');
/* Handling for relative path - prepend home directory */
- if(cp[0] == '/' && cp[1] == '~' && cp[2] == '/') {
- result = Curl_dyn_add(&out, homedir);
- if(!result)
- result = Curl_dyn_addn(&out, "/", 1);
- if(result)
- return result;
+ if(relativePath) {
+ strcpy(*path, homedir);
+ pathLength = strlen(homedir);
+ (*path)[pathLength++] = '/';
+ (*path)[pathLength] = '\0';
cp += 3;
}
/* Copy path name up until first "whitespace" */
- result = Curl_dyn_addn(&out, cp, (end - cp));
- if(result)
- return result;
+ memcpy(&(*path)[pathLength], cp, (int)(end - cp));
+ pathLength += (int)(end - cp);
+ (*path)[pathLength] = '\0';
}
- *path = Curl_dyn_ptr(&out);
return CURLE_OK;
fail:
- Curl_dyn_free(&out);
+ Curl_safefree(*path);
return CURLE_QUOTE_ERROR;
}
diff --git a/contrib/libs/curl/lib/curl_printf.h b/contrib/libs/curl/lib/curl_printf.h
index e851b14a50..46ef344f76 100644
--- a/contrib/libs/curl/lib/curl_printf.h
+++ b/contrib/libs/curl/lib/curl_printf.h
@@ -29,21 +29,14 @@
* *rintf() functions.
*/
-#ifndef CURL_TEMP_PRINTF
-#error "CURL_TEMP_PRINTF must be set before including curl/mprintf.h"
-#endif
-
#include <curl/mprintf.h>
-#define MERR_OK 0
-#define MERR_MEM 1
-#define MERR_TOO_LARGE 2
-
# undef printf
# undef fprintf
# undef msnprintf
# undef vprintf
# undef vfprintf
+# undef vsnprintf
# undef mvsnprintf
# undef aprintf
# undef vaprintf
diff --git a/contrib/libs/curl/lib/curl_range.c b/contrib/libs/curl/lib/curl_range.c
index 49fb5f0778..d499953c9e 100644
--- a/contrib/libs/curl/lib/curl_range.c
+++ b/contrib/libs/curl/lib/curl_range.c
@@ -55,13 +55,15 @@ CURLcode Curl_range(struct Curl_easy *data)
if((to_t == CURL_OFFT_INVAL) && !from_t) {
/* X - */
data->state.resume_from = from;
- DEBUGF(infof(data, "RANGE %" FMT_OFF_T " to end of file", from));
+ DEBUGF(infof(data, "RANGE %" CURL_FORMAT_CURL_OFF_T " to end of file",
+ from));
}
else if((from_t == CURL_OFFT_INVAL) && !to_t) {
/* -Y */
data->req.maxdownload = to;
data->state.resume_from = -to;
- DEBUGF(infof(data, "RANGE the last %" FMT_OFF_T " bytes", to));
+ DEBUGF(infof(data, "RANGE the last %" CURL_FORMAT_CURL_OFF_T " bytes",
+ to));
}
else {
/* X-Y */
@@ -77,12 +79,13 @@ CURLcode Curl_range(struct Curl_easy *data)
data->req.maxdownload = totalsize + 1; /* include last byte */
data->state.resume_from = from;
- DEBUGF(infof(data, "RANGE from %" FMT_OFF_T
- " getting %" FMT_OFF_T " bytes",
+ DEBUGF(infof(data, "RANGE from %" CURL_FORMAT_CURL_OFF_T
+ " getting %" CURL_FORMAT_CURL_OFF_T " bytes",
from, data->req.maxdownload));
}
- DEBUGF(infof(data, "range-download from %" FMT_OFF_T
- " to %" FMT_OFF_T ", totally %" FMT_OFF_T " bytes",
+ DEBUGF(infof(data, "range-download from %" CURL_FORMAT_CURL_OFF_T
+ " to %" CURL_FORMAT_CURL_OFF_T ", totally %"
+ CURL_FORMAT_CURL_OFF_T " bytes",
from, to, data->req.maxdownload));
}
else
diff --git a/contrib/libs/curl/lib/curl_rtmp.c b/contrib/libs/curl/lib/curl_rtmp.c
index 0b4c83c5ec..a1cb4be4fc 100644
--- a/contrib/libs/curl/lib/curl_rtmp.c
+++ b/contrib/libs/curl/lib/curl_rtmp.c
@@ -35,10 +35,8 @@
#include "warnless.h"
#include <curl/curl.h>
#error #include <librtmp/rtmp.h>
-
-/* The last 3 #include files should be in this order */
-#include "curl_printf.h"
#include "curl_memory.h"
+/* The last #include file should be: */
#include "memdebug.h"
#if defined(_WIN32) && !defined(USE_LWIPSOCK)
@@ -68,7 +66,7 @@ static Curl_send rtmp_send;
*/
const struct Curl_handler Curl_handler_rtmp = {
- "rtmp", /* scheme */
+ "RTMP", /* scheme */
rtmp_setup_connection, /* setup_connection */
rtmp_do, /* do_it */
rtmp_done, /* done */
@@ -81,8 +79,7 @@ const struct Curl_handler Curl_handler_rtmp = {
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
rtmp_disconnect, /* disconnect */
- ZERO_NULL, /* write_resp */
- ZERO_NULL, /* write_resp_hd */
+ ZERO_NULL, /* readwrite */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_RTMP, /* defport */
@@ -92,7 +89,7 @@ const struct Curl_handler Curl_handler_rtmp = {
};
const struct Curl_handler Curl_handler_rtmpt = {
- "rtmpt", /* scheme */
+ "RTMPT", /* scheme */
rtmp_setup_connection, /* setup_connection */
rtmp_do, /* do_it */
rtmp_done, /* done */
@@ -105,8 +102,7 @@ const struct Curl_handler Curl_handler_rtmpt = {
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
rtmp_disconnect, /* disconnect */
- ZERO_NULL, /* write_resp */
- ZERO_NULL, /* write_resp_hd */
+ ZERO_NULL, /* readwrite */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_RTMPT, /* defport */
@@ -116,7 +112,7 @@ const struct Curl_handler Curl_handler_rtmpt = {
};
const struct Curl_handler Curl_handler_rtmpe = {
- "rtmpe", /* scheme */
+ "RTMPE", /* scheme */
rtmp_setup_connection, /* setup_connection */
rtmp_do, /* do_it */
rtmp_done, /* done */
@@ -129,8 +125,7 @@ const struct Curl_handler Curl_handler_rtmpe = {
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
rtmp_disconnect, /* disconnect */
- ZERO_NULL, /* write_resp */
- ZERO_NULL, /* write_resp_hd */
+ ZERO_NULL, /* readwrite */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_RTMP, /* defport */
@@ -140,7 +135,7 @@ const struct Curl_handler Curl_handler_rtmpe = {
};
const struct Curl_handler Curl_handler_rtmpte = {
- "rtmpte", /* scheme */
+ "RTMPTE", /* scheme */
rtmp_setup_connection, /* setup_connection */
rtmp_do, /* do_it */
rtmp_done, /* done */
@@ -153,8 +148,7 @@ const struct Curl_handler Curl_handler_rtmpte = {
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
rtmp_disconnect, /* disconnect */
- ZERO_NULL, /* write_resp */
- ZERO_NULL, /* write_resp_hd */
+ ZERO_NULL, /* readwrite */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_RTMPT, /* defport */
@@ -164,7 +158,7 @@ const struct Curl_handler Curl_handler_rtmpte = {
};
const struct Curl_handler Curl_handler_rtmps = {
- "rtmps", /* scheme */
+ "RTMPS", /* scheme */
rtmp_setup_connection, /* setup_connection */
rtmp_do, /* do_it */
rtmp_done, /* done */
@@ -177,8 +171,7 @@ const struct Curl_handler Curl_handler_rtmps = {
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
rtmp_disconnect, /* disconnect */
- ZERO_NULL, /* write_resp */
- ZERO_NULL, /* write_resp_hd */
+ ZERO_NULL, /* readwrite */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_RTMPS, /* defport */
@@ -188,7 +181,7 @@ const struct Curl_handler Curl_handler_rtmps = {
};
const struct Curl_handler Curl_handler_rtmpts = {
- "rtmpts", /* scheme */
+ "RTMPTS", /* scheme */
rtmp_setup_connection, /* setup_connection */
rtmp_do, /* do_it */
rtmp_done, /* done */
@@ -201,8 +194,7 @@ const struct Curl_handler Curl_handler_rtmpts = {
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
rtmp_disconnect, /* disconnect */
- ZERO_NULL, /* write_resp */
- ZERO_NULL, /* write_resp_hd */
+ ZERO_NULL, /* readwrite */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_RTMPS, /* defport */
@@ -236,7 +228,7 @@ static CURLcode rtmp_connect(struct Curl_easy *data, bool *done)
r->m_sb.sb_socket = (int)conn->sock[FIRSTSOCKET];
- /* We have to know if it is a write before we send the
+ /* We have to know if it's a write before we send the
* connect request packet
*/
if(data->state.upload)
@@ -273,10 +265,10 @@ static CURLcode rtmp_do(struct Curl_easy *data, bool *done)
if(data->state.upload) {
Curl_pgrsSetUploadSize(data, data->state.infilesize);
- Curl_xfer_setup1(data, CURL_XFER_SEND, -1, FALSE);
+ Curl_setup_transfer(data, -1, -1, FALSE, FIRSTSOCKET);
}
else
- Curl_xfer_setup1(data, CURL_XFER_RECV, -1, FALSE);
+ Curl_setup_transfer(data, FIRSTSOCKET, -1, FALSE, -1);
*done = TRUE;
return CURLE_OK;
}
@@ -329,14 +321,13 @@ static ssize_t rtmp_recv(struct Curl_easy *data, int sockindex, char *buf,
}
static ssize_t rtmp_send(struct Curl_easy *data, int sockindex,
- const void *buf, size_t len, bool eos, CURLcode *err)
+ const void *buf, size_t len, CURLcode *err)
{
struct connectdata *conn = data->conn;
RTMP *r = conn->proto.rtmp;
ssize_t num;
(void)sockindex; /* unused */
- (void)eos; /* unused */
num = RTMP_Write(r, (char *)buf, curlx_uztosi(len));
if(num < 0)
@@ -344,20 +335,4 @@ static ssize_t rtmp_send(struct Curl_easy *data, int sockindex,
return num;
}
-
-void Curl_rtmp_version(char *version, size_t len)
-{
- char suff[2];
- if(RTMP_LIB_VERSION & 0xff) {
- suff[0] = (RTMP_LIB_VERSION & 0xff) + 'a' - 1;
- suff[1] = '\0';
- }
- else
- suff[0] = '\0';
-
- msnprintf(version, len, "librtmp/%d.%d%s",
- RTMP_LIB_VERSION >> 16, (RTMP_LIB_VERSION >> 8) & 0xff,
- suff);
-}
-
#endif /* USE_LIBRTMP */
diff --git a/contrib/libs/curl/lib/curl_rtmp.h b/contrib/libs/curl/lib/curl_rtmp.h
index 339d3a4384..9b93ee060b 100644
--- a/contrib/libs/curl/lib/curl_rtmp.h
+++ b/contrib/libs/curl/lib/curl_rtmp.h
@@ -30,8 +30,6 @@ extern const struct Curl_handler Curl_handler_rtmpe;
extern const struct Curl_handler Curl_handler_rtmpte;
extern const struct Curl_handler Curl_handler_rtmps;
extern const struct Curl_handler Curl_handler_rtmpts;
-
-void Curl_rtmp_version(char *version, size_t len);
#endif
#endif /* HEADER_CURL_RTMP_H */
diff --git a/contrib/libs/curl/lib/curl_sasl.c b/contrib/libs/curl/lib/curl_sasl.c
index 24f8c8c53c..78ad298f20 100644
--- a/contrib/libs/curl/lib/curl_sasl.c
+++ b/contrib/libs/curl/lib/curl_sasl.c
@@ -205,23 +205,18 @@ void Curl_sasl_init(struct SASL *sasl, struct Curl_easy *data,
sasl->force_ir = FALSE; /* Respect external option */
if(auth != CURLAUTH_BASIC) {
- unsigned short mechs = SASL_AUTH_NONE;
-
- /* If some usable http authentication options have been set, determine
- new defaults from them. */
+ sasl->resetprefs = FALSE;
+ sasl->prefmech = SASL_AUTH_NONE;
if(auth & CURLAUTH_BASIC)
- mechs |= SASL_MECH_PLAIN | SASL_MECH_LOGIN;
+ sasl->prefmech |= SASL_MECH_PLAIN | SASL_MECH_LOGIN;
if(auth & CURLAUTH_DIGEST)
- mechs |= SASL_MECH_DIGEST_MD5;
+ sasl->prefmech |= SASL_MECH_DIGEST_MD5;
if(auth & CURLAUTH_NTLM)
- mechs |= SASL_MECH_NTLM;
+ sasl->prefmech |= SASL_MECH_NTLM;
if(auth & CURLAUTH_BEARER)
- mechs |= SASL_MECH_OAUTHBEARER | SASL_MECH_XOAUTH2;
+ sasl->prefmech |= SASL_MECH_OAUTHBEARER | SASL_MECH_XOAUTH2;
if(auth & CURLAUTH_GSSAPI)
- mechs |= SASL_MECH_GSSAPI;
-
- if(mechs != SASL_AUTH_NONE)
- sasl->prefmech = mechs;
+ sasl->prefmech |= SASL_MECH_GSSAPI;
}
}
@@ -328,7 +323,7 @@ bool Curl_sasl_can_authenticate(struct SASL *sasl, struct Curl_easy *data)
if(data->state.aptr.user)
return TRUE;
- /* EXTERNAL can authenticate without a username and/or password */
+ /* EXTERNAL can authenticate without a user name and/or password */
if(sasl->authmechs & sasl->prefmech & SASL_MECH_EXTERNAL)
return TRUE;
@@ -376,7 +371,7 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data,
sasl->authused = SASL_MECH_EXTERNAL;
if(force_ir || data->set.sasl_ir)
- Curl_auth_create_external_message(conn->user, &resp);
+ result = Curl_auth_create_external_message(conn->user, &resp);
}
else if(data->state.aptr.user) {
#if defined(USE_KERBEROS5)
@@ -498,7 +493,7 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data,
sasl->authused = SASL_MECH_LOGIN;
if(force_ir || data->set.sasl_ir)
- Curl_auth_create_login_message(conn->user, &resp);
+ result = Curl_auth_create_login_message(conn->user, &resp);
}
}
@@ -576,14 +571,14 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
conn->user, conn->passwd, &resp);
break;
case SASL_LOGIN:
- Curl_auth_create_login_message(conn->user, &resp);
+ result = Curl_auth_create_login_message(conn->user, &resp);
newstate = SASL_LOGIN_PASSWD;
break;
case SASL_LOGIN_PASSWD:
- Curl_auth_create_login_message(conn->passwd, &resp);
+ result = Curl_auth_create_login_message(conn->passwd, &resp);
break;
case SASL_EXTERNAL:
- Curl_auth_create_external_message(conn->user, &resp);
+ result = Curl_auth_create_external_message(conn->user, &resp);
break;
#ifdef USE_GSASL
case SASL_GSASL:
diff --git a/contrib/libs/curl/lib/curl_setup.h b/contrib/libs/curl/lib/curl_setup.h
index 810735ebcd..8d719ddfa4 100644
--- a/contrib/libs/curl/lib/curl_setup.h
+++ b/contrib/libs/curl/lib/curl_setup.h
@@ -28,60 +28,11 @@
#define CURL_NO_OLDIES
#endif
-/* Tell "curl/curl.h" not to include "curl/mprintf.h" */
-#define CURL_SKIP_INCLUDE_MPRINTF
-
-/* FIXME: Delete this once the warnings have been fixed. */
-#if !defined(CURL_WARN_SIGN_CONVERSION)
-#ifdef __GNUC__
-#pragma GCC diagnostic ignored "-Wsign-conversion"
-#endif
-#endif
-
/* Set default _WIN32_WINNT */
#ifdef __MINGW32__
#include <_mingw.h>
#endif
-/* Workaround for Homebrew gcc 12.4.0, 13.3.0, 14.1.0 and newer (as of 14.1.0)
- that started advertising the `availability` attribute, which then gets used
- by Apple SDK, but, in a way incompatible with gcc, resulting in a misc
- errors inside SDK headers, e.g.:
- error: attributes should be specified before the declarator in a function
- definition
- error: expected ',' or '}' before
- Followed by missing declarations.
- Fix it by overriding the built-in feature-check macro used by the headers
- to enable the problematic attributes. This makes the feature check fail. */
-#if defined(__APPLE__) && \
- !defined(__clang__) && \
- defined(__GNUC__) && __GNUC__ >= 12 && \
- defined(__has_attribute)
-#define availability curl_pp_attribute_disabled
-#endif
-
-#if defined(__APPLE__)
-#include <sys/types.h>
-#include <TargetConditionals.h>
-/* Fixup faulty target macro initialization in macOS SDK since v14.4 (as of
- 15.0 beta). The SDK target detection in `TargetConditionals.h` correctly
- detects macOS, but fails to set the macro's old name `TARGET_OS_OSX`, then
- continues to set it to a default value of 0. Other parts of the SDK still
- rely on the old name, and with this inconsistency our builds fail due to
- missing declarations. It happens when using mainline llvm older than v18.
- Later versions fixed it by predefining these target macros, avoiding the
- faulty dynamic detection. gcc is not affected (for now) because it lacks
- the necessary dynamic detection features, so the SDK falls back to
- a codepath that sets both the old and new macro to 1. */
-#if defined(TARGET_OS_MAC) && TARGET_OS_MAC && \
- defined(TARGET_OS_OSX) && !TARGET_OS_OSX && \
- (!defined(TARGET_OS_IPHONE) || !TARGET_OS_IPHONE) && \
- (!defined(TARGET_OS_SIMULATOR) || !TARGET_OS_SIMULATOR)
-#undef TARGET_OS_OSX
-#define TARGET_OS_OSX TARGET_OS_MAC
-#endif
-#endif
-
/*
* Disable Visual Studio warnings:
* 4127 "conditional expression is constant"
@@ -92,7 +43,7 @@
#ifdef _WIN32
/*
- * Do not include unneeded stuff in Windows headers to avoid compiler
+ * Don't include unneeded stuff in Windows headers to avoid compiler
* warnings and macro clashes.
* Make sure to define this macro before including any Windows headers.
*/
@@ -114,11 +65,6 @@
# endif
#endif
-/* Compatibility */
-#if defined(ENABLE_IPV6)
-# define USE_IPV6 1
-#endif
-
/*
* Include configuration script results or hand-crafted
* configuration file for platforms which lack config tool.
@@ -307,72 +253,22 @@
* Windows setup file includes some system headers.
*/
-#ifdef _WIN32
+#ifdef HAVE_WINDOWS_H
# include "setup-win32.h"
#endif
#include <curl/system.h>
-/* Helper macro to expand and concatenate two macros.
- * Direct macros concatenation does not work because macros
- * are not expanded before direct concatenation.
- */
-#define CURL_CONC_MACROS_(A,B) A ## B
-#define CURL_CONC_MACROS(A,B) CURL_CONC_MACROS_(A,B)
-
-/* curl uses its own printf() function internally. It understands the GNU
- * format. Use this format, so that is matches the GNU format attribute we
- * use with the MinGW compiler, allowing it to verify them at compile-time.
- */
-#ifdef __MINGW32__
-# undef CURL_FORMAT_CURL_OFF_T
-# undef CURL_FORMAT_CURL_OFF_TU
-# define CURL_FORMAT_CURL_OFF_T "lld"
-# define CURL_FORMAT_CURL_OFF_TU "llu"
-#endif
-
-/* based on logic in "curl/mprintf.h" */
-
-#if (defined(__GNUC__) || defined(__clang__) || \
- defined(__IAR_SYSTEMS_ICC__)) && \
- defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \
- !defined(CURL_NO_FMT_CHECKS)
-#if defined(__MINGW32__) && !defined(__clang__)
-#define CURL_PRINTF(fmt, arg) \
- __attribute__((format(gnu_printf, fmt, arg)))
-#else
-#define CURL_PRINTF(fmt, arg) \
- __attribute__((format(__printf__, fmt, arg)))
-#endif
-#else
-#define CURL_PRINTF(fmt, arg)
-#endif
-
-/* Override default printf mask check rules in "curl/mprintf.h" */
-#define CURL_TEMP_PRINTF CURL_PRINTF
-
-/* Workaround for mainline llvm v16 and earlier missing a built-in macro
- expected by macOS SDK v14 / Xcode v15 (2023) and newer.
- gcc (as of v14) is also missing it. */
-#if defined(__APPLE__) && \
- ((!defined(__apple_build_version__) && \
- defined(__clang__) && __clang_major__ < 17) || \
- (defined(__GNUC__) && __GNUC__ <= 14)) && \
- defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && \
- !defined(__ENVIRONMENT_OS_VERSION_MIN_REQUIRED__)
-#define __ENVIRONMENT_OS_VERSION_MIN_REQUIRED__ \
- __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__
-#endif
-
/*
* Use getaddrinfo to resolve the IPv4 address literal. If the current network
- * interface does not support IPv4, but supports IPv6, NAT64, and DNS64,
+ * interface doesn't support IPv4, but supports IPv6, NAT64, and DNS64,
* performing this task will result in a synthesized IPv6 address.
*/
#if defined(__APPLE__) && !defined(USE_ARES)
+#include <TargetConditionals.h>
#define USE_RESOLVE_ON_IPS 1
# if TARGET_OS_MAC && !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && \
- defined(USE_IPV6)
+ defined(ENABLE_IPV6)
# define CURL_MACOS_CALL_COPYPROXIES 1
# endif
#endif
@@ -450,7 +346,7 @@
#endif
/*
- * Large file (>2Gb) support using Win32 functions.
+ * Large file (>2Gb) support using WIN32 functions.
*/
#ifdef USE_WIN32_LARGE_FILES
@@ -467,13 +363,15 @@
# define LSEEK_ERROR (__int64)-1
# define open curlx_win32_open
# define fopen(fname,mode) curlx_win32_fopen(fname, mode)
+# define access(fname,mode) curlx_win32_access(fname, mode)
int curlx_win32_open(const char *filename, int oflag, ...);
int curlx_win32_stat(const char *path, struct_stat *buffer);
FILE *curlx_win32_fopen(const char *filename, const char *mode);
+ int curlx_win32_access(const char *path, int mode);
#endif
/*
- * Small file (<2Gb) support using Win32 functions.
+ * Small file (<2Gb) support using WIN32 functions.
*/
#ifdef USE_WIN32_SMALL_FILES
@@ -488,9 +386,11 @@
# define struct_stat struct _stat
# define open curlx_win32_open
# define fopen(fname,mode) curlx_win32_fopen(fname, mode)
+# define access(fname,mode) curlx_win32_access(fname, mode)
int curlx_win32_stat(const char *path, struct_stat *buffer);
int curlx_win32_open(const char *filename, int oflag, ...);
FILE *curlx_win32_fopen(const char *filename, const char *mode);
+ int curlx_win32_access(const char *path, int mode);
# endif
# define LSEEK_ERROR (long)-1
#endif
@@ -504,30 +404,12 @@
#endif
#ifndef SIZEOF_TIME_T
-/* assume default size of time_t to be 32 bits */
+/* assume default size of time_t to be 32 bit */
#define SIZEOF_TIME_T 4
#endif
-#ifndef SIZEOF_CURL_SOCKET_T
-/* configure and cmake check and set the define */
-# ifdef _WIN64
-# define SIZEOF_CURL_SOCKET_T 8
-# else
-/* default guess */
-# define SIZEOF_CURL_SOCKET_T 4
-# endif
-#endif
-
-#if SIZEOF_CURL_SOCKET_T < 8
-# define FMT_SOCKET_T "d"
-#elif defined(__MINGW32__)
-# define FMT_SOCKET_T "zd"
-#else
-# define FMT_SOCKET_T "qd"
-#endif
-
/*
- * Default sizeof(off_t) in case it has not been defined in config file.
+ * Default sizeof(off_t) in case it hasn't been defined in config file.
*/
#ifndef SIZEOF_OFF_T
@@ -561,23 +443,6 @@
#endif
#define CURL_OFF_T_MIN (-CURL_OFF_T_MAX - CURL_OFF_T_C(1))
-#if (SIZEOF_CURL_OFF_T != 8)
-# error "curl_off_t must be exactly 64 bits"
-#else
- typedef unsigned CURL_TYPEOF_CURL_OFF_T curl_uint64_t;
- typedef CURL_TYPEOF_CURL_OFF_T curl_int64_t;
-# ifndef CURL_SUFFIX_CURL_OFF_TU
-# error "CURL_SUFFIX_CURL_OFF_TU must be defined"
-# endif
-# define CURL_UINT64_SUFFIX CURL_SUFFIX_CURL_OFF_TU
-# define CURL_UINT64_C(val) CURL_CONC_MACROS(val,CURL_UINT64_SUFFIX)
-# define FMT_PRId64 CURL_FORMAT_CURL_OFF_T
-# define FMT_PRIu64 CURL_FORMAT_CURL_OFF_TU
-#endif
-
-#define FMT_OFF_T CURL_FORMAT_CURL_OFF_T
-#define FMT_OFF_TU CURL_FORMAT_CURL_OFF_TU
-
#if (SIZEOF_TIME_T == 4)
# ifdef HAVE_TIME_T_UNSIGNED
# define TIME_T_MAX UINT_MAX
@@ -597,7 +462,7 @@
#endif
#ifndef SIZE_T_MAX
-/* some limits.h headers have this defined, some do not */
+/* some limits.h headers have this defined, some don't */
#if defined(SIZEOF_SIZE_T) && (SIZEOF_SIZE_T > 4)
#define SIZE_T_MAX 18446744073709551615U
#else
@@ -606,7 +471,7 @@
#endif
#ifndef SSIZE_T_MAX
-/* some limits.h headers have this defined, some do not */
+/* some limits.h headers have this defined, some don't */
#if defined(SIZEOF_SIZE_T) && (SIZEOF_SIZE_T > 4)
#define SSIZE_T_MAX 9223372036854775807
#else
@@ -615,7 +480,7 @@
#endif
/*
- * Arg 2 type for gethostname in case it has not been defined in config file.
+ * Arg 2 type for gethostname in case it hasn't been defined in config file.
*/
#ifndef GETHOSTNAME_TYPE_ARG2
@@ -682,9 +547,9 @@
* Mutually exclusive CURLRES_* definitions.
*/
-#if defined(USE_IPV6) && defined(HAVE_GETADDRINFO)
+#if defined(ENABLE_IPV6) && defined(HAVE_GETADDRINFO)
# define CURLRES_IPV6
-#elif defined(USE_IPV6) && (defined(_WIN32) || defined(__CYGWIN__))
+#elif defined(ENABLE_IPV6) && (defined(_WIN32) || defined(__CYGWIN__))
/* assume on Windows that IPv6 without getaddrinfo is a broken build */
# error "Unexpected build: IPv6 is enabled but getaddrinfo was not found."
#else
@@ -706,14 +571,13 @@
/* ---------------------------------------------------------------- */
-#if defined(HAVE_LIBIDN2) && defined(HAVE_IDN2_H) && \
- !defined(USE_WIN32_IDN) && !defined(USE_APPLE_IDN)
+#if defined(HAVE_LIBIDN2) && defined(HAVE_IDN2_H) && !defined(USE_WIN32_IDN)
/* The lib and header are present */
#define USE_LIBIDN2
#endif
-#if defined(USE_LIBIDN2) && (defined(USE_WIN32_IDN) || defined(USE_APPLE_IDN))
-#error "libidn2 cannot be enabled with WinIDN or AppleIDN, choose one."
+#if defined(USE_LIBIDN2) && defined(USE_WIN32_IDN)
+#error "Both libidn2 and WinIDN are enabled, choose one."
#endif
#define LIBIDN_REQUIRED_VERSION "0.4.1"
@@ -724,11 +588,6 @@
#define USE_SSL /* SSL support has been enabled */
#endif
-#if defined(USE_WOLFSSL) && defined(USE_GNUTLS)
-/* Avoid defining unprefixed wolfSSL SHA macros colliding with nettle ones */
-#define NO_OLD_WC_NAMES
-#endif
-
/* Single point where USE_SPNEGO definition might be defined */
#if !defined(CURL_DISABLE_NEGOTIATE_AUTH) && \
(defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI))
@@ -772,13 +631,6 @@
((__GNUC__ == 2) && defined(__GNUC_MINOR__) && (__GNUC_MINOR__ >= 7)))
# define UNUSED_PARAM __attribute__((__unused__))
# define WARN_UNUSED_RESULT __attribute__((warn_unused_result))
-#elif defined(__IAR_SYSTEMS_ICC__)
-# define UNUSED_PARAM __attribute__((__unused__))
-# if (__VER__ >= 9040001)
-# define WARN_UNUSED_RESULT __attribute__((warn_unused_result))
-# else
-# define WARN_UNUSED_RESULT
-# endif
#else
# define UNUSED_PARAM /* NOTHING */
# define WARN_UNUSED_RESULT
@@ -787,8 +639,7 @@
/* noreturn attribute */
#if !defined(CURL_NORETURN)
-#if (defined(__GNUC__) && (__GNUC__ >= 3)) || defined(__clang__) || \
- defined(__IAR_SYSTEMS_ICC__)
+#if (defined(__GNUC__) && (__GNUC__ >= 3)) || defined(__clang__)
# define CURL_NORETURN __attribute__((__noreturn__))
#elif defined(_MSC_VER) && (_MSC_VER >= 1200)
# define CURL_NORETURN __declspec(noreturn)
@@ -797,17 +648,6 @@
#endif
#endif
-/* fallthrough attribute */
-
-#if !defined(FALLTHROUGH)
-#if (defined(__GNUC__) && __GNUC__ >= 7) || \
- (defined(__clang__) && __clang_major__ >= 10)
-# define FALLTHROUGH() __attribute__((fallthrough))
-#else
-# define FALLTHROUGH() do {} while (0)
-#endif
-#endif
-
/*
* Include macros and defines that should only be processed once.
*/
@@ -829,13 +669,16 @@
*/
#if defined(__LWIP_OPT_H__) || defined(LWIP_HDR_OPT_H)
-# if defined(SOCKET) || defined(USE_WINSOCK)
-# error "Winsock and lwIP TCP/IP stack definitions shall not coexist!"
+# if defined(SOCKET) || \
+ defined(USE_WINSOCK) || \
+ defined(HAVE_WINSOCK2_H) || \
+ defined(HAVE_WS2TCPIP_H)
+# error "WinSock and lwIP TCP/IP stack definitions shall not coexist!"
# endif
#endif
/*
- * shutdown() flags for systems that do not define them
+ * shutdown() flags for systems that don't define them
*/
#ifndef SHUT_RD
@@ -868,7 +711,7 @@ Therefore we specify it explicitly. https://github.com/curl/curl/pull/258
#define FOPEN_WRITETEXT "wt"
#define FOPEN_APPENDTEXT "at"
#elif defined(__CYGWIN__)
-/* Cygwin has specific behavior we need to address when _WIN32 is not defined.
+/* Cygwin has specific behavior we need to address when WIN32 is not defined.
https://cygwin.com/cygwin-ug-net/using-textbinary.html
For write we want our output to have line endings of LF and be compatible with
other Cygwin utilities. For read we want to handle input that may have line
@@ -883,7 +726,7 @@ endings either CRLF or LF so 't' is appropriate.
#define FOPEN_APPENDTEXT "a"
#endif
-/* for systems that do not detect this in configure */
+/* for systems that don't detect this in configure */
#ifndef CURL_SA_FAMILY_T
# if defined(HAVE_SA_FAMILY_T)
# define CURL_SA_FAMILY_T sa_family_t
@@ -912,7 +755,7 @@ int getpwuid_r(uid_t uid, struct passwd *pwd, char *buf,
size_t buflen, struct passwd **result);
#endif
-#ifdef UNITTESTS
+#ifdef DEBUGBUILD
#define UNITTEST
#else
#define UNITTEST static
@@ -924,13 +767,8 @@ int getpwuid_r(uid_t uid, struct passwd *pwd, char *buf,
#endif
#if (defined(USE_NGTCP2) && defined(USE_NGHTTP3)) || \
- (defined(USE_OPENSSL_QUIC) && defined(USE_NGHTTP3)) || \
defined(USE_QUICHE) || defined(USE_MSH3)
-
-#ifdef CURL_WITH_MULTI_SSL
-#error "Multi-SSL combined with QUIC is not supported"
-#endif
-
+#define ENABLE_QUIC
#define USE_HTTP3
#endif
@@ -961,26 +799,4 @@ int getpwuid_r(uid_t uid, struct passwd *pwd, char *buf,
#define OPENSSL_SUPPRESS_DEPRECATED
#endif
-#if defined(inline)
- /* 'inline' is defined as macro and assumed to be correct */
- /* No need for 'inline' replacement */
-#elif defined(__cplusplus)
- /* The code is compiled with C++ compiler.
- C++ always supports 'inline'. */
- /* No need for 'inline' replacement */
-#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901
- /* C99 (and later) supports 'inline' keyword */
- /* No need for 'inline' replacement */
-#elif defined(__GNUC__) && __GNUC__ >= 3
- /* GCC supports '__inline__' as an extension */
-# define inline __inline__
-#elif defined(_MSC_VER) && _MSC_VER >= 1400
- /* MSC supports '__inline' from VS 2005 (or even earlier) */
-# define inline __inline
-#else
- /* Probably 'inline' is not supported by compiler.
- Define to the empty string to be on the safe side. */
-# define inline /* empty */
-#endif
-
#endif /* HEADER_CURL_SETUP_H */
diff --git a/contrib/libs/curl/lib/curl_setup_once.h b/contrib/libs/curl/lib/curl_setup_once.h
index 1521e69f91..bf0ee663d3 100644
--- a/contrib/libs/curl/lib/curl_setup_once.h
+++ b/contrib/libs/curl/lib/curl_setup_once.h
@@ -106,7 +106,7 @@
#endif
/*
- * Definition of timeval struct for platforms that do not have it.
+ * Definition of timeval struct for platforms that don't have it.
*/
#ifndef HAVE_STRUCT_TIMEVAL
@@ -130,7 +130,7 @@ struct timeval {
#if defined(__minix)
-/* Minix does not support recv on TCP sockets */
+/* Minix doesn't support recv on TCP sockets */
#define sread(x,y,z) (ssize_t)read((RECV_TYPE_ARG1)(x), \
(RECV_TYPE_ARG2)(y), \
(RECV_TYPE_ARG3)(z))
@@ -143,7 +143,7 @@ struct timeval {
*
* HAVE_RECV is defined if you have a function named recv()
* which is used to read incoming data from sockets. If your
- * function has another name then do not define HAVE_RECV.
+ * function has another name then don't define HAVE_RECV.
*
* If HAVE_RECV is defined then RECV_TYPE_ARG1, RECV_TYPE_ARG2,
* RECV_TYPE_ARG3, RECV_TYPE_ARG4 and RECV_TYPE_RETV must also
@@ -151,7 +151,7 @@ struct timeval {
*
* HAVE_SEND is defined if you have a function named send()
* which is used to write outgoing data on a connected socket.
- * If yours has another name then do not define HAVE_SEND.
+ * If yours has another name then don't define HAVE_SEND.
*
* If HAVE_SEND is defined then SEND_TYPE_ARG1, SEND_QUAL_ARG2,
* SEND_TYPE_ARG2, SEND_TYPE_ARG3, SEND_TYPE_ARG4 and
@@ -164,13 +164,15 @@ struct timeval {
(RECV_TYPE_ARG4)(0))
#else /* HAVE_RECV */
#ifndef sread
-#error "Missing definition of macro sread!"
+ /* */
+ Error Missing_definition_of_macro_sread
+ /* */
#endif
#endif /* HAVE_RECV */
#if defined(__minix)
-/* Minix does not support send on TCP sockets */
+/* Minix doesn't support send on TCP sockets */
#define swrite(x,y,z) (ssize_t)write((SEND_TYPE_ARG1)(x), \
(SEND_TYPE_ARG2)(y), \
(SEND_TYPE_ARG3)(z))
@@ -182,7 +184,9 @@ struct timeval {
(SEND_TYPE_ARG4)(SEND_4TH_ARG))
#else /* HAVE_SEND */
#ifndef swrite
-#error "Missing definition of macro swrite!"
+ /* */
+ Error Missing_definition_of_macro_swrite
+ /* */
#endif
#endif /* HAVE_SEND */
@@ -226,7 +230,7 @@ struct timeval {
/*
* 'bool' exists on platforms with <stdbool.h>, i.e. C99 platforms.
- * On non-C99 platforms there is no bool, so define an enum for that.
+ * On non-C99 platforms there's no bool, so define an enum for that.
* On C99 platforms 'false' and 'true' also exist. Enum uses a
* global namespace though, so use bool_false and bool_true.
*/
@@ -238,7 +242,7 @@ struct timeval {
} bool;
/*
- * Use a define to let 'true' and 'false' use those enums. There
+ * Use a define to let 'true' and 'false' use those enums. There
* are currently no use of true and false in libcurl proper, but
* there are some in the examples. This will cater for any later
* code happening to use true and false.
diff --git a/contrib/libs/curl/lib/curl_sha256.h b/contrib/libs/curl/lib/curl_sha256.h
index c3cf00a217..9542ba1286 100644
--- a/contrib/libs/curl/lib/curl_sha256.h
+++ b/contrib/libs/curl/lib/curl_sha256.h
@@ -33,8 +33,13 @@
extern const struct HMAC_params Curl_HMAC_SHA256[1];
-#ifndef CURL_SHA256_DIGEST_LENGTH
-#define CURL_SHA256_DIGEST_LENGTH 32 /* fixed size */
+#ifdef USE_WOLFSSL
+/* SHA256_DIGEST_LENGTH is an enum value in wolfSSL. Need to import it from
+ * sha.h */
+#error #include <wolfssl/options.h>
+#error #include <wolfssl/openssl/sha.h>
+#else
+#define SHA256_DIGEST_LENGTH 32
#endif
CURLcode Curl_sha256it(unsigned char *outbuffer, const unsigned char *input,
diff --git a/contrib/libs/curl/lib/curl_sha512_256.c b/contrib/libs/curl/lib/curl_sha512_256.c
deleted file mode 100644
index 3bdd57c325..0000000000
--- a/contrib/libs/curl/lib/curl_sha512_256.c
+++ /dev/null
@@ -1,857 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) Evgeny Grin (Karlson2k), <k2k@narod.ru>.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at https://curl.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * SPDX-License-Identifier: curl
- *
- ***************************************************************************/
-
-#include "curl_setup.h"
-
-#if !defined(CURL_DISABLE_DIGEST_AUTH) && !defined(CURL_DISABLE_SHA512_256)
-
-#include "curl_sha512_256.h"
-#include "warnless.h"
-
-/* The recommended order of the TLS backends:
- * * OpenSSL
- * * GnuTLS
- * * wolfSSL
- * * Schannel SSPI
- * * SecureTransport (Darwin)
- * * mbedTLS
- * * BearSSL
- * * Rustls
- * Skip the backend if it does not support the required algorithm */
-
-#if defined(USE_OPENSSL)
-# include <openssl/opensslv.h>
-# if (!defined(LIBRESSL_VERSION_NUMBER) && \
- defined(OPENSSL_VERSION_NUMBER) && \
- (OPENSSL_VERSION_NUMBER >= 0x10101000L)) || \
- (defined(LIBRESSL_VERSION_NUMBER) && \
- (LIBRESSL_VERSION_NUMBER >= 0x3080000fL))
-# include <openssl/opensslconf.h>
-# if !defined(OPENSSL_NO_SHA) && !defined(OPENSSL_NO_SHA512)
-# include <openssl/evp.h>
-# define USE_OPENSSL_SHA512_256 1
-# define HAS_SHA512_256_IMPLEMENTATION 1
-# ifdef __NetBSD__
-/* Some NetBSD versions has a bug in SHA-512/256.
- * See https://gnats.netbsd.org/cgi-bin/query-pr-single.pl?number=58039
- * The problematic versions:
- * - NetBSD before 9.4
- * - NetBSD 9 all development versions (9.99.x)
- * - NetBSD 10 development versions (10.99.x) before 10.99.11
- * The bug was fixed in NetBSD 9.4 release, NetBSD 10.0 release,
- * NetBSD 10.99.11 development.
- * It is safe to apply the workaround even if the bug is not present, as
- * the workaround just reduces performance slightly. */
-# include <sys/param.h>
-# if __NetBSD_Version__ < 904000000 || \
- (__NetBSD_Version__ >= 999000000 && \
- __NetBSD_Version__ < 1000000000) || \
- (__NetBSD_Version__ >= 1099000000 && \
- __NetBSD_Version__ < 1099001100)
-# define NEED_NETBSD_SHA512_256_WORKAROUND 1
-# include <string.h>
-# endif
-# endif
-# endif
-# endif
-#endif /* USE_OPENSSL */
-
-
-#if !defined(HAS_SHA512_256_IMPLEMENTATION) && defined(USE_GNUTLS)
-# error #include <nettle/sha.h>
-# if defined(SHA512_256_DIGEST_SIZE)
-# define USE_GNUTLS_SHA512_256 1
-# define HAS_SHA512_256_IMPLEMENTATION 1
-# endif
-#endif /* ! HAS_SHA512_256_IMPLEMENTATION && USE_GNUTLS */
-
-#if defined(USE_OPENSSL_SHA512_256)
-
-/* OpenSSL does not provide macros for SHA-512/256 sizes */
-
-/**
- * Size of the SHA-512/256 single processing block in bytes.
- */
-#define CURL_SHA512_256_BLOCK_SIZE 128
-
-/**
- * Size of the SHA-512/256 resulting digest in bytes.
- * This is the final digest size, not intermediate hash.
- */
-#define CURL_SHA512_256_DIGEST_SIZE CURL_SHA512_256_DIGEST_LENGTH
-
-/**
- * Context type used for SHA-512/256 calculations
- */
-typedef EVP_MD_CTX *Curl_sha512_256_ctx;
-
-/**
- * Initialise structure for SHA-512/256 calculation.
- *
- * @param context the calculation context
- * @return CURLE_OK if succeed,
- * error code otherwise
- */
-static CURLcode
-Curl_sha512_256_init(void *context)
-{
- Curl_sha512_256_ctx *const ctx = (Curl_sha512_256_ctx *)context;
-
- *ctx = EVP_MD_CTX_create();
- if(!*ctx)
- return CURLE_OUT_OF_MEMORY;
-
- if(EVP_DigestInit_ex(*ctx, EVP_sha512_256(), NULL)) {
- /* Check whether the header and this file use the same numbers */
- DEBUGASSERT(EVP_MD_CTX_size(*ctx) == CURL_SHA512_256_DIGEST_SIZE);
- /* Check whether the block size is correct */
- DEBUGASSERT(EVP_MD_CTX_block_size(*ctx) == CURL_SHA512_256_BLOCK_SIZE);
-
- return CURLE_OK; /* Success */
- }
-
- /* Cleanup */
- EVP_MD_CTX_destroy(*ctx);
- return CURLE_FAILED_INIT;
-}
-
-
-/**
- * Process portion of bytes.
- *
- * @param context the calculation context
- * @param data bytes to add to hash
- * @return CURLE_OK if succeed,
- * error code otherwise
- */
-static CURLcode
-Curl_sha512_256_update(void *context,
- const unsigned char *data,
- size_t length)
-{
- Curl_sha512_256_ctx *const ctx = (Curl_sha512_256_ctx *)context;
-
- if(!EVP_DigestUpdate(*ctx, data, length))
- return CURLE_SSL_CIPHER;
-
- return CURLE_OK;
-}
-
-
-/**
- * Finalise SHA-512/256 calculation, return digest.
- *
- * @param context the calculation context
- * @param[out] digest set to the hash, must be #CURL_SHA512_256_DIGEST_SIZE
- # bytes
- * @return CURLE_OK if succeed,
- * error code otherwise
- */
-static CURLcode
-Curl_sha512_256_finish(unsigned char *digest,
- void *context)
-{
- CURLcode ret;
- Curl_sha512_256_ctx *const ctx = (Curl_sha512_256_ctx *)context;
-
-#ifdef NEED_NETBSD_SHA512_256_WORKAROUND
- /* Use a larger buffer to work around a bug in NetBSD:
- https://gnats.netbsd.org/cgi-bin/query-pr-single.pl?number=58039 */
- unsigned char tmp_digest[CURL_SHA512_256_DIGEST_SIZE * 2];
- ret = EVP_DigestFinal_ex(*ctx,
- tmp_digest, NULL) ? CURLE_OK : CURLE_SSL_CIPHER;
- if(ret == CURLE_OK)
- memcpy(digest, tmp_digest, CURL_SHA512_256_DIGEST_SIZE);
- explicit_memset(tmp_digest, 0, sizeof(tmp_digest));
-#else /* ! NEED_NETBSD_SHA512_256_WORKAROUND */
- ret = EVP_DigestFinal_ex(*ctx, digest, NULL) ? CURLE_OK : CURLE_SSL_CIPHER;
-#endif /* ! NEED_NETBSD_SHA512_256_WORKAROUND */
-
- EVP_MD_CTX_destroy(*ctx);
- *ctx = NULL;
-
- return ret;
-}
-
-#elif defined(USE_GNUTLS_SHA512_256)
-
-#define CURL_SHA512_256_BLOCK_SIZE SHA512_256_BLOCK_SIZE
-#define CURL_SHA512_256_DIGEST_SIZE SHA512_256_DIGEST_SIZE
-
-/**
- * Context type used for SHA-512/256 calculations
- */
-typedef struct sha512_256_ctx Curl_sha512_256_ctx;
-
-/**
- * Initialise structure for SHA-512/256 calculation.
- *
- * @param context the calculation context
- * @return always CURLE_OK
- */
-static CURLcode
-Curl_sha512_256_init(void *context)
-{
- Curl_sha512_256_ctx *const ctx = (Curl_sha512_256_ctx *)context;
-
- /* Check whether the header and this file use the same numbers */
- DEBUGASSERT(CURL_SHA512_256_DIGEST_LENGTH == CURL_SHA512_256_DIGEST_SIZE);
-
- sha512_256_init(ctx);
-
- return CURLE_OK;
-}
-
-
-/**
- * Process portion of bytes.
- *
- * @param context the calculation context
- * @param data bytes to add to hash
- * @param length number of bytes in @a data
- * @return always CURLE_OK
- */
-static CURLcode
-Curl_sha512_256_update(void *context,
- const unsigned char *data,
- size_t length)
-{
- Curl_sha512_256_ctx *const ctx = (Curl_sha512_256_ctx *)context;
-
- DEBUGASSERT((data != NULL) || (length == 0));
-
- sha512_256_update(ctx, length, (const uint8_t *)data);
-
- return CURLE_OK;
-}
-
-
-/**
- * Finalise SHA-512/256 calculation, return digest.
- *
- * @param context the calculation context
- * @param[out] digest set to the hash, must be #CURL_SHA512_256_DIGEST_SIZE
- # bytes
- * @return always CURLE_OK
- */
-static CURLcode
-Curl_sha512_256_finish(unsigned char *digest,
- void *context)
-{
- Curl_sha512_256_ctx *const ctx = (Curl_sha512_256_ctx *)context;
-
- sha512_256_digest(ctx,
- (size_t)CURL_SHA512_256_DIGEST_SIZE, (uint8_t *)digest);
-
- return CURLE_OK;
-}
-
-#else /* No system or TLS backend SHA-512/256 implementation available */
-
-/* Use local implementation */
-#define HAS_SHA512_256_IMPLEMENTATION 1
-
-/* ** This implementation of SHA-512/256 hash calculation was originally ** *
- * ** written by Evgeny Grin (Karlson2k) for GNU libmicrohttpd. ** *
- * ** The author ported the code to libcurl. The ported code is provided ** *
- * ** under curl license. ** *
- * ** This is a minimal version with minimal optimizations. Performance ** *
- * ** can be significantly improved. Big-endian store and load macros ** *
- * ** are obvious targets for optimization. ** */
-
-#ifdef __GNUC__
-# if defined(__has_attribute) && defined(__STDC_VERSION__)
-# if __has_attribute(always_inline) && __STDC_VERSION__ >= 199901
-# define MHDX_INLINE inline __attribute__((always_inline))
-# endif
-# endif
-#endif
-
-#if !defined(MHDX_INLINE) && \
- defined(_MSC_VER) && !defined(__GNUC__) && !defined(__clang__)
-# if _MSC_VER >= 1400
-# define MHDX_INLINE __forceinline
-# endif
-#endif
-
-#if !defined(MHDX_INLINE)
- /* Assume that 'inline' keyword works or the
- * macro was already defined correctly. */
-# define MHDX_INLINE inline
-#endif
-
-/* Bits manipulation macros and functions.
- Can be moved to other headers to reuse. */
-
-#define MHDX_GET_64BIT_BE(ptr) \
- ( ((curl_uint64_t)(((const unsigned char*)(ptr))[0]) << 56) | \
- ((curl_uint64_t)(((const unsigned char*)(ptr))[1]) << 48) | \
- ((curl_uint64_t)(((const unsigned char*)(ptr))[2]) << 40) | \
- ((curl_uint64_t)(((const unsigned char*)(ptr))[3]) << 32) | \
- ((curl_uint64_t)(((const unsigned char*)(ptr))[4]) << 24) | \
- ((curl_uint64_t)(((const unsigned char*)(ptr))[5]) << 16) | \
- ((curl_uint64_t)(((const unsigned char*)(ptr))[6]) << 8) | \
- (curl_uint64_t)(((const unsigned char*)(ptr))[7]) )
-
-#define MHDX_PUT_64BIT_BE(ptr,val) do { \
- ((unsigned char*)(ptr))[7]=(unsigned char)((curl_uint64_t)(val)); \
- ((unsigned char*)(ptr))[6]=(unsigned char)(((curl_uint64_t)(val)) >> 8); \
- ((unsigned char*)(ptr))[5]=(unsigned char)(((curl_uint64_t)(val)) >> 16); \
- ((unsigned char*)(ptr))[4]=(unsigned char)(((curl_uint64_t)(val)) >> 24); \
- ((unsigned char*)(ptr))[3]=(unsigned char)(((curl_uint64_t)(val)) >> 32); \
- ((unsigned char*)(ptr))[2]=(unsigned char)(((curl_uint64_t)(val)) >> 40); \
- ((unsigned char*)(ptr))[1]=(unsigned char)(((curl_uint64_t)(val)) >> 48); \
- ((unsigned char*)(ptr))[0]=(unsigned char)(((curl_uint64_t)(val)) >> 56); \
- } while(0)
-
-/* Defined as a function. The macro version may duplicate the binary code
- * size as each argument is used twice, so if any calculation is used
- * as an argument, the calculation could be done twice. */
-static MHDX_INLINE curl_uint64_t
-MHDx_rotr64(curl_uint64_t value, unsigned int bits)
-{
- bits %= 64;
- if(0 == bits)
- return value;
- /* Defined in a form which modern compiler could optimize. */
- return (value >> bits) | (value << (64 - bits));
-}
-
-/* SHA-512/256 specific data */
-
-/**
- * Number of bits in a single SHA-512/256 word.
- */
-#define SHA512_256_WORD_SIZE_BITS 64
-
-/**
- * Number of bytes in a single SHA-512/256 word.
- */
-#define SHA512_256_BYTES_IN_WORD (SHA512_256_WORD_SIZE_BITS / 8)
-
-/**
- * Hash is kept internally as 8 64-bit words.
- * This is the intermediate hash size, used during computing the final digest.
- */
-#define SHA512_256_HASH_SIZE_WORDS 8
-
-/**
- * Size of the SHA-512/256 resulting digest in words.
- * This is the final digest size, not intermediate hash.
- */
-#define SHA512_256_DIGEST_SIZE_WORDS (SHA512_256_HASH_SIZE_WORDS / 2)
-
-/**
- * Size of the SHA-512/256 resulting digest in bytes
- * This is the final digest size, not intermediate hash.
- */
-#define CURL_SHA512_256_DIGEST_SIZE \
- (SHA512_256_DIGEST_SIZE_WORDS * SHA512_256_BYTES_IN_WORD)
-
-/**
- * Size of the SHA-512/256 single processing block in bits.
- */
-#define SHA512_256_BLOCK_SIZE_BITS 1024
-
-/**
- * Size of the SHA-512/256 single processing block in bytes.
- */
-#define CURL_SHA512_256_BLOCK_SIZE (SHA512_256_BLOCK_SIZE_BITS / 8)
-
-/**
- * Size of the SHA-512/256 single processing block in words.
- */
-#define SHA512_256_BLOCK_SIZE_WORDS \
- (SHA512_256_BLOCK_SIZE_BITS / SHA512_256_WORD_SIZE_BITS)
-
-/**
- * SHA-512/256 calculation context
- */
-struct mhdx_sha512_256ctx
-{
- /**
- * Intermediate hash value. The variable is properly aligned. Smart
- * compilers may automatically use fast load/store instruction for big
- * endian data on little endian machine.
- */
- curl_uint64_t H[SHA512_256_HASH_SIZE_WORDS];
- /**
- * SHA-512/256 input data buffer. The buffer is properly aligned. Smart
- * compilers may automatically use fast load/store instruction for big
- * endian data on little endian machine.
- */
- curl_uint64_t buffer[SHA512_256_BLOCK_SIZE_WORDS];
- /**
- * The number of bytes, lower part
- */
- curl_uint64_t count;
- /**
- * The number of bits, high part. Unlike lower part, this counts the number
- * of bits, not bytes.
- */
- curl_uint64_t count_bits_hi;
-};
-
-/**
- * Context type used for SHA-512/256 calculations
- */
-typedef struct mhdx_sha512_256ctx Curl_sha512_256_ctx;
-
-
-/**
- * Initialise structure for SHA-512/256 calculation.
- *
- * @param context the calculation context
- * @return always CURLE_OK
- */
-static CURLcode
-MHDx_sha512_256_init(void *context)
-{
- struct mhdx_sha512_256ctx *const ctx = (struct mhdx_sha512_256ctx *) context;
-
- /* Check whether the header and this file use the same numbers */
- DEBUGASSERT(CURL_SHA512_256_DIGEST_LENGTH == CURL_SHA512_256_DIGEST_SIZE);
-
- DEBUGASSERT(sizeof(curl_uint64_t) == 8);
-
- /* Initial hash values, see FIPS PUB 180-4 section 5.3.6.2 */
- /* Values generated by "IV Generation Function" as described in
- * section 5.3.6 */
- ctx->H[0] = CURL_UINT64_C(0x22312194FC2BF72C);
- ctx->H[1] = CURL_UINT64_C(0x9F555FA3C84C64C2);
- ctx->H[2] = CURL_UINT64_C(0x2393B86B6F53B151);
- ctx->H[3] = CURL_UINT64_C(0x963877195940EABD);
- ctx->H[4] = CURL_UINT64_C(0x96283EE2A88EFFE3);
- ctx->H[5] = CURL_UINT64_C(0xBE5E1E2553863992);
- ctx->H[6] = CURL_UINT64_C(0x2B0199FC2C85B8AA);
- ctx->H[7] = CURL_UINT64_C(0x0EB72DDC81C52CA2);
-
- /* Initialise number of bytes and high part of number of bits. */
- ctx->count = CURL_UINT64_C(0);
- ctx->count_bits_hi = CURL_UINT64_C(0);
-
- return CURLE_OK;
-}
-
-
-/**
- * Base of the SHA-512/256 transformation.
- * Gets a full 128 bytes block of data and updates hash values;
- * @param H hash values
- * @param data the data buffer with #CURL_SHA512_256_BLOCK_SIZE bytes block
- */
-static void
-MHDx_sha512_256_transform(curl_uint64_t H[SHA512_256_HASH_SIZE_WORDS],
- const void *data)
-{
- /* Working variables,
- see FIPS PUB 180-4 section 6.7, 6.4. */
- curl_uint64_t a = H[0];
- curl_uint64_t b = H[1];
- curl_uint64_t c = H[2];
- curl_uint64_t d = H[3];
- curl_uint64_t e = H[4];
- curl_uint64_t f = H[5];
- curl_uint64_t g = H[6];
- curl_uint64_t h = H[7];
-
- /* Data buffer, used as a cyclic buffer.
- See FIPS PUB 180-4 section 5.2.2, 6.7, 6.4. */
- curl_uint64_t W[16];
-
- /* 'Ch' and 'Maj' macro functions are defined with widely-used optimization.
- See FIPS PUB 180-4 formulae 4.8, 4.9. */
-#define Sha512_Ch(x,y,z) ( (z) ^ ((x) & ((y) ^ (z))) )
-#define Sha512_Maj(x,y,z) ( ((x) & (y)) ^ ((z) & ((x) ^ (y))) )
-
- /* Four 'Sigma' macro functions.
- See FIPS PUB 180-4 formulae 4.10, 4.11, 4.12, 4.13. */
-#define SIG0(x) \
- ( MHDx_rotr64((x), 28) ^ MHDx_rotr64((x), 34) ^ MHDx_rotr64((x), 39) )
-#define SIG1(x) \
- ( MHDx_rotr64((x), 14) ^ MHDx_rotr64((x), 18) ^ MHDx_rotr64((x), 41) )
-#define sig0(x) \
- ( MHDx_rotr64((x), 1) ^ MHDx_rotr64((x), 8) ^ ((x) >> 7) )
-#define sig1(x) \
- ( MHDx_rotr64((x), 19) ^ MHDx_rotr64((x), 61) ^ ((x) >> 6) )
-
- if(1) {
- unsigned int t;
- /* K constants array.
- See FIPS PUB 180-4 section 4.2.3 for K values. */
- static const curl_uint64_t K[80] = {
- CURL_UINT64_C(0x428a2f98d728ae22), CURL_UINT64_C(0x7137449123ef65cd),
- CURL_UINT64_C(0xb5c0fbcfec4d3b2f), CURL_UINT64_C(0xe9b5dba58189dbbc),
- CURL_UINT64_C(0x3956c25bf348b538), CURL_UINT64_C(0x59f111f1b605d019),
- CURL_UINT64_C(0x923f82a4af194f9b), CURL_UINT64_C(0xab1c5ed5da6d8118),
- CURL_UINT64_C(0xd807aa98a3030242), CURL_UINT64_C(0x12835b0145706fbe),
- CURL_UINT64_C(0x243185be4ee4b28c), CURL_UINT64_C(0x550c7dc3d5ffb4e2),
- CURL_UINT64_C(0x72be5d74f27b896f), CURL_UINT64_C(0x80deb1fe3b1696b1),
- CURL_UINT64_C(0x9bdc06a725c71235), CURL_UINT64_C(0xc19bf174cf692694),
- CURL_UINT64_C(0xe49b69c19ef14ad2), CURL_UINT64_C(0xefbe4786384f25e3),
- CURL_UINT64_C(0x0fc19dc68b8cd5b5), CURL_UINT64_C(0x240ca1cc77ac9c65),
- CURL_UINT64_C(0x2de92c6f592b0275), CURL_UINT64_C(0x4a7484aa6ea6e483),
- CURL_UINT64_C(0x5cb0a9dcbd41fbd4), CURL_UINT64_C(0x76f988da831153b5),
- CURL_UINT64_C(0x983e5152ee66dfab), CURL_UINT64_C(0xa831c66d2db43210),
- CURL_UINT64_C(0xb00327c898fb213f), CURL_UINT64_C(0xbf597fc7beef0ee4),
- CURL_UINT64_C(0xc6e00bf33da88fc2), CURL_UINT64_C(0xd5a79147930aa725),
- CURL_UINT64_C(0x06ca6351e003826f), CURL_UINT64_C(0x142929670a0e6e70),
- CURL_UINT64_C(0x27b70a8546d22ffc), CURL_UINT64_C(0x2e1b21385c26c926),
- CURL_UINT64_C(0x4d2c6dfc5ac42aed), CURL_UINT64_C(0x53380d139d95b3df),
- CURL_UINT64_C(0x650a73548baf63de), CURL_UINT64_C(0x766a0abb3c77b2a8),
- CURL_UINT64_C(0x81c2c92e47edaee6), CURL_UINT64_C(0x92722c851482353b),
- CURL_UINT64_C(0xa2bfe8a14cf10364), CURL_UINT64_C(0xa81a664bbc423001),
- CURL_UINT64_C(0xc24b8b70d0f89791), CURL_UINT64_C(0xc76c51a30654be30),
- CURL_UINT64_C(0xd192e819d6ef5218), CURL_UINT64_C(0xd69906245565a910),
- CURL_UINT64_C(0xf40e35855771202a), CURL_UINT64_C(0x106aa07032bbd1b8),
- CURL_UINT64_C(0x19a4c116b8d2d0c8), CURL_UINT64_C(0x1e376c085141ab53),
- CURL_UINT64_C(0x2748774cdf8eeb99), CURL_UINT64_C(0x34b0bcb5e19b48a8),
- CURL_UINT64_C(0x391c0cb3c5c95a63), CURL_UINT64_C(0x4ed8aa4ae3418acb),
- CURL_UINT64_C(0x5b9cca4f7763e373), CURL_UINT64_C(0x682e6ff3d6b2b8a3),
- CURL_UINT64_C(0x748f82ee5defb2fc), CURL_UINT64_C(0x78a5636f43172f60),
- CURL_UINT64_C(0x84c87814a1f0ab72), CURL_UINT64_C(0x8cc702081a6439ec),
- CURL_UINT64_C(0x90befffa23631e28), CURL_UINT64_C(0xa4506cebde82bde9),
- CURL_UINT64_C(0xbef9a3f7b2c67915), CURL_UINT64_C(0xc67178f2e372532b),
- CURL_UINT64_C(0xca273eceea26619c), CURL_UINT64_C(0xd186b8c721c0c207),
- CURL_UINT64_C(0xeada7dd6cde0eb1e), CURL_UINT64_C(0xf57d4f7fee6ed178),
- CURL_UINT64_C(0x06f067aa72176fba), CURL_UINT64_C(0x0a637dc5a2c898a6),
- CURL_UINT64_C(0x113f9804bef90dae), CURL_UINT64_C(0x1b710b35131c471b),
- CURL_UINT64_C(0x28db77f523047d84), CURL_UINT64_C(0x32caab7b40c72493),
- CURL_UINT64_C(0x3c9ebe0a15c9bebc), CURL_UINT64_C(0x431d67c49c100d4c),
- CURL_UINT64_C(0x4cc5d4becb3e42b6), CURL_UINT64_C(0x597f299cfc657e2a),
- CURL_UINT64_C(0x5fcb6fab3ad6faec), CURL_UINT64_C(0x6c44198c4a475817)
- };
-
- /* One step of SHA-512/256 computation,
- see FIPS PUB 180-4 section 6.4.2 step 3.
- * Note: this macro updates working variables in-place, without rotation.
- * Note: the first (vH += SIG1(vE) + Ch(vE,vF,vG) + kt + wt) equals T1 in
- FIPS PUB 180-4 section 6.4.2 step 3.
- the second (vH += SIG0(vA) + Maj(vE,vF,vC) equals T1 + T2 in
- FIPS PUB 180-4 section 6.4.2 step 3.
- * Note: 'wt' must be used exactly one time in this macro as macro for
- 'wt' calculation may change other data as well every time when
- used. */
-#define SHA2STEP64(vA,vB,vC,vD,vE,vF,vG,vH,kt,wt) do { \
- (vD) += ((vH) += SIG1((vE)) + Sha512_Ch((vE),(vF),(vG)) + (kt) + (wt)); \
- (vH) += SIG0((vA)) + Sha512_Maj((vA),(vB),(vC)); } while (0)
-
- /* One step of SHA-512/256 computation with working variables rotation,
- see FIPS PUB 180-4 section 6.4.2 step 3. This macro version reassigns
- all working variables on each step. */
-#define SHA2STEP64RV(vA,vB,vC,vD,vE,vF,vG,vH,kt,wt) do { \
- curl_uint64_t tmp_h_ = (vH); \
- SHA2STEP64((vA),(vB),(vC),(vD),(vE),(vF),(vG),tmp_h_,(kt),(wt)); \
- (vH) = (vG); \
- (vG) = (vF); \
- (vF) = (vE); \
- (vE) = (vD); \
- (vD) = (vC); \
- (vC) = (vB); \
- (vB) = (vA); \
- (vA) = tmp_h_; } while(0)
-
- /* Get value of W(t) from input data buffer for 0 <= t <= 15,
- See FIPS PUB 180-4 section 6.2.
- Input data must be read in big-endian bytes order,
- see FIPS PUB 180-4 section 3.1.2. */
-#define SHA512_GET_W_FROM_DATA(buf,t) \
- MHDX_GET_64BIT_BE( \
- ((const unsigned char*) (buf)) + (t) * SHA512_256_BYTES_IN_WORD)
-
- /* During first 16 steps, before making any calculation on each step, the
- W element is read from the input data buffer as a big-endian value and
- stored in the array of W elements. */
- for(t = 0; t < 16; ++t) {
- SHA2STEP64RV(a, b, c, d, e, f, g, h, K[t], \
- W[t] = SHA512_GET_W_FROM_DATA(data, t));
- }
-
- /* 'W' generation and assignment for 16 <= t <= 79.
- See FIPS PUB 180-4 section 6.4.2.
- As only the last 16 'W' are used in calculations, it is possible to
- use 16 elements array of W as a cyclic buffer.
- Note: ((t-16) & 15) have same value as (t & 15) */
-#define Wgen(w,t) \
- (curl_uint64_t)( (w)[(t - 16) & 15] + sig1((w)[((t) - 2) & 15]) \
- + (w)[((t) - 7) & 15] + sig0((w)[((t) - 15) & 15]) )
-
- /* During the last 64 steps, before making any calculation on each step,
- current W element is generated from other W elements of the cyclic
- buffer and the generated value is stored back in the cyclic buffer. */
- for(t = 16; t < 80; ++t) {
- SHA2STEP64RV(a, b, c, d, e, f, g, h, K[t], \
- W[t & 15] = Wgen(W, t));
- }
- }
-
- /* Compute and store the intermediate hash.
- See FIPS PUB 180-4 section 6.4.2 step 4. */
- H[0] += a;
- H[1] += b;
- H[2] += c;
- H[3] += d;
- H[4] += e;
- H[5] += f;
- H[6] += g;
- H[7] += h;
-}
-
-
-/**
- * Process portion of bytes.
- *
- * @param context the calculation context
- * @param data bytes to add to hash
- * @param length number of bytes in @a data
- * @return always CURLE_OK
- */
-static CURLcode
-MHDx_sha512_256_update(void *context,
- const unsigned char *data,
- size_t length)
-{
- unsigned int bytes_have; /**< Number of bytes in the context buffer */
- struct mhdx_sha512_256ctx *const ctx = (struct mhdx_sha512_256ctx *)context;
- /* the void pointer here is required to mute Intel compiler warning */
- void *const ctx_buf = ctx->buffer;
-
- DEBUGASSERT((data != NULL) || (length == 0));
-
- if(0 == length)
- return CURLE_OK; /* Shortcut, do nothing */
-
- /* Note: (count & (CURL_SHA512_256_BLOCK_SIZE-1))
- equals (count % CURL_SHA512_256_BLOCK_SIZE) for this block size. */
- bytes_have = (unsigned int) (ctx->count & (CURL_SHA512_256_BLOCK_SIZE - 1));
- ctx->count += length;
- if(length > ctx->count)
- ctx->count_bits_hi += 1U << 3; /* Value wrap */
- ctx->count_bits_hi += ctx->count >> 61;
- ctx->count &= CURL_UINT64_C(0x1FFFFFFFFFFFFFFF);
-
- if(0 != bytes_have) {
- unsigned int bytes_left = CURL_SHA512_256_BLOCK_SIZE - bytes_have;
- if(length >= bytes_left) {
- /* Combine new data with data in the buffer and process the full
- block. */
- memcpy(((unsigned char *) ctx_buf) + bytes_have,
- data,
- bytes_left);
- data += bytes_left;
- length -= bytes_left;
- MHDx_sha512_256_transform(ctx->H, ctx->buffer);
- bytes_have = 0;
- }
- }
-
- while(CURL_SHA512_256_BLOCK_SIZE <= length) {
- /* Process any full blocks of new data directly,
- without copying to the buffer. */
- MHDx_sha512_256_transform(ctx->H, data);
- data += CURL_SHA512_256_BLOCK_SIZE;
- length -= CURL_SHA512_256_BLOCK_SIZE;
- }
-
- if(0 != length) {
- /* Copy incomplete block of new data (if any)
- to the buffer. */
- memcpy(((unsigned char *) ctx_buf) + bytes_have, data, length);
- }
-
- return CURLE_OK;
-}
-
-
-
-/**
- * Size of "length" insertion in bits.
- * See FIPS PUB 180-4 section 5.1.2.
- */
-#define SHA512_256_SIZE_OF_LEN_ADD_BITS 128
-
-/**
- * Size of "length" insertion in bytes.
- */
-#define SHA512_256_SIZE_OF_LEN_ADD (SHA512_256_SIZE_OF_LEN_ADD_BITS / 8)
-
-/**
- * Finalise SHA-512/256 calculation, return digest.
- *
- * @param context the calculation context
- * @param[out] digest set to the hash, must be #CURL_SHA512_256_DIGEST_SIZE
- # bytes
- * @return always CURLE_OK
- */
-static CURLcode
-MHDx_sha512_256_finish(unsigned char *digest,
- void *context)
-{
- struct mhdx_sha512_256ctx *const ctx = (struct mhdx_sha512_256ctx *)context;
- curl_uint64_t num_bits; /**< Number of processed bits */
- unsigned int bytes_have; /**< Number of bytes in the context buffer */
- /* the void pointer here is required to mute Intel compiler warning */
- void *const ctx_buf = ctx->buffer;
-
- /* Memorise the number of processed bits.
- The padding and other data added here during the postprocessing must
- not change the amount of hashed data. */
- num_bits = ctx->count << 3;
-
- /* Note: (count & (CURL_SHA512_256_BLOCK_SIZE-1))
- equals (count % CURL_SHA512_256_BLOCK_SIZE) for this block size. */
- bytes_have = (unsigned int) (ctx->count & (CURL_SHA512_256_BLOCK_SIZE - 1));
-
- /* Input data must be padded with a single bit "1", then with zeros and
- the finally the length of data in bits must be added as the final bytes
- of the last block.
- See FIPS PUB 180-4 section 5.1.2. */
-
- /* Data is always processed in form of bytes (not by individual bits),
- therefore position of the first padding bit in byte is always
- predefined (0x80). */
- /* Buffer always have space at least for one byte (as full buffers are
- processed when formed). */
- ((unsigned char *) ctx_buf)[bytes_have++] = 0x80U;
-
- if(CURL_SHA512_256_BLOCK_SIZE - bytes_have < SHA512_256_SIZE_OF_LEN_ADD) {
- /* No space in the current block to put the total length of message.
- Pad the current block with zeros and process it. */
- if(bytes_have < CURL_SHA512_256_BLOCK_SIZE)
- memset(((unsigned char *) ctx_buf) + bytes_have, 0,
- CURL_SHA512_256_BLOCK_SIZE - bytes_have);
- /* Process the full block. */
- MHDx_sha512_256_transform(ctx->H, ctx->buffer);
- /* Start the new block. */
- bytes_have = 0;
- }
-
- /* Pad the rest of the buffer with zeros. */
- memset(((unsigned char *) ctx_buf) + bytes_have, 0,
- CURL_SHA512_256_BLOCK_SIZE - SHA512_256_SIZE_OF_LEN_ADD - bytes_have);
- /* Put high part of number of bits in processed message and then lower
- part of number of bits as big-endian values.
- See FIPS PUB 180-4 section 5.1.2. */
- /* Note: the target location is predefined and buffer is always aligned */
- MHDX_PUT_64BIT_BE(((unsigned char *) ctx_buf) \
- + CURL_SHA512_256_BLOCK_SIZE \
- - SHA512_256_SIZE_OF_LEN_ADD, \
- ctx->count_bits_hi);
- MHDX_PUT_64BIT_BE(((unsigned char *) ctx_buf) \
- + CURL_SHA512_256_BLOCK_SIZE \
- - SHA512_256_SIZE_OF_LEN_ADD \
- + SHA512_256_BYTES_IN_WORD, \
- num_bits);
- /* Process the full final block. */
- MHDx_sha512_256_transform(ctx->H, ctx->buffer);
-
- /* Put in BE mode the leftmost part of the hash as the final digest.
- See FIPS PUB 180-4 section 6.7. */
-
- MHDX_PUT_64BIT_BE((digest + 0 * SHA512_256_BYTES_IN_WORD), ctx->H[0]);
- MHDX_PUT_64BIT_BE((digest + 1 * SHA512_256_BYTES_IN_WORD), ctx->H[1]);
- MHDX_PUT_64BIT_BE((digest + 2 * SHA512_256_BYTES_IN_WORD), ctx->H[2]);
- MHDX_PUT_64BIT_BE((digest + 3 * SHA512_256_BYTES_IN_WORD), ctx->H[3]);
-
- /* Erase potentially sensitive data. */
- memset(ctx, 0, sizeof(struct mhdx_sha512_256ctx));
-
- return CURLE_OK;
-}
-
-/* Map to the local implementation */
-#define Curl_sha512_256_init MHDx_sha512_256_init
-#define Curl_sha512_256_update MHDx_sha512_256_update
-#define Curl_sha512_256_finish MHDx_sha512_256_finish
-
-#endif /* Local SHA-512/256 code */
-
-
-/**
- * Compute SHA-512/256 hash for the given data in one function call
- * @param[out] output the pointer to put the hash
- * @param[in] input the pointer to the data to process
- * @param input_size the size of the data pointed by @a input
- * @return always #CURLE_OK
- */
-CURLcode
-Curl_sha512_256it(unsigned char *output, const unsigned char *input,
- size_t input_size)
-{
- Curl_sha512_256_ctx ctx;
- CURLcode res;
-
- res = Curl_sha512_256_init(&ctx);
- if(res != CURLE_OK)
- return res;
-
- res = Curl_sha512_256_update(&ctx, (const void *) input, input_size);
-
- if(res != CURLE_OK) {
- (void) Curl_sha512_256_finish(output, &ctx);
- return res;
- }
-
- return Curl_sha512_256_finish(output, &ctx);
-}
-
-/* Wrapper function, takes 'unsigned int' as length type, returns void */
-static void
-Curl_sha512_256_update_i(void *context,
- const unsigned char *data,
- unsigned int length)
-{
- /* Hypothetically the function may fail, but assume it does not */
- (void) Curl_sha512_256_update(context, data, length);
-}
-
-/* Wrapper function, returns void */
-static void
-Curl_sha512_256_finish_v(unsigned char *result,
- void *context)
-{
- /* Hypothetically the function may fail, but assume it does not */
- (void) Curl_sha512_256_finish(result, context);
-}
-
-/* Wrapper function, takes 'unsigned int' as length type, returns void */
-
-const struct HMAC_params Curl_HMAC_SHA512_256[] = {
- {
- /* Initialize context procedure. */
- Curl_sha512_256_init,
- /* Update context with data. */
- Curl_sha512_256_update_i,
- /* Get final result procedure. */
- Curl_sha512_256_finish_v,
- /* Context structure size. */
- sizeof(Curl_sha512_256_ctx),
- /* Maximum key length (bytes). */
- CURL_SHA512_256_BLOCK_SIZE,
- /* Result length (bytes). */
- CURL_SHA512_256_DIGEST_SIZE
- }
-};
-
-#endif /* !CURL_DISABLE_DIGEST_AUTH && !CURL_DISABLE_SHA512_256 */
diff --git a/contrib/libs/curl/lib/curl_sha512_256.h b/contrib/libs/curl/lib/curl_sha512_256.h
deleted file mode 100644
index a84e77bc30..0000000000
--- a/contrib/libs/curl/lib/curl_sha512_256.h
+++ /dev/null
@@ -1,44 +0,0 @@
-#ifndef HEADER_CURL_SHA512_256_H
-#define HEADER_CURL_SHA512_256_H
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) Evgeny Grin (Karlson2k), <k2k@narod.ru>.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at https://curl.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * SPDX-License-Identifier: curl
- *
- ***************************************************************************/
-
-#if !defined(CURL_DISABLE_DIGEST_AUTH) && !defined(CURL_DISABLE_SHA512_256)
-
-#include <curl/curl.h>
-#include "curl_hmac.h"
-
-#define CURL_HAVE_SHA512_256
-
-extern const struct HMAC_params Curl_HMAC_SHA512_256[1];
-
-#define CURL_SHA512_256_DIGEST_LENGTH 32
-
-CURLcode
-Curl_sha512_256it(unsigned char *output, const unsigned char *input,
- size_t input_size);
-
-#endif /* !CURL_DISABLE_DIGEST_AUTH && !CURL_DISABLE_SHA512_256 */
-
-#endif /* HEADER_CURL_SHA256_H */
diff --git a/contrib/libs/curl/lib/curl_sspi.c b/contrib/libs/curl/lib/curl_sspi.c
index 680bb661b2..eb21e7e2b0 100644
--- a/contrib/libs/curl/lib/curl_sspi.c
+++ b/contrib/libs/curl/lib/curl_sspi.c
@@ -52,10 +52,10 @@ typedef PSecurityFunctionTable (APIENTRY *INITSECURITYINTERFACE_FN)(VOID);
#endif
/* Handle of security.dll or secur32.dll, depending on Windows version */
-HMODULE Curl_hSecDll = NULL;
+HMODULE s_hSecDll = NULL;
/* Pointer to SSPI dispatch table */
-PSecurityFunctionTable Curl_pSecFn = NULL;
+PSecurityFunctionTable s_pSecFn = NULL;
/*
* Curl_sspi_global_init()
@@ -79,29 +79,29 @@ CURLcode Curl_sspi_global_init(void)
INITSECURITYINTERFACE_FN pInitSecurityInterface;
/* If security interface is not yet initialized try to do this */
- if(!Curl_hSecDll) {
+ if(!s_hSecDll) {
/* Security Service Provider Interface (SSPI) functions are located in
* security.dll on WinNT 4.0 and in secur32.dll on Win9x. Win2K and XP
* have both these DLLs (security.dll forwards calls to secur32.dll) */
/* Load SSPI dll into the address space of the calling process */
if(curlx_verify_windows_version(4, 0, 0, PLATFORM_WINNT, VERSION_EQUAL))
- Curl_hSecDll = Curl_load_library(TEXT("security.dll"));
+ s_hSecDll = Curl_load_library(TEXT("security.dll"));
else
- Curl_hSecDll = Curl_load_library(TEXT("secur32.dll"));
- if(!Curl_hSecDll)
+ s_hSecDll = Curl_load_library(TEXT("secur32.dll"));
+ if(!s_hSecDll)
return CURLE_FAILED_INIT;
/* Get address of the InitSecurityInterfaceA function from the SSPI dll */
pInitSecurityInterface =
CURLX_FUNCTION_CAST(INITSECURITYINTERFACE_FN,
- (GetProcAddress(Curl_hSecDll, SECURITYENTRYPOINT)));
+ (GetProcAddress(s_hSecDll, SECURITYENTRYPOINT)));
if(!pInitSecurityInterface)
return CURLE_FAILED_INIT;
/* Get pointer to Security Service Provider Interface dispatch table */
- Curl_pSecFn = pInitSecurityInterface();
- if(!Curl_pSecFn)
+ s_pSecFn = pInitSecurityInterface();
+ if(!s_pSecFn)
return CURLE_FAILED_INIT;
}
@@ -119,10 +119,10 @@ CURLcode Curl_sspi_global_init(void)
*/
void Curl_sspi_global_cleanup(void)
{
- if(Curl_hSecDll) {
- FreeLibrary(Curl_hSecDll);
- Curl_hSecDll = NULL;
- Curl_pSecFn = NULL;
+ if(s_hSecDll) {
+ FreeLibrary(s_hSecDll);
+ s_hSecDll = NULL;
+ s_pSecFn = NULL;
}
}
@@ -134,7 +134,7 @@ void Curl_sspi_global_cleanup(void)
*
* Parameters:
*
- * userp [in] - The username in the format User or Domain\User.
+ * userp [in] - The user name in the format User or Domain\User.
* passwdp [in] - The user's password.
* identity [in/out] - The identity structure.
*
diff --git a/contrib/libs/curl/lib/curl_sspi.h b/contrib/libs/curl/lib/curl_sspi.h
index 535a1ff650..b26c391569 100644
--- a/contrib/libs/curl/lib/curl_sspi.h
+++ b/contrib/libs/curl/lib/curl_sspi.h
@@ -57,8 +57,8 @@ CURLcode Curl_create_sspi_identity(const char *userp, const char *passwdp,
void Curl_sspi_free_identity(SEC_WINNT_AUTH_IDENTITY *identity);
/* Forward-declaration of global variables defined in curl_sspi.c */
-extern HMODULE Curl_hSecDll;
-extern PSecurityFunctionTable Curl_pSecFn;
+extern HMODULE s_hSecDll;
+extern PSecurityFunctionTable s_pSecFn;
/* Provide some definitions missing in old headers */
#define SP_NAME_DIGEST "WDigest"
diff --git a/contrib/libs/curl/lib/curl_threads.c b/contrib/libs/curl/lib/curl_threads.c
index 6d73273f78..222d9364f0 100644
--- a/contrib/libs/curl/lib/curl_threads.c
+++ b/contrib/libs/curl/lib/curl_threads.c
@@ -35,9 +35,7 @@
#endif
#include "curl_threads.h"
-#ifdef BUILDING_LIBCURL
#include "curl_memory.h"
-#endif
/* The last #include file should be: */
#include "memdebug.h"
@@ -102,23 +100,18 @@ int Curl_thread_join(curl_thread_t *hnd)
#elif defined(USE_THREADS_WIN32)
-curl_thread_t Curl_thread_create(
-#if defined(_WIN32_WCE) || defined(CURL_WINDOWS_APP)
- DWORD
-#else
- unsigned int
-#endif
- (CURL_STDCALL *func) (void *),
+/* !checksrc! disable SPACEBEFOREPAREN 1 */
+curl_thread_t Curl_thread_create(unsigned int (CURL_STDCALL *func) (void *),
void *arg)
{
-#if defined(_WIN32_WCE) || defined(CURL_WINDOWS_APP)
+#ifdef _WIN32_WCE
typedef HANDLE curl_win_thread_handle_t;
#else
typedef uintptr_t curl_win_thread_handle_t;
#endif
curl_thread_t t;
curl_win_thread_handle_t thread_handle;
-#if defined(_WIN32_WCE) || defined(CURL_WINDOWS_APP)
+#ifdef _WIN32_WCE
thread_handle = CreateThread(NULL, 0, func, arg, 0, NULL);
#else
thread_handle = _beginthreadex(NULL, 0, func, arg, 0, NULL);
@@ -138,8 +131,7 @@ curl_thread_t Curl_thread_create(
void Curl_thread_destroy(curl_thread_t hnd)
{
- if(hnd != curl_thread_t_null)
- CloseHandle(hnd);
+ CloseHandle(hnd);
}
int Curl_thread_join(curl_thread_t *hnd)
diff --git a/contrib/libs/curl/lib/curl_threads.h b/contrib/libs/curl/lib/curl_threads.h
index be22352dcb..27a478d4c7 100644
--- a/contrib/libs/curl/lib/curl_threads.h
+++ b/contrib/libs/curl/lib/curl_threads.h
@@ -52,13 +52,8 @@
#if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32)
-curl_thread_t Curl_thread_create(
-#if defined(_WIN32_WCE) || defined(CURL_WINDOWS_APP)
- DWORD
-#else
- unsigned int
-#endif
- (CURL_STDCALL *func) (void *),
+/* !checksrc! disable SPACEBEFOREPAREN 1 */
+curl_thread_t Curl_thread_create(unsigned int (CURL_STDCALL *func) (void *),
void *arg);
void Curl_thread_destroy(curl_thread_t hnd);
diff --git a/contrib/libs/curl/lib/curl_trc.c b/contrib/libs/curl/lib/curl_trc.c
index 58512d74d0..0ebe40b8f7 100644
--- a/contrib/libs/curl/lib/curl_trc.c
+++ b/contrib/libs/curl/lib/curl_trc.c
@@ -36,7 +36,6 @@
#include "cf-socket.h"
#include "connect.h"
-#include "doh.h"
#include "http2.h"
#include "http_proxy.h"
#include "cf-h1-proxy.h"
@@ -53,9 +52,6 @@
#include "curl_memory.h"
#include "memdebug.h"
-#ifndef ARRAYSIZE
-#define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
-#endif
void Curl_debug(struct Curl_easy *data, curl_infotype type,
char *ptr, size_t size)
@@ -114,36 +110,19 @@ void Curl_failf(struct Curl_easy *data, const char *fmt, ...)
/* Curl_infof() is for info message along the way */
#define MAXINFO 2048
-static void trc_infof(struct Curl_easy *data, struct curl_trc_feat *feat,
- const char * const fmt, va_list ap) CURL_PRINTF(3, 0);
-
-static void trc_infof(struct Curl_easy *data, struct curl_trc_feat *feat,
- const char * const fmt, va_list ap)
-{
- int len = 0;
- char buffer[MAXINFO + 5];
- if(feat)
- len = msnprintf(buffer, (MAXINFO + 1), "[%s] ", feat->name);
- len += mvsnprintf(buffer + len, (MAXINFO + 1) - len, fmt, ap);
- if(len >= MAXINFO) { /* too long, shorten with '...' */
- --len;
- buffer[len++] = '.';
- buffer[len++] = '.';
- buffer[len++] = '.';
- }
- buffer[len++] = '\n';
- buffer[len] = '\0';
- Curl_debug(data, CURLINFO_TEXT, buffer, len);
-}
-
void Curl_infof(struct Curl_easy *data, const char *fmt, ...)
{
DEBUGASSERT(!strchr(fmt, '\n'));
- if(Curl_trc_is_verbose(data)) {
+ if(data && data->set.verbose) {
va_list ap;
+ int len;
+ char buffer[MAXINFO + 2];
va_start(ap, fmt);
- trc_infof(data, data->state.feat, fmt, ap);
+ len = mvsnprintf(buffer, MAXINFO, fmt, ap);
va_end(ap);
+ buffer[len++] = '\n';
+ buffer[len] = '\0';
+ Curl_debug(data, CURLINFO_TEXT, buffer, len);
}
}
@@ -153,16 +132,9 @@ void Curl_trc_cf_infof(struct Curl_easy *data, struct Curl_cfilter *cf,
DEBUGASSERT(cf);
if(Curl_trc_cf_is_verbose(cf, data)) {
va_list ap;
- int len = 0;
+ int len;
char buffer[MAXINFO + 2];
- if(data->state.feat)
- len += msnprintf(buffer + len, MAXINFO - len, "[%s] ",
- data->state.feat->name);
- if(cf->sockindex)
- len += msnprintf(buffer + len, MAXINFO - len, "[%s-%d] ",
- cf->cft->name, cf->sockindex);
- else
- len += msnprintf(buffer + len, MAXINFO - len, "[%s] ", cf->cft->name);
+ len = msnprintf(buffer, MAXINFO, "[%s] ", cf->cft->name);
va_start(ap, fmt);
len += mvsnprintf(buffer + len, MAXINFO - len, fmt, ap);
va_end(ap);
@@ -172,193 +144,45 @@ void Curl_trc_cf_infof(struct Curl_easy *data, struct Curl_cfilter *cf,
}
}
-struct curl_trc_feat Curl_trc_feat_read = {
- "READ",
- CURL_LOG_LVL_NONE,
-};
-struct curl_trc_feat Curl_trc_feat_write = {
- "WRITE",
- CURL_LOG_LVL_NONE,
-};
-
-void Curl_trc_read(struct Curl_easy *data, const char *fmt, ...)
-{
- DEBUGASSERT(!strchr(fmt, '\n'));
- if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_read)) {
- va_list ap;
- va_start(ap, fmt);
- trc_infof(data, &Curl_trc_feat_read, fmt, ap);
- va_end(ap);
- }
-}
-
-void Curl_trc_write(struct Curl_easy *data, const char *fmt, ...)
-{
- DEBUGASSERT(!strchr(fmt, '\n'));
- if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_write)) {
- va_list ap;
- va_start(ap, fmt);
- trc_infof(data, &Curl_trc_feat_write, fmt, ap);
- va_end(ap);
- }
-}
-
-#ifndef CURL_DISABLE_FTP
-struct curl_trc_feat Curl_trc_feat_ftp = {
- "FTP",
- CURL_LOG_LVL_NONE,
-};
-
-void Curl_trc_ftp(struct Curl_easy *data, const char *fmt, ...)
-{
- DEBUGASSERT(!strchr(fmt, '\n'));
- if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_ftp)) {
- va_list ap;
- va_start(ap, fmt);
- trc_infof(data, &Curl_trc_feat_ftp, fmt, ap);
- va_end(ap);
- }
-}
-#endif /* !CURL_DISABLE_FTP */
-
-#ifndef CURL_DISABLE_SMTP
-struct curl_trc_feat Curl_trc_feat_smtp = {
- "SMTP",
- CURL_LOG_LVL_NONE,
-};
-
-void Curl_trc_smtp(struct Curl_easy *data, const char *fmt, ...)
-{
- DEBUGASSERT(!strchr(fmt, '\n'));
- if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_smtp)) {
- va_list ap;
- va_start(ap, fmt);
- trc_infof(data, &Curl_trc_feat_smtp, fmt, ap);
- va_end(ap);
- }
-}
-#endif /* !CURL_DISABLE_SMTP */
-
-#if defined(USE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP)
-struct curl_trc_feat Curl_trc_feat_ws = {
- "WS",
- CURL_LOG_LVL_NONE,
-};
-
-void Curl_trc_ws(struct Curl_easy *data, const char *fmt, ...)
-{
- DEBUGASSERT(!strchr(fmt, '\n'));
- if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_ws)) {
- va_list ap;
- va_start(ap, fmt);
- trc_infof(data, &Curl_trc_feat_ws, fmt, ap);
- va_end(ap);
- }
-}
-#endif /* USE_WEBSOCKETS && !CURL_DISABLE_HTTP */
-
-#define TRC_CT_NONE (0)
-#define TRC_CT_PROTOCOL (1<<(0))
-#define TRC_CT_NETWORK (1<<(1))
-#define TRC_CT_PROXY (1<<(2))
-
-struct trc_feat_def {
- struct curl_trc_feat *feat;
- unsigned int category;
-};
-
-static struct trc_feat_def trc_feats[] = {
- { &Curl_trc_feat_read, TRC_CT_NONE },
- { &Curl_trc_feat_write, TRC_CT_NONE },
-#ifndef CURL_DISABLE_FTP
- { &Curl_trc_feat_ftp, TRC_CT_PROTOCOL },
-#endif
-#ifndef CURL_DISABLE_DOH
- { &Curl_doh_trc, TRC_CT_NETWORK },
-#endif
-#ifndef CURL_DISABLE_SMTP
- { &Curl_trc_feat_smtp, TRC_CT_PROTOCOL },
-#endif
-#if defined(USE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP)
- { &Curl_trc_feat_ws, TRC_CT_PROTOCOL },
-#endif
-};
-
-struct trc_cft_def {
- struct Curl_cftype *cft;
- unsigned int category;
-};
-static struct trc_cft_def trc_cfts[] = {
- { &Curl_cft_tcp, TRC_CT_NETWORK },
- { &Curl_cft_udp, TRC_CT_NETWORK },
- { &Curl_cft_unix, TRC_CT_NETWORK },
- { &Curl_cft_tcp_accept, TRC_CT_NETWORK },
- { &Curl_cft_happy_eyeballs, TRC_CT_NETWORK },
- { &Curl_cft_setup, TRC_CT_PROTOCOL },
+static struct Curl_cftype *cf_types[] = {
+ &Curl_cft_tcp,
+ &Curl_cft_udp,
+ &Curl_cft_unix,
+ &Curl_cft_tcp_accept,
+ &Curl_cft_happy_eyeballs,
+ &Curl_cft_setup,
#ifdef USE_NGHTTP2
- { &Curl_cft_nghttp2, TRC_CT_PROTOCOL },
+ &Curl_cft_nghttp2,
#endif
#ifdef USE_SSL
- { &Curl_cft_ssl, TRC_CT_NETWORK },
-#ifndef CURL_DISABLE_PROXY
- { &Curl_cft_ssl_proxy, TRC_CT_PROXY },
-#endif
+ &Curl_cft_ssl,
+ &Curl_cft_ssl_proxy,
#endif
#if !defined(CURL_DISABLE_PROXY)
#if !defined(CURL_DISABLE_HTTP)
- { &Curl_cft_h1_proxy, TRC_CT_PROXY },
+ &Curl_cft_h1_proxy,
#ifdef USE_NGHTTP2
- { &Curl_cft_h2_proxy, TRC_CT_PROXY },
+ &Curl_cft_h2_proxy,
#endif
- { &Curl_cft_http_proxy, TRC_CT_PROXY },
+ &Curl_cft_http_proxy,
#endif /* !CURL_DISABLE_HTTP */
- { &Curl_cft_haproxy, TRC_CT_PROXY },
- { &Curl_cft_socks_proxy, TRC_CT_PROXY },
+ &Curl_cft_haproxy,
+ &Curl_cft_socks_proxy,
#endif /* !CURL_DISABLE_PROXY */
-#ifdef USE_HTTP3
- { &Curl_cft_http3, TRC_CT_PROTOCOL },
+#ifdef ENABLE_QUIC
+ &Curl_cft_http3,
#endif
#if !defined(CURL_DISABLE_HTTP) && !defined(USE_HYPER)
- { &Curl_cft_http_connect, TRC_CT_PROTOCOL },
+ &Curl_cft_http_connect,
#endif
+ NULL,
};
-static void trc_apply_level_by_name(const char * const token, int lvl)
-{
- size_t i;
-
- for(i = 0; i < ARRAYSIZE(trc_cfts); ++i) {
- if(strcasecompare(token, trc_cfts[i].cft->name)) {
- trc_cfts[i].cft->log_level = lvl;
- break;
- }
- }
- for(i = 0; i < ARRAYSIZE(trc_feats); ++i) {
- if(strcasecompare(token, trc_feats[i].feat->name)) {
- trc_feats[i].feat->log_level = lvl;
- break;
- }
- }
-}
-
-static void trc_apply_level_by_category(int category, int lvl)
-{
- size_t i;
-
- for(i = 0; i < ARRAYSIZE(trc_cfts); ++i) {
- if(!category || (trc_cfts[i].category & category))
- trc_cfts[i].cft->log_level = lvl;
- }
- for(i = 0; i < ARRAYSIZE(trc_feats); ++i) {
- if(!category || (trc_feats[i].category & category))
- trc_feats[i].feat->log_level = lvl;
- }
-}
-
-static CURLcode trc_opt(const char *config)
+CURLcode Curl_trc_opt(const char *config)
{
char *token, *tok_buf, *tmp;
+ size_t i;
int lvl;
tmp = strdup(config);
@@ -380,46 +204,33 @@ static CURLcode trc_opt(const char *config)
lvl = CURL_LOG_LVL_INFO;
break;
}
- if(strcasecompare(token, "all"))
- trc_apply_level_by_category(TRC_CT_NONE, lvl);
- else if(strcasecompare(token, "protocol"))
- trc_apply_level_by_category(TRC_CT_PROTOCOL, lvl);
- else if(strcasecompare(token, "network"))
- trc_apply_level_by_category(TRC_CT_NETWORK, lvl);
- else if(strcasecompare(token, "proxy"))
- trc_apply_level_by_category(TRC_CT_PROXY, lvl);
- else
- trc_apply_level_by_name(token, lvl);
-
+ for(i = 0; cf_types[i]; ++i) {
+ if(strcasecompare(token, "all")) {
+ cf_types[i]->log_level = lvl;
+ }
+ else if(strcasecompare(token, cf_types[i]->name)) {
+ cf_types[i]->log_level = lvl;
+ break;
+ }
+ }
token = strtok_r(NULL, ", ", &tok_buf);
}
free(tmp);
return CURLE_OK;
}
-CURLcode Curl_trc_opt(const char *config)
+CURLcode Curl_trc_init(void)
{
- CURLcode result = config? trc_opt(config) : CURLE_OK;
#ifdef DEBUGBUILD
- /* CURL_DEBUG can override anything */
- if(!result) {
- const char *dbg_config = getenv("CURL_DEBUG");
- if(dbg_config)
- result = trc_opt(dbg_config);
+ /* WIP: we use the auto-init from an env var only in DEBUG builds for
+ * convenience. */
+ const char *config = getenv("CURL_DEBUG");
+ if(config) {
+ return Curl_trc_opt(config);
}
#endif /* DEBUGBUILD */
- return result;
-}
-
-CURLcode Curl_trc_init(void)
-{
-#ifdef DEBUGBUILD
- return Curl_trc_opt(NULL);
-#else
return CURLE_OK;
-#endif
}
-
#else /* defined(CURL_DISABLE_VERBOSE_STRINGS) */
CURLcode Curl_trc_init(void)
diff --git a/contrib/libs/curl/lib/curl_trc.h b/contrib/libs/curl/lib/curl_trc.h
index 5f675b453f..ade9108ac7 100644
--- a/contrib/libs/curl/lib/curl_trc.h
+++ b/contrib/libs/curl/lib/curl_trc.h
@@ -58,7 +58,14 @@ void Curl_debug(struct Curl_easy *data, curl_infotype type,
* Output a failure message on registered callbacks for transfer.
*/
void Curl_failf(struct Curl_easy *data,
- const char *fmt, ...) CURL_PRINTF(2, 3);
+#if defined(__GNUC__) && !defined(printf) && \
+ defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \
+ !defined(__MINGW32__)
+ const char *fmt, ...)
+ __attribute__((format(printf, 2, 3)));
+#else
+ const char *fmt, ...);
+#endif
#define failf Curl_failf
@@ -77,111 +84,50 @@ void Curl_failf(struct Curl_easy *data,
#define CURL_TRC_CF(data, cf, ...) \
do { if(Curl_trc_cf_is_verbose(cf, data)) \
Curl_trc_cf_infof(data, cf, __VA_ARGS__); } while(0)
-#define CURL_TRC_WRITE(data, ...) \
- do { if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_write)) \
- Curl_trc_write(data, __VA_ARGS__); } while(0)
-#define CURL_TRC_READ(data, ...) \
- do { if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_read)) \
- Curl_trc_read(data, __VA_ARGS__); } while(0)
-
-#ifndef CURL_DISABLE_FTP
-#define CURL_TRC_FTP(data, ...) \
- do { if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_ftp)) \
- Curl_trc_ftp(data, __VA_ARGS__); } while(0)
-#endif /* !CURL_DISABLE_FTP */
-#ifndef CURL_DISABLE_SMTP
-#define CURL_TRC_SMTP(data, ...) \
- do { if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_smtp)) \
- Curl_trc_smtp(data, __VA_ARGS__); } while(0)
-#endif /* !CURL_DISABLE_SMTP */
-#if defined(USE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP)
-#define CURL_TRC_WS(data, ...) \
- do { if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_ws)) \
- Curl_trc_ws(data, __VA_ARGS__); } while(0)
-#endif /* USE_WEBSOCKETS && !CURL_DISABLE_HTTP */
-
-#else /* CURL_HAVE_C99 */
+#else
#define infof Curl_infof
#define CURL_TRC_CF Curl_trc_cf_infof
-#define CURL_TRC_WRITE Curl_trc_write
-#define CURL_TRC_READ Curl_trc_read
-
-#ifndef CURL_DISABLE_FTP
-#define CURL_TRC_FTP Curl_trc_ftp
-#endif
-#ifndef CURL_DISABLE_SMTP
-#define CURL_TRC_SMTP Curl_trc_smtp
-#endif
-#if defined(USE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP)
-#define CURL_TRC_WS Curl_trc_ws
#endif
-#endif /* !CURL_HAVE_C99 */
-
#ifndef CURL_DISABLE_VERBOSE_STRINGS
/* informational messages enabled */
-struct curl_trc_feat {
- const char *name;
- int log_level;
-};
-extern struct curl_trc_feat Curl_trc_feat_read;
-extern struct curl_trc_feat Curl_trc_feat_write;
-
-#define Curl_trc_is_verbose(data) \
- ((data) && (data)->set.verbose && \
- (!(data)->state.feat || \
- ((data)->state.feat->log_level >= CURL_LOG_LVL_INFO)))
+#define Curl_trc_is_verbose(data) ((data) && (data)->set.verbose)
#define Curl_trc_cf_is_verbose(cf, data) \
- (Curl_trc_is_verbose(data) && \
- (cf) && (cf)->cft->log_level >= CURL_LOG_LVL_INFO)
-#define Curl_trc_ft_is_verbose(data, ft) \
- (Curl_trc_is_verbose(data) && \
- (ft)->log_level >= CURL_LOG_LVL_INFO)
+ ((data) && (data)->set.verbose && \
+ (cf) && (cf)->cft->log_level >= CURL_LOG_LVL_INFO)
/**
* Output an informational message when transfer's verbose logging is enabled.
*/
void Curl_infof(struct Curl_easy *data,
- const char *fmt, ...) CURL_PRINTF(2, 3);
+#if defined(__GNUC__) && !defined(printf) && defined(CURL_HAVE_C99) && \
+ !defined(__MINGW32__)
+ const char *fmt, ...)
+ __attribute__((format(printf, 2, 3)));
+#else
+ const char *fmt, ...);
+#endif
/**
* Output an informational message when both transfer's verbose logging
* and connection filters verbose logging are enabled.
*/
void Curl_trc_cf_infof(struct Curl_easy *data, struct Curl_cfilter *cf,
- const char *fmt, ...) CURL_PRINTF(3, 4);
-void Curl_trc_ft_infof(struct Curl_easy *data, struct curl_trc_feat *ft,
- const char *fmt, ...) CURL_PRINTF(3, 4);
-void Curl_trc_write(struct Curl_easy *data,
- const char *fmt, ...) CURL_PRINTF(2, 3);
-void Curl_trc_read(struct Curl_easy *data,
- const char *fmt, ...) CURL_PRINTF(2, 3);
-
-#ifndef CURL_DISABLE_FTP
-extern struct curl_trc_feat Curl_trc_feat_ftp;
-void Curl_trc_ftp(struct Curl_easy *data,
- const char *fmt, ...) CURL_PRINTF(2, 3);
-#endif
-#ifndef CURL_DISABLE_SMTP
-extern struct curl_trc_feat Curl_trc_feat_smtp;
-void Curl_trc_smtp(struct Curl_easy *data,
- const char *fmt, ...) CURL_PRINTF(2, 3);
-#endif
-#if defined(USE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP)
-extern struct curl_trc_feat Curl_trc_feat_ws;
-void Curl_trc_ws(struct Curl_easy *data,
- const char *fmt, ...) CURL_PRINTF(2, 3);
+#if defined(__GNUC__) && !defined(printf) && defined(CURL_HAVE_C99) && \
+ !defined(__MINGW32__)
+ const char *fmt, ...)
+ __attribute__((format(printf, 3, 4)));
+#else
+ const char *fmt, ...);
#endif
-
#else /* defined(CURL_DISABLE_VERBOSE_STRINGS) */
/* All informational messages are not compiled in for size savings */
-#define Curl_trc_is_verbose(d) (FALSE)
-#define Curl_trc_cf_is_verbose(x,y) (FALSE)
-#define Curl_trc_ft_is_verbose(x,y) (FALSE)
+#define Curl_trc_is_verbose(d) ((void)(d), FALSE)
+#define Curl_trc_cf_is_verbose(x,y) ((void)(x), (void)(y), FALSE)
static void Curl_infof(struct Curl_easy *data, const char *fmt, ...)
{
@@ -195,38 +141,6 @@ static void Curl_trc_cf_infof(struct Curl_easy *data,
(void)data; (void)cf; (void)fmt;
}
-struct curl_trc_feat;
-
-static void Curl_trc_ft_infof(struct Curl_easy *data,
- struct curl_trc_feat *ft,
- const char *fmt, ...)
-{
- (void)data; (void)ft; (void)fmt;
-}
-
-static void Curl_trc_write(struct Curl_easy *data, const char *fmt, ...)
-{
- (void)data; (void)fmt;
-}
-
-static void Curl_trc_read(struct Curl_easy *data, const char *fmt, ...)
-{
- (void)data; (void)fmt;
-}
-
-#ifndef CURL_DISABLE_FTP
-static void Curl_trc_ftp(struct Curl_easy *data, const char *fmt, ...)
-{
- (void)data; (void)fmt;
-}
-#endif
-#ifndef CURL_DISABLE_SMTP
-static void Curl_trc_smtp(struct Curl_easy *data, const char *fmt, ...)
-{
- (void)data; (void)fmt;
-}
-#endif
-
#endif /* !defined(CURL_DISABLE_VERBOSE_STRINGS) */
#endif /* HEADER_CURL_TRC_H */
diff --git a/contrib/libs/curl/lib/curlx.h b/contrib/libs/curl/lib/curlx.h
index 0391d7cd7f..7a753d6824 100644
--- a/contrib/libs/curl/lib/curlx.h
+++ b/contrib/libs/curl/lib/curlx.h
@@ -31,8 +31,10 @@
* be.
*/
-/* map standard printf functions to curl implementations */
-#include "curl_printf.h"
+#include <curl/mprintf.h>
+/* this is still a public header file that provides the curl_mprintf()
+ functions while they still are offered publicly. They will be made library-
+ private one day */
#include "strcase.h"
/* "strcase.h" provides the strcasecompare protos */
@@ -75,4 +77,42 @@
*/
+#define curlx_getenv curl_getenv
+#define curlx_mvsnprintf curl_mvsnprintf
+#define curlx_msnprintf curl_msnprintf
+#define curlx_maprintf curl_maprintf
+#define curlx_mvaprintf curl_mvaprintf
+#define curlx_msprintf curl_msprintf
+#define curlx_mprintf curl_mprintf
+#define curlx_mfprintf curl_mfprintf
+#define curlx_mvsprintf curl_mvsprintf
+#define curlx_mvprintf curl_mvprintf
+#define curlx_mvfprintf curl_mvfprintf
+
+#ifdef ENABLE_CURLX_PRINTF
+/* If this define is set, we define all "standard" printf() functions to use
+ the curlx_* version instead. It makes the source code transparent and
+ easier to understand/patch. Undefine them first. */
+# undef printf
+# undef fprintf
+# undef sprintf
+# undef msnprintf
+# undef vprintf
+# undef vfprintf
+# undef vsprintf
+# undef mvsnprintf
+# undef aprintf
+# undef vaprintf
+
+# define printf curlx_mprintf
+# define fprintf curlx_mfprintf
+# define sprintf curlx_msprintf
+# define msnprintf curlx_msnprintf
+# define vprintf curlx_mvprintf
+# define vfprintf curlx_mvfprintf
+# define mvsnprintf curlx_mvsnprintf
+# define aprintf curlx_maprintf
+# define vaprintf curlx_mvaprintf
+#endif /* ENABLE_CURLX_PRINTF */
+
#endif /* HEADER_CURL_CURLX_H */
diff --git a/contrib/libs/curl/lib/cw-out.c b/contrib/libs/curl/lib/cw-out.c
deleted file mode 100644
index 56ec4162e8..0000000000
--- a/contrib/libs/curl/lib/cw-out.c
+++ /dev/null
@@ -1,474 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at https://curl.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * SPDX-License-Identifier: curl
- *
- ***************************************************************************/
-
-#include "curl_setup.h"
-
-#include <curl/curl.h>
-
-#include "urldata.h"
-#include "cfilters.h"
-#include "headers.h"
-#include "multiif.h"
-#include "sendf.h"
-#include "cw-out.h"
-
-/* The last 3 #include files should be in this order */
-#include "curl_printf.h"
-#include "curl_memory.h"
-#include "memdebug.h"
-
-
-/**
- * OVERALL DESIGN of this client writer
- *
- * The 'cw-out' writer is supposed to be the last writer in a transfer's
- * stack. It is always added when that stack is initialized. Its purpose
- * is to pass BODY and HEADER bytes to the client-installed callback
- * functions.
- *
- * These callback may return `CURL_WRITEFUNC_PAUSE` to indicate that the
- * data had not been written and the whole transfer should stop receiving
- * new data. Or at least, stop calling the functions. When the transfer
- * is "unpaused" by the client, the previous data shall be passed as
- * if nothing happened.
- *
- * The `cw-out` writer therefore manages buffers for bytes that could
- * not be written. Data that was already in flight from the server also
- * needs buffering on paused transfer when it arrives.
- *
- * In addition, the writer allows buffering of "small" body writes,
- * so client functions are called less often. That is only enabled on a
- * number of conditions.
- *
- * HEADER and BODY data may arrive in any order. For paused transfers,
- * a list of `struct cw_out_buf` is kept for `cw_out_type` types. The
- * list may be: [BODY]->[HEADER]->[BODY]->[HEADER]....
- * When unpausing, this list is "played back" to the client callbacks.
- *
- * The amount of bytes being buffered is limited by `DYN_PAUSE_BUFFER`
- * and when that is exceeded `CURLE_TOO_LARGE` is returned as error.
- */
-typedef enum {
- CW_OUT_NONE,
- CW_OUT_BODY,
- CW_OUT_HDS
-} cw_out_type;
-
-struct cw_out_buf {
- struct cw_out_buf *next;
- struct dynbuf b;
- cw_out_type type;
-};
-
-static struct cw_out_buf *cw_out_buf_create(cw_out_type otype)
-{
- struct cw_out_buf *cwbuf = calloc(1, sizeof(*cwbuf));
- if(cwbuf) {
- cwbuf->type = otype;
- Curl_dyn_init(&cwbuf->b, DYN_PAUSE_BUFFER);
- }
- return cwbuf;
-}
-
-static void cw_out_buf_free(struct cw_out_buf *cwbuf)
-{
- if(cwbuf) {
- Curl_dyn_free(&cwbuf->b);
- free(cwbuf);
- }
-}
-
-struct cw_out_ctx {
- struct Curl_cwriter super;
- struct cw_out_buf *buf;
- BIT(paused);
- BIT(errored);
-};
-
-static CURLcode cw_out_write(struct Curl_easy *data,
- struct Curl_cwriter *writer, int type,
- const char *buf, size_t nbytes);
-static void cw_out_close(struct Curl_easy *data, struct Curl_cwriter *writer);
-static CURLcode cw_out_init(struct Curl_easy *data,
- struct Curl_cwriter *writer);
-
-struct Curl_cwtype Curl_cwt_out = {
- "cw-out",
- NULL,
- cw_out_init,
- cw_out_write,
- cw_out_close,
- sizeof(struct cw_out_ctx)
-};
-
-static CURLcode cw_out_init(struct Curl_easy *data,
- struct Curl_cwriter *writer)
-{
- struct cw_out_ctx *ctx = writer->ctx;
- (void)data;
- ctx->buf = NULL;
- return CURLE_OK;
-}
-
-static void cw_out_bufs_free(struct cw_out_ctx *ctx)
-{
- while(ctx->buf) {
- struct cw_out_buf *next = ctx->buf->next;
- cw_out_buf_free(ctx->buf);
- ctx->buf = next;
- }
-}
-
-static size_t cw_out_bufs_len(struct cw_out_ctx *ctx)
-{
- struct cw_out_buf *cwbuf = ctx->buf;
- size_t len = 0;
- while(cwbuf) {
- len += Curl_dyn_len(&cwbuf->b);
- cwbuf = cwbuf->next;
- }
- return len;
-}
-
-static void cw_out_close(struct Curl_easy *data, struct Curl_cwriter *writer)
-{
- struct cw_out_ctx *ctx = writer->ctx;
-
- (void)data;
- cw_out_bufs_free(ctx);
-}
-
-/**
- * Return the current curl_write_callback and user_data for the buf type
- */
-static void cw_get_writefunc(struct Curl_easy *data, cw_out_type otype,
- curl_write_callback *pwcb, void **pwcb_data,
- size_t *pmax_write, size_t *pmin_write)
-{
- switch(otype) {
- case CW_OUT_BODY:
- *pwcb = data->set.fwrite_func;
- *pwcb_data = data->set.out;
- *pmax_write = CURL_MAX_WRITE_SIZE;
- /* if we ever want buffering of BODY output, we can set `min_write`
- * the preferred size. The default should always be to pass data
- * to the client as it comes without delay */
- *pmin_write = 0;
- break;
- case CW_OUT_HDS:
- *pwcb = data->set.fwrite_header? data->set.fwrite_header :
- (data->set.writeheader? data->set.fwrite_func : NULL);
- *pwcb_data = data->set.writeheader;
- *pmax_write = 0; /* do not chunk-write headers, write them as they are */
- *pmin_write = 0;
- break;
- default:
- *pwcb = NULL;
- *pwcb_data = NULL;
- *pmax_write = CURL_MAX_WRITE_SIZE;
- *pmin_write = 0;
- }
-}
-
-static CURLcode cw_out_ptr_flush(struct cw_out_ctx *ctx,
- struct Curl_easy *data,
- cw_out_type otype,
- bool flush_all,
- const char *buf, size_t blen,
- size_t *pconsumed)
-{
- curl_write_callback wcb;
- void *wcb_data;
- size_t max_write, min_write;
- size_t wlen, nwritten;
-
- /* If we errored once, we do not invoke the client callback again */
- if(ctx->errored)
- return CURLE_WRITE_ERROR;
-
- /* write callbacks may get NULLed by the client between calls. */
- cw_get_writefunc(data, otype, &wcb, &wcb_data, &max_write, &min_write);
- if(!wcb) {
- *pconsumed = blen;
- return CURLE_OK;
- }
-
- *pconsumed = 0;
- while(blen && !ctx->paused) {
- if(!flush_all && blen < min_write)
- break;
- wlen = max_write? CURLMIN(blen, max_write) : blen;
- Curl_set_in_callback(data, TRUE);
- nwritten = wcb((char *)buf, 1, wlen, wcb_data);
- Curl_set_in_callback(data, FALSE);
- CURL_TRC_WRITE(data, "cw_out, wrote %zu %s bytes -> %zu",
- wlen, (otype == CW_OUT_BODY)? "body" : "header",
- nwritten);
- if(CURL_WRITEFUNC_PAUSE == nwritten) {
- if(data->conn && data->conn->handler->flags & PROTOPT_NONETWORK) {
- /* Protocols that work without network cannot be paused. This is
- actually only FILE:// just now, and it cannot pause since the
- transfer is not done using the "normal" procedure. */
- failf(data, "Write callback asked for PAUSE when not supported");
- return CURLE_WRITE_ERROR;
- }
- /* mark the connection as RECV paused */
- data->req.keepon |= KEEP_RECV_PAUSE;
- ctx->paused = TRUE;
- CURL_TRC_WRITE(data, "cw_out, PAUSE requested by client");
- break;
- }
- else if(CURL_WRITEFUNC_ERROR == nwritten) {
- failf(data, "client returned ERROR on write of %zu bytes", wlen);
- return CURLE_WRITE_ERROR;
- }
- else if(nwritten != wlen) {
- failf(data, "Failure writing output to destination, "
- "passed %zu returned %zd", wlen, nwritten);
- return CURLE_WRITE_ERROR;
- }
- *pconsumed += nwritten;
- blen -= nwritten;
- buf += nwritten;
- }
- return CURLE_OK;
-}
-
-static CURLcode cw_out_buf_flush(struct cw_out_ctx *ctx,
- struct Curl_easy *data,
- struct cw_out_buf *cwbuf,
- bool flush_all)
-{
- CURLcode result = CURLE_OK;
-
- if(Curl_dyn_len(&cwbuf->b)) {
- size_t consumed;
-
- result = cw_out_ptr_flush(ctx, data, cwbuf->type, flush_all,
- Curl_dyn_ptr(&cwbuf->b),
- Curl_dyn_len(&cwbuf->b),
- &consumed);
- if(result)
- return result;
-
- if(consumed) {
- if(consumed == Curl_dyn_len(&cwbuf->b)) {
- Curl_dyn_free(&cwbuf->b);
- }
- else {
- DEBUGASSERT(consumed < Curl_dyn_len(&cwbuf->b));
- result = Curl_dyn_tail(&cwbuf->b, Curl_dyn_len(&cwbuf->b) - consumed);
- if(result)
- return result;
- }
- }
- }
- return result;
-}
-
-static CURLcode cw_out_flush_chain(struct cw_out_ctx *ctx,
- struct Curl_easy *data,
- struct cw_out_buf **pcwbuf,
- bool flush_all)
-{
- struct cw_out_buf *cwbuf = *pcwbuf;
- CURLcode result;
-
- if(!cwbuf)
- return CURLE_OK;
- if(ctx->paused)
- return CURLE_OK;
-
- /* write the end of the chain until it blocks or gets empty */
- while(cwbuf->next) {
- struct cw_out_buf **plast = &cwbuf->next;
- while((*plast)->next)
- plast = &(*plast)->next;
- result = cw_out_flush_chain(ctx, data, plast, flush_all);
- if(result)
- return result;
- if(*plast) {
- /* could not write last, paused again? */
- DEBUGASSERT(ctx->paused);
- return CURLE_OK;
- }
- }
-
- result = cw_out_buf_flush(ctx, data, cwbuf, flush_all);
- if(result)
- return result;
- if(!Curl_dyn_len(&cwbuf->b)) {
- cw_out_buf_free(cwbuf);
- *pcwbuf = NULL;
- }
- return CURLE_OK;
-}
-
-static CURLcode cw_out_append(struct cw_out_ctx *ctx,
- cw_out_type otype,
- const char *buf, size_t blen)
-{
- if(cw_out_bufs_len(ctx) + blen > DYN_PAUSE_BUFFER)
- return CURLE_TOO_LARGE;
-
- /* if we do not have a buffer, or it is of another type, make a new one.
- * And for CW_OUT_HDS always make a new one, so we "replay" headers
- * exactly as they came in */
- if(!ctx->buf || (ctx->buf->type != otype) || (otype == CW_OUT_HDS)) {
- struct cw_out_buf *cwbuf = cw_out_buf_create(otype);
- if(!cwbuf)
- return CURLE_OUT_OF_MEMORY;
- cwbuf->next = ctx->buf;
- ctx->buf = cwbuf;
- }
- DEBUGASSERT(ctx->buf && (ctx->buf->type == otype));
- return Curl_dyn_addn(&ctx->buf->b, buf, blen);
-}
-
-static CURLcode cw_out_do_write(struct cw_out_ctx *ctx,
- struct Curl_easy *data,
- cw_out_type otype,
- bool flush_all,
- const char *buf, size_t blen)
-{
- CURLcode result = CURLE_OK;
-
- /* if we have buffered data and it is a different type than what
- * we are writing now, try to flush all */
- if(ctx->buf && ctx->buf->type != otype) {
- result = cw_out_flush_chain(ctx, data, &ctx->buf, TRUE);
- if(result)
- goto out;
- }
-
- if(ctx->buf) {
- /* still have buffered data, append and flush */
- result = cw_out_append(ctx, otype, buf, blen);
- if(result)
- return result;
- result = cw_out_flush_chain(ctx, data, &ctx->buf, flush_all);
- if(result)
- goto out;
- }
- else {
- /* nothing buffered, try direct write */
- size_t consumed;
- result = cw_out_ptr_flush(ctx, data, otype, flush_all,
- buf, blen, &consumed);
- if(result)
- return result;
- if(consumed < blen) {
- /* did not write all, append the rest */
- result = cw_out_append(ctx, otype, buf + consumed, blen - consumed);
- if(result)
- goto out;
- }
- }
-
-out:
- if(result) {
- /* We do not want to invoked client callbacks a second time after
- * encountering an error. See issue #13337 */
- ctx->errored = TRUE;
- cw_out_bufs_free(ctx);
- }
- return result;
-}
-
-static CURLcode cw_out_write(struct Curl_easy *data,
- struct Curl_cwriter *writer, int type,
- const char *buf, size_t blen)
-{
- struct cw_out_ctx *ctx = writer->ctx;
- CURLcode result;
- bool flush_all;
-
- flush_all = (type & CLIENTWRITE_EOS)? TRUE:FALSE;
- if((type & CLIENTWRITE_BODY) ||
- ((type & CLIENTWRITE_HEADER) && data->set.include_header)) {
- result = cw_out_do_write(ctx, data, CW_OUT_BODY, flush_all, buf, blen);
- if(result)
- return result;
- }
-
- if(type & (CLIENTWRITE_HEADER|CLIENTWRITE_INFO)) {
- result = cw_out_do_write(ctx, data, CW_OUT_HDS, flush_all, buf, blen);
- if(result)
- return result;
- }
-
- return CURLE_OK;
-}
-
-bool Curl_cw_out_is_paused(struct Curl_easy *data)
-{
- struct Curl_cwriter *cw_out;
- struct cw_out_ctx *ctx;
-
- cw_out = Curl_cwriter_get_by_type(data, &Curl_cwt_out);
- if(!cw_out)
- return FALSE;
-
- ctx = (struct cw_out_ctx *)cw_out;
- CURL_TRC_WRITE(data, "cw-out is%spaused", ctx->paused? "" : " not");
- return ctx->paused;
-}
-
-static CURLcode cw_out_flush(struct Curl_easy *data,
- bool unpause, bool flush_all)
-{
- struct Curl_cwriter *cw_out;
- CURLcode result = CURLE_OK;
-
- cw_out = Curl_cwriter_get_by_type(data, &Curl_cwt_out);
- if(cw_out) {
- struct cw_out_ctx *ctx = (struct cw_out_ctx *)cw_out;
- if(ctx->errored)
- return CURLE_WRITE_ERROR;
- if(unpause && ctx->paused)
- ctx->paused = FALSE;
- if(ctx->paused)
- return CURLE_OK; /* not doing it */
-
- result = cw_out_flush_chain(ctx, data, &ctx->buf, flush_all);
- if(result) {
- ctx->errored = TRUE;
- cw_out_bufs_free(ctx);
- return result;
- }
- }
- return result;
-}
-
-CURLcode Curl_cw_out_unpause(struct Curl_easy *data)
-{
- CURL_TRC_WRITE(data, "cw-out unpause");
- return cw_out_flush(data, TRUE, FALSE);
-}
-
-CURLcode Curl_cw_out_done(struct Curl_easy *data)
-{
- CURL_TRC_WRITE(data, "cw-out done");
- return cw_out_flush(data, FALSE, TRUE);
-}
diff --git a/contrib/libs/curl/lib/dict.c b/contrib/libs/curl/lib/dict.c
index 7d9c18dc9d..3172b38290 100644
--- a/contrib/libs/curl/lib/dict.c
+++ b/contrib/libs/curl/lib/dict.c
@@ -76,7 +76,7 @@ static CURLcode dict_do(struct Curl_easy *data, bool *done);
*/
const struct Curl_handler Curl_handler_dict = {
- "dict", /* scheme */
+ "DICT", /* scheme */
ZERO_NULL, /* setup_connection */
dict_do, /* do_it */
ZERO_NULL, /* done */
@@ -89,8 +89,7 @@ const struct Curl_handler Curl_handler_dict = {
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
ZERO_NULL, /* disconnect */
- ZERO_NULL, /* write_resp */
- ZERO_NULL, /* write_resp_hd */
+ ZERO_NULL, /* readwrite */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_DICT, /* defport */
@@ -123,12 +122,10 @@ static char *unescape_word(const char *input)
}
/* sendf() sends formatted data to the server */
-static CURLcode sendf(struct Curl_easy *data,
- const char *fmt, ...) CURL_PRINTF(2, 3);
-
-static CURLcode sendf(struct Curl_easy *data, const char *fmt, ...)
+static CURLcode sendf(curl_socket_t sockfd, struct Curl_easy *data,
+ const char *fmt, ...)
{
- size_t bytes_written;
+ ssize_t bytes_written;
size_t write_len;
CURLcode result = CURLE_OK;
char *s;
@@ -146,7 +143,7 @@ static CURLcode sendf(struct Curl_easy *data, const char *fmt, ...)
for(;;) {
/* Write the buffer to the socket */
- result = Curl_xfer_send(data, sptr, write_len, FALSE, &bytes_written);
+ result = Curl_write(data, sockfd, sptr, write_len, &bytes_written);
if(result)
break;
@@ -178,6 +175,8 @@ static CURLcode dict_do(struct Curl_easy *data, bool *done)
char *nthdef = NULL; /* This is not part of the protocol, but required
by RFC 2229 */
CURLcode result;
+ struct connectdata *conn = data->conn;
+ curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
char *path;
@@ -226,7 +225,7 @@ static CURLcode dict_do(struct Curl_easy *data, bool *done)
goto error;
}
- result = sendf(data,
+ result = sendf(sockfd, data,
"CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\r\n"
"MATCH "
"%s " /* database */
@@ -241,7 +240,7 @@ static CURLcode dict_do(struct Curl_easy *data, bool *done)
failf(data, "Failed sending DICT request");
goto error;
}
- Curl_xfer_setup1(data, CURL_XFER_RECV, -1, FALSE); /* no upload */
+ Curl_setup_transfer(data, FIRSTSOCKET, -1, FALSE, -1); /* no upload */
}
else if(strncasecompare(path, DICT_DEFINE, sizeof(DICT_DEFINE)-1) ||
strncasecompare(path, DICT_DEFINE2, sizeof(DICT_DEFINE2)-1) ||
@@ -274,7 +273,7 @@ static CURLcode dict_do(struct Curl_easy *data, bool *done)
goto error;
}
- result = sendf(data,
+ result = sendf(sockfd, data,
"CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\r\n"
"DEFINE "
"%s " /* database */
@@ -287,7 +286,7 @@ static CURLcode dict_do(struct Curl_easy *data, bool *done)
failf(data, "Failed sending DICT request");
goto error;
}
- Curl_xfer_setup1(data, CURL_XFER_RECV, -1, FALSE);
+ Curl_setup_transfer(data, FIRSTSOCKET, -1, FALSE, -1);
}
else {
@@ -300,7 +299,7 @@ static CURLcode dict_do(struct Curl_easy *data, bool *done)
if(ppath[i] == ':')
ppath[i] = ' ';
}
- result = sendf(data,
+ result = sendf(sockfd, data,
"CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\r\n"
"%s\r\n"
"QUIT\r\n", ppath);
@@ -309,7 +308,7 @@ static CURLcode dict_do(struct Curl_easy *data, bool *done)
goto error;
}
- Curl_xfer_setup1(data, CURL_XFER_RECV, -1, FALSE);
+ Curl_setup_transfer(data, FIRSTSOCKET, -1, FALSE, -1);
}
}
diff --git a/contrib/libs/curl/lib/dllmain.c b/contrib/libs/curl/lib/dllmain.c
deleted file mode 100644
index 41e97b37eb..0000000000
--- a/contrib/libs/curl/lib/dllmain.c
+++ /dev/null
@@ -1,81 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at https://curl.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * SPDX-License-Identifier: curl
- *
- ***************************************************************************/
-
-#include "curl_setup.h"
-
-#ifdef USE_OPENSSL
-#include <openssl/crypto.h>
-#endif
-
-/* The fourth-to-last include */
-#ifdef __CYGWIN__
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-#ifdef _WIN32
-#undef _WIN32
-#endif
-#endif
-
-/* The last 3 #include files should be in this order */
-#include "curl_printf.h"
-#include "curl_memory.h"
-#include "memdebug.h"
-
-/* DllMain() must only be defined for Windows and Cygwin DLL builds. */
-#if (defined(_WIN32) || defined(__CYGWIN__)) && !defined(CURL_STATICLIB)
-
-#if defined(USE_OPENSSL) && \
- !defined(OPENSSL_IS_AWSLC) && \
- !defined(OPENSSL_IS_BORINGSSL) && \
- !defined(LIBRESSL_VERSION_NUMBER) && \
- (OPENSSL_VERSION_NUMBER >= 0x10100000L)
-#define PREVENT_OPENSSL_MEMLEAK
-#endif
-
-#ifdef PREVENT_OPENSSL_MEMLEAK
-BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved);
-BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
-{
- (void)hinstDLL;
- (void)lpvReserved;
-
- switch(fdwReason) {
- case DLL_PROCESS_ATTACH:
- break;
- case DLL_PROCESS_DETACH:
- break;
- case DLL_THREAD_ATTACH:
- break;
- case DLL_THREAD_DETACH:
- /* Call OPENSSL_thread_stop to prevent a memory leak in case OpenSSL is
- linked statically.
- https://github.com/curl/curl/issues/12327#issuecomment-1826405944 */
- OPENSSL_thread_stop();
- break;
- }
- return TRUE;
-}
-#endif /* OpenSSL */
-
-#endif /* DLL build */
diff --git a/contrib/libs/curl/lib/doh.c b/contrib/libs/curl/lib/doh.c
index 52b3574589..1d928e92c7 100644
--- a/contrib/libs/curl/lib/doh.c
+++ b/contrib/libs/curl/lib/doh.c
@@ -42,13 +42,9 @@
#include "curl_printf.h"
#include "curl_memory.h"
#include "memdebug.h"
-#include "escape.h"
#define DNS_CLASS_IN 0x01
-/* doh_print_buf truncates if the hex string will be more than this */
-#define LOCAL_PB_HEXMAX 400
-
#ifndef CURL_DISABLE_VERBOSE_STRINGS
static const char * const errors[]={
"",
@@ -73,41 +69,36 @@ static const char *doh_strerror(DOHcode code)
return errors[code];
return "bad error code";
}
-
-struct curl_trc_feat Curl_doh_trc = {
- "DoH",
- CURL_LOG_LVL_NONE,
-};
-#endif /* !CURL_DISABLE_VERBOSE_STRINGS */
+#endif
/* @unittest 1655
*/
-UNITTEST DOHcode doh_req_encode(const char *host,
- DNStype dnstype,
- unsigned char *dnsp, /* buffer */
- size_t len, /* buffer size */
- size_t *olen) /* output length */
+UNITTEST DOHcode doh_encode(const char *host,
+ DNStype dnstype,
+ unsigned char *dnsp, /* buffer */
+ size_t len, /* buffer size */
+ size_t *olen) /* output length */
{
const size_t hostlen = strlen(host);
unsigned char *orig = dnsp;
const char *hostp = host;
/* The expected output length is 16 bytes more than the length of
- * the QNAME-encoding of the hostname.
+ * the QNAME-encoding of the host name.
*
* A valid DNS name may not contain a zero-length label, except at
- * the end. For this reason, a name beginning with a dot, or
+ * the end. For this reason, a name beginning with a dot, or
* containing a sequence of two or more consecutive dots, is invalid
* and cannot be encoded as a QNAME.
*
- * If the hostname ends with a trailing dot, the corresponding
- * QNAME-encoding is one byte longer than the hostname. If (as is
+ * If the host name ends with a trailing dot, the corresponding
+ * QNAME-encoding is one byte longer than the host name. If (as is
* also valid) the hostname is shortened by the omission of the
* trailing dot, then its QNAME-encoding will be two bytes longer
- * than the hostname.
+ * than the host name.
*
* Each [ label, dot ] pair is encoded as [ length, label ],
- * preserving overall length. A final [ label ] without a dot is
+ * preserving overall length. A final [ label ] without a dot is
* also encoded as [ length, label ], increasing overall length
* by one. The encoding is completed by appending a zero byte,
* representing the zero-length root label, again increasing
@@ -191,49 +182,22 @@ doh_write_cb(const void *contents, size_t size, size_t nmemb, void *userp)
return realsize;
}
-#if defined(USE_HTTPSRR) && defined(DEBUGBUILD)
-static void doh_print_buf(struct Curl_easy *data,
- const char *prefix,
- unsigned char *buf, size_t len)
-{
- unsigned char hexstr[LOCAL_PB_HEXMAX];
- size_t hlen = LOCAL_PB_HEXMAX;
- bool truncated = false;
-
- if(len > (LOCAL_PB_HEXMAX / 2))
- truncated = true;
- Curl_hexencode(buf, len, hexstr, hlen);
- if(!truncated)
- infof(data, "%s: len=%d, val=%s", prefix, (int)len, hexstr);
- else
- infof(data, "%s: len=%d (truncated)val=%s", prefix, (int)len, hexstr);
- return;
-}
-#endif
-
/* called from multi.c when this DoH transfer is complete */
static int doh_done(struct Curl_easy *doh, CURLcode result)
{
- struct Curl_easy *data; /* the transfer that asked for the DoH probe */
-
- data = Curl_multi_get_handle(doh->multi, doh->set.dohfor_mid);
- if(!data) {
- DEBUGF(infof(doh, "doh_done: xfer for mid=%" FMT_OFF_T
- " not found", doh->set.dohfor_mid));
- DEBUGASSERT(0);
- }
- else {
- struct doh_probes *dohp = data->req.doh;
- /* one of the DoH request done for the 'data' transfer is now complete! */
- dohp->pending--;
- infof(doh, "a DoH request is completed, %u to go", dohp->pending);
- if(result)
- infof(doh, "DoH request %s", curl_easy_strerror(result));
+ struct Curl_easy *data = doh->set.dohfor;
+ struct dohdata *dohp = data->req.doh;
+ /* so one of the DoH request done for the 'data' transfer is now complete! */
+ dohp->pending--;
+ infof(data, "a DoH request is completed, %u to go", dohp->pending);
+ if(result)
+ infof(data, "DoH request %s", curl_easy_strerror(result));
- if(!dohp->pending) {
- /* DoH completed, run the transfer picking up the results */
- Curl_expire(data, 0, EXPIRE_RUN_NOW);
- }
+ if(!dohp->pending) {
+ /* DoH completed */
+ curl_slist_free_all(dohp->headers);
+ dohp->headers = NULL;
+ Curl_expire(data, 0, EXPIRE_RUN_NOW);
}
return 0;
}
@@ -247,24 +211,25 @@ do { \
goto error; \
} while(0)
-static CURLcode doh_run_probe(struct Curl_easy *data,
- struct doh_probe *p, DNStype dnstype,
- const char *host,
- const char *url, CURLM *multi,
- struct curl_slist *headers)
+static CURLcode dohprobe(struct Curl_easy *data,
+ struct dnsprobe *p, DNStype dnstype,
+ const char *host,
+ const char *url, CURLM *multi,
+ struct curl_slist *headers)
{
struct Curl_easy *doh = NULL;
+ char *nurl = NULL;
CURLcode result = CURLE_OK;
timediff_t timeout_ms;
- DOHcode d = doh_req_encode(host, dnstype, p->req_body, sizeof(p->req_body),
- &p->req_body_len);
+ DOHcode d = doh_encode(host, dnstype, p->dohbuffer, sizeof(p->dohbuffer),
+ &p->dohlen);
if(d) {
failf(data, "Failed to encode DoH packet [%d]", d);
return CURLE_OUT_OF_MEMORY;
}
p->dnstype = dnstype;
- Curl_dyn_init(&p->resp_body, DYN_DOH_RESPONSE);
+ Curl_dyn_init(&p->serverdoh, DYN_DOH_RESPONSE);
timeout_ms = Curl_timeleft(data, NULL, TRUE);
if(timeout_ms <= 0) {
@@ -273,126 +238,125 @@ static CURLcode doh_run_probe(struct Curl_easy *data,
}
/* Curl_open() is the internal version of curl_easy_init() */
result = Curl_open(&doh);
- if(result)
- goto error;
-
- /* pass in the struct pointer via a local variable to please coverity and
- the gcc typecheck helpers */
- doh->state.internal = true;
-#ifndef CURL_DISABLE_VERBOSE_STRINGS
- doh->state.feat = &Curl_doh_trc;
-#endif
- ERROR_CHECK_SETOPT(CURLOPT_URL, url);
- ERROR_CHECK_SETOPT(CURLOPT_DEFAULT_PROTOCOL, "https");
- ERROR_CHECK_SETOPT(CURLOPT_WRITEFUNCTION, doh_write_cb);
- ERROR_CHECK_SETOPT(CURLOPT_WRITEDATA, &p->resp_body);
- ERROR_CHECK_SETOPT(CURLOPT_POSTFIELDS, p->req_body);
- ERROR_CHECK_SETOPT(CURLOPT_POSTFIELDSIZE, (long)p->req_body_len);
- ERROR_CHECK_SETOPT(CURLOPT_HTTPHEADER, headers);
+ if(!result) {
+ /* pass in the struct pointer via a local variable to please coverity and
+ the gcc typecheck helpers */
+ struct dynbuf *resp = &p->serverdoh;
+ doh->state.internal = true;
+ ERROR_CHECK_SETOPT(CURLOPT_URL, url);
+ ERROR_CHECK_SETOPT(CURLOPT_DEFAULT_PROTOCOL, "https");
+ ERROR_CHECK_SETOPT(CURLOPT_WRITEFUNCTION, doh_write_cb);
+ ERROR_CHECK_SETOPT(CURLOPT_WRITEDATA, resp);
+ ERROR_CHECK_SETOPT(CURLOPT_POSTFIELDS, p->dohbuffer);
+ ERROR_CHECK_SETOPT(CURLOPT_POSTFIELDSIZE, (long)p->dohlen);
+ ERROR_CHECK_SETOPT(CURLOPT_HTTPHEADER, headers);
#ifdef USE_HTTP2
- ERROR_CHECK_SETOPT(CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2TLS);
- ERROR_CHECK_SETOPT(CURLOPT_PIPEWAIT, 1L);
+ ERROR_CHECK_SETOPT(CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2TLS);
+ ERROR_CHECK_SETOPT(CURLOPT_PIPEWAIT, 1L);
#endif
-#ifndef DEBUGBUILD
- /* enforce HTTPS if not debug */
- ERROR_CHECK_SETOPT(CURLOPT_PROTOCOLS, CURLPROTO_HTTPS);
+#ifndef CURLDEBUG
+ /* enforce HTTPS if not debug */
+ ERROR_CHECK_SETOPT(CURLOPT_PROTOCOLS, CURLPROTO_HTTPS);
#else
- /* in debug mode, also allow http */
- ERROR_CHECK_SETOPT(CURLOPT_PROTOCOLS, CURLPROTO_HTTP|CURLPROTO_HTTPS);
+ /* in debug mode, also allow http */
+ ERROR_CHECK_SETOPT(CURLOPT_PROTOCOLS, CURLPROTO_HTTP|CURLPROTO_HTTPS);
#endif
- ERROR_CHECK_SETOPT(CURLOPT_TIMEOUT_MS, (long)timeout_ms);
- ERROR_CHECK_SETOPT(CURLOPT_SHARE, data->share);
- if(data->set.err && data->set.err != stderr)
- ERROR_CHECK_SETOPT(CURLOPT_STDERR, data->set.err);
- if(Curl_trc_ft_is_verbose(data, &Curl_doh_trc))
- ERROR_CHECK_SETOPT(CURLOPT_VERBOSE, 1L);
- if(data->set.no_signal)
- ERROR_CHECK_SETOPT(CURLOPT_NOSIGNAL, 1L);
-
- ERROR_CHECK_SETOPT(CURLOPT_SSL_VERIFYHOST,
- data->set.doh_verifyhost ? 2L : 0L);
- ERROR_CHECK_SETOPT(CURLOPT_SSL_VERIFYPEER,
- data->set.doh_verifypeer ? 1L : 0L);
- ERROR_CHECK_SETOPT(CURLOPT_SSL_VERIFYSTATUS,
- data->set.doh_verifystatus ? 1L : 0L);
-
- /* Inherit *some* SSL options from the user's transfer. This is a
- best-guess as to which options are needed for compatibility. #3661
-
- Note DoH does not inherit the user's proxy server so proxy SSL settings
- have no effect and are not inherited. If that changes then two new
- options should be added to check doh proxy insecure separately,
- CURLOPT_DOH_PROXY_SSL_VERIFYHOST and CURLOPT_DOH_PROXY_SSL_VERIFYPEER.
- */
- if(data->set.ssl.falsestart)
- ERROR_CHECK_SETOPT(CURLOPT_SSL_FALSESTART, 1L);
- if(data->set.str[STRING_SSL_CAFILE]) {
- ERROR_CHECK_SETOPT(CURLOPT_CAINFO,
- data->set.str[STRING_SSL_CAFILE]);
- }
- if(data->set.blobs[BLOB_CAINFO]) {
- ERROR_CHECK_SETOPT(CURLOPT_CAINFO_BLOB,
- data->set.blobs[BLOB_CAINFO]);
- }
- if(data->set.str[STRING_SSL_CAPATH]) {
- ERROR_CHECK_SETOPT(CURLOPT_CAPATH,
- data->set.str[STRING_SSL_CAPATH]);
- }
- if(data->set.str[STRING_SSL_CRLFILE]) {
- ERROR_CHECK_SETOPT(CURLOPT_CRLFILE,
- data->set.str[STRING_SSL_CRLFILE]);
- }
- if(data->set.ssl.certinfo)
- ERROR_CHECK_SETOPT(CURLOPT_CERTINFO, 1L);
- if(data->set.ssl.fsslctx)
- ERROR_CHECK_SETOPT(CURLOPT_SSL_CTX_FUNCTION, data->set.ssl.fsslctx);
- if(data->set.ssl.fsslctxp)
- ERROR_CHECK_SETOPT(CURLOPT_SSL_CTX_DATA, data->set.ssl.fsslctxp);
- if(data->set.fdebug)
- ERROR_CHECK_SETOPT(CURLOPT_DEBUGFUNCTION, data->set.fdebug);
- if(data->set.debugdata)
- ERROR_CHECK_SETOPT(CURLOPT_DEBUGDATA, data->set.debugdata);
- if(data->set.str[STRING_SSL_EC_CURVES]) {
- ERROR_CHECK_SETOPT(CURLOPT_SSL_EC_CURVES,
- data->set.str[STRING_SSL_EC_CURVES]);
- }
+ ERROR_CHECK_SETOPT(CURLOPT_TIMEOUT_MS, (long)timeout_ms);
+ ERROR_CHECK_SETOPT(CURLOPT_SHARE, data->share);
+ if(data->set.err && data->set.err != stderr)
+ ERROR_CHECK_SETOPT(CURLOPT_STDERR, data->set.err);
+ if(data->set.verbose)
+ ERROR_CHECK_SETOPT(CURLOPT_VERBOSE, 1L);
+ if(data->set.no_signal)
+ ERROR_CHECK_SETOPT(CURLOPT_NOSIGNAL, 1L);
+
+ ERROR_CHECK_SETOPT(CURLOPT_SSL_VERIFYHOST,
+ data->set.doh_verifyhost ? 2L : 0L);
+ ERROR_CHECK_SETOPT(CURLOPT_SSL_VERIFYPEER,
+ data->set.doh_verifypeer ? 1L : 0L);
+ ERROR_CHECK_SETOPT(CURLOPT_SSL_VERIFYSTATUS,
+ data->set.doh_verifystatus ? 1L : 0L);
+
+ /* Inherit *some* SSL options from the user's transfer. This is a
+ best-guess as to which options are needed for compatibility. #3661
+
+ Note DoH does not inherit the user's proxy server so proxy SSL settings
+ have no effect and are not inherited. If that changes then two new
+ options should be added to check doh proxy insecure separately,
+ CURLOPT_DOH_PROXY_SSL_VERIFYHOST and CURLOPT_DOH_PROXY_SSL_VERIFYPEER.
+ */
+ if(data->set.ssl.falsestart)
+ ERROR_CHECK_SETOPT(CURLOPT_SSL_FALSESTART, 1L);
+ if(data->set.str[STRING_SSL_CAFILE]) {
+ ERROR_CHECK_SETOPT(CURLOPT_CAINFO,
+ data->set.str[STRING_SSL_CAFILE]);
+ }
+ if(data->set.blobs[BLOB_CAINFO]) {
+ ERROR_CHECK_SETOPT(CURLOPT_CAINFO_BLOB,
+ data->set.blobs[BLOB_CAINFO]);
+ }
+ if(data->set.str[STRING_SSL_CAPATH]) {
+ ERROR_CHECK_SETOPT(CURLOPT_CAPATH,
+ data->set.str[STRING_SSL_CAPATH]);
+ }
+ if(data->set.str[STRING_SSL_CRLFILE]) {
+ ERROR_CHECK_SETOPT(CURLOPT_CRLFILE,
+ data->set.str[STRING_SSL_CRLFILE]);
+ }
+ if(data->set.ssl.certinfo)
+ ERROR_CHECK_SETOPT(CURLOPT_CERTINFO, 1L);
+ if(data->set.ssl.fsslctx)
+ ERROR_CHECK_SETOPT(CURLOPT_SSL_CTX_FUNCTION, data->set.ssl.fsslctx);
+ if(data->set.ssl.fsslctxp)
+ ERROR_CHECK_SETOPT(CURLOPT_SSL_CTX_DATA, data->set.ssl.fsslctxp);
+ if(data->set.fdebug)
+ ERROR_CHECK_SETOPT(CURLOPT_DEBUGFUNCTION, data->set.fdebug);
+ if(data->set.debugdata)
+ ERROR_CHECK_SETOPT(CURLOPT_DEBUGDATA, data->set.debugdata);
+ if(data->set.str[STRING_SSL_EC_CURVES]) {
+ ERROR_CHECK_SETOPT(CURLOPT_SSL_EC_CURVES,
+ data->set.str[STRING_SSL_EC_CURVES]);
+ }
- {
- long mask =
- (data->set.ssl.enable_beast ?
- CURLSSLOPT_ALLOW_BEAST : 0) |
- (data->set.ssl.no_revoke ?
- CURLSSLOPT_NO_REVOKE : 0) |
- (data->set.ssl.no_partialchain ?
- CURLSSLOPT_NO_PARTIALCHAIN : 0) |
- (data->set.ssl.revoke_best_effort ?
- CURLSSLOPT_REVOKE_BEST_EFFORT : 0) |
- (data->set.ssl.native_ca_store ?
- CURLSSLOPT_NATIVE_CA : 0) |
- (data->set.ssl.auto_client_cert ?
- CURLSSLOPT_AUTO_CLIENT_CERT : 0);
-
- (void)curl_easy_setopt(doh, CURLOPT_SSL_OPTIONS, mask);
- }
+ {
+ long mask =
+ (data->set.ssl.enable_beast ?
+ CURLSSLOPT_ALLOW_BEAST : 0) |
+ (data->set.ssl.no_revoke ?
+ CURLSSLOPT_NO_REVOKE : 0) |
+ (data->set.ssl.no_partialchain ?
+ CURLSSLOPT_NO_PARTIALCHAIN : 0) |
+ (data->set.ssl.revoke_best_effort ?
+ CURLSSLOPT_REVOKE_BEST_EFFORT : 0) |
+ (data->set.ssl.native_ca_store ?
+ CURLSSLOPT_NATIVE_CA : 0) |
+ (data->set.ssl.auto_client_cert ?
+ CURLSSLOPT_AUTO_CLIENT_CERT : 0);
+
+ (void)curl_easy_setopt(doh, CURLOPT_SSL_OPTIONS, mask);
+ }
- doh->set.fmultidone = doh_done;
- doh->set.dohfor_mid = data->mid; /* for which transfer this is done */
+ doh->set.fmultidone = doh_done;
+ doh->set.dohfor = data; /* identify for which transfer this is done */
+ p->easy = doh;
- /* DoH handles must not inherit private_data. The handles may be passed to
- the user via callbacks and the user will be able to identify them as
- internal handles because private data is not set. The user can then set
- private_data via CURLOPT_PRIVATE if they so choose. */
- DEBUGASSERT(!doh->set.private_data);
+ /* DoH handles must not inherit private_data. The handles may be passed to
+ the user via callbacks and the user will be able to identify them as
+ internal handles because private data is not set. The user can then set
+ private_data via CURLOPT_PRIVATE if they so choose. */
+ DEBUGASSERT(!doh->set.private_data);
- if(curl_multi_add_handle(multi, doh))
+ if(curl_multi_add_handle(multi, doh))
+ goto error;
+ }
+ else
goto error;
-
- p->easy_mid = doh->mid;
+ free(nurl);
return CURLE_OK;
error:
+ free(nurl);
Curl_close(&doh);
- p->easy_mid = -1;
return result;
}
@@ -407,15 +371,9 @@ struct Curl_addrinfo *Curl_doh(struct Curl_easy *data,
int *waitp)
{
CURLcode result = CURLE_OK;
- struct doh_probes *dohp;
+ int slot;
+ struct dohdata *dohp;
struct connectdata *conn = data->conn;
- size_t i;
-#ifdef USE_HTTPSRR
- /* for now, this is only used when ECH is enabled */
-# ifdef USE_ECH
- char *qname = NULL;
-# endif
-#endif
*waitp = FALSE;
(void)hostname;
(void)port;
@@ -424,83 +382,54 @@ struct Curl_addrinfo *Curl_doh(struct Curl_easy *data,
DEBUGASSERT(conn);
/* start clean, consider allocating this struct on demand */
- dohp = data->req.doh = calloc(1, sizeof(struct doh_probes));
+ dohp = data->req.doh = calloc(1, sizeof(struct dohdata));
if(!dohp)
return NULL;
- for(i = 0; i < DOH_SLOT_COUNT; ++i) {
- dohp->probe[i].easy_mid = -1;
- }
-
conn->bits.doh = TRUE;
dohp->host = hostname;
dohp->port = port;
- dohp->req_hds =
+ dohp->headers =
curl_slist_append(NULL,
"Content-Type: application/dns-message");
- if(!dohp->req_hds)
+ if(!dohp->headers)
goto error;
/* create IPv4 DoH request */
- result = doh_run_probe(data, &dohp->probe[DOH_SLOT_IPV4],
- DNS_TYPE_A, hostname, data->set.str[STRING_DOH],
- data->multi, dohp->req_hds);
+ result = dohprobe(data, &dohp->probe[DOH_PROBE_SLOT_IPADDR_V4],
+ DNS_TYPE_A, hostname, data->set.str[STRING_DOH],
+ data->multi, dohp->headers);
if(result)
goto error;
dohp->pending++;
-#ifdef USE_IPV6
+#ifdef ENABLE_IPV6
if((conn->ip_version != CURL_IPRESOLVE_V4) && Curl_ipv6works(data)) {
/* create IPv6 DoH request */
- result = doh_run_probe(data, &dohp->probe[DOH_SLOT_IPV6],
- DNS_TYPE_AAAA, hostname, data->set.str[STRING_DOH],
- data->multi, dohp->req_hds);
+ result = dohprobe(data, &dohp->probe[DOH_PROBE_SLOT_IPADDR_V6],
+ DNS_TYPE_AAAA, hostname, data->set.str[STRING_DOH],
+ data->multi, dohp->headers);
if(result)
goto error;
dohp->pending++;
}
#endif
-
-#ifdef USE_HTTPSRR
- /*
- * TODO: Figure out the conditions under which we want to make
- * a request for an HTTPS RR when we are not doing ECH. For now,
- * making this request breaks a bunch of DoH tests, e.g. test2100,
- * where the additional request does not match the pre-cooked data
- * files, so there is a bit of work attached to making the request
- * in a non-ECH use-case. For the present, we will only make the
- * request when ECH is enabled in the build and is being used for
- * the curl operation.
- */
-# ifdef USE_ECH
- if(data->set.tls_ech & CURLECH_ENABLE
- || data->set.tls_ech & CURLECH_HARD) {
- if(port == 443)
- qname = strdup(hostname);
- else
- qname = aprintf("_%d._https.%s", port, hostname);
- if(!qname)
- goto error;
- result = doh_run_probe(data, &dohp->probe[DOH_SLOT_HTTPS_RR],
- DNS_TYPE_HTTPS, qname, data->set.str[STRING_DOH],
- data->multi, dohp->req_hds);
- Curl_safefree(qname);
- if(result)
- goto error;
- dohp->pending++;
- }
-# endif
-#endif
*waitp = TRUE; /* this never returns synchronously */
return NULL;
error:
- Curl_doh_cleanup(data);
+ curl_slist_free_all(dohp->headers);
+ data->req.doh->headers = NULL;
+ for(slot = 0; slot < DOH_PROBE_SLOTS; slot++) {
+ (void)curl_multi_remove_handle(data->multi, dohp->probe[slot].easy);
+ Curl_close(&dohp->probe[slot].easy);
+ }
+ Curl_safefree(data->req.doh);
return NULL;
}
-static DOHcode doh_skipqname(const unsigned char *doh, size_t dohlen,
- unsigned int *indexp)
+static DOHcode skipqname(const unsigned char *doh, size_t dohlen,
+ unsigned int *indexp)
{
unsigned char length;
do {
@@ -518,32 +447,29 @@ static DOHcode doh_skipqname(const unsigned char *doh, size_t dohlen,
return DOH_DNS_BAD_LABEL;
if(dohlen < (*indexp + 1 + length))
return DOH_DNS_OUT_OF_RANGE;
- *indexp += (unsigned int)(1 + length);
+ *indexp += 1 + length;
} while(length);
return DOH_OK;
}
-static unsigned short doh_get16bit(const unsigned char *doh,
- unsigned int index)
+static unsigned short get16bit(const unsigned char *doh, int index)
{
return (unsigned short)((doh[index] << 8) | doh[index + 1]);
}
-static unsigned int doh_get32bit(const unsigned char *doh, unsigned int index)
+static unsigned int get32bit(const unsigned char *doh, int index)
{
- /* make clang and gcc optimize this to bswap by incrementing
- the pointer first. */
- doh += index;
-
- /* avoid undefined behavior by casting to unsigned before shifting
- 24 bits, possibly into the sign bit. codegen is same, but
- ub sanitizer will not be upset */
- return ((unsigned)doh[0] << 24) | ((unsigned)doh[1] << 16) |
- ((unsigned)doh[2] << 8) | doh[3];
+ /* make clang and gcc optimize this to bswap by incrementing
+ the pointer first. */
+ doh += index;
+
+ /* avoid undefined behavior by casting to unsigned before shifting
+ 24 bits, possibly into the sign bit. codegen is same, but
+ ub sanitizer won't be upset */
+ return ( (unsigned)doh[0] << 24) | (doh[1] << 16) |(doh[2] << 8) | doh[3];
}
-static void doh_store_a(const unsigned char *doh, int index,
- struct dohentry *d)
+static DOHcode store_a(const unsigned char *doh, int index, struct dohentry *d)
{
/* silently ignore addresses over the limit */
if(d->numaddr < DOH_MAX_ADDR) {
@@ -552,10 +478,12 @@ static void doh_store_a(const unsigned char *doh, int index,
memcpy(&a->ip.v4, &doh[index], 4);
d->numaddr++;
}
+ return DOH_OK;
}
-static void doh_store_aaaa(const unsigned char *doh, int index,
- struct dohentry *d)
+static DOHcode store_aaaa(const unsigned char *doh,
+ int index,
+ struct dohentry *d)
{
/* silently ignore addresses over the limit */
if(d->numaddr < DOH_MAX_ADDR) {
@@ -564,27 +492,13 @@ static void doh_store_aaaa(const unsigned char *doh, int index,
memcpy(&a->ip.v6, &doh[index], 16);
d->numaddr++;
}
-}
-
-#ifdef USE_HTTPSRR
-static DOHcode doh_store_https(const unsigned char *doh, int index,
- struct dohentry *d, uint16_t len)
-{
- /* silently ignore RRs over the limit */
- if(d->numhttps_rrs < DOH_MAX_HTTPS) {
- struct dohhttps_rr *h = &d->https_rrs[d->numhttps_rrs];
- h->val = Curl_memdup(&doh[index], len);
- if(!h->val)
- return DOH_OUT_OF_MEM;
- h->len = len;
- d->numhttps_rrs++;
- }
return DOH_OK;
}
-#endif
-static DOHcode doh_store_cname(const unsigned char *doh, size_t dohlen,
- unsigned int index, struct dohentry *d)
+static DOHcode store_cname(const unsigned char *doh,
+ size_t dohlen,
+ unsigned int index,
+ struct dohentry *d)
{
struct dynbuf *c;
unsigned int loop = 128; /* a valid DNS name can never loop this much */
@@ -606,7 +520,7 @@ static DOHcode doh_store_cname(const unsigned char *doh, size_t dohlen,
/* move to the new index */
newpos = (length & 0x3f) << 8 | doh[index + 1];
- index = (unsigned int)newpos;
+ index = newpos;
continue;
}
else if(length & 0xc0)
@@ -633,40 +547,36 @@ static DOHcode doh_store_cname(const unsigned char *doh, size_t dohlen,
return DOH_OK;
}
-static DOHcode doh_rdata(const unsigned char *doh,
- size_t dohlen,
- unsigned short rdlength,
- unsigned short type,
- int index,
- struct dohentry *d)
+static DOHcode rdata(const unsigned char *doh,
+ size_t dohlen,
+ unsigned short rdlength,
+ unsigned short type,
+ int index,
+ struct dohentry *d)
{
/* RDATA
- A (TYPE 1): 4 bytes
- AAAA (TYPE 28): 16 bytes
- - NS (TYPE 2): N bytes
- - HTTPS (TYPE 65): N bytes */
+ - NS (TYPE 2): N bytes */
DOHcode rc;
switch(type) {
case DNS_TYPE_A:
if(rdlength != 4)
return DOH_DNS_RDATA_LEN;
- doh_store_a(doh, index, d);
+ rc = store_a(doh, index, d);
+ if(rc)
+ return rc;
break;
case DNS_TYPE_AAAA:
if(rdlength != 16)
return DOH_DNS_RDATA_LEN;
- doh_store_aaaa(doh, index, d);
- break;
-#ifdef USE_HTTPSRR
- case DNS_TYPE_HTTPS:
- rc = doh_store_https(doh, index, d, rdlength);
+ rc = store_aaaa(doh, index, d);
if(rc)
return rc;
break;
-#endif
case DNS_TYPE_CNAME:
- rc = doh_store_cname(doh, dohlen, (unsigned int)index, d);
+ rc = store_cname(doh, dohlen, index, d);
if(rc)
return rc;
break;
@@ -690,10 +600,10 @@ UNITTEST void de_init(struct dohentry *de)
}
-UNITTEST DOHcode doh_resp_decode(const unsigned char *doh,
- size_t dohlen,
- DNStype dnstype,
- struct dohentry *d)
+UNITTEST DOHcode doh_decode(const unsigned char *doh,
+ size_t dohlen,
+ DNStype dnstype,
+ struct dohentry *d)
{
unsigned char rcode;
unsigned short qdcount;
@@ -713,9 +623,9 @@ UNITTEST DOHcode doh_resp_decode(const unsigned char *doh,
if(rcode)
return DOH_DNS_BAD_RCODE; /* bad rcode */
- qdcount = doh_get16bit(doh, 4);
+ qdcount = get16bit(doh, 4);
while(qdcount) {
- rc = doh_skipqname(doh, dohlen, &index);
+ rc = skipqname(doh, dohlen, &index);
if(rc)
return rc; /* bad qname */
if(dohlen < (index + 4))
@@ -724,19 +634,19 @@ UNITTEST DOHcode doh_resp_decode(const unsigned char *doh,
qdcount--;
}
- ancount = doh_get16bit(doh, 6);
+ ancount = get16bit(doh, 6);
while(ancount) {
unsigned short class;
unsigned int ttl;
- rc = doh_skipqname(doh, dohlen, &index);
+ rc = skipqname(doh, dohlen, &index);
if(rc)
return rc; /* bad qname */
if(dohlen < (index + 2))
return DOH_DNS_OUT_OF_RANGE;
- type = doh_get16bit(doh, index);
+ type = get16bit(doh, index);
if((type != DNS_TYPE_CNAME) /* may be synthesized from DNAME */
&& (type != DNS_TYPE_DNAME) /* if present, accept and ignore */
&& (type != dnstype))
@@ -746,7 +656,7 @@ UNITTEST DOHcode doh_resp_decode(const unsigned char *doh,
if(dohlen < (index + 2))
return DOH_DNS_OUT_OF_RANGE;
- class = doh_get16bit(doh, index);
+ class = get16bit(doh, index);
if(DNS_CLASS_IN != class)
return DOH_DNS_UNEXPECTED_CLASS; /* unsupported */
index += 2;
@@ -754,7 +664,7 @@ UNITTEST DOHcode doh_resp_decode(const unsigned char *doh,
if(dohlen < (index + 4))
return DOH_DNS_OUT_OF_RANGE;
- ttl = doh_get32bit(doh, index);
+ ttl = get32bit(doh, index);
if(ttl < d->ttl)
d->ttl = ttl;
index += 4;
@@ -762,21 +672,21 @@ UNITTEST DOHcode doh_resp_decode(const unsigned char *doh,
if(dohlen < (index + 2))
return DOH_DNS_OUT_OF_RANGE;
- rdlength = doh_get16bit(doh, index);
+ rdlength = get16bit(doh, index);
index += 2;
if(dohlen < (index + rdlength))
return DOH_DNS_OUT_OF_RANGE;
- rc = doh_rdata(doh, dohlen, rdlength, type, (int)index, d);
+ rc = rdata(doh, dohlen, rdlength, type, index, d);
if(rc)
- return rc; /* bad doh_rdata */
+ return rc; /* bad rdata */
index += rdlength;
ancount--;
}
- nscount = doh_get16bit(doh, 8);
+ nscount = get16bit(doh, 8);
while(nscount) {
- rc = doh_skipqname(doh, dohlen, &index);
+ rc = skipqname(doh, dohlen, &index);
if(rc)
return rc; /* bad qname */
@@ -788,7 +698,7 @@ UNITTEST DOHcode doh_resp_decode(const unsigned char *doh,
if(dohlen < (index + 2))
return DOH_DNS_OUT_OF_RANGE;
- rdlength = doh_get16bit(doh, index);
+ rdlength = get16bit(doh, index);
index += 2;
if(dohlen < (index + rdlength))
return DOH_DNS_OUT_OF_RANGE;
@@ -796,9 +706,9 @@ UNITTEST DOHcode doh_resp_decode(const unsigned char *doh,
nscount--;
}
- arcount = doh_get16bit(doh, 10);
+ arcount = get16bit(doh, 10);
while(arcount) {
- rc = doh_skipqname(doh, dohlen, &index);
+ rc = skipqname(doh, dohlen, &index);
if(rc)
return rc; /* bad qname */
@@ -810,7 +720,7 @@ UNITTEST DOHcode doh_resp_decode(const unsigned char *doh,
if(dohlen < (index + 2))
return DOH_DNS_OUT_OF_RANGE;
- rdlength = doh_get16bit(doh, index);
+ rdlength = get16bit(doh, index);
index += 2;
if(dohlen < (index + rdlength))
return DOH_DNS_OUT_OF_RANGE;
@@ -821,11 +731,7 @@ UNITTEST DOHcode doh_resp_decode(const unsigned char *doh,
if(index != dohlen)
return DOH_DNS_MALFORMAT; /* something is wrong */
-#ifdef USE_HTTTPS
- if((type != DNS_TYPE_NS) && !d->numcname && !d->numaddr && !d->numhttps_rrs)
-#else
if((type != DNS_TYPE_NS) && !d->numcname && !d->numaddr)
-#endif
/* nothing stored! */
return DOH_NO_CONTENT;
@@ -833,15 +739,15 @@ UNITTEST DOHcode doh_resp_decode(const unsigned char *doh,
}
#ifndef CURL_DISABLE_VERBOSE_STRINGS
-static void doh_show(struct Curl_easy *data,
- const struct dohentry *d)
+static void showdoh(struct Curl_easy *data,
+ const struct dohentry *d)
{
int i;
- infof(data, "[DoH] TTL: %u seconds", d->ttl);
+ infof(data, "TTL: %u seconds", d->ttl);
for(i = 0; i < d->numaddr; i++) {
const struct dohaddr *a = &d->addr[i];
if(a->type == DNS_TYPE_A) {
- infof(data, "[DoH] A: %u.%u.%u.%u",
+ infof(data, "DoH A: %u.%u.%u.%u",
a->ip.v4[0], a->ip.v4[1],
a->ip.v4[2], a->ip.v4[3]);
}
@@ -850,9 +756,9 @@ static void doh_show(struct Curl_easy *data,
char buffer[128];
char *ptr;
size_t len;
- len = msnprintf(buffer, 128, "[DoH] AAAA: ");
- ptr = &buffer[len];
- len = sizeof(buffer) - len;
+ msnprintf(buffer, 128, "DoH AAAA: ");
+ ptr = &buffer[10];
+ len = 118;
for(j = 0; j < 16; j += 2) {
size_t l;
msnprintf(ptr, len, "%s%02x%02x", j?":":"", d->addr[i].ip.v6[j],
@@ -864,22 +770,12 @@ static void doh_show(struct Curl_easy *data,
infof(data, "%s", buffer);
}
}
-#ifdef USE_HTTPSRR
- for(i = 0; i < d->numhttps_rrs; i++) {
-# ifdef DEBUGBUILD
- doh_print_buf(data, "DoH HTTPS",
- d->https_rrs[i].val, d->https_rrs[i].len);
-# else
- infof(data, "DoH HTTPS RR: length %d", d->https_rrs[i].len);
-# endif
- }
-#endif
for(i = 0; i < d->numcname; i++) {
infof(data, "CNAME: %s", Curl_dyn_ptr(&d->cname[i]));
}
}
#else
-#define doh_show(x,y)
+#define showdoh(x,y)
#endif
/*
@@ -887,11 +783,11 @@ static void doh_show(struct Curl_easy *data,
*
* This function returns a pointer to the first element of a newly allocated
* Curl_addrinfo struct linked list filled with the data from a set of DoH
- * lookups. Curl_addrinfo is meant to work like the addrinfo struct does for
+ * lookups. Curl_addrinfo is meant to work like the addrinfo struct does for
* a IPv6 stack, but usable also for IPv4, all hosts and environments.
*
* The memory allocated by this function *MUST* be free'd later on calling
- * Curl_freeaddrinfo(). For each successful call to this function there
+ * Curl_freeaddrinfo(). For each successful call to this function there
* must be an associated call later to Curl_freeaddrinfo().
*/
@@ -902,7 +798,7 @@ static CURLcode doh2ai(const struct dohentry *de, const char *hostname,
struct Curl_addrinfo *prevai = NULL;
struct Curl_addrinfo *firstai = NULL;
struct sockaddr_in *addr;
-#ifdef USE_IPV6
+#ifdef ENABLE_IPV6
struct sockaddr_in6 *addr6;
#endif
CURLcode result = CURLE_OK;
@@ -918,8 +814,8 @@ static CURLcode doh2ai(const struct dohentry *de, const char *hostname,
size_t ss_size;
CURL_SA_FAMILY_T addrtype;
if(de->addr[i].type == DNS_TYPE_AAAA) {
-#ifndef USE_IPV6
- /* we cannot handle IPv6 addresses */
+#ifndef ENABLE_IPV6
+ /* we can't handle IPv6 addresses */
continue;
#else
ss_size = sizeof(struct sockaddr_in6);
@@ -963,24 +859,16 @@ static CURLcode doh2ai(const struct dohentry *de, const char *hostname,
addr = (void *)ai->ai_addr; /* storage area for this info */
DEBUGASSERT(sizeof(struct in_addr) == sizeof(de->addr[i].ip.v4));
memcpy(&addr->sin_addr, &de->addr[i].ip.v4, sizeof(struct in_addr));
-#ifdef __MINGW32__
- addr->sin_family = (short)addrtype;
-#else
addr->sin_family = addrtype;
-#endif
addr->sin_port = htons((unsigned short)port);
break;
-#ifdef USE_IPV6
+#ifdef ENABLE_IPV6
case AF_INET6:
addr6 = (void *)ai->ai_addr; /* storage area for this info */
DEBUGASSERT(sizeof(struct in6_addr) == sizeof(de->addr[i].ip.v6));
memcpy(&addr6->sin6_addr, &de->addr[i].ip.v6, sizeof(struct in6_addr));
-#ifdef __MINGW32__
- addr6->sin6_family = (short)addrtype;
-#else
addr6->sin6_family = addrtype;
-#endif
addr6->sin6_port = htons((unsigned short)port);
break;
#endif
@@ -999,20 +887,9 @@ static CURLcode doh2ai(const struct dohentry *de, const char *hostname,
}
#ifndef CURL_DISABLE_VERBOSE_STRINGS
-static const char *doh_type2name(DNStype dnstype)
+static const char *type2name(DNStype dnstype)
{
- switch(dnstype) {
- case DNS_TYPE_A:
- return "A";
- case DNS_TYPE_AAAA:
- return "AAAA";
-#ifdef USE_HTTPSRR
- case DNS_TYPE_HTTPS:
- return "HTTPS";
-#endif
- default:
- return "unknown";
- }
+ return (dnstype == DNS_TYPE_A)?"A":"AAAA";
}
#endif
@@ -1022,329 +899,62 @@ UNITTEST void de_cleanup(struct dohentry *d)
for(i = 0; i < d->numcname; i++) {
Curl_dyn_free(&d->cname[i]);
}
-#ifdef USE_HTTPSRR
- for(i = 0; i < d->numhttps_rrs; i++)
- Curl_safefree(d->https_rrs[i].val);
-#endif
}
-#ifdef USE_HTTPSRR
-
-/*
- * @brief decode the DNS name in a binary RRData
- * @param buf points to the buffer (in/out)
- * @param remaining points to the remaining buffer length (in/out)
- * @param dnsname returns the string form name on success
- * @return is 1 for success, error otherwise
- *
- * The encoding here is defined in
- * https://tools.ietf.org/html/rfc1035#section-3.1
- *
- * The input buffer pointer will be modified so it points to
- * just after the end of the DNS name encoding on output. (And
- * that is why it is an "unsigned char **" :-)
- */
-static CURLcode doh_decode_rdata_name(unsigned char **buf, size_t *remaining,
- char **dnsname)
-{
- unsigned char *cp = NULL;
- int rem = 0;
- unsigned char clen = 0; /* chunk len */
- struct dynbuf thename;
-
- DEBUGASSERT(buf && remaining && dnsname);
- if(!buf || !remaining || !dnsname)
- return CURLE_OUT_OF_MEMORY;
- rem = (int)*remaining;
- if(rem <= 0) {
- Curl_dyn_free(&thename);
- return CURLE_OUT_OF_MEMORY;
- }
- Curl_dyn_init(&thename, CURL_MAXLEN_host_name);
- cp = *buf;
- clen = *cp++;
- if(clen == 0) {
- /* special case - return "." as name */
- if(Curl_dyn_addn(&thename, ".", 1))
- return CURLE_OUT_OF_MEMORY;
- }
- while(clen) {
- if(clen >= rem) {
- Curl_dyn_free(&thename);
- return CURLE_OUT_OF_MEMORY;
- }
- if(Curl_dyn_addn(&thename, cp, clen) ||
- Curl_dyn_addn(&thename, ".", 1))
- return CURLE_TOO_LARGE;
-
- cp += clen;
- rem -= (clen + 1);
- if(rem <= 0) {
- Curl_dyn_free(&thename);
- return CURLE_OUT_OF_MEMORY;
- }
- clen = *cp++;
- }
- *buf = cp;
- *remaining = rem - 1;
- *dnsname = Curl_dyn_ptr(&thename);
- return CURLE_OK;
-}
-
-static CURLcode doh_decode_rdata_alpn(unsigned char *rrval, size_t len,
- char **alpns)
-{
- /*
- * spec here is as per draft-ietf-dnsop-svcb-https, section-7.1.1
- * encoding is catenated list of strings each preceded by a one
- * octet length
- * output is comma-sep list of the strings
- * implementations may or may not handle quoting of comma within
- * string values, so we might see a comma within the wire format
- * version of a string, in which case we will precede that by a
- * backslash - same goes for a backslash character, and of course
- * we need to use two backslashes in strings when we mean one;-)
- */
- int remaining = (int) len;
- char *oval;
- size_t i;
- unsigned char *cp = rrval;
- struct dynbuf dval;
-
- if(!alpns)
- return CURLE_OUT_OF_MEMORY;
- Curl_dyn_init(&dval, DYN_DOH_RESPONSE);
- remaining = (int)len;
- cp = rrval;
- while(remaining > 0) {
- size_t tlen = (size_t) *cp++;
-
- /* if not 1st time, add comma */
- if(remaining != (int)len && Curl_dyn_addn(&dval, ",", 1))
- goto err;
- remaining--;
- if(tlen > (size_t)remaining)
- goto err;
- /* add escape char if needed, clunky but easier to read */
- for(i = 0; i != tlen; i++) {
- if('\\' == *cp || ',' == *cp) {
- if(Curl_dyn_addn(&dval, "\\", 1))
- goto err;
- }
- if(Curl_dyn_addn(&dval, cp++, 1))
- goto err;
- }
- remaining -= (int)tlen;
- }
- /* this string is always null terminated */
- oval = Curl_dyn_ptr(&dval);
- if(!oval)
- goto err;
- *alpns = oval;
- return CURLE_OK;
-err:
- Curl_dyn_free(&dval);
- return CURLE_BAD_CONTENT_ENCODING;
-}
-
-#ifdef DEBUGBUILD
-static CURLcode doh_test_alpn_escapes(void)
-{
- /* we will use an example from draft-ietf-dnsop-svcb, figure 10 */
- static unsigned char example[] = {
- 0x08, /* length 8 */
- 0x66, 0x5c, 0x6f, 0x6f, 0x2c, 0x62, 0x61, 0x72, /* value "f\\oo,bar" */
- 0x02, /* length 2 */
- 0x68, 0x32 /* value "h2" */
- };
- size_t example_len = sizeof(example);
- char *aval = NULL;
- static const char *expected = "f\\\\oo\\,bar,h2";
-
- if(doh_decode_rdata_alpn(example, example_len, &aval) != CURLE_OK)
- return CURLE_BAD_CONTENT_ENCODING;
- if(strlen(aval) != strlen(expected))
- return CURLE_BAD_CONTENT_ENCODING;
- if(memcmp(aval, expected, strlen(aval)))
- return CURLE_BAD_CONTENT_ENCODING;
- return CURLE_OK;
-}
-#endif
-
-static CURLcode doh_resp_decode_httpsrr(unsigned char *rrval, size_t len,
- struct Curl_https_rrinfo **hrr)
-{
- size_t remaining = len;
- unsigned char *cp = rrval;
- uint16_t pcode = 0, plen = 0;
- struct Curl_https_rrinfo *lhrr = NULL;
- char *dnsname = NULL;
-
-#ifdef DEBUGBUILD
- /* a few tests of escaping, should not be here but ok for now */
- if(doh_test_alpn_escapes() != CURLE_OK)
- return CURLE_OUT_OF_MEMORY;
-#endif
- lhrr = calloc(1, sizeof(struct Curl_https_rrinfo));
- if(!lhrr)
- return CURLE_OUT_OF_MEMORY;
- lhrr->val = Curl_memdup(rrval, len);
- if(!lhrr->val)
- goto err;
- lhrr->len = len;
- if(remaining <= 2)
- goto err;
- lhrr->priority = (uint16_t)((cp[0] << 8) + cp[1]);
- cp += 2;
- remaining -= (uint16_t)2;
- if(doh_decode_rdata_name(&cp, &remaining, &dnsname) != CURLE_OK)
- goto err;
- lhrr->target = dnsname;
- while(remaining >= 4) {
- pcode = (uint16_t)((*cp << 8) + (*(cp + 1)));
- cp += 2;
- plen = (uint16_t)((*cp << 8) + (*(cp + 1)));
- cp += 2;
- remaining -= 4;
- if(pcode == HTTPS_RR_CODE_ALPN) {
- if(doh_decode_rdata_alpn(cp, plen, &lhrr->alpns) != CURLE_OK)
- goto err;
- }
- if(pcode == HTTPS_RR_CODE_NO_DEF_ALPN)
- lhrr->no_def_alpn = TRUE;
- else if(pcode == HTTPS_RR_CODE_IPV4) {
- if(!plen)
- goto err;
- lhrr->ipv4hints = Curl_memdup(cp, plen);
- if(!lhrr->ipv4hints)
- goto err;
- lhrr->ipv4hints_len = (size_t)plen;
- }
- else if(pcode == HTTPS_RR_CODE_ECH) {
- if(!plen)
- goto err;
- lhrr->echconfiglist = Curl_memdup(cp, plen);
- if(!lhrr->echconfiglist)
- goto err;
- lhrr->echconfiglist_len = (size_t)plen;
- }
- else if(pcode == HTTPS_RR_CODE_IPV6) {
- if(!plen)
- goto err;
- lhrr->ipv6hints = Curl_memdup(cp, plen);
- if(!lhrr->ipv6hints)
- goto err;
- lhrr->ipv6hints_len = (size_t)plen;
- }
- if(plen > 0 && plen <= remaining) {
- cp += plen;
- remaining -= plen;
- }
- }
- DEBUGASSERT(!remaining);
- *hrr = lhrr;
- return CURLE_OK;
-err:
- if(lhrr) {
- Curl_safefree(lhrr->target);
- Curl_safefree(lhrr->echconfiglist);
- Curl_safefree(lhrr->val);
- Curl_safefree(lhrr->alpns);
- Curl_safefree(lhrr);
- }
- return CURLE_OUT_OF_MEMORY;
-}
-
-# ifdef DEBUGBUILD
-static void doh_print_httpsrr(struct Curl_easy *data,
- struct Curl_https_rrinfo *hrr)
-{
- DEBUGASSERT(hrr);
- infof(data, "HTTPS RR: priority %d, target: %s",
- hrr->priority, hrr->target);
- if(hrr->alpns)
- infof(data, "HTTPS RR: alpns %s", hrr->alpns);
- else
- infof(data, "HTTPS RR: no alpns");
- if(hrr->no_def_alpn)
- infof(data, "HTTPS RR: no_def_alpn set");
- else
- infof(data, "HTTPS RR: no_def_alpn not set");
- if(hrr->ipv4hints) {
- doh_print_buf(data, "HTTPS RR: ipv4hints",
- hrr->ipv4hints, hrr->ipv4hints_len);
- }
- else
- infof(data, "HTTPS RR: no ipv4hints");
- if(hrr->echconfiglist) {
- doh_print_buf(data, "HTTPS RR: ECHConfigList",
- hrr->echconfiglist, hrr->echconfiglist_len);
- }
- else
- infof(data, "HTTPS RR: no ECHConfigList");
- if(hrr->ipv6hints) {
- doh_print_buf(data, "HTTPS RR: ipv6hint",
- hrr->ipv6hints, hrr->ipv6hints_len);
- }
- else
- infof(data, "HTTPS RR: no ipv6hints");
- return;
-}
-# endif
-#endif
-
CURLcode Curl_doh_is_resolved(struct Curl_easy *data,
struct Curl_dns_entry **dnsp)
{
+ struct connectdata *conn = data->conn;
CURLcode result;
- struct doh_probes *dohp = data->req.doh;
+ struct dohdata *dohp = data->req.doh;
*dnsp = NULL; /* defaults to no response */
if(!dohp)
return CURLE_OUT_OF_MEMORY;
- if(dohp->probe[DOH_SLOT_IPV4].easy_mid < 0 &&
- dohp->probe[DOH_SLOT_IPV6].easy_mid < 0) {
- failf(data, "Could not DoH-resolve: %s", data->state.async.hostname);
+ if(!dohp->probe[DOH_PROBE_SLOT_IPADDR_V4].easy &&
+ !dohp->probe[DOH_PROBE_SLOT_IPADDR_V6].easy) {
+ failf(data, "Could not DoH-resolve: %s", conn->resolve_async.hostname);
return CONN_IS_PROXIED(data->conn)?CURLE_COULDNT_RESOLVE_PROXY:
CURLE_COULDNT_RESOLVE_HOST;
}
else if(!dohp->pending) {
- DOHcode rc[DOH_SLOT_COUNT];
+ DOHcode rc[DOH_PROBE_SLOTS] = {
+ DOH_OK, DOH_OK
+ };
struct dohentry de;
int slot;
-
- memset(rc, 0, sizeof(rc));
/* remove DoH handles from multi handle and close them */
- Curl_doh_close(data);
+ for(slot = 0; slot < DOH_PROBE_SLOTS; slot++) {
+ curl_multi_remove_handle(data->multi, dohp->probe[slot].easy);
+ Curl_close(&dohp->probe[slot].easy);
+ }
/* parse the responses, create the struct and return it! */
de_init(&de);
- for(slot = 0; slot < DOH_SLOT_COUNT; slot++) {
- struct doh_probe *p = &dohp->probe[slot];
+ for(slot = 0; slot < DOH_PROBE_SLOTS; slot++) {
+ struct dnsprobe *p = &dohp->probe[slot];
if(!p->dnstype)
continue;
- rc[slot] = doh_resp_decode(Curl_dyn_uptr(&p->resp_body),
- Curl_dyn_len(&p->resp_body),
- p->dnstype, &de);
- Curl_dyn_free(&p->resp_body);
+ rc[slot] = doh_decode(Curl_dyn_uptr(&p->serverdoh),
+ Curl_dyn_len(&p->serverdoh),
+ p->dnstype,
+ &de);
+ Curl_dyn_free(&p->serverdoh);
#ifndef CURL_DISABLE_VERBOSE_STRINGS
if(rc[slot]) {
infof(data, "DoH: %s type %s for %s", doh_strerror(rc[slot]),
- doh_type2name(p->dnstype), dohp->host);
+ type2name(p->dnstype), dohp->host);
}
#endif
} /* next slot */
result = CURLE_COULDNT_RESOLVE_HOST; /* until we know better */
- if(!rc[DOH_SLOT_IPV4] || !rc[DOH_SLOT_IPV6]) {
+ if(!rc[DOH_PROBE_SLOT_IPADDR_V4] || !rc[DOH_PROBE_SLOT_IPADDR_V6]) {
/* we have an address, of one kind or other */
struct Curl_dns_entry *dns;
struct Curl_addrinfo *ai;
-
- if(Curl_trc_ft_is_verbose(data, &Curl_doh_trc)) {
- infof(data, "[DoH] hostname: %s", dohp->host);
- doh_show(data, &de);
- }
+ infof(data, "DoH Host name: %s", dohp->host);
+ showdoh(data, &de);
result = doh2ai(&de, dohp->host, dohp->port, &ai);
if(result) {
@@ -1356,7 +966,7 @@ CURLcode Curl_doh_is_resolved(struct Curl_easy *data,
Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
/* we got a response, store it in the cache */
- dns = Curl_cache_addr(data, ai, dohp->host, 0, dohp->port, FALSE);
+ dns = Curl_cache_addr(data, ai, dohp->host, 0, dohp->port);
if(data->share)
Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
@@ -1366,33 +976,17 @@ CURLcode Curl_doh_is_resolved(struct Curl_easy *data,
Curl_freeaddrinfo(ai);
}
else {
- data->state.async.dns = dns;
+ conn->resolve_async.dns = dns;
*dnsp = dns;
result = CURLE_OK; /* address resolution OK */
}
} /* address processing done */
/* Now process any build-specific attributes retrieved from DNS */
-#ifdef USE_HTTPSRR
- if(de.numhttps_rrs > 0 && result == CURLE_OK && *dnsp) {
- struct Curl_https_rrinfo *hrr = NULL;
- result = doh_resp_decode_httpsrr(de.https_rrs->val, de.https_rrs->len,
- &hrr);
- if(result) {
- infof(data, "Failed to decode HTTPS RR");
- return result;
- }
- infof(data, "Some HTTPS RR to process");
-# ifdef DEBUGBUILD
- doh_print_httpsrr(data, hrr);
-# endif
- (*dnsp)->hinfo = hrr;
- }
-#endif
/* All done */
de_cleanup(&de);
- Curl_doh_cleanup(data);
+ Curl_safefree(data->req.doh);
return result;
} /* !dohp->pending */
@@ -1401,43 +995,4 @@ CURLcode Curl_doh_is_resolved(struct Curl_easy *data,
return CURLE_OK;
}
-void Curl_doh_close(struct Curl_easy *data)
-{
- struct doh_probes *doh = data->req.doh;
- if(doh && data->multi) {
- struct Curl_easy *probe_data;
- curl_off_t mid;
- size_t slot;
- for(slot = 0; slot < DOH_SLOT_COUNT; slot++) {
- mid = doh->probe[slot].easy_mid;
- if(mid < 0)
- continue;
- doh->probe[slot].easy_mid = -1;
- /* should have been called before data is removed from multi handle */
- DEBUGASSERT(data->multi);
- probe_data = data->multi? Curl_multi_get_handle(data->multi, mid) : NULL;
- if(!probe_data) {
- DEBUGF(infof(data, "Curl_doh_close: xfer for mid=%"
- FMT_OFF_T " not found!",
- doh->probe[slot].easy_mid));
- continue;
- }
- /* data->multi might already be reset at this time */
- curl_multi_remove_handle(data->multi, probe_data);
- Curl_close(&probe_data);
- }
- }
-}
-
-void Curl_doh_cleanup(struct Curl_easy *data)
-{
- struct doh_probes *doh = data->req.doh;
- if(doh) {
- Curl_doh_close(data);
- curl_slist_free_all(doh->req_hds);
- data->req.doh->req_hds = NULL;
- Curl_safefree(data->req.doh);
- }
-}
-
#endif /* CURL_DISABLE_DOH */
diff --git a/contrib/libs/curl/lib/doh.h b/contrib/libs/curl/lib/doh.h
index aae32a6540..7d7b694f33 100644
--- a/contrib/libs/curl/lib/doh.h
+++ b/contrib/libs/curl/lib/doh.h
@@ -26,9 +26,6 @@
#include "urldata.h"
#include "curl_addrinfo.h"
-#ifdef USE_HTTPSRR
-# include <stdint.h>
-#endif
#ifndef CURL_DISABLE_DOH
@@ -54,44 +51,22 @@ typedef enum {
DNS_TYPE_NS = 2,
DNS_TYPE_CNAME = 5,
DNS_TYPE_AAAA = 28,
- DNS_TYPE_DNAME = 39, /* RFC6672 */
- DNS_TYPE_HTTPS = 65
+ DNS_TYPE_DNAME = 39 /* RFC6672 */
} DNStype;
/* one of these for each DoH request */
-struct doh_probe {
- curl_off_t easy_mid; /* multi id of easy handle doing the lookup */
+struct dnsprobe {
+ CURL *easy;
DNStype dnstype;
- unsigned char req_body[512];
- size_t req_body_len;
- struct dynbuf resp_body;
+ unsigned char dohbuffer[512];
+ size_t dohlen;
+ struct dynbuf serverdoh;
};
-enum doh_slot_num {
- /* Explicit values for first two symbols so as to match hard-coded
- * constants in existing code
- */
- DOH_SLOT_IPV4 = 0, /* make 'V4' stand out for readability */
- DOH_SLOT_IPV6 = 1, /* 'V6' likewise */
-
- /* Space here for (possibly build-specific) additional slot definitions */
-#ifdef USE_HTTPSRR
- DOH_SLOT_HTTPS_RR = 2, /* for HTTPS RR */
-#endif
-
- /* for example */
- /* #ifdef WANT_DOH_FOOBAR_TXT */
- /* DOH_PROBE_SLOT_FOOBAR_TXT, */
- /* #endif */
-
- /* AFTER all slot definitions, establish how many we have */
- DOH_SLOT_COUNT
-};
-
-struct doh_probes {
- struct curl_slist *req_hds;
- struct doh_probe probe[DOH_SLOT_COUNT];
- unsigned int pending; /* still outstanding probes */
+struct dohdata {
+ struct curl_slist *headers;
+ struct dnsprobe probe[DOH_PROBE_SLOTS];
+ unsigned int pending; /* still outstanding requests */
int port;
const char *host;
};
@@ -109,9 +84,10 @@ struct Curl_addrinfo *Curl_doh(struct Curl_easy *data,
CURLcode Curl_doh_is_resolved(struct Curl_easy *data,
struct Curl_dns_entry **dns);
+int Curl_doh_getsock(struct connectdata *conn, curl_socket_t *socks);
+
#define DOH_MAX_ADDR 24
#define DOH_MAX_CNAME 4
-#define DOH_MAX_HTTPS 4
struct dohaddr {
int type;
@@ -121,65 +97,28 @@ struct dohaddr {
} ip;
};
-#ifdef USE_HTTPSRR
-
-/*
- * These are the code points for DNS wire format SvcParams as
- * per draft-ietf-dnsop-svcb-https
- * Not all are supported now, and even those that are may need
- * more work in future to fully support the spec.
- */
-#define HTTPS_RR_CODE_ALPN 0x01
-#define HTTPS_RR_CODE_NO_DEF_ALPN 0x02
-#define HTTPS_RR_CODE_PORT 0x03
-#define HTTPS_RR_CODE_IPV4 0x04
-#define HTTPS_RR_CODE_ECH 0x05
-#define HTTPS_RR_CODE_IPV6 0x06
-
-/*
- * These may need escaping when found within an ALPN string
- * value.
- */
-#define COMMA_CHAR ','
-#define BACKSLASH_CHAR '\\'
-
-struct dohhttps_rr {
- uint16_t len; /* raw encoded length */
- unsigned char *val; /* raw encoded octets */
-};
-#endif
-
struct dohentry {
struct dynbuf cname[DOH_MAX_CNAME];
struct dohaddr addr[DOH_MAX_ADDR];
int numaddr;
unsigned int ttl;
int numcname;
-#ifdef USE_HTTPSRR
- struct dohhttps_rr https_rrs[DOH_MAX_HTTPS];
- int numhttps_rrs;
-#endif
};
-void Curl_doh_close(struct Curl_easy *data);
-void Curl_doh_cleanup(struct Curl_easy *data);
-
-#ifdef UNITTESTS
-UNITTEST DOHcode doh_req_encode(const char *host,
- DNStype dnstype,
- unsigned char *dnsp, /* buffer */
- size_t len, /* buffer size */
- size_t *olen); /* output length */
-UNITTEST DOHcode doh_resp_decode(const unsigned char *doh,
- size_t dohlen,
- DNStype dnstype,
- struct dohentry *d);
-
-UNITTEST void de_init(struct dohentry *d);
-UNITTEST void de_cleanup(struct dohentry *d);
-#endif
-extern struct curl_trc_feat Curl_doh_trc;
+#ifdef DEBUGBUILD
+DOHcode doh_encode(const char *host,
+ DNStype dnstype,
+ unsigned char *dnsp, /* buffer */
+ size_t len, /* buffer size */
+ size_t *olen); /* output length */
+DOHcode doh_decode(const unsigned char *doh,
+ size_t dohlen,
+ DNStype dnstype,
+ struct dohentry *d);
+void de_init(struct dohentry *d);
+void de_cleanup(struct dohentry *d);
+#endif
#else /* if DoH is disabled */
#define Curl_doh(a,b,c,d) NULL
diff --git a/contrib/libs/curl/lib/dynbuf.c b/contrib/libs/curl/lib/dynbuf.c
index eab07efbf0..2973d8da29 100644
--- a/contrib/libs/curl/lib/dynbuf.c
+++ b/contrib/libs/curl/lib/dynbuf.c
@@ -51,7 +51,7 @@ void Curl_dyn_init(struct dynbuf *s, size_t toobig)
}
/*
- * free the buffer and re-init the necessary fields. It does not touch the
+ * free the buffer and re-init the necessary fields. It doesn't touch the
* 'init' field and thus this buffer can be reused to add data to again.
*/
void Curl_dyn_free(struct dynbuf *s)
@@ -71,7 +71,7 @@ static CURLcode dyn_nappend(struct dynbuf *s,
size_t a = s->allc;
size_t fit = len + indx + 1; /* new string + old string + zero byte */
- /* try to detect if there is rubbish in the struct */
+ /* try to detect if there's rubbish in the struct */
DEBUGASSERT(s->init == DYNINIT);
DEBUGASSERT(s->toobig);
DEBUGASSERT(indx < s->toobig);
@@ -81,7 +81,7 @@ static CURLcode dyn_nappend(struct dynbuf *s,
if(fit > s->toobig) {
Curl_dyn_free(s);
- return CURLE_TOO_LARGE;
+ return CURLE_OUT_OF_MEMORY;
}
else if(!a) {
DEBUGASSERT(!indx);
@@ -199,9 +199,6 @@ CURLcode Curl_dyn_vaddf(struct dynbuf *s, const char *fmt, va_list ap)
if(!rc)
return CURLE_OK;
- else if(rc == MERR_TOO_LARGE)
- return CURLE_TOO_LARGE;
- return CURLE_OUT_OF_MEMORY;
#else
char *str;
str = vaprintf(fmt, ap); /* this allocs a new string to append */
@@ -213,8 +210,8 @@ CURLcode Curl_dyn_vaddf(struct dynbuf *s, const char *fmt, va_list ap)
}
/* If we failed, we cleanup the whole buffer and return error */
Curl_dyn_free(s);
- return CURLE_OUT_OF_MEMORY;
#endif
+ return CURLE_OUT_OF_MEMORY;
}
/*
diff --git a/contrib/libs/curl/lib/dynbuf.h b/contrib/libs/curl/lib/dynbuf.h
index 7dbaab886e..31a9130197 100644
--- a/contrib/libs/curl/lib/dynbuf.h
+++ b/contrib/libs/curl/lib/dynbuf.h
@@ -61,9 +61,9 @@ CURLcode Curl_dyn_addn(struct dynbuf *s, const void *mem, size_t len)
CURLcode Curl_dyn_add(struct dynbuf *s, const char *str)
WARN_UNUSED_RESULT;
CURLcode Curl_dyn_addf(struct dynbuf *s, const char *fmt, ...)
- WARN_UNUSED_RESULT CURL_PRINTF(2, 3);
+ WARN_UNUSED_RESULT;
CURLcode Curl_dyn_vaddf(struct dynbuf *s, const char *fmt, va_list ap)
- WARN_UNUSED_RESULT CURL_PRINTF(2, 0);
+ WARN_UNUSED_RESULT;
void Curl_dyn_reset(struct dynbuf *s);
CURLcode Curl_dyn_tail(struct dynbuf *s, size_t trail);
CURLcode Curl_dyn_setlen(struct dynbuf *s, size_t set);
diff --git a/contrib/libs/curl/lib/dynhds.c b/contrib/libs/curl/lib/dynhds.c
index 9153838e3a..d7548959b2 100644
--- a/contrib/libs/curl/lib/dynhds.c
+++ b/contrib/libs/curl/lib/dynhds.c
@@ -275,7 +275,7 @@ CURLcode Curl_dynhds_h1_cadd_line(struct dynhds *dynhds, const char *line)
return Curl_dynhds_h1_add_line(dynhds, line, line? strlen(line) : 0);
}
-#ifdef UNITTESTS
+#ifdef DEBUGBUILD
/* used by unit2602.c */
bool Curl_dynhds_contains(struct dynhds *dynhds,
diff --git a/contrib/libs/curl/lib/dynhds.h b/contrib/libs/curl/lib/dynhds.h
index fb162a30de..3b536000a2 100644
--- a/contrib/libs/curl/lib/dynhds.h
+++ b/contrib/libs/curl/lib/dynhds.h
@@ -95,9 +95,6 @@ struct dynhds_entry *Curl_dynhds_get(struct dynhds *dynhds,
const char *name, size_t namelen);
struct dynhds_entry *Curl_dynhds_cget(struct dynhds *dynhds, const char *name);
-#ifdef UNITTESTS
-/* used by unit2602.c */
-
/**
* Return TRUE iff one or more headers with the given name exist.
*/
@@ -119,6 +116,20 @@ size_t Curl_dynhds_count_name(struct dynhds *dynhds,
size_t Curl_dynhds_ccount_name(struct dynhds *dynhds, const char *name);
/**
+ * Add a header, name + value, to `dynhds` at the end. Does *not*
+ * check for duplicate names.
+ */
+CURLcode Curl_dynhds_add(struct dynhds *dynhds,
+ const char *name, size_t namelen,
+ const char *value, size_t valuelen);
+
+/**
+ * Add a header, c-string name + value, to `dynhds` at the end.
+ */
+CURLcode Curl_dynhds_cadd(struct dynhds *dynhds,
+ const char *name, const char *value);
+
+/**
* Remove all entries with the given name.
* Returns number of entries removed.
*/
@@ -135,34 +146,19 @@ size_t Curl_dynhds_cremove(struct dynhds *dynhds, const char *name);
CURLcode Curl_dynhds_set(struct dynhds *dynhds,
const char *name, size_t namelen,
const char *value, size_t valuelen);
-#endif
CURLcode Curl_dynhds_cset(struct dynhds *dynhds,
const char *name, const char *value);
/**
- * Add a header, name + value, to `dynhds` at the end. Does *not*
- * check for duplicate names.
- */
-CURLcode Curl_dynhds_add(struct dynhds *dynhds,
- const char *name, size_t namelen,
- const char *value, size_t valuelen);
-
-/**
- * Add a header, c-string name + value, to `dynhds` at the end.
- */
-CURLcode Curl_dynhds_cadd(struct dynhds *dynhds,
- const char *name, const char *value);
-
-/**
- * Add a single header from an HTTP/1.1 formatted line at the end. Line
+ * Add a single header from a HTTP/1.1 formatted line at the end. Line
* may contain a delimiting \r\n or just \n. Any characters after
* that will be ignored.
*/
CURLcode Curl_dynhds_h1_cadd_line(struct dynhds *dynhds, const char *line);
/**
- * Add a single header from an HTTP/1.1 formatted line at the end. Line
+ * Add a single header from a HTTP/1.1 formatted line at the end. Line
* may contain a delimiting \r\n or just \n. Any characters after
* that will be ignored.
*/
diff --git a/contrib/libs/curl/lib/easy.c b/contrib/libs/curl/lib/easy.c
index 261445aeef..322d1a41b8 100644
--- a/contrib/libs/curl/lib/easy.c
+++ b/contrib/libs/curl/lib/easy.c
@@ -113,7 +113,6 @@ static curl_simple_lock s_lock = CURL_SIMPLE_LOCK_INIT;
#endif
#if defined(_MSC_VER) && defined(_DLL)
-# pragma warning(push)
# pragma warning(disable:4232) /* MSVC extension, dllimport identity */
#endif
@@ -131,7 +130,7 @@ curl_wcsdup_callback Curl_cwcsdup = Curl_wcsdup;
#endif
#if defined(_MSC_VER) && defined(_DLL)
-# pragma warning(pop)
+# pragma warning(default:4232) /* MSVC extension, dllimport identity */
#endif
#ifdef DEBUGBUILD
@@ -243,7 +242,7 @@ CURLcode curl_global_init_mem(long flags, curl_malloc_callback m,
global_init_lock();
if(initialized) {
- /* Already initialized, do not do it again, but bump the variable anyway to
+ /* Already initialized, don't do it again, but bump the variable anyway to
work like curl_global_init() and require the same amount of cleanup
calls. */
initialized++;
@@ -269,8 +268,7 @@ CURLcode curl_global_init_mem(long flags, curl_malloc_callback m,
/**
* curl_global_cleanup() globally cleanups curl, uses the value of
- * "easy_init_flags" to determine what needs to be cleaned up and what does
- * not.
+ * "easy_init_flags" to determine what needs to be cleaned up and what doesn't.
*/
void curl_global_cleanup(void)
{
@@ -376,7 +374,7 @@ struct Curl_easy *curl_easy_init(void)
return data;
}
-#ifdef DEBUGBUILD
+#ifdef CURLDEBUG
struct socketmonitor {
struct socketmonitor *next; /* the next node in the list or NULL */
@@ -391,22 +389,25 @@ struct events {
int running_handles; /* store the returned number */
};
-#define DEBUG_EV_POLL 0
-
/* events_timer
*
* Callback that gets called with a new value when the timeout should be
* updated.
*/
+
static int events_timer(struct Curl_multi *multi, /* multi handle */
long timeout_ms, /* see above */
void *userp) /* private callback pointer */
{
struct events *ev = userp;
(void)multi;
-#if DEBUG_EV_POLL
- fprintf(stderr, "events_timer: set timeout %ldms\n", timeout_ms);
-#endif
+ if(timeout_ms == -1)
+ /* timeout removed */
+ timeout_ms = 0;
+ else if(timeout_ms == 0)
+ /* timeout is already reached! */
+ timeout_ms = 1; /* trigger asap */
+
ev->ms = timeout_ms;
ev->msbump = TRUE;
return 0;
@@ -460,7 +461,6 @@ static int events_socket(struct Curl_easy *easy, /* easy handle */
struct events *ev = userp;
struct socketmonitor *m;
struct socketmonitor *prev = NULL;
- bool found = FALSE;
#if defined(CURL_DISABLE_VERBOSE_STRINGS)
(void) easy;
@@ -470,7 +470,7 @@ static int events_socket(struct Curl_easy *easy, /* easy handle */
m = ev->list;
while(m) {
if(m->socket.fd == s) {
- found = TRUE;
+
if(what == CURL_POLL_REMOVE) {
struct socketmonitor *nxt = m->next;
/* remove this node from the list of monitored sockets */
@@ -479,14 +479,14 @@ static int events_socket(struct Curl_easy *easy, /* easy handle */
else
ev->list = nxt;
free(m);
- infof(easy, "socket cb: socket %" FMT_SOCKET_T " REMOVED", s);
+ m = nxt;
+ infof(easy, "socket cb: socket %d REMOVED", s);
}
else {
/* The socket 's' is already being monitored, update the activity
mask. Convert from libcurl bitmask to the poll one. */
m->socket.events = socketcb2poll(what);
- infof(easy, "socket cb: socket %" FMT_SOCKET_T
- " UPDATED as %s%s", s,
+ infof(easy, "socket cb: socket %d UPDATED as %s%s", s,
(what&CURL_POLL_IN)?"IN":"",
(what&CURL_POLL_OUT)?"OUT":"");
}
@@ -495,13 +495,12 @@ static int events_socket(struct Curl_easy *easy, /* easy handle */
prev = m;
m = m->next; /* move to next node */
}
-
- if(!found) {
+ if(!m) {
if(what == CURL_POLL_REMOVE) {
- /* should not happen if our logic is correct, but is no drama. */
- DEBUGF(infof(easy, "socket cb: asked to REMOVE socket %"
- FMT_SOCKET_T "but not present!", s));
- DEBUGASSERT(0);
+ /* this happens a bit too often, libcurl fix perhaps? */
+ /* fprintf(stderr,
+ "%s: socket %d asked to be REMOVED but not present!\n",
+ __func__, s); */
}
else {
m = malloc(sizeof(struct socketmonitor));
@@ -511,7 +510,7 @@ static int events_socket(struct Curl_easy *easy, /* easy handle */
m->socket.events = socketcb2poll(what);
m->socket.revents = 0;
ev->list = m;
- infof(easy, "socket cb: socket %" FMT_SOCKET_T " ADDED as %s%s", s,
+ infof(easy, "socket cb: socket %d ADDED as %s%s", s,
(what&CURL_POLL_IN)?"IN":"",
(what&CURL_POLL_OUT)?"OUT":"");
}
@@ -561,15 +560,14 @@ static CURLcode wait_or_timeout(struct Curl_multi *multi, struct events *ev)
int pollrc;
int i;
struct curltime before;
+ struct curltime after;
/* populate the fds[] array */
for(m = ev->list, f = &fds[0]; m; m = m->next) {
f->fd = m->socket.fd;
f->events = m->socket.events;
f->revents = 0;
-#if DEBUG_EV_POLL
- fprintf(stderr, "poll() %d check socket %d\n", numfds, f->fd);
-#endif
+ /* fprintf(stderr, "poll() %d check socket %d\n", numfds, f->fd); */
f++;
numfds++;
}
@@ -577,27 +575,12 @@ static CURLcode wait_or_timeout(struct Curl_multi *multi, struct events *ev)
/* get the time stamp to use to figure out how long poll takes */
before = Curl_now();
- if(numfds) {
- /* wait for activity or timeout */
-#if DEBUG_EV_POLL
- fprintf(stderr, "poll(numfds=%d, timeout=%ldms)\n", numfds, ev->ms);
-#endif
- pollrc = Curl_poll(fds, (unsigned int)numfds, ev->ms);
-#if DEBUG_EV_POLL
- fprintf(stderr, "poll(numfds=%d, timeout=%ldms) -> %d\n",
- numfds, ev->ms, pollrc);
-#endif
- if(pollrc < 0)
- return CURLE_UNRECOVERABLE_POLL;
- }
- else {
-#if DEBUG_EV_POLL
- fprintf(stderr, "poll, but no fds, wait timeout=%ldms\n", ev->ms);
-#endif
- pollrc = 0;
- if(ev->ms > 0)
- Curl_wait_ms(ev->ms);
- }
+ /* wait for activity or timeout */
+ pollrc = Curl_poll(fds, numfds, ev->ms);
+ if(pollrc < 0)
+ return CURLE_UNRECOVERABLE_POLL;
+
+ after = Curl_now();
ev->msbump = FALSE; /* reset here */
@@ -610,37 +593,25 @@ static CURLcode wait_or_timeout(struct Curl_multi *multi, struct events *ev)
}
else {
/* here pollrc is > 0 */
- struct Curl_llist_node *e = Curl_llist_head(&multi->process);
- struct Curl_easy *data;
- DEBUGASSERT(e);
- data = Curl_node_elem(e);
- DEBUGASSERT(data);
/* loop over the monitored sockets to see which ones had activity */
for(i = 0; i< numfds; i++) {
if(fds[i].revents) {
/* socket activity, tell libcurl */
int act = poll2cselect(fds[i].revents); /* convert */
-
- /* sending infof "randomly" to the first easy handle */
- infof(data, "call curl_multi_socket_action(socket "
- "%" FMT_SOCKET_T ")", (curl_socket_t)fds[i].fd);
+ infof(multi->easyp, "call curl_multi_socket_action(socket %d)",
+ fds[i].fd);
mcode = curl_multi_socket_action(multi, fds[i].fd, act,
&ev->running_handles);
}
}
-
- if(!ev->msbump && ev->ms >= 0) {
+ if(!ev->msbump) {
/* If nothing updated the timeout, we decrease it by the spent time.
* If it was updated, it has the new timeout time stored already.
*/
- timediff_t timediff = Curl_timediff(Curl_now(), before);
+ timediff_t timediff = Curl_timediff(after, before);
if(timediff > 0) {
-#if DEBUG_EV_POLL
- fprintf(stderr, "poll timeout %ldms not updated, decrease by "
- "time spent %ldms\n", ev->ms, (long)timediff);
-#endif
if(timediff > ev->ms)
ev->ms = 0;
else
@@ -652,7 +623,7 @@ static CURLcode wait_or_timeout(struct Curl_multi *multi, struct events *ev)
if(mcode)
return CURLE_URL_MALFORMAT;
- /* we do not really care about the "msgs_in_queue" value returned in the
+ /* we don't really care about the "msgs_in_queue" value returned in the
second argument */
msg = curl_multi_info_read(multi, &pollrc);
if(msg) {
@@ -673,15 +644,15 @@ static CURLcode easy_events(struct Curl_multi *multi)
{
/* this struct is made static to allow it to be used after this function
returns and curl_multi_remove_handle() is called */
- static struct events evs = {-1, FALSE, 0, NULL, 0};
+ static struct events evs = {2, FALSE, 0, NULL, 0};
/* if running event-based, do some further multi inits */
events_setup(multi, &evs);
return wait_or_timeout(multi, &evs);
}
-#else /* DEBUGBUILD */
-/* when not built with debug, this function does not exist */
+#else /* CURLDEBUG */
+/* when not built with debug, this function doesn't exist */
#define easy_events(x) CURLE_NOT_BUILT_IN
#endif
@@ -713,9 +684,9 @@ static CURLcode easy_transfer(struct Curl_multi *multi)
/* Make sure to return some kind of error if there was a multi problem */
if(mcode) {
result = (mcode == CURLM_OUT_OF_MEMORY) ? CURLE_OUT_OF_MEMORY :
- /* The other multi errors should never happen, so return
- something suitably generic */
- CURLE_BAD_FUNCTION_ARGUMENT;
+ /* The other multi errors should never happen, so return
+ something suitably generic */
+ CURLE_BAD_FUNCTION_ARGUMENT;
}
return result;
@@ -731,7 +702,7 @@ static CURLcode easy_transfer(struct Curl_multi *multi)
* easy handle, destroys the multi handle and returns the easy handle's return
* code.
*
- * REALITY: it cannot just create and destroy the multi handle that easily. It
+ * REALITY: it can't just create and destroy the multi handle that easily. It
* needs to keep it around since if this easy handle is used again by this
* function, the same multi handle must be reused so that the same pools and
* caches can be used.
@@ -753,8 +724,6 @@ static CURLcode easy_perform(struct Curl_easy *data, bool events)
/* clear this as early as possible */
data->set.errorbuffer[0] = 0;
- data->state.os_errno = 0;
-
if(data->multi) {
failf(data, "easy handle already used in multi handle");
return CURLE_FAILED_INIT;
@@ -768,6 +737,7 @@ static CURLcode easy_perform(struct Curl_easy *data, bool events)
multi = Curl_multi_handle(1, 3, 7);
if(!multi)
return CURLE_OUT_OF_MEMORY;
+ data->multi_easy = multi;
}
if(multi->in_callback)
@@ -776,25 +746,21 @@ static CURLcode easy_perform(struct Curl_easy *data, bool events)
/* Copy the MAXCONNECTS option to the multi handle */
curl_multi_setopt(multi, CURLMOPT_MAXCONNECTS, (long)data->set.maxconnects);
- data->multi_easy = NULL; /* pretend it does not exist */
mcode = curl_multi_add_handle(multi, data);
if(mcode) {
curl_multi_cleanup(multi);
+ data->multi_easy = NULL;
if(mcode == CURLM_OUT_OF_MEMORY)
return CURLE_OUT_OF_MEMORY;
return CURLE_FAILED_INIT;
}
- /* assign this after curl_multi_add_handle() */
- data->multi_easy = multi;
-
- sigpipe_init(&pipe_st);
- sigpipe_apply(data, &pipe_st);
+ sigpipe_ignore(data, &pipe_st);
/* run the transfer */
result = events ? easy_events(multi) : easy_transfer(multi);
- /* ignoring the return code is not nice, but atm we cannot really handle
+ /* ignoring the return code isn't nice, but atm we can't really handle
a failure here, room for future improvement! */
(void)curl_multi_remove_handle(multi, data);
@@ -814,7 +780,7 @@ CURLcode curl_easy_perform(struct Curl_easy *data)
return easy_perform(data, FALSE);
}
-#ifdef DEBUGBUILD
+#ifdef CURLDEBUG
/*
* curl_easy_perform_ev() is the external interface that performs a blocking
* transfer using the event-based API internally.
@@ -938,7 +904,8 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data)
Curl_dyn_init(&outcurl->state.headerb, CURL_MAX_HTTP_HEADER);
- /* the connection pool is setup on demand */
+ /* the connection cache is setup on demand */
+ outcurl->state.conn_cache = NULL;
outcurl->state.lastconnect_id = -1;
outcurl->state.recent_conn_id = -1;
outcurl->id = -1;
@@ -1006,38 +973,6 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data)
}
#endif
-#ifdef CURLRES_ASYNCH
- /* Clone the resolver handle, if present, for the new handle */
- if(Curl_resolver_duphandle(outcurl,
- &outcurl->state.async.resolver,
- data->state.async.resolver))
- goto fail;
-#endif
-
-#ifdef USE_ARES
- {
- CURLcode rc;
-
- rc = Curl_set_dns_servers(outcurl, data->set.str[STRING_DNS_SERVERS]);
- if(rc && rc != CURLE_NOT_BUILT_IN)
- goto fail;
-
- rc = Curl_set_dns_interface(outcurl, data->set.str[STRING_DNS_INTERFACE]);
- if(rc && rc != CURLE_NOT_BUILT_IN)
- goto fail;
-
- rc = Curl_set_dns_local_ip4(outcurl, data->set.str[STRING_DNS_LOCAL_IP4]);
- if(rc && rc != CURLE_NOT_BUILT_IN)
- goto fail;
-
- rc = Curl_set_dns_local_ip6(outcurl, data->set.str[STRING_DNS_LOCAL_IP6]);
- if(rc && rc != CURLE_NOT_BUILT_IN)
- goto fail;
- }
-#endif /* USE_ARES */
-#ifndef CURL_DISABLE_HTTP
- Curl_llist_init(&outcurl->state.httphdrs, NULL);
-#endif
Curl_initinfo(outcurl);
outcurl->magic = CURLEASY_MAGIC_NUMBER;
@@ -1052,6 +987,7 @@ fail:
#ifndef CURL_DISABLE_COOKIES
free(outcurl->cookies);
#endif
+ free(outcurl->state.buffer);
Curl_dyn_free(&outcurl->state.headerb);
Curl_altsvc_cleanup(&outcurl->asi);
Curl_hsts_cleanup(&outcurl->hsts);
@@ -1068,7 +1004,7 @@ fail:
*/
void curl_easy_reset(struct Curl_easy *data)
{
- Curl_req_hard_reset(&data->req, data);
+ Curl_free_request_state(data);
/* zero out UserDefined data: */
Curl_freeset(data);
@@ -1114,10 +1050,9 @@ CURLcode curl_easy_pause(struct Curl_easy *data, int action)
int oldstate;
int newstate;
bool recursive = FALSE;
- bool keep_changed, unpause_read, not_all_paused;
if(!GOOD_EASY_HANDLE(data) || !data->conn)
- /* crazy input, do not continue */
+ /* crazy input, don't continue */
return CURLE_BAD_FUNCTION_ARGUMENT;
if(Curl_is_in_callback(data))
@@ -1130,52 +1065,60 @@ CURLcode curl_easy_pause(struct Curl_easy *data, int action)
((action & CURLPAUSE_RECV)?KEEP_RECV_PAUSE:0) |
((action & CURLPAUSE_SEND)?KEEP_SEND_PAUSE:0);
- keep_changed = ((newstate & (KEEP_RECV_PAUSE| KEEP_SEND_PAUSE)) != oldstate);
- not_all_paused = (newstate & (KEEP_RECV_PAUSE|KEEP_SEND_PAUSE)) !=
- (KEEP_RECV_PAUSE|KEEP_SEND_PAUSE);
- unpause_read = ((k->keepon & ~newstate & KEEP_SEND_PAUSE) &&
- (data->mstate == MSTATE_PERFORMING ||
- data->mstate == MSTATE_RATELIMITING));
- /* Unpausing writes is detected on the next run in
- * transfer.c:Curl_sendrecv(). This is because this may result
- * in a transfer error if the application's callbacks fail */
-
- /* Set the new keepon state, so it takes effect no matter what error
- * may happen afterwards. */
- k->keepon = newstate;
+ if((newstate & (KEEP_RECV_PAUSE| KEEP_SEND_PAUSE)) == oldstate) {
+ /* Not changing any pause state, return */
+ DEBUGF(infof(data, "pause: no change, early return"));
+ return CURLE_OK;
+ }
- /* If not completely pausing both directions now, run again in any case. */
- if(not_all_paused) {
- Curl_expire(data, 0, EXPIRE_RUN_NOW);
- /* reset the too-slow time keeper */
- data->state.keeps_speed.tv_sec = 0;
- /* Simulate socket events on next run for unpaused directions */
- if(!(newstate & KEEP_SEND_PAUSE))
- data->state.select_bits |= CURL_CSELECT_OUT;
- if(!(newstate & KEEP_RECV_PAUSE))
- data->state.select_bits |= CURL_CSELECT_IN;
- /* On changes, tell application to update its timers. */
- if(keep_changed && data->multi) {
- if(Curl_update_timer(data->multi)) {
- result = CURLE_ABORTED_BY_CALLBACK;
- goto out;
- }
- }
+ /* Unpause parts in active mime tree. */
+ if((k->keepon & ~newstate & KEEP_SEND_PAUSE) &&
+ (data->mstate == MSTATE_PERFORMING ||
+ data->mstate == MSTATE_RATELIMITING) &&
+ data->state.fread_func == (curl_read_callback) Curl_mime_read) {
+ Curl_mime_unpause(data->state.in);
}
- if(unpause_read) {
- result = Curl_creader_unpause(data);
+ /* put it back in the keepon */
+ k->keepon = newstate;
+
+ if(!(newstate & KEEP_RECV_PAUSE)) {
+ Curl_conn_ev_data_pause(data, FALSE);
+ result = Curl_client_unpause(data);
if(result)
- goto out;
+ return result;
}
- if(!(k->keepon & KEEP_RECV_PAUSE) && Curl_cwriter_is_paused(data)) {
- Curl_conn_ev_data_pause(data, FALSE);
- result = Curl_cwriter_unpause(data);
+#ifdef USE_HYPER
+ if(!(newstate & KEEP_SEND_PAUSE)) {
+ /* need to wake the send body waker */
+ if(data->hyp.send_body_waker) {
+ hyper_waker_wake(data->hyp.send_body_waker);
+ data->hyp.send_body_waker = NULL;
+ }
+ }
+#endif
+
+ /* if there's no error and we're not pausing both directions, we want
+ to have this handle checked soon */
+ if((newstate & (KEEP_RECV_PAUSE|KEEP_SEND_PAUSE)) !=
+ (KEEP_RECV_PAUSE|KEEP_SEND_PAUSE)) {
+ Curl_expire(data, 0, EXPIRE_RUN_NOW); /* get this handle going again */
+
+ /* reset the too-slow time keeper */
+ data->state.keeps_speed.tv_sec = 0;
+
+ if(!data->state.tempcount)
+ /* if not pausing again, force a recv/send check of this connection as
+ the data might've been read off the socket already */
+ data->conn->cselect_bits = CURL_CSELECT_IN | CURL_CSELECT_OUT;
+ if(data->multi) {
+ if(Curl_update_timer(data->multi))
+ return CURLE_ABORTED_BY_CALLBACK;
+ }
}
-out:
- if(!result && !data->state.done && keep_changed)
+ if(!data->state.done)
/* This transfer may have been moved in or out of the bundle, update the
corresponding socket callback, if used */
result = Curl_updatesocket(data);
@@ -1189,11 +1132,9 @@ out:
}
-static CURLcode easy_connection(struct Curl_easy *data,
+static CURLcode easy_connection(struct Curl_easy *data, curl_socket_t *sfd,
struct connectdata **connp)
{
- curl_socket_t sfd;
-
if(!data)
return CURLE_BAD_FUNCTION_ARGUMENT;
@@ -1203,9 +1144,9 @@ static CURLcode easy_connection(struct Curl_easy *data,
return CURLE_UNSUPPORTED_PROTOCOL;
}
- sfd = Curl_getconnectinfo(data, connp);
+ *sfd = Curl_getconnectinfo(data, connp);
- if(sfd == CURL_SOCKET_BAD) {
+ if(*sfd == CURL_SOCKET_BAD) {
failf(data, "Failed to get recent socket");
return CURLE_UNSUPPORTED_PROTOCOL;
}
@@ -1221,6 +1162,7 @@ static CURLcode easy_connection(struct Curl_easy *data,
CURLcode curl_easy_recv(struct Curl_easy *data, void *buffer, size_t buflen,
size_t *n)
{
+ curl_socket_t sfd;
CURLcode result;
ssize_t n1;
struct connectdata *c;
@@ -1228,7 +1170,7 @@ CURLcode curl_easy_recv(struct Curl_easy *data, void *buffer, size_t buflen,
if(Curl_is_in_callback(data))
return CURLE_RECURSIVE_API_CALL;
- result = easy_connection(data, &c);
+ result = easy_connection(data, &sfd, &c);
if(result)
return result;
@@ -1238,7 +1180,7 @@ CURLcode curl_easy_recv(struct Curl_easy *data, void *buffer, size_t buflen,
Curl_attach_connection(data, c);
*n = 0;
- result = Curl_conn_recv(data, FIRSTSOCKET, buffer, buflen, &n1);
+ result = Curl_read(data, sfd, buffer, buflen, &n1);
if(result)
return result;
@@ -1250,10 +1192,11 @@ CURLcode curl_easy_recv(struct Curl_easy *data, void *buffer, size_t buflen,
#ifdef USE_WEBSOCKETS
CURLcode Curl_connect_only_attach(struct Curl_easy *data)
{
+ curl_socket_t sfd;
CURLcode result;
struct connectdata *c = NULL;
- result = easy_connection(data, &c);
+ result = easy_connection(data, &sfd, &c);
if(result)
return result;
@@ -1272,14 +1215,15 @@ CURLcode Curl_connect_only_attach(struct Curl_easy *data)
* This is the private internal version of curl_easy_send()
*/
CURLcode Curl_senddata(struct Curl_easy *data, const void *buffer,
- size_t buflen, size_t *n)
+ size_t buflen, ssize_t *n)
{
+ curl_socket_t sfd;
CURLcode result;
+ ssize_t n1;
struct connectdata *c = NULL;
SIGPIPE_VARIABLE(pipe_st);
- *n = 0;
- result = easy_connection(data, &c);
+ result = easy_connection(data, &sfd, &c);
if(result)
return result;
@@ -1288,12 +1232,20 @@ CURLcode Curl_senddata(struct Curl_easy *data, const void *buffer,
needs to be reattached */
Curl_attach_connection(data, c);
+ *n = 0;
sigpipe_ignore(data, &pipe_st);
- result = Curl_conn_send(data, FIRSTSOCKET, buffer, buflen, FALSE, n);
+ result = Curl_write(data, sfd, buffer, buflen, &n1);
sigpipe_restore(&pipe_st);
- if(result && result != CURLE_AGAIN)
+ if(n1 == -1)
return CURLE_SEND_ERROR;
+
+ /* detect EAGAIN */
+ if(!result && !n1)
+ return CURLE_AGAIN;
+
+ *n = n1;
+
return result;
}
@@ -1304,17 +1256,58 @@ CURLcode Curl_senddata(struct Curl_easy *data, const void *buffer,
CURLcode curl_easy_send(struct Curl_easy *data, const void *buffer,
size_t buflen, size_t *n)
{
- size_t written = 0;
+ ssize_t written = 0;
CURLcode result;
if(Curl_is_in_callback(data))
return CURLE_RECURSIVE_API_CALL;
result = Curl_senddata(data, buffer, buflen, &written);
- *n = written;
+ *n = (size_t)written;
return result;
}
/*
+ * Wrapper to call functions in Curl_conncache_foreach()
+ *
+ * Returns always 0.
+ */
+static int conn_upkeep(struct Curl_easy *data,
+ struct connectdata *conn,
+ void *param)
+{
+ struct curltime *now = param;
+
+ if(Curl_timediff(*now, conn->keepalive) <= data->set.upkeep_interval_ms)
+ return 0;
+
+ /* briefly attach for action */
+ Curl_attach_connection(data, conn);
+ if(conn->handler->connection_check) {
+ /* Do a protocol-specific keepalive check on the connection. */
+ conn->handler->connection_check(data, conn, CONNCHECK_KEEPALIVE);
+ }
+ else {
+ /* Do the generic action on the FIRSTSOCKE filter chain */
+ Curl_conn_keep_alive(data, conn, FIRSTSOCKET);
+ }
+ Curl_detach_connection(data);
+
+ conn->keepalive = *now;
+ return 0; /* continue iteration */
+}
+
+static CURLcode upkeep(struct conncache *conn_cache, void *data)
+{
+ struct curltime now = Curl_now();
+ /* Loop over every connection and make connection alive. */
+ Curl_conncache_foreach(data,
+ conn_cache,
+ &now,
+ conn_upkeep);
+ return CURLE_OK;
+}
+
+/*
* Performs connection upkeep for the given session handle.
*/
CURLcode curl_easy_upkeep(struct Curl_easy *data)
@@ -1323,9 +1316,12 @@ CURLcode curl_easy_upkeep(struct Curl_easy *data)
if(!GOOD_EASY_HANDLE(data))
return CURLE_BAD_FUNCTION_ARGUMENT;
- if(Curl_is_in_callback(data))
- return CURLE_RECURSIVE_API_CALL;
-
- /* Use the common function to keep connections alive. */
- return Curl_cpool_upkeep(data);
+ if(data->multi_easy) {
+ /* Use the common function to keep connections alive. */
+ return upkeep(&data->multi_easy->conn_cache, data);
+ }
+ else {
+ /* No connections, so just return success */
+ return CURLE_OK;
+ }
}
diff --git a/contrib/libs/curl/lib/easygetopt.c b/contrib/libs/curl/lib/easygetopt.c
index 86833bf6b9..2b8a521cd2 100644
--- a/contrib/libs/curl/lib/easygetopt.c
+++ b/contrib/libs/curl/lib/easygetopt.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* ___|___/|_| ______|
*
- * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) Daniel Stenberg, <daniel.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -42,7 +42,7 @@ static struct curl_easyoption *lookup(const char *name, CURLoption id)
}
else {
if((o->id == id) && !(o->flags & CURLOT_FLAG_ALIAS))
- /* do not match alias options */
+ /* don't match alias options */
return o;
}
o++;
diff --git a/contrib/libs/curl/lib/easyif.h b/contrib/libs/curl/lib/easyif.h
index d77bb98f92..6448952966 100644
--- a/contrib/libs/curl/lib/easyif.h
+++ b/contrib/libs/curl/lib/easyif.h
@@ -28,13 +28,13 @@
* Prototypes for library-wide functions provided by easy.c
*/
CURLcode Curl_senddata(struct Curl_easy *data, const void *buffer,
- size_t buflen, size_t *n);
+ size_t buflen, ssize_t *n);
#ifdef USE_WEBSOCKETS
CURLcode Curl_connect_only_attach(struct Curl_easy *data);
#endif
-#ifdef DEBUGBUILD
+#ifdef CURLDEBUG
CURL_EXTERN CURLcode curl_easy_perform_ev(struct Curl_easy *easy);
#endif
diff --git a/contrib/libs/curl/lib/easyoptions.c b/contrib/libs/curl/lib/easyoptions.c
index 81091c405a..e69c658b0c 100644
--- a/contrib/libs/curl/lib/easyoptions.c
+++ b/contrib/libs/curl/lib/easyoptions.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) Daniel Stenberg, <daniel.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -86,7 +86,6 @@ struct curl_easyoption Curl_easyopts[] = {
{"DOH_SSL_VERIFYPEER", CURLOPT_DOH_SSL_VERIFYPEER, CURLOT_LONG, 0},
{"DOH_SSL_VERIFYSTATUS", CURLOPT_DOH_SSL_VERIFYSTATUS, CURLOT_LONG, 0},
{"DOH_URL", CURLOPT_DOH_URL, CURLOT_STRING, 0},
- {"ECH", CURLOPT_ECH, CURLOT_STRING, 0},
{"EGDSOCKET", CURLOPT_EGDSOCKET, CURLOT_STRING, 0},
{"ENCODING", CURLOPT_ACCEPT_ENCODING, CURLOT_STRING, CURLOT_FLAG_ALIAS},
{"ERRORBUFFER", CURLOPT_ERRORBUFFER, CURLOT_OBJECT, 0},
@@ -275,8 +274,6 @@ struct curl_easyoption Curl_easyopts[] = {
{"SEEKFUNCTION", CURLOPT_SEEKFUNCTION, CURLOT_FUNCTION, 0},
{"SERVER_RESPONSE_TIMEOUT", CURLOPT_SERVER_RESPONSE_TIMEOUT,
CURLOT_LONG, 0},
- {"SERVER_RESPONSE_TIMEOUT_MS", CURLOPT_SERVER_RESPONSE_TIMEOUT_MS,
- CURLOT_LONG, 0},
{"SERVICE_NAME", CURLOPT_SERVICE_NAME, CURLOT_STRING, 0},
{"SHARE", CURLOPT_SHARE, CURLOT_OBJECT, 0},
{"SOCKOPTDATA", CURLOPT_SOCKOPTDATA, CURLOT_CBPTR, 0},
@@ -328,7 +325,6 @@ struct curl_easyoption Curl_easyopts[] = {
CURLOT_LONG, 0},
{"TCP_FASTOPEN", CURLOPT_TCP_FASTOPEN, CURLOT_LONG, 0},
{"TCP_KEEPALIVE", CURLOPT_TCP_KEEPALIVE, CURLOT_LONG, 0},
- {"TCP_KEEPCNT", CURLOPT_TCP_KEEPCNT, CURLOT_LONG, 0},
{"TCP_KEEPIDLE", CURLOPT_TCP_KEEPIDLE, CURLOT_LONG, 0},
{"TCP_KEEPINTVL", CURLOPT_TCP_KEEPINTVL, CURLOT_LONG, 0},
{"TCP_NODELAY", CURLOPT_TCP_NODELAY, CURLOT_LONG, 0},
@@ -377,6 +373,6 @@ struct curl_easyoption Curl_easyopts[] = {
*/
int Curl_easyopts_check(void)
{
- return ((CURLOPT_LASTENTRY%10000) != (326 + 1));
+ return ((CURLOPT_LASTENTRY%10000) != (323 + 1));
}
#endif
diff --git a/contrib/libs/curl/lib/escape.c b/contrib/libs/curl/lib/escape.c
index 9b6edb4433..5af00c3514 100644
--- a/contrib/libs/curl/lib/escape.c
+++ b/contrib/libs/curl/lib/escape.c
@@ -60,18 +60,17 @@ char *curl_easy_escape(struct Curl_easy *data, const char *string,
struct dynbuf d;
(void)data;
- if(!string || (inlength < 0))
+ if(inlength < 0)
return NULL;
+ Curl_dyn_init(&d, CURL_MAX_INPUT_LENGTH * 3);
+
length = (inlength?(size_t)inlength:strlen(string));
if(!length)
return strdup("");
- Curl_dyn_init(&d, length * 3 + 1);
-
while(length--) {
- /* treat the characters unsigned */
- unsigned char in = (unsigned char)*string++;
+ unsigned char in = *string++; /* treat the characters unsigned */
if(ISUNRESERVED(in)) {
/* append this */
@@ -138,7 +137,7 @@ CURLcode Curl_urldecode(const char *string, size_t length,
*ostring = ns;
while(alloc) {
- unsigned char in = (unsigned char)*string;
+ unsigned char in = *string;
if(('%' == in) && (alloc > 2) &&
ISXDIGIT(string[1]) && ISXDIGIT(string[2])) {
/* this is two hexadecimal digits following a '%' */
@@ -158,7 +157,7 @@ CURLcode Curl_urldecode(const char *string, size_t length,
return CURLE_URL_MALFORMAT;
}
- *ns++ = (char)in;
+ *ns++ = in;
}
*ns = 0; /* terminate it */
@@ -181,7 +180,7 @@ char *curl_easy_unescape(struct Curl_easy *data, const char *string,
{
char *str = NULL;
(void)data;
- if(string && (length >= 0)) {
+ if(length >= 0) {
size_t inputlen = (size_t)length;
size_t outputlen;
CURLcode res = Curl_urldecode(string, inputlen, &str, &outputlen,
@@ -223,8 +222,8 @@ void Curl_hexencode(const unsigned char *src, size_t len, /* input length */
while(len-- && (olen >= 3)) {
/* clang-tidy warns on this line without this comment: */
/* NOLINTNEXTLINE(clang-analyzer-core.UndefinedBinaryOperatorResult) */
- *out++ = (unsigned char)hex[(*src & 0xF0)>>4];
- *out++ = (unsigned char)hex[*src & 0x0F];
+ *out++ = hex[(*src & 0xF0)>>4];
+ *out++ = hex[*src & 0x0F];
++src;
olen -= 2;
}
diff --git a/contrib/libs/curl/lib/file.c b/contrib/libs/curl/lib/file.c
index 01af52e72f..c985071376 100644
--- a/contrib/libs/curl/lib/file.c
+++ b/contrib/libs/curl/lib/file.c
@@ -50,14 +50,6 @@
#include <fcntl.h>
#endif
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-
-#ifdef HAVE_DIRENT_H
-#include <dirent.h>
-#endif
-
#include "strtoofft.h"
#include "urldata.h"
#include <curl/curl.h>
@@ -67,7 +59,6 @@
#include "file.h"
#include "speedcheck.h"
#include "getinfo.h"
-#include "multiif.h"
#include "transfer.h"
#include "url.h"
#include "parsedate.h" /* for the week day and month names */
@@ -109,7 +100,7 @@ static CURLcode file_setup_connection(struct Curl_easy *data,
*/
const struct Curl_handler Curl_handler_file = {
- "file", /* scheme */
+ "FILE", /* scheme */
file_setup_connection, /* setup_connection */
file_do, /* do_it */
file_done, /* done */
@@ -122,8 +113,7 @@ const struct Curl_handler Curl_handler_file = {
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
file_disconnect, /* disconnect */
- ZERO_NULL, /* write_resp */
- ZERO_NULL, /* write_resp_hd */
+ ZERO_NULL, /* readwrite */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
0, /* defport */
@@ -147,7 +137,7 @@ static CURLcode file_setup_connection(struct Curl_easy *data,
/*
* file_connect() gets called from Curl_protocol_connect() to allow us to
- * do protocol-specific actions at connect-time. We emulate a
+ * do protocol-specific actions at connect-time. We emulate a
* connect-then-transfer protocol and "connect" to the file here
*/
static CURLcode file_connect(struct Curl_easy *data, bool *done)
@@ -177,18 +167,18 @@ static CURLcode file_connect(struct Curl_easy *data, bool *done)
return result;
#ifdef DOS_FILESYSTEM
- /* If the first character is a slash, and there is
+ /* If the first character is a slash, and there's
something that looks like a drive at the beginning of
- the path, skip the slash. If we remove the initial
+ the path, skip the slash. If we remove the initial
slash in all cases, paths without drive letters end up
- relative to the current directory which is not how
+ relative to the current directory which isn't how
browsers work.
Some browsers accept | instead of : as the drive letter
separator, so we do too.
On other platforms, we need the slash to indicate an
- absolute pathname. On Windows, absolute paths start
+ absolute pathname. On Windows, absolute paths start
with a drive letter.
*/
actual_path = real_path;
@@ -223,7 +213,7 @@ static CURLcode file_connect(struct Curl_easy *data, bool *done)
* A leading slash in an AmigaDOS path denotes the parent
* directory, and hence we block this as it is relative.
* Absolute paths start with 'volumename:', so we check for
- * this first. Failing that, we treat the path as a real Unix
+ * this first. Failing that, we treat the path as a real unix
* path, but only if the application was compiled with -lunix.
*/
fd = -1;
@@ -300,17 +290,16 @@ static CURLcode file_upload(struct Curl_easy *data)
int fd;
int mode;
CURLcode result = CURLE_OK;
- char *xfer_ulbuf;
- size_t xfer_ulblen;
+ char *buf = data->state.buffer;
curl_off_t bytecount = 0;
struct_stat file_stat;
- const char *sendbuf;
- bool eos = FALSE;
+ const char *buf2;
/*
- * Since FILE: does not do the full init, we need to provide some extra
+ * Since FILE: doesn't do the full init, we need to provide some extra
* assignments here.
*/
+ data->req.upload_fromhere = buf;
if(!dir)
return CURLE_FILE_COULDNT_READ_FILE; /* fix: better error code */
@@ -331,7 +320,7 @@ static CURLcode file_upload(struct Curl_easy *data)
fd = open(file->path, mode, data->set.new_file_perms);
if(fd < 0) {
- failf(data, "cannot open %s for writing", file->path);
+ failf(data, "Can't open %s for writing", file->path);
return CURLE_WRITE_ERROR;
}
@@ -343,22 +332,17 @@ static CURLcode file_upload(struct Curl_easy *data)
if(data->state.resume_from < 0) {
if(fstat(fd, &file_stat)) {
close(fd);
- failf(data, "cannot get the size of %s", file->path);
+ failf(data, "Can't get the size of %s", file->path);
return CURLE_WRITE_ERROR;
}
data->state.resume_from = (curl_off_t)file_stat.st_size;
}
- result = Curl_multi_xfer_ulbuf_borrow(data, &xfer_ulbuf, &xfer_ulblen);
- if(result)
- goto out;
-
- while(!result && !eos) {
+ while(!result) {
size_t nread;
ssize_t nwrite;
size_t readcount;
-
- result = Curl_client_read(data, xfer_ulbuf, xfer_ulblen, &readcount, &eos);
+ result = Curl_fillreadbuffer(data, data->set.buffer_size, &readcount);
if(result)
break;
@@ -372,19 +356,19 @@ static CURLcode file_upload(struct Curl_easy *data)
if((curl_off_t)nread <= data->state.resume_from) {
data->state.resume_from -= nread;
nread = 0;
- sendbuf = xfer_ulbuf;
+ buf2 = buf;
}
else {
- sendbuf = xfer_ulbuf + data->state.resume_from;
+ buf2 = buf + data->state.resume_from;
nread -= (size_t)data->state.resume_from;
data->state.resume_from = 0;
}
}
else
- sendbuf = xfer_ulbuf;
+ buf2 = buf;
/* write the data to the target */
- nwrite = write(fd, sendbuf, nread);
+ nwrite = write(fd, buf2, nread);
if((size_t)nwrite != nread) {
result = CURLE_SEND_ERROR;
break;
@@ -402,9 +386,7 @@ static CURLcode file_upload(struct Curl_easy *data)
if(!result && Curl_pgrsUpdate(data))
result = CURLE_ABORTED_BY_CALLBACK;
-out:
close(fd);
- Curl_multi_xfer_ulbuf_release(data, xfer_ulbuf);
return result;
}
@@ -413,13 +395,13 @@ out:
* file_do() is the protocol-specific function for the do-phase, separated
* from the connect-phase above. Other protocols merely setup the transfer in
* the do-phase, to have it done in the main transfer loop but since some
- * platforms we support do not allow select()ing etc on file handles (as
+ * platforms we support don't allow select()ing etc on file handles (as
* opposed to sockets) we instead perform the whole do-operation in this
* function.
*/
static CURLcode file_do(struct Curl_easy *data, bool *done)
{
- /* This implementation ignores the hostname in conformance with
+ /* This implementation ignores the host name in conformance with
RFC 1738. Only local files (reachable via the standard file system)
are supported. This means that files on remotely mounted directories
(via NFS, Samba, NT sharing) can be accessed through a file:// URL
@@ -431,13 +413,14 @@ static CURLcode file_do(struct Curl_easy *data, bool *done)
curl_off_t expected_size = -1;
bool size_known;
bool fstated = FALSE;
+ char *buf = data->state.buffer;
int fd;
struct FILEPROTO *file;
- char *xfer_buf;
- size_t xfer_blen;
*done = TRUE; /* unconditionally */
+ Curl_pgrsStartNow(data);
+
if(data->state.upload)
return file_upload(data);
@@ -455,9 +438,12 @@ static CURLcode file_do(struct Curl_easy *data, bool *done)
fstated = TRUE;
}
- if(fstated && !data->state.range && data->set.timecondition &&
- !Curl_meets_timecondition(data, data->info.filetime))
- return CURLE_OK;
+ if(fstated && !data->state.range && data->set.timecondition) {
+ if(!Curl_meets_timecondition(data, data->info.filetime)) {
+ *done = TRUE;
+ return CURLE_OK;
+ }
+ }
if(fstated) {
time_t filetime;
@@ -465,17 +451,17 @@ static CURLcode file_do(struct Curl_easy *data, bool *done)
const struct tm *tm = &buffer;
char header[80];
int headerlen;
- static const char accept_ranges[]= { "Accept-ranges: bytes\r\n" };
+ char accept_ranges[24]= { "Accept-ranges: bytes\r\n" };
if(expected_size >= 0) {
- headerlen =
- msnprintf(header, sizeof(header), "Content-Length: %" FMT_OFF_T "\r\n",
- expected_size);
+ headerlen = msnprintf(header, sizeof(header),
+ "Content-Length: %" CURL_FORMAT_CURL_OFF_T "\r\n",
+ expected_size);
result = Curl_client_write(data, CLIENTWRITE_HEADER, header, headerlen);
if(result)
return result;
result = Curl_client_write(data, CLIENTWRITE_HEADER,
- accept_ranges, sizeof(accept_ranges) - 1);
+ accept_ranges, strlen(accept_ranges));
if(result != CURLE_OK)
return result;
}
@@ -486,26 +472,23 @@ static CURLcode file_do(struct Curl_easy *data, bool *done)
return result;
/* format: "Tue, 15 Nov 1994 12:45:26 GMT" */
- headerlen =
- msnprintf(header, sizeof(header),
- "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n",
- Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
- tm->tm_mday,
- Curl_month[tm->tm_mon],
- tm->tm_year + 1900,
- tm->tm_hour,
- tm->tm_min,
- tm->tm_sec);
+ headerlen = msnprintf(header, sizeof(header),
+ "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n%s",
+ Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
+ tm->tm_mday,
+ Curl_month[tm->tm_mon],
+ tm->tm_year + 1900,
+ tm->tm_hour,
+ tm->tm_min,
+ tm->tm_sec,
+ data->req.no_body ? "": "\r\n");
result = Curl_client_write(data, CLIENTWRITE_HEADER, header, headerlen);
- if(!result)
- /* end of headers */
- result = Curl_client_write(data, CLIENTWRITE_HEADER, "\r\n", 2);
if(result)
return result;
/* set the file size to make it available post transfer */
Curl_pgrsSetDownloadSize(data, expected_size);
if(data->req.no_body)
- return CURLE_OK;
+ return result;
}
/* Check whether file range has been specified */
@@ -517,7 +500,7 @@ static CURLcode file_do(struct Curl_easy *data, bool *done)
* of the stream if the filesize could be determined */
if(data->state.resume_from < 0) {
if(!fstated) {
- failf(data, "cannot get the size of file.");
+ failf(data, "Can't get the size of file.");
return CURLE_READ_ERROR;
}
data->state.resume_from += (curl_off_t)statbuf.st_size;
@@ -525,7 +508,7 @@ static CURLcode file_do(struct Curl_easy *data, bool *done)
if(data->state.resume_from > 0) {
/* We check explicitly if we have a start offset, because
- * expected_size may be -1 if we do not know how large the file is,
+ * expected_size may be -1 if we don't know how large the file is,
* in which case we should not adjust it. */
if(data->state.resume_from <= expected_size)
expected_size -= data->state.resume_from;
@@ -552,90 +535,48 @@ static CURLcode file_do(struct Curl_easy *data, bool *done)
Curl_pgrsSetDownloadSize(data, expected_size);
if(data->state.resume_from) {
- if(!S_ISDIR(statbuf.st_mode)) {
- if(data->state.resume_from !=
- lseek(fd, data->state.resume_from, SEEK_SET))
- return CURLE_BAD_DOWNLOAD_RESUME;
- }
- else {
+ if(data->state.resume_from !=
+ lseek(fd, data->state.resume_from, SEEK_SET))
return CURLE_BAD_DOWNLOAD_RESUME;
- }
}
- result = Curl_multi_xfer_buf_borrow(data, &xfer_buf, &xfer_blen);
- if(result)
- goto out;
+ Curl_pgrsTime(data, TIMER_STARTTRANSFER);
- if(!S_ISDIR(statbuf.st_mode)) {
- while(!result) {
- ssize_t nread;
- /* Do not fill a whole buffer if we want less than all data */
- size_t bytestoread;
+ while(!result) {
+ ssize_t nread;
+ /* Don't fill a whole buffer if we want less than all data */
+ size_t bytestoread;
- if(size_known) {
- bytestoread = (expected_size < (curl_off_t)(xfer_blen-1)) ?
- curlx_sotouz(expected_size) : (xfer_blen-1);
- }
- else
- bytestoread = xfer_blen-1;
+ if(size_known) {
+ bytestoread = (expected_size < data->set.buffer_size) ?
+ curlx_sotouz(expected_size) : (size_t)data->set.buffer_size;
+ }
+ else
+ bytestoread = data->set.buffer_size-1;
- nread = read(fd, xfer_buf, bytestoread);
+ nread = read(fd, buf, bytestoread);
- if(nread > 0)
- xfer_buf[nread] = 0;
+ if(nread > 0)
+ buf[nread] = 0;
- if(nread <= 0 || (size_known && (expected_size == 0)))
- break;
+ if(nread <= 0 || (size_known && (expected_size == 0)))
+ break;
- if(size_known)
- expected_size -= nread;
+ if(size_known)
+ expected_size -= nread;
- result = Curl_client_write(data, CLIENTWRITE_BODY, xfer_buf, nread);
- if(result)
- goto out;
+ result = Curl_client_write(data, CLIENTWRITE_BODY, buf, nread);
+ if(result)
+ return result;
- if(Curl_pgrsUpdate(data))
- result = CURLE_ABORTED_BY_CALLBACK;
- else
- result = Curl_speedcheck(data, Curl_now());
- if(result)
- goto out;
- }
- }
- else {
-#ifdef HAVE_OPENDIR
- DIR *dir = opendir(file->path);
- struct dirent *entry;
-
- if(!dir) {
- result = CURLE_READ_ERROR;
- goto out;
- }
- else {
- while((entry = readdir(dir))) {
- if(entry->d_name[0] != '.') {
- result = Curl_client_write(data, CLIENTWRITE_BODY,
- entry->d_name, strlen(entry->d_name));
- if(result)
- break;
- result = Curl_client_write(data, CLIENTWRITE_BODY, "\n", 1);
- if(result)
- break;
- }
- }
- closedir(dir);
- }
-#else
- failf(data, "Directory listing not yet implemented on this platform.");
- result = CURLE_READ_ERROR;
-#endif
+ if(Curl_pgrsUpdate(data))
+ result = CURLE_ABORTED_BY_CALLBACK;
+ else
+ result = Curl_speedcheck(data, Curl_now());
}
-
if(Curl_pgrsUpdate(data))
result = CURLE_ABORTED_BY_CALLBACK;
-out:
- Curl_multi_xfer_buf_release(data, xfer_buf);
return result;
}
diff --git a/contrib/libs/curl/lib/fileinfo.h b/contrib/libs/curl/lib/fileinfo.h
index 0b3f56d9d4..ce009da06d 100644
--- a/contrib/libs/curl/lib/fileinfo.h
+++ b/contrib/libs/curl/lib/fileinfo.h
@@ -30,7 +30,7 @@
struct fileinfo {
struct curl_fileinfo info;
- struct Curl_llist_node list;
+ struct Curl_llist_element list;
struct dynbuf buf;
};
diff --git a/contrib/libs/curl/lib/fopen.c b/contrib/libs/curl/lib/fopen.c
index 7373e08831..851279fe12 100644
--- a/contrib/libs/curl/lib/fopen.c
+++ b/contrib/libs/curl/lib/fopen.c
@@ -42,12 +42,12 @@
/*
The dirslash() function breaks a null-terminated pathname string into
directory and filename components then returns the directory component up
- to, *AND INCLUDING*, a final '/'. If there is no directory in the path,
+ to, *AND INCLUDING*, a final '/'. If there is no directory in the path,
this instead returns a "" string.
This function returns a pointer to malloc'ed memory.
- The input path to this function is expected to have a filename part.
+ The input path to this function is expected to have a file name part.
*/
#ifdef _WIN32
@@ -88,7 +88,7 @@ static char *dirslash(const char *path)
* Curl_fopen() opens a file for writing with a temp name, to be renamed
* to the final name when completed. If there is an existing file using this
* name at the time of the open, this function will clone the mode from that
- * file. if 'tempname' is non-NULL, it needs a rename after the file is
+ * file. if 'tempname' is non-NULL, it needs a rename after the file is
* written.
*/
CURLcode Curl_fopen(struct Curl_easy *data, const char *filename,
@@ -117,7 +117,7 @@ CURLcode Curl_fopen(struct Curl_easy *data, const char *filename,
dir = dirslash(filename);
if(dir) {
- /* The temp filename should not end up too long for the target file
+ /* The temp file name should not end up too long for the target file
system */
tempstore = aprintf("%s%s.tmp", dir, randbuf);
free(dir);
@@ -129,12 +129,7 @@ CURLcode Curl_fopen(struct Curl_easy *data, const char *filename,
}
result = CURLE_WRITE_ERROR;
-#if (defined(ANDROID) || defined(__ANDROID__)) && \
- (defined(__i386__) || defined(__arm__))
- fd = open(tempstore, O_WRONLY | O_CREAT | O_EXCL, (mode_t)(0600|sb.st_mode));
-#else
fd = open(tempstore, O_WRONLY | O_CREAT | O_EXCL, 0600|sb.st_mode);
-#endif
if(fd == -1)
goto fail;
diff --git a/contrib/libs/curl/lib/formdata.c b/contrib/libs/curl/lib/formdata.c
index c260d442bd..05dc9b53d6 100644
--- a/contrib/libs/curl/lib/formdata.c
+++ b/contrib/libs/curl/lib/formdata.c
@@ -216,8 +216,8 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost,
struct curl_forms *forms = NULL;
char *array_value = NULL; /* value read from an array */
- /* This is a state variable, that if TRUE means that we are parsing an
- array that we got passed to us. If FALSE we are parsing the input
+ /* This is a state variable, that if TRUE means that we're parsing an
+ array that we got passed to us. If FALSE we're parsing the input
va_list arguments. */
bool array_state = FALSE;
@@ -260,7 +260,7 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost,
switch(option) {
case CURLFORM_ARRAY:
if(array_state)
- /* we do not support an array from within an array */
+ /* we don't support an array from within an array */
return_value = CURL_FORMADD_ILLEGAL_ARRAY;
else {
forms = va_arg(params, struct curl_forms *);
@@ -277,7 +277,7 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost,
case CURLFORM_PTRNAME:
current_form->flags |= HTTPPOST_PTRNAME; /* fall through */
- FALLTHROUGH();
+ /* FALLTHROUGH */
case CURLFORM_COPYNAME:
if(current_form->name)
return_value = CURL_FORMADD_OPTION_TWICE;
@@ -303,7 +303,7 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost,
*/
case CURLFORM_PTRCONTENTS:
current_form->flags |= HTTPPOST_PTRCONTENTS;
- FALLTHROUGH();
+ /* FALLTHROUGH */
case CURLFORM_COPYCONTENTS:
if(current_form->value)
return_value = CURL_FORMADD_OPTION_TWICE;
@@ -327,7 +327,7 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost,
array_state?(curl_off_t)(size_t)array_value:va_arg(params, curl_off_t);
break;
- /* Get contents from a given filename */
+ /* Get contents from a given file name */
case CURLFORM_FILECONTENT:
if(current_form->flags & (HTTPPOST_PTRCONTENTS|HTTPPOST_READFILE))
return_value = CURL_FORMADD_OPTION_TWICE;
@@ -429,7 +429,7 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost,
array_state?array_value:va_arg(params, char *);
if(userp) {
current_form->userp = userp;
- current_form->value = userp; /* this is not strictly true but we
+ current_form->value = userp; /* this isn't strictly true but we
derive a value from this later on
and we need this non-NULL to be
accepted as a fine form part */
@@ -599,11 +599,11 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost,
}
if(!(form->flags & HTTPPOST_PTRNAME) &&
(form == first_form) ) {
- /* Note that there is small risk that form->name is NULL here if the
+ /* Note that there's small risk that form->name is NULL here if the
app passed in a bad combo, so we better check for that first. */
if(form->name) {
/* copy name (without strdup; possibly not null-terminated) */
- form->name = Curl_memdup0(form->name, form->namelength?
+ form->name = Curl_strndup(form->name, form->namelength?
form->namelength:
strlen(form->name));
}
@@ -764,7 +764,7 @@ void curl_formfree(struct curl_httppost *form)
)
free(form->contents); /* free the contents */
free(form->contenttype); /* free the content type */
- free(form->showfilename); /* free the faked filename */
+ free(form->showfilename); /* free the faked file name */
free(form); /* free the struct */
form = next;
} while(form); /* continue */
@@ -779,9 +779,11 @@ static CURLcode setname(curl_mimepart *part, const char *name, size_t len)
if(!name || !len)
return curl_mime_name(part, name);
- zname = Curl_memdup0(name, len);
+ zname = malloc(len + 1);
if(!zname)
return CURLE_OUT_OF_MEMORY;
+ memcpy(zname, name, len);
+ zname[len] = '\0';
res = curl_mime_name(part, zname);
free(zname);
return res;
@@ -790,10 +792,10 @@ static CURLcode setname(curl_mimepart *part, const char *name, size_t len)
/* wrap call to fseeko so it matches the calling convention of callback */
static int fseeko_wrapper(void *stream, curl_off_t offset, int whence)
{
-#if defined(HAVE__FSEEKI64)
- return _fseeki64(stream, (__int64)offset, whence);
-#elif defined(HAVE_FSEEKO) && defined(HAVE_DECL_FSEEKO)
+#if defined(HAVE_FSEEKO) && defined(HAVE_DECL_FSEEKO)
return fseeko(stream, (off_t)offset, whence);
+#elif defined(HAVE__FSEEKI64)
+ return _fseeki64(stream, (__int64)offset, whence);
#else
if(offset > LONG_MAX)
return -1;
@@ -880,10 +882,10 @@ CURLcode Curl_getformdata(struct Curl_easy *data,
if(post->flags & (HTTPPOST_FILENAME | HTTPPOST_READFILE)) {
if(!strcmp(file->contents, "-")) {
- /* There are a few cases where the code below will not work; in
+ /* There are a few cases where the code below won't work; in
particular, freopen(stdin) by the caller is not guaranteed
to result as expected. This feature has been kept for backward
- compatibility: use of "-" pseudo filename should be avoided. */
+ compatibility: use of "-" pseudo file name should be avoided. */
result = curl_mime_data_cb(part, (curl_off_t) -1,
(curl_read_callback) fread,
fseeko_wrapper,
@@ -915,7 +917,7 @@ CURLcode Curl_getformdata(struct Curl_easy *data,
}
}
- /* Set fake filename. */
+ /* Set fake file name. */
if(!result && post->showfilename)
if(post->more || (post->flags & (HTTPPOST_FILENAME | HTTPPOST_BUFFER |
HTTPPOST_CALLBACK)))
diff --git a/contrib/libs/curl/lib/formdata.h b/contrib/libs/curl/lib/formdata.h
index 2ed96ffcf6..af466249fd 100644
--- a/contrib/libs/curl/lib/formdata.h
+++ b/contrib/libs/curl/lib/formdata.h
@@ -38,8 +38,8 @@ struct FormInfo {
long flags;
char *buffer; /* pointer to existing buffer used for file upload */
size_t bufferlength;
- char *showfilename; /* The filename to show. If not set, the actual
- filename will be used */
+ char *showfilename; /* The file name to show. If not set, the actual
+ file name will be used */
char *userp; /* pointer for the read callback */
struct curl_slist *contentheader;
struct FormInfo *more;
diff --git a/contrib/libs/curl/lib/ftp.c b/contrib/libs/curl/lib/ftp.c
index 02477fd1d6..a8dcedf531 100644
--- a/contrib/libs/curl/lib/ftp.c
+++ b/contrib/libs/curl/lib/ftp.c
@@ -72,7 +72,6 @@
#include "warnless.h"
#include "http_proxy.h"
#include "socks.h"
-#include "strdup.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
#include "curl_memory.h"
@@ -85,99 +84,21 @@
#define INET_ADDRSTRLEN 16
#endif
-/* macro to check for a three-digit ftp status code at the start of the
- given string */
-#define STATUSCODE(line) (ISDIGIT(line[0]) && ISDIGIT(line[1]) && \
- ISDIGIT(line[2]))
-
-/* macro to check for the last line in an FTP server response */
-#define LASTLINE(line) (STATUSCODE(line) && (' ' == line[3]))
-
#ifdef CURL_DISABLE_VERBOSE_STRINGS
#define ftp_pasv_verbose(a,b,c,d) Curl_nop_stmt
-#define FTP_CSTATE(c) ""
-#define FTP_DSTATE(d) ""
-#else /* CURL_DISABLE_VERBOSE_STRINGS */
- /* for tracing purposes */
-static const char * const ftp_state_names[]={
- "STOP",
- "WAIT220",
- "AUTH",
- "USER",
- "PASS",
- "ACCT",
- "PBSZ",
- "PROT",
- "CCC",
- "PWD",
- "SYST",
- "NAMEFMT",
- "QUOTE",
- "RETR_PREQUOTE",
- "STOR_PREQUOTE",
- "POSTQUOTE",
- "CWD",
- "MKD",
- "MDTM",
- "TYPE",
- "LIST_TYPE",
- "RETR_TYPE",
- "STOR_TYPE",
- "SIZE",
- "RETR_SIZE",
- "STOR_SIZE",
- "REST",
- "RETR_REST",
- "PORT",
- "PRET",
- "PASV",
- "LIST",
- "RETR",
- "STOR",
- "QUIT"
-};
-#define FTP_CSTATE(c) ((c)? ftp_state_names[(c)->proto.ftpc.state] : "???")
-#define FTP_DSTATE(d) (((d) && (d)->conn)? \
- ftp_state_names[(d)->conn->proto.ftpc.state] : "???")
-
-#endif /* !CURL_DISABLE_VERBOSE_STRINGS */
-
-/* This is the ONLY way to change FTP state! */
-static void _ftp_state(struct Curl_easy *data,
- ftpstate newstate
-#ifdef DEBUGBUILD
- , int lineno
-#endif
- )
-{
- struct connectdata *conn = data->conn;
- struct ftp_conn *ftpc = &conn->proto.ftpc;
-
-#if defined(CURL_DISABLE_VERBOSE_STRINGS)
-#ifdef DEBUGBUILD
- (void)lineno;
-#endif
-#else /* CURL_DISABLE_VERBOSE_STRINGS */
- if(ftpc->state != newstate)
-#ifdef DEBUGBUILD
- CURL_TRC_FTP(data, "[%s] -> [%s] (line %d)", FTP_DSTATE(data),
- ftp_state_names[newstate], lineno);
-#else
- CURL_TRC_FTP(data, "[%s] -> [%s]", FTP_DSTATE(data),
- ftp_state_names[newstate]);
#endif
-#endif /* !CURL_DISABLE_VERBOSE_STRINGS */
-
- ftpc->state = newstate;
-}
-
/* Local API functions */
#ifndef DEBUGBUILD
+static void _ftp_state(struct Curl_easy *data,
+ ftpstate newstate);
#define ftp_state(x,y) _ftp_state(x,y)
-#else /* !DEBUGBUILD */
+#else
+static void _ftp_state(struct Curl_easy *data,
+ ftpstate newstate,
+ int lineno);
#define ftp_state(x,y) _ftp_state(x,y,__LINE__)
-#endif /* DEBUGBUILD */
+#endif
static CURLcode ftp_sendquote(struct Curl_easy *data,
struct connectdata *conn,
@@ -188,7 +109,7 @@ static CURLcode ftp_regular_transfer(struct Curl_easy *data, bool *done);
#ifndef CURL_DISABLE_VERBOSE_STRINGS
static void ftp_pasv_verbose(struct Curl_easy *data,
struct Curl_addrinfo *ai,
- char *newhost, /* ASCII version */
+ char *newhost, /* ascii version */
int port);
#endif
static CURLcode ftp_state_prepare_transfer(struct Curl_easy *data);
@@ -221,7 +142,7 @@ static CURLcode wc_statemach(struct Curl_easy *data);
static void wc_data_dtor(void *ptr);
static CURLcode ftp_state_retr(struct Curl_easy *data, curl_off_t filesize);
static CURLcode ftp_readresp(struct Curl_easy *data,
- int sockindex,
+ curl_socket_t sockfd,
struct pingpong *pp,
int *ftpcode,
size_t *size);
@@ -233,7 +154,7 @@ static CURLcode ftp_dophase_done(struct Curl_easy *data,
*/
const struct Curl_handler Curl_handler_ftp = {
- "ftp", /* scheme */
+ "FTP", /* scheme */
ftp_setup_connection, /* setup_connection */
ftp_do, /* do_it */
ftp_done, /* done */
@@ -246,8 +167,7 @@ const struct Curl_handler Curl_handler_ftp = {
ftp_domore_getsock, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
ftp_disconnect, /* disconnect */
- ZERO_NULL, /* write_resp */
- ZERO_NULL, /* write_resp_hd */
+ ZERO_NULL, /* readwrite */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_FTP, /* defport */
@@ -265,7 +185,7 @@ const struct Curl_handler Curl_handler_ftp = {
*/
const struct Curl_handler Curl_handler_ftps = {
- "ftps", /* scheme */
+ "FTPS", /* scheme */
ftp_setup_connection, /* setup_connection */
ftp_do, /* do_it */
ftp_done, /* done */
@@ -278,8 +198,7 @@ const struct Curl_handler Curl_handler_ftps = {
ftp_domore_getsock, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
ftp_disconnect, /* disconnect */
- ZERO_NULL, /* write_resp */
- ZERO_NULL, /* write_resp_hd */
+ ZERO_NULL, /* readwrite */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_FTPS, /* defport */
@@ -290,11 +209,11 @@ const struct Curl_handler Curl_handler_ftps = {
};
#endif
-static void close_secondarysocket(struct Curl_easy *data)
+static void close_secondarysocket(struct Curl_easy *data,
+ struct connectdata *conn)
{
- CURL_TRC_FTP(data, "[%s] closing DATA connection", FTP_DSTATE(data));
Curl_conn_close(data, SECONDARYSOCKET);
- Curl_conn_cf_discard_all(data, data->conn, SECONDARYSOCKET);
+ Curl_conn_cf_discard_all(data, conn, SECONDARYSOCKET);
}
/*
@@ -327,96 +246,6 @@ static void freedirs(struct ftp_conn *ftpc)
Curl_safefree(ftpc->newhost);
}
-#ifdef CURL_PREFER_LF_LINEENDS
-/***********************************************************************
- *
- * Lineend Conversions
- * On ASCII transfers, e.g. directory listings, we might get lines
- * ending in '\r\n' and we prefer just '\n'.
- * We might also get a lonely '\r' which we convert into a '\n'.
- */
-struct ftp_cw_lc_ctx {
- struct Curl_cwriter super;
- bool newline_pending;
-};
-
-static CURLcode ftp_cw_lc_write(struct Curl_easy *data,
- struct Curl_cwriter *writer, int type,
- const char *buf, size_t blen)
-{
- static const char nl = '\n';
- struct ftp_cw_lc_ctx *ctx = writer->ctx;
-
- if(!(type & CLIENTWRITE_BODY) ||
- data->conn->proto.ftpc.transfertype != 'A')
- return Curl_cwriter_write(data, writer->next, type, buf, blen);
-
- /* ASCII mode BODY data, convert lineends */
- while(blen) {
- /* do not pass EOS when writing parts */
- int chunk_type = (type & ~CLIENTWRITE_EOS);
- const char *cp;
- size_t chunk_len;
- CURLcode result;
-
- if(ctx->newline_pending) {
- if(buf[0] != '\n') {
- /* previous chunk ended in '\r' and we do not see a '\n' in this one,
- * need to write a newline. */
- result = Curl_cwriter_write(data, writer->next, chunk_type, &nl, 1);
- if(result)
- return result;
- }
- /* either we just wrote the newline or it is part of the next
- * chunk of bytes we write. */
- ctx->newline_pending = FALSE;
- }
-
- cp = memchr(buf, '\r', blen);
- if(!cp)
- break;
-
- /* write the bytes before the '\r', excluding the '\r' */
- chunk_len = cp - buf;
- if(chunk_len) {
- result = Curl_cwriter_write(data, writer->next, chunk_type,
- buf, chunk_len);
- if(result)
- return result;
- }
- /* skip the '\r', we now have a newline pending */
- buf = cp + 1;
- blen = blen - chunk_len - 1;
- ctx->newline_pending = TRUE;
- }
-
- /* Any remaining data does not contain a '\r' */
- if(blen) {
- DEBUGASSERT(!ctx->newline_pending);
- return Curl_cwriter_write(data, writer->next, type, buf, blen);
- }
- else if(type & CLIENTWRITE_EOS) {
- /* EndOfStream, if we have a trailing cr, now is the time to write it */
- if(ctx->newline_pending) {
- ctx->newline_pending = FALSE;
- return Curl_cwriter_write(data, writer->next, type, &nl, 1);
- }
- /* Always pass on the EOS type indicator */
- return Curl_cwriter_write(data, writer->next, type, buf, 0);
- }
- return CURLE_OK;
-}
-
-static const struct Curl_cwtype ftp_cw_lc = {
- "ftp-lineconv",
- NULL,
- Curl_cwriter_def_init,
- ftp_cw_lc_write,
- Curl_cwriter_def_close,
- sizeof(struct ftp_cw_lc_ctx)
-};
-
-#endif /* CURL_PREFER_LF_LINEENDS */
/***********************************************************************
*
* AcceptServerConnect()
@@ -430,7 +259,7 @@ static CURLcode AcceptServerConnect(struct Curl_easy *data)
struct connectdata *conn = data->conn;
curl_socket_t sock = conn->sock[SECONDARYSOCKET];
curl_socket_t s = CURL_SOCKET_BAD;
-#ifdef USE_IPV6
+#ifdef ENABLE_IPV6
struct Curl_sockaddr_storage add;
#else
struct sockaddr_in add;
@@ -456,10 +285,8 @@ static CURLcode AcceptServerConnect(struct Curl_easy *data)
(void)curlx_nonblock(s, TRUE); /* enable non-blocking */
/* Replace any filter on SECONDARY with one listening on this socket */
result = Curl_conn_tcp_accepted_set(data, conn, SECONDARYSOCKET, &s);
- if(result) {
- sclose(s);
+ if(result)
return result;
- }
if(data->set.fsockopt) {
int error = 0;
@@ -472,7 +299,7 @@ static CURLcode AcceptServerConnect(struct Curl_easy *data)
Curl_set_in_callback(data, false);
if(error) {
- close_secondarysocket(data);
+ close_secondarysocket(data, conn);
return CURLE_ABORTED_BY_CALLBACK;
}
}
@@ -535,11 +362,10 @@ static CURLcode ReceivedServerConnect(struct Curl_easy *data, bool *received)
curl_socket_t data_sock = conn->sock[SECONDARYSOCKET];
struct ftp_conn *ftpc = &conn->proto.ftpc;
struct pingpong *pp = &ftpc->pp;
- int socketstate = 0;
+ int result;
timediff_t timeout_ms;
ssize_t nread;
int ftpcode;
- bool response = FALSE;
*received = FALSE;
@@ -552,21 +378,17 @@ static CURLcode ReceivedServerConnect(struct Curl_easy *data, bool *received)
}
/* First check whether there is a cached response from server */
- if(Curl_dyn_len(&pp->recvbuf) && (*Curl_dyn_ptr(&pp->recvbuf) > '3')) {
+ if(pp->cache_size && pp->cache && pp->cache[0] > '3') {
/* Data connection could not be established, let's return */
infof(data, "There is negative response in cache while serv connect");
(void)Curl_GetFTPResponse(data, &nread, &ftpcode);
return CURLE_FTP_ACCEPT_FAILED;
}
- if(pp->overflow)
- /* there is pending control data still in the buffer to read */
- response = TRUE;
- else
- socketstate = Curl_socket_check(ctrl_sock, data_sock, CURL_SOCKET_BAD, 0);
+ result = Curl_socket_check(ctrl_sock, data_sock, CURL_SOCKET_BAD, 0);
/* see if the connection request is already here */
- switch(socketstate) {
+ switch(result) {
case -1: /* error */
/* let's die here */
failf(data, "Error while waiting for server connect");
@@ -574,47 +396,23 @@ static CURLcode ReceivedServerConnect(struct Curl_easy *data, bool *received)
case 0: /* Server connect is not received yet */
break; /* loop */
default:
- if(socketstate & CURL_CSELECT_IN2) {
+
+ if(result & CURL_CSELECT_IN2) {
infof(data, "Ready to accept data connection from server");
*received = TRUE;
}
- else if(socketstate & CURL_CSELECT_IN)
- response = TRUE;
- break;
- }
- if(response) {
- infof(data, "Ctrl conn has data while waiting for data conn");
- if(pp->overflow > 3) {
- char *r = Curl_dyn_ptr(&pp->recvbuf);
-
- DEBUGASSERT((pp->overflow + pp->nfinal) <=
- Curl_dyn_len(&pp->recvbuf));
- /* move over the most recently handled response line */
- r += pp->nfinal;
-
- if(LASTLINE(r)) {
- int status = curlx_sltosi(strtol(r, NULL, 10));
- if(status == 226) {
- /* funny timing situation where we get the final message on the
- control connection before traffic on the data connection has been
- noticed. Leave the 226 in there and use this as a trigger to read
- the data socket. */
- infof(data, "Got 226 before data activity");
- *received = TRUE;
- return CURLE_OK;
- }
- }
- }
-
- (void)Curl_GetFTPResponse(data, &nread, &ftpcode);
+ else if(result & CURL_CSELECT_IN) {
+ infof(data, "Ctrl conn has data while waiting for data conn");
+ (void)Curl_GetFTPResponse(data, &nread, &ftpcode);
- infof(data, "FTP code: %03d", ftpcode);
+ if(ftpcode/100 > 3)
+ return CURLE_FTP_ACCEPT_FAILED;
- if(ftpcode/100 > 3)
- return CURLE_FTP_ACCEPT_FAILED;
+ return CURLE_WEIRD_SERVER_REPLY;
+ }
- return CURLE_WEIRD_SERVER_REPLY;
- }
+ break;
+ } /* switch() */
return CURLE_OK;
}
@@ -634,7 +432,7 @@ static CURLcode InitiateTransfer(struct Curl_easy *data)
struct connectdata *conn = data->conn;
bool connected;
- CURL_TRC_FTP(data, "InitiateTransfer()");
+ DEBUGF(infof(data, "ftp InitiateTransfer()"));
if(conn->bits.ftp_use_data_ssl && data->set.ftp_use_port &&
!Curl_conn_is_ssl(conn, SECONDARYSOCKET)) {
result = Curl_ssl_cfilter_add(data, conn, SECONDARYSOCKET);
@@ -646,19 +444,19 @@ static CURLcode InitiateTransfer(struct Curl_easy *data)
return result;
if(conn->proto.ftpc.state_saved == FTP_STOR) {
- /* When we know we are uploading a specified file, we can get the file
+ /* When we know we're uploading a specified file, we can get the file
size prior to the actual upload. */
Curl_pgrsSetUploadSize(data, data->state.infilesize);
/* set the SO_SNDBUF for the secondary socket for those who need it */
- Curl_sndbuf_init(conn->sock[SECONDARYSOCKET]);
+ Curl_sndbufset(conn->sock[SECONDARYSOCKET]);
- Curl_xfer_setup2(data, CURL_XFER_SEND, -1, TRUE);
+ Curl_setup_transfer(data, -1, -1, FALSE, SECONDARYSOCKET);
}
else {
/* FTP download: */
- Curl_xfer_setup2(data, CURL_XFER_RECV,
- conn->proto.ftpc.retr_size_saved, TRUE);
+ Curl_setup_transfer(data, SECONDARYSOCKET,
+ conn->proto.ftpc.retr_size_saved, FALSE, -1);
}
conn->proto.ftpc.pp.pending_resp = TRUE; /* expect server response */
@@ -671,7 +469,7 @@ static CURLcode InitiateTransfer(struct Curl_easy *data)
*
* AllowServerConnect()
*
- * When we have issue the PORT command, we have told the server to connect to
+ * When we've issue the PORT command, we have told the server to connect to
* us. This function checks whether data connection is established if so it is
* accepted.
*
@@ -717,10 +515,18 @@ static CURLcode AllowServerConnect(struct Curl_easy *data, bool *connected)
}
out:
- CURL_TRC_FTP(data, "AllowServerConnect() -> %d", result);
+ DEBUGF(infof(data, "ftp AllowServerConnect() -> %d", result));
return result;
}
+/* macro to check for a three-digit ftp status code at the start of the
+ given string */
+#define STATUSCODE(line) (ISDIGIT(line[0]) && ISDIGIT(line[1]) && \
+ ISDIGIT(line[2]))
+
+/* macro to check for the last line in an FTP server response */
+#define LASTLINE(line) (STATUSCODE(line) && (' ' == line[3]))
+
static bool ftp_endofresp(struct Curl_easy *data, struct connectdata *conn,
char *line, size_t len, int *code)
{
@@ -736,18 +542,18 @@ static bool ftp_endofresp(struct Curl_easy *data, struct connectdata *conn,
}
static CURLcode ftp_readresp(struct Curl_easy *data,
- int sockindex,
+ curl_socket_t sockfd,
struct pingpong *pp,
int *ftpcode, /* return the ftp-code if done */
size_t *size) /* size of the response */
{
int code;
- CURLcode result = Curl_pp_readresp(data, sockindex, pp, &code, size);
+ CURLcode result = Curl_pp_readresp(data, sockfd, pp, &code, size);
#ifdef HAVE_GSSAPI
{
struct connectdata *conn = data->conn;
- char * const buf = Curl_dyn_ptr(&data->conn->proto.ftpc.pp.recvbuf);
+ char * const buf = data->state.buffer;
/* handle the security-oriented responses 6xx ***/
switch(code) {
@@ -803,7 +609,7 @@ CURLcode Curl_GetFTPResponse(struct Curl_easy *data,
{
/*
* We cannot read just one byte per read() and then go back to select() as
- * the OpenSSL read() does not grok that properly.
+ * the OpenSSL read() doesn't grok that properly.
*
* Alas, read as much as possible, split up into lines, use the ending
* line in a response or continue reading. */
@@ -817,8 +623,6 @@ CURLcode Curl_GetFTPResponse(struct Curl_easy *data,
int cache_skip = 0;
int value_to_be_ignored = 0;
- CURL_TRC_FTP(data, "getFTPResponse start");
-
if(ftpcode)
*ftpcode = 0; /* 0 for errors */
else
@@ -848,48 +652,42 @@ CURLcode Curl_GetFTPResponse(struct Curl_easy *data,
*
* A caution here is that the ftp_readresp() function has a cache that may
* contain pieces of a response from the previous invoke and we need to
- * make sure we do not just wait for input while there is unhandled data in
+ * make sure we don't just wait for input while there is unhandled data in
* that cache. But also, if the cache is there, we call ftp_readresp() and
- * the cache was not good enough to continue we must not just busy-loop
+ * the cache wasn't good enough to continue we must not just busy-loop
* around this function.
*
*/
- if(Curl_dyn_len(&pp->recvbuf) && (cache_skip < 2)) {
+ if(pp->cache && (cache_skip < 2)) {
/*
- * There is a cache left since before. We then skipping the wait for
+ * There's a cache left since before. We then skipping the wait for
* socket action, unless this is the same cache like the previous round
* as then the cache was deemed not enough to act on and we then need to
* wait for more data anyway.
*/
}
else if(!Curl_conn_data_pending(data, FIRSTSOCKET)) {
- curl_socket_t wsock = Curl_pp_needs_flush(data, pp)?
- sockfd : CURL_SOCKET_BAD;
- int ev = Curl_socket_check(sockfd, CURL_SOCKET_BAD, wsock, interval_ms);
- if(ev < 0) {
+ switch(SOCKET_READABLE(sockfd, interval_ms)) {
+ case -1: /* select() error, stop reading */
failf(data, "FTP response aborted due to select/poll error: %d",
SOCKERRNO);
return CURLE_RECV_ERROR;
- }
- else if(ev == 0) {
+
+ case 0: /* timeout */
if(Curl_pgrsUpdate(data))
return CURLE_ABORTED_BY_CALLBACK;
continue; /* just continue in our loop for the timeout duration */
- }
- }
- if(Curl_pp_needs_flush(data, pp)) {
- result = Curl_pp_flushsend(data, pp);
- if(result)
+ default: /* for clarity */
break;
+ }
}
-
- result = ftp_readresp(data, FIRSTSOCKET, pp, ftpcode, &nread);
+ result = ftp_readresp(data, sockfd, pp, ftpcode, &nread);
if(result)
break;
- if(!nread && Curl_dyn_len(&pp->recvbuf))
+ if(!nread && pp->cache)
/* bump cache skip counter as on repeated skips we must wait for more
data */
cache_skip++;
@@ -900,15 +698,80 @@ CURLcode Curl_GetFTPResponse(struct Curl_easy *data,
*nreadp += nread;
- } /* while there is buffer left and loop is requested */
+ } /* while there's buffer left and loop is requested */
pp->pending_resp = FALSE;
- CURL_TRC_FTP(data, "getFTPResponse -> result=%d, nread=%zd, ftpcode=%d",
- result, *nreadp, *ftpcode);
return result;
}
+#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
+ /* for debug purposes */
+static const char * const ftp_state_names[]={
+ "STOP",
+ "WAIT220",
+ "AUTH",
+ "USER",
+ "PASS",
+ "ACCT",
+ "PBSZ",
+ "PROT",
+ "CCC",
+ "PWD",
+ "SYST",
+ "NAMEFMT",
+ "QUOTE",
+ "RETR_PREQUOTE",
+ "STOR_PREQUOTE",
+ "POSTQUOTE",
+ "CWD",
+ "MKD",
+ "MDTM",
+ "TYPE",
+ "LIST_TYPE",
+ "RETR_TYPE",
+ "STOR_TYPE",
+ "SIZE",
+ "RETR_SIZE",
+ "STOR_SIZE",
+ "REST",
+ "RETR_REST",
+ "PORT",
+ "PRET",
+ "PASV",
+ "LIST",
+ "RETR",
+ "STOR",
+ "QUIT"
+};
+#endif
+
+/* This is the ONLY way to change FTP state! */
+static void _ftp_state(struct Curl_easy *data,
+ ftpstate newstate
+#ifdef DEBUGBUILD
+ , int lineno
+#endif
+ )
+{
+ struct connectdata *conn = data->conn;
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+
+#if defined(DEBUGBUILD)
+
+#if defined(CURL_DISABLE_VERBOSE_STRINGS)
+ (void) lineno;
+#else
+ if(ftpc->state != newstate)
+ infof(data, "FTP %p (line %d) state change from %s to %s",
+ (void *)ftpc, lineno, ftp_state_names[ftpc->state],
+ ftp_state_names[newstate]);
+#endif
+#endif
+
+ ftpc->state = newstate;
+}
+
static CURLcode ftp_state_user(struct Curl_easy *data,
struct connectdata *conn)
{
@@ -952,18 +815,24 @@ static int ftp_domore_getsock(struct Curl_easy *data,
* remote site, or we could wait for that site to connect to us. Or just
* handle ordinary commands.
*/
- CURL_TRC_FTP(data, "[%s] ftp_domore_getsock()", FTP_DSTATE(data));
+
+ DEBUGF(infof(data, "ftp_domore_getsock()"));
+ if(conn->cfilter[SECONDARYSOCKET]
+ && !Curl_conn_is_connected(conn, SECONDARYSOCKET))
+ return 0;
if(FTP_STOP == ftpc->state) {
- /* if stopped and still in this state, then we are also waiting for a
+ int bits = GETSOCK_READSOCK(0);
+
+ /* if stopped and still in this state, then we're also waiting for a
connect on the secondary connection */
- DEBUGASSERT(conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD ||
- (conn->cfilter[SECONDARYSOCKET] &&
- !Curl_conn_is_connected(conn, SECONDARYSOCKET)));
socks[0] = conn->sock[FIRSTSOCKET];
- /* An unconnected SECONDARY will add its socket by itself
- * via its adjust_pollset() */
- return GETSOCK_READSOCK(0);
+ if(conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD) {
+ socks[1] = conn->sock[SECONDARYSOCKET];
+ bits |= GETSOCK_WRITESOCK(1) | GETSOCK_READSOCK(1);
+ }
+
+ return bits;
}
return Curl_pp_getsock(data, &conn->proto.ftpc.pp, socks);
}
@@ -1042,7 +911,7 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
char hbuf[NI_MAXHOST];
struct sockaddr *sa = (struct sockaddr *)&ss;
struct sockaddr_in * const sa4 = (void *)sa;
-#ifdef USE_IPV6
+#ifdef ENABLE_IPV6
struct sockaddr_in6 * const sa6 = (void *)sa;
#endif
static const char mode[][5] = { "EPRT", "PORT" };
@@ -1050,15 +919,13 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
int error;
char *host = NULL;
char *string_ftpport = data->set.str[STRING_FTPPORT];
- struct Curl_dns_entry *dns_entry = NULL;
+ struct Curl_dns_entry *h = NULL;
unsigned short port_min = 0;
unsigned short port_max = 0;
unsigned short port;
bool possibly_non_local = TRUE;
char buffer[STRERROR_LEN];
char *addr = NULL;
- size_t addrlen = 0;
- char ipstr[50];
/* Step 1, figure out what is requested,
* accepted format :
@@ -1067,17 +934,32 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
if(data->set.str[STRING_FTPPORT] &&
(strlen(data->set.str[STRING_FTPPORT]) > 1)) {
+
+#ifdef ENABLE_IPV6
+ size_t addrlen = INET6_ADDRSTRLEN > strlen(string_ftpport) ?
+ INET6_ADDRSTRLEN : strlen(string_ftpport);
+#else
+ size_t addrlen = INET_ADDRSTRLEN > strlen(string_ftpport) ?
+ INET_ADDRSTRLEN : strlen(string_ftpport);
+#endif
+ char *ip_start = string_ftpport;
char *ip_end = NULL;
+ char *port_start = NULL;
+ char *port_sep = NULL;
+
+ addr = calloc(1, addrlen + 1);
+ if(!addr) {
+ result = CURLE_OUT_OF_MEMORY;
+ goto out;
+ }
-#ifdef USE_IPV6
+#ifdef ENABLE_IPV6
if(*string_ftpport == '[') {
/* [ipv6]:port(-range) */
- char *ip_start = string_ftpport + 1;
- ip_end = strchr(ip_start, ']');
- if(ip_end) {
- addrlen = ip_end - ip_start;
- addr = ip_start;
- }
+ ip_start = string_ftpport + 1;
+ ip_end = strchr(string_ftpport, ']');
+ if(ip_end)
+ strncpy(addr, ip_start, ip_end - ip_start);
}
else
#endif
@@ -1087,27 +969,28 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
}
else {
ip_end = strchr(string_ftpport, ':');
- addr = string_ftpport;
if(ip_end) {
/* either ipv6 or (ipv4|domain|interface):port(-range) */
- addrlen = ip_end - string_ftpport;
-#ifdef USE_IPV6
+#ifdef ENABLE_IPV6
if(Curl_inet_pton(AF_INET6, string_ftpport, &sa6->sin6_addr) == 1) {
/* ipv6 */
port_min = port_max = 0;
+ strcpy(addr, string_ftpport);
ip_end = NULL; /* this got no port ! */
}
+ else
#endif
+ /* (ipv4|domain|interface):port(-range) */
+ strncpy(addr, string_ftpport, ip_end - ip_start);
}
else
/* ipv4|interface */
- addrlen = strlen(string_ftpport);
+ strcpy(addr, string_ftpport);
}
/* parse the port */
if(ip_end) {
- char *port_sep = NULL;
- char *port_start = strchr(ip_end, ':');
+ port_start = strchr(ip_end, ':');
if(port_start) {
port_min = curlx_ultous(strtoul(port_start + 1, NULL, 10));
port_sep = strchr(port_start, '-');
@@ -1128,29 +1011,22 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
if(port_min > port_max)
port_min = port_max = 0;
- if(addrlen) {
- DEBUGASSERT(addr);
- if(addrlen >= sizeof(ipstr))
- goto out;
- memcpy(ipstr, addr, addrlen);
- ipstr[addrlen] = 0;
-
+ if(*addr != '\0') {
/* attempt to get the address of the given interface name */
switch(Curl_if2ip(conn->remote_addr->family,
-#ifdef USE_IPV6
+#ifdef ENABLE_IPV6
Curl_ipv6_scope(&conn->remote_addr->sa_addr),
conn->scope_id,
#endif
- ipstr, hbuf, sizeof(hbuf))) {
+ addr, hbuf, sizeof(hbuf))) {
case IF2IP_NOT_FOUND:
- /* not an interface, use the given string as hostname instead */
- host = ipstr;
+ /* not an interface, use the given string as host name instead */
+ host = addr;
break;
case IF2IP_AF_NOT_SUPPORTED:
goto out;
case IF2IP_FOUND:
- host = hbuf; /* use the hbuf for hostname */
- break;
+ host = hbuf; /* use the hbuf for host name */
}
}
else
@@ -1160,7 +1036,7 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
if(!host) {
const char *r;
- /* not an interface and not a hostname, get default by extracting
+ /* not an interface and not a host name, get default by extracting
the IP from the control connection */
sslen = sizeof(ss);
if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) {
@@ -1169,7 +1045,7 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
goto out;
}
switch(sa->sa_family) {
-#ifdef USE_IPV6
+#ifdef ENABLE_IPV6
case AF_INET6:
r = Curl_inet_ntop(sa->sa_family, &sa6->sin6_addr, hbuf, sizeof(hbuf));
break;
@@ -1181,17 +1057,20 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
if(!r) {
goto out;
}
- host = hbuf; /* use this hostname */
+ host = hbuf; /* use this host name */
possibly_non_local = FALSE; /* we know it is local now */
}
/* resolv ip/host to ip */
- rc = Curl_resolv(data, host, 0, FALSE, &dns_entry);
+ rc = Curl_resolv(data, host, 0, FALSE, &h);
if(rc == CURLRESOLV_PENDING)
- (void)Curl_resolver_wait_resolv(data, &dns_entry);
- if(dns_entry) {
- res = dns_entry->addr;
- }
+ (void)Curl_resolver_wait_resolv(data, &h);
+ if(h) {
+ res = h->addr;
+ /* when we return from this function, we can forget about this entry
+ to we can unlock it now already */
+ Curl_resolv_unlock(data, h);
+ } /* (h) */
else
res = NULL; /* failure! */
@@ -1216,8 +1095,7 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
Curl_strerror(error, buffer, sizeof(buffer)));
goto out;
}
- CURL_TRC_FTP(data, "[%s] ftp_state_use_port(), opened socket",
- FTP_DSTATE(data));
+ DEBUGF(infof(data, "ftp_state_use_port(), opened socket"));
/* step 3, bind to a suitable local address */
@@ -1227,7 +1105,7 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
for(port = port_min; port <= port_max;) {
if(sa->sa_family == AF_INET)
sa4->sin_port = htons(port);
-#ifdef USE_IPV6
+#ifdef ENABLE_IPV6
else
sa6->sin6_port = htons(port);
#endif
@@ -1236,7 +1114,7 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
/* It failed. */
error = SOCKERRNO;
if(possibly_non_local && (error == EADDRNOTAVAIL)) {
- /* The requested bind address is not local. Use the address used for
+ /* The requested bind address is not local. Use the address used for
* the control connection instead and restart the port loop
*/
infof(data, "bind(port=%hu) on non-local address failed: %s", port,
@@ -1249,7 +1127,7 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
goto out;
}
port = port_min;
- possibly_non_local = FALSE; /* do not try this again */
+ possibly_non_local = FALSE; /* don't try this again */
continue;
}
if(error != EADDRINUSE && error != EACCES) {
@@ -1278,8 +1156,7 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
goto out;
}
- CURL_TRC_FTP(data, "[%s] ftp_state_use_port(), socket bound to port %d",
- FTP_DSTATE(data), port);
+ DEBUGF(infof(data, "ftp_state_use_port(), socket bound to port %d", port));
/* step 4, listen on the socket */
@@ -1288,8 +1165,7 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
goto out;
}
- CURL_TRC_FTP(data, "[%s] ftp_state_use_port(), listening on %d",
- FTP_DSTATE(data), port);
+ DEBUGF(infof(data, "ftp_state_use_port(), listening on %d", port));
/* step 5, send the proper FTP command */
@@ -1297,19 +1173,13 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
below */
Curl_printable_address(ai, myhost, sizeof(myhost));
-#ifdef USE_IPV6
+#ifdef ENABLE_IPV6
if(!conn->bits.ftp_use_eprt && conn->bits.ipv6)
/* EPRT is disabled but we are connected to a IPv6 host, so we ignore the
request and enable EPRT again! */
conn->bits.ftp_use_eprt = TRUE;
#endif
- /* Replace any filter on SECONDARY with one listening on this socket */
- result = Curl_conn_tcp_listen_set(data, conn, SECONDARYSOCKET, &portsock);
- if(result)
- goto out;
- portsock = CURL_SOCKET_BAD; /* now held in filter */
-
for(; fcmd != DONE; fcmd++) {
if(!conn->bits.ftp_use_eprt && (EPRT == fcmd))
@@ -1324,7 +1194,7 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
case AF_INET:
port = ntohs(sa4->sin_port);
break;
-#ifdef USE_IPV6
+#ifdef ENABLE_IPV6
case AF_INET6:
port = ntohs(sa6->sin6_port);
break;
@@ -1359,7 +1229,7 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
char *dest = target;
/* translate x.x.x.x to x,x,x,x */
- while(*source) {
+ while(source && *source) {
if(*source == '.')
*dest = ',';
else
@@ -1383,17 +1253,20 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
/* store which command was sent */
ftpc->count1 = fcmd;
+ /* Replace any filter on SECONDARY with one listening on this socket */
+ result = Curl_conn_tcp_listen_set(data, conn, SECONDARYSOCKET, &portsock);
+ if(result)
+ goto out;
+ portsock = CURL_SOCKET_BAD; /* now held in filter */
ftp_state(data, FTP_PORT);
out:
- /* If we looked up a dns_entry, now is the time to safely release it */
- if(dns_entry)
- Curl_resolv_unlink(data, &dns_entry);
if(result) {
ftp_state(data, FTP_STOP);
}
if(portsock != CURL_SOCKET_BAD)
Curl_socket_close(data, conn, portsock);
+ free(addr);
return result;
}
@@ -1451,7 +1324,7 @@ static CURLcode ftp_state_prepare_transfer(struct Curl_easy *data)
struct connectdata *conn = data->conn;
if(ftp->transfer != PPTRANSFER_BODY) {
- /* does not transfer any data */
+ /* doesn't transfer any data */
/* still possibly do PRE QUOTE jobs */
ftp_state(data, FTP_RETR_PREQUOTE);
@@ -1519,7 +1392,7 @@ static CURLcode ftp_state_size(struct Curl_easy *data,
if((ftp->transfer == PPTRANSFER_INFO) && ftpc->file) {
/* if a "head"-like request is being made (on a file) */
- /* we know ftpc->file is a valid pointer to a filename */
+ /* we know ftpc->file is a valid pointer to a file name */
result = Curl_pp_sendf(data, &ftpc->pp, "SIZE %s", ftpc->file);
if(!result)
ftp_state(data, FTP_SIZE);
@@ -1597,13 +1470,13 @@ static CURLcode ftp_state_list(struct Curl_easy *data)
static CURLcode ftp_state_retr_prequote(struct Curl_easy *data)
{
- /* We have sent the TYPE, now we must send the list of prequote strings */
+ /* We've sent the TYPE, now we must send the list of prequote strings */
return ftp_state_quote(data, TRUE, FTP_RETR_PREQUOTE);
}
static CURLcode ftp_state_stor_prequote(struct Curl_easy *data)
{
- /* We have sent the TYPE, now we must send the list of prequote strings */
+ /* We've sent the TYPE, now we must send the list of prequote strings */
return ftp_state_quote(data, TRUE, FTP_STOR_PREQUOTE);
}
@@ -1615,7 +1488,7 @@ static CURLcode ftp_state_type(struct Curl_easy *data)
struct ftp_conn *ftpc = &conn->proto.ftpc;
/* If we have selected NOBODY and HEADER, it means that we only want file
- information. Which in FTP cannot be much more than the file size and
+ information. Which in FTP can't be much more than the file size and
date. */
if(data->req.no_body && ftpc->file &&
ftp_need_type(conn, data->state.prefer_ascii)) {
@@ -1675,13 +1548,13 @@ static CURLcode ftp_state_ul_setup(struct Curl_easy *data,
if((data->state.resume_from && !sizechecked) ||
((data->state.resume_from > 0) && sizechecked)) {
- /* we are about to continue the uploading of a file */
+ /* we're about to continue the uploading of a file */
/* 1. get already existing file's size. We use the SIZE command for this
which may not exist in the server! The SIZE command is not in
RFC959. */
/* 2. This used to set REST. But since we can do append, we
- do not another ftp command. We just skip the source file
+ don't another ftp command. We just skip the source file
offset and then we APPEND the rest on the file instead */
/* 3. pass file-size number of bytes in the source file */
@@ -1701,10 +1574,10 @@ static CURLcode ftp_state_ul_setup(struct Curl_easy *data,
append = TRUE;
/* Let's read off the proper amount of bytes from the input. */
- if(data->set.seek_func) {
+ if(conn->seek_func) {
Curl_set_in_callback(data, true);
- seekerr = data->set.seek_func(data->set.seek_client,
- data->state.resume_from, SEEK_SET);
+ seekerr = conn->seek_func(conn->seek_client, data->state.resume_from,
+ SEEK_SET);
Curl_set_in_callback(data, false);
}
@@ -1714,16 +1587,15 @@ static CURLcode ftp_state_ul_setup(struct Curl_easy *data,
failf(data, "Could not seek stream");
return CURLE_FTP_COULDNT_USE_REST;
}
- /* seekerr == CURL_SEEKFUNC_CANTSEEK (cannot seek to offset) */
+ /* seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */
do {
- char scratch[4*1024];
size_t readthisamountnow =
- (data->state.resume_from - passed > (curl_off_t)sizeof(scratch)) ?
- sizeof(scratch) :
+ (data->state.resume_from - passed > data->set.buffer_size) ?
+ (size_t)data->set.buffer_size :
curlx_sotouz(data->state.resume_from - passed);
size_t actuallyread =
- data->state.fread_func(scratch, 1, readthisamountnow,
+ data->state.fread_func(data->state.buffer, 1, readthisamountnow,
data->state.in);
passed += actuallyread;
@@ -1743,17 +1615,17 @@ static CURLcode ftp_state_ul_setup(struct Curl_easy *data,
infof(data, "File already completely uploaded");
/* no data to transfer */
- Curl_xfer_setup_nop(data);
+ Curl_setup_transfer(data, -1, -1, FALSE, -1);
- /* Set ->transfer so that we will not get any error in
- * ftp_done() because we did not transfer anything! */
+ /* Set ->transfer so that we won't get any error in
+ * ftp_done() because we didn't transfer anything! */
ftp->transfer = PPTRANSFER_NONE;
ftp_state(data, FTP_STOP);
return CURLE_OK;
}
}
- /* we have passed, proceed as normal */
+ /* we've passed, proceed as normal */
} /* resume_from */
result = Curl_pp_sendf(data, &ftpc->pp, append?"APPE %s":"STOR %s",
@@ -1842,16 +1714,16 @@ static CURLcode ftp_state_quote(struct Curl_easy *data,
}
else {
if(data->set.ignorecl || data->state.prefer_ascii) {
- /* 'ignorecl' is used to support download of growing files. It
+ /* 'ignorecl' is used to support download of growing files. It
prevents the state machine from requesting the file size from
- the server. With an unknown file size the download continues
+ the server. With an unknown file size the download continues
until the server terminates it, otherwise the client stops if
- the received byte count exceeds the reported file size. Set
+ the received byte count exceeds the reported file size. Set
option CURLOPT_IGNORE_CONTENT_LENGTH to 1 to enable this
behavior.
In addition: asking for the size for 'TYPE A' transfers is not
- constructive since servers do not report the converted size. So
+ constructive since servers don't report the converted size. So
skip it.
*/
result = Curl_pp_sendf(data, &ftpc->pp, "RETR %s", ftpc->file);
@@ -1889,7 +1761,7 @@ static CURLcode ftp_epsv_disable(struct Curl_easy *data,
&& !(conn->bits.tunnel_proxy || conn->bits.socksproxy)
#endif
) {
- /* We cannot disable EPSV when doing IPv6, so this is instead a fail */
+ /* We can't disable EPSV when doing IPv6, so this is instead a fail */
failf(data, "Failed EPSV attempt, exiting");
return CURLE_WEIRD_SERVER_REPLY;
}
@@ -1914,14 +1786,14 @@ static CURLcode ftp_epsv_disable(struct Curl_easy *data,
static char *control_address(struct connectdata *conn)
{
/* Returns the control connection IP address.
- If a proxy tunnel is used, returns the original hostname instead, because
+ If a proxy tunnel is used, returns the original host name instead, because
the effective control connection address is the proxy address,
not the ftp host. */
#ifndef CURL_DISABLE_PROXY
if(conn->bits.tunnel_proxy || conn->bits.socksproxy)
return conn->host.name;
#endif
- return conn->primary.remote_ip;
+ return conn->primary_ip;
}
static bool match_pasv_6nums(const char *p,
@@ -1956,9 +1828,7 @@ static CURLcode ftp_state_pasv_resp(struct Curl_easy *data,
struct Curl_dns_entry *addr = NULL;
enum resolve_t rc;
unsigned short connectport; /* the local port connect() should use! */
- struct pingpong *pp = &ftpc->pp;
- char *str =
- Curl_dyn_ptr(&pp->recvbuf) + 4; /* start on the first letter */
+ char *str = &data->state.buffer[4]; /* start on the first letter */
/* if we come here again, make sure the former name is cleared */
Curl_safefree(ftpc->newhost);
@@ -2053,22 +1923,22 @@ static CURLcode ftp_state_pasv_resp(struct Curl_easy *data,
if(conn->bits.proxy) {
/*
* This connection uses a proxy and we need to connect to the proxy again
- * here. We do not want to rely on a former host lookup that might've
+ * here. We don't want to rely on a former host lookup that might've
* expired now, instead we remake the lookup here and now!
*/
const char * const host_name = conn->bits.socksproxy ?
conn->socks_proxy.host.name : conn->http_proxy.host.name;
- rc = Curl_resolv(data, host_name, conn->primary.remote_port, FALSE, &addr);
+ rc = Curl_resolv(data, host_name, conn->port, FALSE, &addr);
if(rc == CURLRESOLV_PENDING)
/* BLOCKING, ignores the return code but 'addr' will be NULL in
case of failure */
(void)Curl_resolver_wait_resolv(data, &addr);
- /* we connect to the proxy's port */
- connectport = (unsigned short)conn->primary.remote_port;
+ connectport =
+ (unsigned short)conn->port; /* we connect to the proxy's port */
if(!addr) {
- failf(data, "cannot resolve proxy host %s:%hu", host_name, connectport);
+ failf(data, "Can't resolve proxy host %s:%hu", host_name, connectport);
return CURLE_COULDNT_RESOLVE_PROXY;
}
}
@@ -2080,6 +1950,7 @@ static CURLcode ftp_state_pasv_resp(struct Curl_easy *data,
/* postponed address resolution in case of tcp fastopen */
if(conn->bits.tcp_fastopen && !conn->bits.reuse && !ftpc->newhost[0]) {
+ Curl_conn_ev_update_info(data, conn);
Curl_safefree(ftpc->newhost);
ftpc->newhost = strdup(control_address(conn));
if(!ftpc->newhost)
@@ -2094,8 +1965,7 @@ static CURLcode ftp_state_pasv_resp(struct Curl_easy *data,
connectport = ftpc->newport; /* we connect to the remote port */
if(!addr) {
- failf(data, "cannot resolve new host %s:%hu",
- ftpc->newhost, connectport);
+ failf(data, "Can't resolve new host %s:%hu", ftpc->newhost, connectport);
return CURLE_FTP_CANT_GET_HOST;
}
}
@@ -2105,7 +1975,7 @@ static CURLcode ftp_state_pasv_resp(struct Curl_easy *data,
CURL_CF_SSL_ENABLE : CURL_CF_SSL_DISABLE);
if(result) {
- Curl_resolv_unlink(data, &addr); /* we are done using this address */
+ Curl_resolv_unlock(data, addr); /* we're done using this address */
if(ftpc->count1 == 0 && ftpcode == 229)
return ftp_epsv_disable(data, conn);
@@ -2123,7 +1993,7 @@ static CURLcode ftp_state_pasv_resp(struct Curl_easy *data,
/* this just dumps information about this second connection */
ftp_pasv_verbose(data, addr->addr, ftpc->newhost, connectport);
- Curl_resolv_unlink(data, &addr); /* we are done using this address */
+ Curl_resolv_unlock(data, addr); /* we're done using this address */
Curl_safefree(conn->secondaryhostname);
conn->secondary_port = ftpc->newport;
@@ -2211,7 +2081,7 @@ static CURLcode client_write_header(struct Curl_easy *data,
* call to Curl_client_write() so it does the right thing.
*
* Notice that we cannot enable this flag for FTP in general,
- * as an FTP transfer might involve an HTTP proxy connection and
+ * as an FTP transfer might involve a HTTP proxy connection and
* headers from CONNECT should not automatically be part of the
* output. */
CURLcode result;
@@ -2236,9 +2106,8 @@ static CURLcode ftp_state_mdtm_resp(struct Curl_easy *data,
/* we got a time. Format should be: "YYYYMMDDHHMMSS[.sss]" where the
last .sss part is optional and means fractions of a second */
int year, month, day, hour, minute, second;
- struct pingpong *pp = &ftpc->pp;
- char *resp = Curl_dyn_ptr(&pp->recvbuf) + 4;
- if(ftp_213_date(resp, &year, &month, &day, &hour, &minute, &second)) {
+ if(ftp_213_date(&data->state.buffer[4],
+ &year, &month, &day, &hour, &minute, &second)) {
/* we have a time, reformat it */
char timebuf[24];
msnprintf(timebuf, sizeof(timebuf),
@@ -2367,7 +2236,7 @@ static CURLcode ftp_state_retr(struct Curl_easy *data,
struct connectdata *conn = data->conn;
struct ftp_conn *ftpc = &conn->proto.ftpc;
- CURL_TRC_FTP(data, "[%s] ftp_state_retr()", FTP_DSTATE(data));
+ DEBUGF(infof(data, "ftp_state_retr()"));
if(data->set.max_filesize && (filesize > data->set.max_filesize)) {
failf(data, "Maximum file size exceeded");
return CURLE_FILESIZE_EXCEEDED;
@@ -2378,20 +2247,20 @@ static CURLcode ftp_state_retr(struct Curl_easy *data,
/* We always (attempt to) get the size of downloads, so it is done before
this even when not doing resumes. */
if(filesize == -1) {
- infof(data, "ftp server does not support SIZE");
- /* We could not get the size and therefore we cannot know if there really
+ infof(data, "ftp server doesn't support SIZE");
+ /* We couldn't get the size and therefore we can't know if there really
is a part of the file left to get, although the server will just
- close the connection when we start the connection so it will not cause
+ close the connection when we start the connection so it won't cause
us any harm, just not make us exit as nicely. */
}
else {
/* We got a file size report, so we check that there actually is a
part of the file left to get, or else we go home. */
if(data->state.resume_from< 0) {
- /* We are supposed to download the last abs(from) bytes */
+ /* We're supposed to download the last abs(from) bytes */
if(filesize < -data->state.resume_from) {
- failf(data, "Offset (%" FMT_OFF_T
- ") was beyond file size (%" FMT_OFF_T ")",
+ failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T
+ ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")",
data->state.resume_from, filesize);
return CURLE_BAD_DOWNLOAD_RESUME;
}
@@ -2402,8 +2271,8 @@ static CURLcode ftp_state_retr(struct Curl_easy *data,
}
else {
if(filesize < data->state.resume_from) {
- failf(data, "Offset (%" FMT_OFF_T
- ") was beyond file size (%" FMT_OFF_T ")",
+ failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T
+ ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")",
data->state.resume_from, filesize);
return CURLE_BAD_DOWNLOAD_RESUME;
}
@@ -2414,21 +2283,21 @@ static CURLcode ftp_state_retr(struct Curl_easy *data,
if(ftp->downloadsize == 0) {
/* no data to transfer */
- Curl_xfer_setup_nop(data);
+ Curl_setup_transfer(data, -1, -1, FALSE, -1);
infof(data, "File already completely downloaded");
- /* Set ->transfer so that we will not get any error in ftp_done()
- * because we did not transfer the any file */
+ /* Set ->transfer so that we won't get any error in ftp_done()
+ * because we didn't transfer the any file */
ftp->transfer = PPTRANSFER_NONE;
ftp_state(data, FTP_STOP);
return CURLE_OK;
}
/* Set resume file transfer offset */
- infof(data, "Instructs server to resume from offset %" FMT_OFF_T,
- data->state.resume_from);
+ infof(data, "Instructs server to resume from offset %"
+ CURL_FORMAT_CURL_OFF_T, data->state.resume_from);
- result = Curl_pp_sendf(data, &ftpc->pp, "REST %" FMT_OFF_T,
+ result = Curl_pp_sendf(data, &ftpc->pp, "REST %" CURL_FORMAT_CURL_OFF_T,
data->state.resume_from);
if(!result)
ftp_state(data, FTP_RETR_REST);
@@ -2449,8 +2318,7 @@ static CURLcode ftp_state_size_resp(struct Curl_easy *data,
{
CURLcode result = CURLE_OK;
curl_off_t filesize = -1;
- char *buf = Curl_dyn_ptr(&data->conn->proto.ftpc.pp.recvbuf);
- size_t len = data->conn->proto.ftpc.pp.nfinal;
+ char *buf = data->state.buffer;
/* get the size from the ascii string: */
if(ftpcode == 213) {
@@ -2458,13 +2326,13 @@ static CURLcode ftp_state_size_resp(struct Curl_easy *data,
for all the digits at the end of the response and parse only those as a
number. */
char *start = &buf[4];
- char *fdigit = memchr(start, '\r', len);
+ char *fdigit = strchr(start, '\r');
if(fdigit) {
- fdigit--;
- if(*fdigit == '\n')
- fdigit--;
- while(ISDIGIT(fdigit[-1]) && (fdigit > start))
+ do
fdigit--;
+ while(ISDIGIT(*fdigit) && (fdigit > start));
+ if(!ISDIGIT(*fdigit))
+ fdigit++;
}
else
fdigit = start;
@@ -2486,7 +2354,7 @@ static CURLcode ftp_state_size_resp(struct Curl_easy *data,
if(-1 != filesize) {
char clbuf[128];
int clbuflen = msnprintf(clbuf, sizeof(clbuf),
- "Content-Length: %" FMT_OFF_T "\r\n", filesize);
+ "Content-Length: %" CURL_FORMAT_CURL_OFF_T "\r\n", filesize);
result = client_write_header(data, clbuf, clbuflen);
if(result)
return result;
@@ -2626,14 +2494,14 @@ static CURLcode ftp_state_get_resp(struct Curl_easy *data,
!data->set.ignorecl &&
(ftp->downloadsize < 1)) {
/*
- * It seems directory listings either do not show the size or very
+ * It seems directory listings either don't show the size or very
* often uses size 0 anyway. ASCII transfers may very well turn out
* that the transferred amount of data is not the same as this line
* tells, why using this number in those cases only confuses us.
*
* Example D above makes this parsing a little tricky */
char *bytes;
- char *buf = Curl_dyn_ptr(&conn->proto.ftpc.pp.recvbuf);
+ char *buf = data->state.buffer;
bytes = strstr(buf, " bytes");
if(bytes) {
long in = (long)(--bytes-buf);
@@ -2666,10 +2534,12 @@ static CURLcode ftp_state_get_resp(struct Curl_easy *data,
else if((instate != FTP_LIST) && (data->state.prefer_ascii))
size = -1; /* kludge for servers that understate ASCII mode file size */
- infof(data, "Maxdownload = %" FMT_OFF_T, data->req.maxdownload);
+ infof(data, "Maxdownload = %" CURL_FORMAT_CURL_OFF_T,
+ data->req.maxdownload);
if(instate != FTP_LIST)
- infof(data, "Getting file with size: %" FMT_OFF_T, size);
+ infof(data, "Getting file with size: %" CURL_FORMAT_CURL_OFF_T,
+ size);
/* FTP download: */
conn->proto.ftpc.state_saved = instate;
@@ -2695,7 +2565,7 @@ static CURLcode ftp_state_get_resp(struct Curl_easy *data,
else {
if((instate == FTP_LIST) && (ftpcode == 450)) {
/* simply no matching files in the dir listing */
- ftp->transfer = PPTRANSFER_NONE; /* do not download anything */
+ ftp->transfer = PPTRANSFER_NONE; /* don't download anything */
ftp_state(data, FTP_STOP); /* this phase is over */
}
else {
@@ -2782,7 +2652,7 @@ static CURLcode ftp_state_user_resp(struct Curl_easy *data,
if(data->set.str[STRING_FTP_ALTERNATIVE_TO_USER] &&
!ftpc->ftp_trying_alternative) {
- /* Ok, USER failed. Let's try the supplied command. */
+ /* Ok, USER failed. Let's try the supplied command. */
result =
Curl_pp_sendf(data, &ftpc->pp, "%s",
data->set.str[STRING_FTP_ALTERNATIVE_TO_USER]);
@@ -2819,6 +2689,7 @@ static CURLcode ftp_statemachine(struct Curl_easy *data,
struct connectdata *conn)
{
CURLcode result;
+ curl_socket_t sock = conn->sock[FIRSTSOCKET];
int ftpcode;
struct ftp_conn *ftpc = &conn->proto.ftpc;
struct pingpong *pp = &ftpc->pp;
@@ -2828,7 +2699,7 @@ static CURLcode ftp_statemachine(struct Curl_easy *data,
if(pp->sendleft)
return Curl_pp_flushsend(data, pp);
- result = ftp_readresp(data, FIRSTSOCKET, pp, &ftpcode, &nread);
+ result = ftp_readresp(data, sock, pp, &ftpcode, &nread);
if(result)
return result;
@@ -2868,7 +2739,7 @@ static CURLcode ftp_statemachine(struct Curl_easy *data,
#endif
if(data->set.use_ssl && !conn->bits.ftp_use_control_ssl) {
- /* We do not have a SSL/TLS control connection yet, but FTPS is
+ /* We don't have a SSL/TLS control connection yet, but FTPS is
requested. Try a FTPS connection now */
ftpc->count3 = 0;
@@ -2885,7 +2756,7 @@ static CURLcode ftp_statemachine(struct Curl_easy *data,
default:
failf(data, "unsupported parameter to CURLOPT_FTPSSLAUTH: %d",
(int)data->set.ftpsslauth);
- return CURLE_UNKNOWN_OPTION; /* we do not know what to do */
+ return CURLE_UNKNOWN_OPTION; /* we don't know what to do */
}
result = Curl_pp_sendf(data, &ftpc->pp, "AUTH %s",
ftpauth[ftpc->count1]);
@@ -2899,7 +2770,7 @@ static CURLcode ftp_statemachine(struct Curl_easy *data,
case FTP_AUTH:
/* we have gotten the response to a previous AUTH command */
- if(pp->overflow)
+ if(pp->cache_size)
return CURLE_WEIRD_SERVER_REPLY; /* Forbid pipelining in response. */
/* RFC2228 (page 5) says:
@@ -2985,13 +2856,7 @@ static CURLcode ftp_statemachine(struct Curl_easy *data,
case FTP_CCC:
if(ftpcode < 500) {
/* First shut down the SSL layer (note: this call will block) */
- /* This has only been tested on the proftpd server, and the mod_tls
- * code sends a close notify alert without waiting for a close notify
- * alert in response. Thus we wait for a close notify alert from the
- * server, but we do not send one. Let's hope other servers do
- * the same... */
- result = Curl_ssl_cfilter_remove(data, FIRSTSOCKET,
- (data->set.ftp_ccc == CURLFTPSSL_CCC_ACTIVE));
+ result = Curl_ssl_cfilter_remove(data, FIRSTSOCKET);
if(result)
failf(data, "Failed to clear the command channel (CCC)");
@@ -3003,11 +2868,14 @@ static CURLcode ftp_statemachine(struct Curl_easy *data,
case FTP_PWD:
if(ftpcode == 257) {
- char *ptr = Curl_dyn_ptr(&pp->recvbuf) + 4; /* start on the first
- letter */
+ char *ptr = &data->state.buffer[4]; /* start on the first letter */
+ const size_t buf_size = data->set.buffer_size;
+ char *dir;
bool entry_extracted = FALSE;
- struct dynbuf out;
- Curl_dyn_init(&out, 1000);
+
+ dir = malloc(nread + 1);
+ if(!dir)
+ return CURLE_OUT_OF_MEMORY;
/* Reply format is like
257<space>[rubbish]"<directory-name>"<space><commentary> and the
@@ -3019,30 +2887,33 @@ static CURLcode ftp_statemachine(struct Curl_easy *data,
*/
/* scan for the first double-quote for non-standard responses */
- while(*ptr != '\n' && *ptr != '\0' && *ptr != '"')
+ while(ptr < &data->state.buffer[buf_size]
+ && *ptr != '\n' && *ptr != '\0' && *ptr != '"')
ptr++;
if('\"' == *ptr) {
/* it started good */
- for(ptr++; *ptr; ptr++) {
+ char *store;
+ ptr++;
+ for(store = dir; *ptr;) {
if('\"' == *ptr) {
if('\"' == ptr[1]) {
/* "quote-doubling" */
- result = Curl_dyn_addn(&out, &ptr[1], 1);
+ *store = ptr[1];
ptr++;
}
else {
/* end of path */
- if(Curl_dyn_len(&out))
- entry_extracted = TRUE;
+ entry_extracted = TRUE;
break; /* get out of this loop */
}
}
else
- result = Curl_dyn_addn(&out, ptr, 1);
- if(result)
- return result;
+ *store = *ptr;
+ store++;
+ ptr++;
}
+ *store = '\0'; /* null-terminate */
}
if(entry_extracted) {
/* If the path name does not look like an absolute path (i.e.: it
@@ -3056,7 +2927,6 @@ static CURLcode ftp_statemachine(struct Curl_easy *data,
The method used here is to check the server OS: we do it only
if the path name looks strange to minimize overhead on other
systems. */
- char *dir = Curl_dyn_ptr(&out);
if(!ftpc->server_os && dir[0] != '/') {
result = Curl_pp_sendf(data, &ftpc->pp, "%s", "SYST");
@@ -3080,34 +2950,36 @@ static CURLcode ftp_statemachine(struct Curl_easy *data,
data->state.most_recent_ftp_entrypath = ftpc->entrypath;
}
else {
- /* could not get the path */
- Curl_dyn_free(&out);
+ /* couldn't get the path */
+ free(dir);
infof(data, "Failed to figure out path");
}
}
ftp_state(data, FTP_STOP); /* we are done with the CONNECT phase! */
- CURL_TRC_FTP(data, "[%s] protocol connect phase DONE", FTP_DSTATE(data));
+ DEBUGF(infof(data, "protocol connect phase DONE"));
break;
case FTP_SYST:
if(ftpcode == 215) {
- char *ptr = Curl_dyn_ptr(&pp->recvbuf) + 4; /* start on the first
- letter */
+ char *ptr = &data->state.buffer[4]; /* start on the first letter */
char *os;
- char *start;
+ char *store;
+
+ os = malloc(nread + 1);
+ if(!os)
+ return CURLE_OUT_OF_MEMORY;
/* Reply format is like
215<space><OS-name><space><commentary>
*/
while(*ptr == ' ')
ptr++;
- for(start = ptr; *ptr && *ptr != ' '; ptr++)
- ;
- os = Curl_memdup0(start, ptr - start);
- if(!os)
- return CURLE_OUT_OF_MEMORY;
+ for(store = os; *ptr && *ptr != ' ';)
+ *store++ = *ptr++;
+ *store = '\0'; /* null-terminate */
/* Check for special servers here. */
+
if(strcasecompare(os, "OS/400")) {
/* Force OS400 name format 1. */
result = Curl_pp_sendf(data, &ftpc->pp, "%s", "SITE NAMEFMT 1");
@@ -3131,7 +3003,7 @@ static CURLcode ftp_statemachine(struct Curl_easy *data,
}
ftp_state(data, FTP_STOP); /* we are done with the CONNECT phase! */
- CURL_TRC_FTP(data, "[%s] protocol connect phase DONE", FTP_DSTATE(data));
+ DEBUGF(infof(data, "protocol connect phase DONE"));
break;
case FTP_NAMEFMT:
@@ -3142,7 +3014,7 @@ static CURLcode ftp_statemachine(struct Curl_easy *data,
}
ftp_state(data, FTP_STOP); /* we are done with the CONNECT phase! */
- CURL_TRC_FTP(data, "[%s] protocol connect phase DONE", FTP_DSTATE(data));
+ DEBUGF(infof(data, "protocol connect phase DONE"));
break;
case FTP_QUOTE:
@@ -3179,7 +3051,7 @@ static CURLcode ftp_statemachine(struct Curl_easy *data,
else {
/* return failure */
failf(data, "Server denied you to change to the given directory");
- ftpc->cwdfail = TRUE; /* do not remember this path as we failed
+ ftpc->cwdfail = TRUE; /* don't remember this path as we failed
to enter it */
result = CURLE_REMOTE_ACCESS_DENIED;
}
@@ -3259,6 +3131,7 @@ static CURLcode ftp_statemachine(struct Curl_easy *data,
break;
case FTP_QUIT:
+ /* fallthrough, just stop! */
default:
/* internal error */
ftp_state(data, FTP_STOP);
@@ -3333,7 +3206,8 @@ static CURLcode ftp_connect(struct Curl_easy *data,
conn->bits.ftp_use_control_ssl = TRUE;
}
- Curl_pp_init(pp); /* once per transfer */
+ Curl_pp_setup(pp); /* once per transfer */
+ Curl_pp_init(data, pp); /* init the generic pingpong data */
/* When we connect, we start in the state where we await the 220
response */
@@ -3384,13 +3258,14 @@ static CURLcode ftp_done(struct Curl_easy *data, CURLcode status,
case CURLE_REMOTE_FILE_NOT_FOUND:
case CURLE_WRITE_ERROR:
/* the connection stays alive fine even though this happened */
- case CURLE_OK: /* does not affect the control connection's status */
+ /* fall-through */
+ case CURLE_OK: /* doesn't affect the control connection's status */
if(!premature)
break;
/* until we cope better with prematurely ended requests, let them
* fallback as if in complete failure */
- FALLTHROUGH();
+ /* FALLTHROUGH */
default: /* by default, an error means the control connection is
wedged and should not be used anymore */
ftpc->ctl_valid = FALSE;
@@ -3450,7 +3325,7 @@ static CURLcode ftp_done(struct Curl_easy *data, CURLcode status,
/* free the dir tree and file parts */
freedirs(ftpc);
- /* shut down the socket to inform the server we are done */
+ /* shut down the socket to inform the server we're done */
#ifdef _WIN32_WCE
shutdown(conn->sock[SECONDARYSOCKET], 2); /* SD_BOTH */
@@ -3468,7 +3343,7 @@ static CURLcode ftp_done(struct Curl_easy *data, CURLcode status,
}
}
- close_secondarysocket(data);
+ close_secondarysocket(data, conn);
}
if(!result && (ftp->transfer == PPTRANSFER_BODY) && ftpc->ctl_valid &&
@@ -3534,8 +3409,8 @@ static CURLcode ftp_done(struct Curl_easy *data, CURLcode status,
(data->state.infilesize != data->req.writebytecount) &&
!data->set.crlf &&
(ftp->transfer == PPTRANSFER_BODY)) {
- failf(data, "Uploaded unaligned file size (%" FMT_OFF_T
- " out of %" FMT_OFF_T " bytes)",
+ failf(data, "Uploaded unaligned file size (%" CURL_FORMAT_CURL_OFF_T
+ " out of %" CURL_FORMAT_CURL_OFF_T " bytes)",
data->req.writebytecount, data->state.infilesize);
result = CURLE_PARTIAL_FILE;
}
@@ -3543,9 +3418,17 @@ static CURLcode ftp_done(struct Curl_easy *data, CURLcode status,
else {
if((-1 != data->req.size) &&
(data->req.size != data->req.bytecount) &&
+#ifdef CURL_DO_LINEEND_CONV
+ /* Most FTP servers don't adjust their file SIZE response for CRLFs, so
+ * we'll check to see if the discrepancy can be explained by the number
+ * of CRLFs we've changed to LFs.
+ */
+ ((data->req.size + data->state.crlf_conversions) !=
+ data->req.bytecount) &&
+#endif /* CURL_DO_LINEEND_CONV */
(data->req.maxdownload != data->req.bytecount)) {
- failf(data, "Received only partial file: %" FMT_OFF_T " bytes",
- data->req.bytecount);
+ failf(data, "Received only partial file: %" CURL_FORMAT_CURL_OFF_T
+ " bytes", data->req.bytecount);
result = CURLE_PARTIAL_FILE;
}
else if(!ftpc->dont_check &&
@@ -3563,7 +3446,6 @@ static CURLcode ftp_done(struct Curl_easy *data, CURLcode status,
/* Send any post-transfer QUOTE strings? */
if(!status && !result && !premature && data->set.postquote)
result = ftp_sendquote(data, conn, data->set.postquote);
- CURL_TRC_FTP(data, "[%s] done, result=%d", FTP_DSTATE(data), result);
Curl_safefree(ftp->pathalloc);
return result;
}
@@ -3673,7 +3555,7 @@ static CURLcode ftp_nb_type(struct Curl_easy *data,
* ftp_pasv_verbose()
*
* This function only outputs some informationals about this second connection
- * when we have issued a PASV command before and thus we have connected to a
+ * when we've issued a PASV command before and thus we have connected to a
* possibly new IP address.
*
*/
@@ -3681,7 +3563,7 @@ static CURLcode ftp_nb_type(struct Curl_easy *data,
static void
ftp_pasv_verbose(struct Curl_easy *data,
struct Curl_addrinfo *ai,
- char *newhost, /* ASCII version */
+ char *newhost, /* ascii version */
int port)
{
char buf[256];
@@ -3714,7 +3596,7 @@ static CURLcode ftp_do_more(struct Curl_easy *data, int *completep)
* complete */
struct FTP *ftp = NULL;
- /* if the second connection is not done yet, wait for it to have
+ /* if the second connection isn't done yet, wait for it to have
* connected to the remote host. When using proxy tunneling, this
* means the tunnel needs to have been establish. However, we
* can not expect the remote host to talk to us in any way yet.
@@ -3742,20 +3624,20 @@ static CURLcode ftp_do_more(struct Curl_easy *data, int *completep)
*completep = (int)complete;
- /* if we got an error or if we do not wait for a data connection return
+ /* if we got an error or if we don't wait for a data connection return
immediately */
if(result || !ftpc->wait_data_conn)
return result;
/* if we reach the end of the FTP state machine here, *complete will be
TRUE but so is ftpc->wait_data_conn, which says we need to wait for the
- data connection and therefore we are not actually complete */
+ data connection and therefore we're not actually complete */
*completep = 0;
}
if(ftp->transfer <= PPTRANSFER_INFO) {
- /* a transfer is about to take place, or if not a filename was given so we
- will do a SIZE on it later and then we need the right TYPE first */
+ /* a transfer is about to take place, or if not a file name was given
+ so we'll do a SIZE on it later and then we need the right TYPE first */
if(ftpc->wait_data_conn) {
bool serv_conned;
@@ -3794,7 +3676,7 @@ static CURLcode ftp_do_more(struct Curl_easy *data, int *completep)
result = Curl_range(data);
if(result == CURLE_OK && data->req.maxdownload >= 0) {
- /* Do not check for successful transfer */
+ /* Don't check for successful transfer */
ftpc->dont_check = TRUE;
}
@@ -3827,13 +3709,12 @@ static CURLcode ftp_do_more(struct Curl_easy *data, int *completep)
}
/* no data to transfer */
- Curl_xfer_setup_nop(data);
+ Curl_setup_transfer(data, -1, -1, FALSE, -1);
if(!ftpc->wait_data_conn) {
/* no waiting for the data connection so this is now complete */
*completep = 1;
- CURL_TRC_FTP(data, "[%s] DO-MORE phase ends with %d", FTP_DSTATE(data),
- (int)result);
+ DEBUGF(infof(data, "DO-MORE phase ends with %d", (int)result));
}
return result;
@@ -3857,7 +3738,7 @@ CURLcode ftp_perform(struct Curl_easy *data,
/* this is FTP and no proxy */
CURLcode result = CURLE_OK;
- CURL_TRC_FTP(data, "[%s] DO phase starts", FTP_DSTATE(data));
+ DEBUGF(infof(data, "DO phase starts"));
if(data->req.no_body) {
/* requested no body means no transfer... */
@@ -3877,15 +3758,10 @@ CURLcode ftp_perform(struct Curl_easy *data,
*connected = Curl_conn_is_connected(data->conn, SECONDARYSOCKET);
- if(*connected)
- infof(data, "[FTP] [%s] perform, DATA connection established",
- FTP_DSTATE(data));
- else
- CURL_TRC_FTP(data, "[%s] perform, awaiting DATA connect",
- FTP_DSTATE(data));
+ infof(data, "ftp_perform ends with SECONDARY: %d", *connected);
if(*dophase_done)
- CURL_TRC_FTP(data, "[%s] DO phase is complete1", FTP_DSTATE(data));
+ DEBUGF(infof(data, "DO phase is complete1"));
return result;
}
@@ -3958,7 +3834,7 @@ static CURLcode init_wc_data(struct Curl_easy *data)
if(data->set.ftp_filemethod == FTPFILE_NOCWD)
data->set.ftp_filemethod = FTPFILE_MULTICWD;
- /* try to parse ftp URL */
+ /* try to parse ftp url */
result = ftp_parse_url_path(data);
if(result) {
goto fail;
@@ -4024,7 +3900,7 @@ static CURLcode wc_statemach(struct Curl_easy *data)
wildcard->state = CURLWC_CLEAN;
continue;
}
- if(Curl_llist_count(&wildcard->filelist) == 0) {
+ if(wildcard->filelist.size == 0) {
/* no corresponding file */
wildcard->state = CURLWC_CLEAN;
return CURLE_REMOTE_FILE_NOT_FOUND;
@@ -4035,8 +3911,7 @@ static CURLcode wc_statemach(struct Curl_easy *data)
case CURLWC_DOWNLOADING: {
/* filelist has at least one file, lets get first one */
struct ftp_conn *ftpc = &conn->proto.ftpc;
- struct Curl_llist_node *head = Curl_llist_head(&wildcard->filelist);
- struct curl_fileinfo *finfo = Curl_node_elem(head);
+ struct curl_fileinfo *finfo = wildcard->filelist.head->ptr;
struct FTP *ftp = data->req.p.ftp;
char *tmp_path = aprintf("%s%s", wildcard->path, finfo->filename);
@@ -4052,8 +3927,7 @@ static CURLcode wc_statemach(struct Curl_easy *data)
long userresponse;
Curl_set_in_callback(data, true);
userresponse = data->set.chunk_bgn(
- finfo, data->set.wildcardptr,
- (int)Curl_llist_count(&wildcard->filelist));
+ finfo, data->set.wildcardptr, (int)wildcard->filelist.size);
Curl_set_in_callback(data, false);
switch(userresponse) {
case CURL_CHUNK_BGN_FUNC_SKIP:
@@ -4078,11 +3952,10 @@ static CURLcode wc_statemach(struct Curl_easy *data)
if(result)
return result;
- /* we do not need the Curl_fileinfo of first file anymore */
- Curl_node_remove(Curl_llist_head(&wildcard->filelist));
+ /* we don't need the Curl_fileinfo of first file anymore */
+ Curl_llist_remove(&wildcard->filelist, wildcard->filelist.head, NULL);
- if(Curl_llist_count(&wildcard->filelist) == 0) {
- /* remains only one file to down. */
+ if(wildcard->filelist.size == 0) { /* remains only one file to down. */
wildcard->state = CURLWC_CLEAN;
/* after that will be ftp_do called once again and no transfer
will be done because of CURLWC_CLEAN state */
@@ -4097,8 +3970,8 @@ static CURLcode wc_statemach(struct Curl_easy *data)
data->set.chunk_end(data->set.wildcardptr);
Curl_set_in_callback(data, false);
}
- Curl_node_remove(Curl_llist_head(&wildcard->filelist));
- wildcard->state = (Curl_llist_count(&wildcard->filelist) == 0) ?
+ Curl_llist_remove(&wildcard->filelist, wildcard->filelist.head, NULL);
+ wildcard->state = (wildcard->filelist.size == 0) ?
CURLWC_CLEAN : CURLWC_DOWNLOADING;
continue;
}
@@ -4144,24 +4017,6 @@ static CURLcode ftp_do(struct Curl_easy *data, bool *done)
*done = FALSE; /* default to false */
ftpc->wait_data_conn = FALSE; /* default to no such wait */
-#ifdef CURL_PREFER_LF_LINEENDS
- {
- /* FTP data may need conversion. */
- struct Curl_cwriter *ftp_lc_writer;
-
- result = Curl_cwriter_create(&ftp_lc_writer, data, &ftp_cw_lc,
- CURL_CW_CONTENT_DECODE);
- if(result)
- return result;
-
- result = Curl_cwriter_add(data, ftp_lc_writer);
- if(result) {
- Curl_cwriter_free(data, ftp_lc_writer);
- return result;
- }
- }
-#endif /* CURL_PREFER_LF_LINEENDS */
-
if(data->state.wildcardmatch) {
result = wc_statemach(data);
if(data->wildcard->state == CURLWC_SKIP ||
@@ -4234,7 +4089,7 @@ static CURLcode ftp_disconnect(struct Curl_easy *data,
bad in any way, sending quit and waiting around here will make the
disconnect wait in vain and cause more problems than we need to.
- ftp_quit() will check the state of ftp->ctl_valid. If it is ok it
+ ftp_quit() will check the state of ftp->ctl_valid. If it's ok it
will try to send the QUIT command, otherwise it will just return.
*/
if(dead_connection)
@@ -4322,17 +4177,18 @@ CURLcode ftp_parse_url_path(struct Curl_easy *data)
return CURLE_OUT_OF_MEMORY;
}
- ftpc->dirs[0] = Curl_memdup0(rawPath, dirlen);
+ ftpc->dirs[0] = calloc(1, dirlen + 1);
if(!ftpc->dirs[0]) {
free(rawPath);
return CURLE_OUT_OF_MEMORY;
}
+ strncpy(ftpc->dirs[0], rawPath, dirlen);
ftpc->dirdepth = 1; /* we consider it to be a single dir */
- fileName = slashPos + 1; /* rest is filename */
+ fileName = slashPos + 1; /* rest is file name */
}
else
- fileName = rawPath; /* filename only (or empty) */
+ fileName = rawPath; /* file name only (or empty) */
break;
default: /* allow pretty much anything */
@@ -4363,21 +4219,22 @@ CURLcode ftp_parse_url_path(struct Curl_easy *data)
++compLen;
/* we skip empty path components, like "x//y" since the FTP command
- CWD requires a parameter and a non-existent parameter a) does not
+ CWD requires a parameter and a non-existent parameter a) doesn't
work on many servers and b) has no effect on the others. */
if(compLen > 0) {
- char *comp = Curl_memdup0(curPos, compLen);
+ char *comp = calloc(1, compLen + 1);
if(!comp) {
free(rawPath);
return CURLE_OUT_OF_MEMORY;
}
+ strncpy(comp, curPos, compLen);
ftpc->dirs[ftpc->dirdepth++] = comp;
}
curPos = slashPos + 1;
}
}
DEBUGASSERT((size_t)ftpc->dirdepth <= dirAlloc);
- fileName = curPos; /* the rest is the filename (or empty) */
+ fileName = curPos; /* the rest is the file name (or empty) */
}
break;
} /* switch */
@@ -4389,8 +4246,8 @@ CURLcode ftp_parse_url_path(struct Curl_easy *data)
we make it a NULL pointer */
if(data->state.upload && !ftpc->file && (ftp->transfer == PPTRANSFER_BODY)) {
- /* We need a filename when uploading. Return error! */
- failf(data, "Uploading to a URL without a filename");
+ /* We need a file name when uploading. Return error! */
+ failf(data, "Uploading to a URL without a file name");
free(rawPath);
return CURLE_URL_MALFORMAT;
}
@@ -4431,16 +4288,16 @@ static CURLcode ftp_dophase_done(struct Curl_easy *data, bool connected)
CURLcode result = ftp_do_more(data, &completed);
if(result) {
- close_secondarysocket(data);
+ close_secondarysocket(data, conn);
return result;
}
}
if(ftp->transfer != PPTRANSFER_BODY)
/* no data to transfer */
- Curl_xfer_setup_nop(data);
+ Curl_setup_transfer(data, -1, -1, FALSE, -1);
else if(!connected)
- /* since we did not connect now, we want do_more to get called */
+ /* since we didn't connect now, we want do_more to get called */
conn->bits.do_more = TRUE;
ftpc->ctl_valid = TRUE; /* seems good */
@@ -4455,11 +4312,11 @@ static CURLcode ftp_doing(struct Curl_easy *data,
CURLcode result = ftp_multi_statemach(data, dophase_done);
if(result)
- CURL_TRC_FTP(data, "[%s] DO phase failed", FTP_DSTATE(data));
+ DEBUGF(infof(data, "DO phase failed"));
else if(*dophase_done) {
result = ftp_dophase_done(data, FALSE /* not connected */);
- CURL_TRC_FTP(data, "[%s] DO phase is complete2", FTP_DSTATE(data));
+ DEBUGF(infof(data, "DO phase is complete2"));
}
return result;
}
@@ -4545,10 +4402,10 @@ static CURLcode ftp_setup_connection(struct Curl_easy *data,
}
data->req.p.ftp = ftp;
- ftp->path = &data->state.up.path[1]; /* do not include the initial slash */
+ ftp->path = &data->state.up.path[1]; /* don't include the initial slash */
/* FTP URLs support an extension like ";type=<typecode>" that
- * we will try to get now! */
+ * we'll try to get now! */
type = strstr(ftp->path, ";type=");
if(!type)
@@ -4583,7 +4440,6 @@ static CURLcode ftp_setup_connection(struct Curl_easy *data,
ftpc->use_ssl = data->set.use_ssl;
ftpc->ccc = data->set.ftp_ccc;
- CURL_TRC_FTP(data, "[%s] setup connection -> %d", FTP_CSTATE(conn), result);
return result;
}
diff --git a/contrib/libs/curl/lib/ftp.h b/contrib/libs/curl/lib/ftp.h
index 3d0af01587..977fc883b1 100644
--- a/contrib/libs/curl/lib/ftp.h
+++ b/contrib/libs/curl/lib/ftp.h
@@ -61,7 +61,7 @@ enum {
FTP_STOR_PREQUOTE,
FTP_POSTQUOTE,
FTP_CWD, /* change dir */
- FTP_MKD, /* if the dir did not exist */
+ FTP_MKD, /* if the dir didn't exist */
FTP_MDTM, /* to figure out the datestamp */
FTP_TYPE, /* to set type when doing a head-like request */
FTP_LIST_TYPE, /* set type when about to do a dir list */
@@ -123,7 +123,7 @@ struct ftp_conn {
char *account;
char *alternative_to_user;
char *entrypath; /* the PWD reply when we logged on */
- char *file; /* url-decoded filename (or path) */
+ char *file; /* url-decoded file name (or path) */
char **dirs; /* realloc()ed array for path components */
char *newhost;
char *prevpath; /* url-decoded conn->path from the previous transfer */
@@ -139,7 +139,7 @@ struct ftp_conn {
int count1; /* general purpose counter for the state machine */
int count2; /* general purpose counter for the state machine */
int count3; /* general purpose counter for the state machine */
- /* newhost is the (allocated) IP addr or hostname to connect the data
+ /* newhost is the (allocated) IP addr or host name to connect the data
connection to */
unsigned short newport;
ftpstate state; /* always use ftp.c:state() to change state! */
diff --git a/contrib/libs/curl/lib/ftplistparser.c b/contrib/libs/curl/lib/ftplistparser.c
index 448f3a43ab..82f1ea00d3 100644
--- a/contrib/libs/curl/lib/ftplistparser.c
+++ b/contrib/libs/curl/lib/ftplistparser.c
@@ -349,7 +349,7 @@ static CURLcode ftp_pl_insert_finfo(struct Curl_easy *data,
Curl_set_in_callback(data, false);
if(add) {
- Curl_llist_append(llist, finfo, &infop->list);
+ Curl_llist_insert_next(llist, llist->tail, finfo, &infop->list);
}
else {
Curl_fileinfo_cleanup(infop);
diff --git a/contrib/libs/curl/lib/getenv.c b/contrib/libs/curl/lib/getenv.c
index 49a2e50fa3..48ee972289 100644
--- a/contrib/libs/curl/lib/getenv.c
+++ b/contrib/libs/curl/lib/getenv.c
@@ -37,7 +37,7 @@ static char *GetEnv(const char *variable)
return NULL;
#elif defined(_WIN32)
/* This uses Windows API instead of C runtime getenv() to get the environment
- variable since some changes are not always visible to the latter. #4774 */
+ variable since some changes aren't always visible to the latter. #4774 */
char *buf = NULL;
char *tmp;
DWORD bufsize;
@@ -54,8 +54,8 @@ static char *GetEnv(const char *variable)
buf = tmp;
bufsize = rc;
- /* it is possible for rc to be 0 if the variable was found but empty.
- Since getenv does not make that distinction we ignore it as well. */
+ /* It's possible for rc to be 0 if the variable was found but empty.
+ Since getenv doesn't make that distinction we ignore it as well. */
rc = GetEnvironmentVariableA(variable, buf, bufsize);
if(!rc || rc == bufsize || rc > max) {
free(buf);
diff --git a/contrib/libs/curl/lib/getinfo.c b/contrib/libs/curl/lib/getinfo.c
index 714610156f..f1574e097b 100644
--- a/contrib/libs/curl/lib/getinfo.c
+++ b/contrib/libs/curl/lib/getinfo.c
@@ -53,7 +53,6 @@ CURLcode Curl_initinfo(struct Curl_easy *data)
pro->t_connect = 0;
pro->t_appconnect = 0;
pro->t_pretransfer = 0;
- pro->t_posttransfer = 0;
pro->t_starttransfer = 0;
pro->timespent = 0;
pro->t_redirect = 0;
@@ -77,9 +76,10 @@ CURLcode Curl_initinfo(struct Curl_easy *data)
free(info->wouldredirect);
info->wouldredirect = NULL;
- memset(&info->primary, 0, sizeof(info->primary));
- info->primary.remote_port = -1;
- info->primary.local_port = -1;
+ info->conn_primary_ip[0] = '\0';
+ info->conn_local_ip[0] = '\0';
+ info->conn_primary_port = 0;
+ info->conn_local_port = 0;
info->retry_after = 0;
info->conn_scheme = 0;
@@ -153,19 +153,15 @@ static CURLcode getinfo_char(struct Curl_easy *data, CURLINFO info,
break;
case CURLINFO_PRIMARY_IP:
/* Return the ip address of the most recent (primary) connection */
- *param_charp = data->info.primary.remote_ip;
+ *param_charp = data->info.conn_primary_ip;
break;
case CURLINFO_LOCAL_IP:
/* Return the source/local ip address of the most recent (primary)
connection */
- *param_charp = data->info.primary.local_ip;
+ *param_charp = data->info.conn_local_ip;
break;
case CURLINFO_RTSP_SESSION_ID:
-#ifndef CURL_DISABLE_RTSP
*param_charp = data->set.str[STRING_RTSP_SESSION_ID];
-#else
- *param_charp = NULL;
-#endif
break;
case CURLINFO_SCHEME:
*param_charp = data->info.conn_scheme;
@@ -184,6 +180,7 @@ static CURLcode getinfo_char(struct Curl_easy *data, CURLINFO info,
*param_charp = NULL;
#endif
break;
+
default:
return CURLE_UNKNOWN_OPTION;
}
@@ -204,7 +201,7 @@ static CURLcode getinfo_long(struct Curl_easy *data, CURLINFO info,
#ifdef DEBUGBUILD
char *timestr = getenv("CURL_TIME");
if(timestr) {
- unsigned long val = strtoul(timestr, NULL, 10);
+ unsigned long val = strtol(timestr, NULL, 10);
switch(info) {
case CURLINFO_LOCAL_PORT:
*param_longp = (long)val;
@@ -216,7 +213,7 @@ static CURLcode getinfo_long(struct Curl_easy *data, CURLINFO info,
/* use another variable for this to allow different values */
timestr = getenv("CURL_DEBUG_SIZE");
if(timestr) {
- unsigned long val = strtoul(timestr, NULL, 10);
+ unsigned long val = strtol(timestr, NULL, 10);
switch(info) {
case CURLINFO_HEADER_SIZE:
case CURLINFO_REQUEST_SIZE:
@@ -252,13 +249,11 @@ static CURLcode getinfo_long(struct Curl_easy *data, CURLINFO info,
case CURLINFO_SSL_VERIFYRESULT:
*param_longp = data->set.ssl.certverifyresult;
break;
- case CURLINFO_PROXY_SSL_VERIFYRESULT:
#ifndef CURL_DISABLE_PROXY
+ case CURLINFO_PROXY_SSL_VERIFYRESULT:
*param_longp = data->set.proxy_ssl.certverifyresult;
-#else
- *param_longp = 0;
-#endif
break;
+#endif
case CURLINFO_REDIRECT_COUNT:
*param_longp = data->state.followlocation;
break;
@@ -279,8 +274,8 @@ static CURLcode getinfo_long(struct Curl_easy *data, CURLINFO info,
case CURLINFO_LASTSOCKET:
sockfd = Curl_getconnectinfo(data, NULL);
- /* note: this is not a good conversion for systems with 64-bit sockets and
- 32-bit longs */
+ /* note: this is not a good conversion for systems with 64 bit sockets and
+ 32 bit longs */
if(sockfd != CURL_SOCKET_BAD)
*param_longp = (long)sockfd;
else
@@ -290,11 +285,11 @@ static CURLcode getinfo_long(struct Curl_easy *data, CURLINFO info,
break;
case CURLINFO_PRIMARY_PORT:
/* Return the (remote) port of the most recent (primary) connection */
- *param_longp = data->info.primary.remote_port;
+ *param_longp = data->info.conn_primary_port;
break;
case CURLINFO_LOCAL_PORT:
/* Return the local port of the most recent (primary) connection */
- *param_longp = data->info.primary.local_port;
+ *param_longp = data->info.conn_local_port;
break;
case CURLINFO_PROXY_ERROR:
*param_longp = (long)data->info.pxcode;
@@ -316,12 +311,6 @@ static CURLcode getinfo_long(struct Curl_easy *data, CURLINFO info,
case CURLINFO_RTSP_CSEQ_RECV:
*param_longp = data->state.rtsp_CSeq_recv;
break;
-#else
- case CURLINFO_RTSP_CLIENT_CSEQ:
- case CURLINFO_RTSP_SERVER_CSEQ:
- case CURLINFO_RTSP_CSEQ_RECV:
- *param_longp = 0;
- break;
#endif
case CURLINFO_HTTP_VERSION:
switch(data->info.httpversion) {
@@ -343,16 +332,7 @@ static CURLcode getinfo_long(struct Curl_easy *data, CURLINFO info,
}
break;
case CURLINFO_PROTOCOL:
- *param_longp = (long)data->info.conn_protocol;
- break;
- case CURLINFO_USED_PROXY:
- *param_longp =
-#ifdef CURL_DISABLE_PROXY
- 0
-#else
- data->info.used_proxy
-#endif
- ;
+ *param_longp = data->info.conn_protocol;
break;
default:
return CURLE_UNKNOWN_OPTION;
@@ -369,14 +349,13 @@ static CURLcode getinfo_offt(struct Curl_easy *data, CURLINFO info,
#ifdef DEBUGBUILD
char *timestr = getenv("CURL_TIME");
if(timestr) {
- unsigned long val = strtoul(timestr, NULL, 10);
+ unsigned long val = strtol(timestr, NULL, 10);
switch(info) {
case CURLINFO_TOTAL_TIME_T:
case CURLINFO_NAMELOOKUP_TIME_T:
case CURLINFO_CONNECT_TIME_T:
case CURLINFO_APPCONNECT_TIME_T:
case CURLINFO_PRETRANSFER_TIME_T:
- case CURLINFO_POSTTRANSFER_TIME_T:
case CURLINFO_STARTTRANSFER_TIME_T:
case CURLINFO_REDIRECT_TIME_T:
case CURLINFO_SPEED_DOWNLOAD_T:
@@ -393,24 +372,24 @@ static CURLcode getinfo_offt(struct Curl_easy *data, CURLINFO info,
*param_offt = (curl_off_t)data->info.filetime;
break;
case CURLINFO_SIZE_UPLOAD_T:
- *param_offt = data->progress.ul.cur_size;
+ *param_offt = data->progress.uploaded;
break;
case CURLINFO_SIZE_DOWNLOAD_T:
- *param_offt = data->progress.dl.cur_size;
+ *param_offt = data->progress.downloaded;
break;
case CURLINFO_SPEED_DOWNLOAD_T:
- *param_offt = data->progress.dl.speed;
+ *param_offt = data->progress.dlspeed;
break;
case CURLINFO_SPEED_UPLOAD_T:
- *param_offt = data->progress.ul.speed;
+ *param_offt = data->progress.ulspeed;
break;
case CURLINFO_CONTENT_LENGTH_DOWNLOAD_T:
*param_offt = (data->progress.flags & PGRS_DL_SIZE_KNOWN)?
- data->progress.dl.total_size:-1;
+ data->progress.size_dl:-1;
break;
case CURLINFO_CONTENT_LENGTH_UPLOAD_T:
*param_offt = (data->progress.flags & PGRS_UL_SIZE_KNOWN)?
- data->progress.ul.total_size:-1;
+ data->progress.size_ul:-1;
break;
case CURLINFO_TOTAL_TIME_T:
*param_offt = data->progress.timespent;
@@ -427,15 +406,9 @@ static CURLcode getinfo_offt(struct Curl_easy *data, CURLINFO info,
case CURLINFO_PRETRANSFER_TIME_T:
*param_offt = data->progress.t_pretransfer;
break;
- case CURLINFO_POSTTRANSFER_TIME_T:
- *param_offt = data->progress.t_posttransfer;
- break;
case CURLINFO_STARTTRANSFER_TIME_T:
*param_offt = data->progress.t_starttransfer;
break;
- case CURLINFO_QUEUE_TIME_T:
- *param_offt = data->progress.t_postqueue;
- break;
case CURLINFO_REDIRECT_TIME_T:
*param_offt = data->progress.t_redirect;
break;
@@ -447,7 +420,7 @@ static CURLcode getinfo_offt(struct Curl_easy *data, CURLINFO info,
break;
case CURLINFO_CONN_ID:
*param_offt = data->conn?
- data->conn->connection_id : data->state.recent_conn_id;
+ data->conn->connection_id : data->state.recent_conn_id;
break;
default:
return CURLE_UNKNOWN_OPTION;
@@ -462,7 +435,7 @@ static CURLcode getinfo_double(struct Curl_easy *data, CURLINFO info,
#ifdef DEBUGBUILD
char *timestr = getenv("CURL_TIME");
if(timestr) {
- unsigned long val = strtoul(timestr, NULL, 10);
+ unsigned long val = strtol(timestr, NULL, 10);
switch(info) {
case CURLINFO_TOTAL_TIME:
case CURLINFO_NAMELOOKUP_TIME:
@@ -500,24 +473,24 @@ static CURLcode getinfo_double(struct Curl_easy *data, CURLINFO info,
*param_doublep = DOUBLE_SECS(data->progress.t_starttransfer);
break;
case CURLINFO_SIZE_UPLOAD:
- *param_doublep = (double)data->progress.ul.cur_size;
+ *param_doublep = (double)data->progress.uploaded;
break;
case CURLINFO_SIZE_DOWNLOAD:
- *param_doublep = (double)data->progress.dl.cur_size;
+ *param_doublep = (double)data->progress.downloaded;
break;
case CURLINFO_SPEED_DOWNLOAD:
- *param_doublep = (double)data->progress.dl.speed;
+ *param_doublep = (double)data->progress.dlspeed;
break;
case CURLINFO_SPEED_UPLOAD:
- *param_doublep = (double)data->progress.ul.speed;
+ *param_doublep = (double)data->progress.ulspeed;
break;
case CURLINFO_CONTENT_LENGTH_DOWNLOAD:
*param_doublep = (data->progress.flags & PGRS_DL_SIZE_KNOWN)?
- (double)data->progress.dl.total_size:-1;
+ (double)data->progress.size_dl:-1;
break;
case CURLINFO_CONTENT_LENGTH_UPLOAD:
*param_doublep = (data->progress.flags & PGRS_UL_SIZE_KNOWN)?
- (double)data->progress.ul.total_size:-1;
+ (double)data->progress.size_ul:-1;
break;
case CURLINFO_REDIRECT_TIME:
*param_doublep = DOUBLE_SECS(data->progress.t_redirect);
diff --git a/contrib/libs/curl/lib/gopher.c b/contrib/libs/curl/lib/gopher.c
index 051e6e7ab5..61e41b7e47 100644
--- a/contrib/libs/curl/lib/gopher.c
+++ b/contrib/libs/curl/lib/gopher.c
@@ -62,7 +62,7 @@ static CURLcode gopher_connecting(struct Curl_easy *data, bool *done);
*/
const struct Curl_handler Curl_handler_gopher = {
- "gopher", /* scheme */
+ "GOPHER", /* scheme */
ZERO_NULL, /* setup_connection */
gopher_do, /* do_it */
ZERO_NULL, /* done */
@@ -75,8 +75,7 @@ const struct Curl_handler Curl_handler_gopher = {
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
ZERO_NULL, /* disconnect */
- ZERO_NULL, /* write_resp */
- ZERO_NULL, /* write_resp_hd */
+ ZERO_NULL, /* readwrite */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_GOPHER, /* defport */
@@ -87,7 +86,7 @@ const struct Curl_handler Curl_handler_gopher = {
#ifdef USE_SSL
const struct Curl_handler Curl_handler_gophers = {
- "gophers", /* scheme */
+ "GOPHERS", /* scheme */
ZERO_NULL, /* setup_connection */
gopher_do, /* do_it */
ZERO_NULL, /* done */
@@ -100,8 +99,7 @@ const struct Curl_handler Curl_handler_gophers = {
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
ZERO_NULL, /* disconnect */
- ZERO_NULL, /* write_resp */
- ZERO_NULL, /* write_resp_hd */
+ ZERO_NULL, /* readwrite */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_GOPHER, /* defport */
@@ -141,8 +139,8 @@ static CURLcode gopher_do(struct Curl_easy *data, bool *done)
char *sel = NULL;
char *sel_org = NULL;
timediff_t timeout_ms;
- ssize_t k;
- size_t amount, len;
+ ssize_t amount, k;
+ size_t len;
int what;
*done = TRUE; /* unconditionally */
@@ -187,7 +185,7 @@ static CURLcode gopher_do(struct Curl_easy *data, bool *done)
if(strlen(sel) < 1)
break;
- result = Curl_xfer_send(data, sel, k, FALSE, &amount);
+ result = Curl_nwrite(data, FIRSTSOCKET, sel, k, &amount);
if(!result) { /* Which may not have written it all! */
result = Curl_client_write(data, CLIENTWRITE_HEADER, sel, amount);
if(result)
@@ -209,9 +207,9 @@ static CURLcode gopher_do(struct Curl_easy *data, bool *done)
if(!timeout_ms)
timeout_ms = TIMEDIFF_T_MAX;
- /* Do not busyloop. The entire loop thing is a work-around as it causes a
+ /* Don't busyloop. The entire loop thing is a work-around as it causes a
BLOCKING behavior which is a NO-NO. This function should rather be
- split up in a do and a doing piece where the pieces that are not
+ split up in a do and a doing piece where the pieces that aren't
possible to send now will be sent in the doing function repeatedly
until the entire request is sent.
*/
@@ -229,7 +227,7 @@ static CURLcode gopher_do(struct Curl_easy *data, bool *done)
free(sel_org);
if(!result)
- result = Curl_xfer_send(data, "\r\n", 2, FALSE, &amount);
+ result = Curl_nwrite(data, FIRSTSOCKET, "\r\n", 2, &amount);
if(result) {
failf(data, "Failed sending Gopher request");
return result;
@@ -238,7 +236,7 @@ static CURLcode gopher_do(struct Curl_easy *data, bool *done)
if(result)
return result;
- Curl_xfer_setup1(data, CURL_XFER_RECV, -1, FALSE);
+ Curl_setup_transfer(data, FIRSTSOCKET, -1, FALSE, -1);
return CURLE_OK;
}
#endif /* CURL_DISABLE_GOPHER */
diff --git a/contrib/libs/curl/lib/hash.c b/contrib/libs/curl/lib/hash.c
index 1910ac5dc4..30f28e2352 100644
--- a/contrib/libs/curl/lib/hash.c
+++ b/contrib/libs/curl/lib/hash.c
@@ -33,10 +33,6 @@
/* The last #include file should be: */
#include "memdebug.h"
-/* random patterns for API verification */
-#define HASHINIT 0x7017e781
-#define ITERINIT 0x5FEDCBA9
-
static void
hash_element_dtor(void *user, void *element)
{
@@ -44,10 +40,7 @@ hash_element_dtor(void *user, void *element)
struct Curl_hash_element *e = (struct Curl_hash_element *) element;
if(e->ptr) {
- if(e->dtor)
- e->dtor(e->key, e->key_len, e->ptr);
- else
- h->dtor(e->ptr);
+ h->dtor(e->ptr);
e->ptr = NULL;
}
@@ -64,7 +57,7 @@ hash_element_dtor(void *user, void *element)
*/
void
Curl_hash_init(struct Curl_hash *h,
- size_t slots,
+ int slots,
hash_function hfunc,
comp_function comparator,
Curl_hash_dtor dtor)
@@ -81,14 +74,10 @@ Curl_hash_init(struct Curl_hash *h,
h->dtor = dtor;
h->size = 0;
h->slots = slots;
-#ifdef DEBUGBUILD
- h->init = HASHINIT;
-#endif
}
static struct Curl_hash_element *
-mk_hash_element(const void *key, size_t key_len, const void *p,
- Curl_hash_elem_dtor dtor)
+mk_hash_element(const void *key, size_t key_len, const void *p)
{
/* allocate the struct plus memory after it to store the key */
struct Curl_hash_element *he = malloc(sizeof(struct Curl_hash_element) +
@@ -98,25 +87,31 @@ mk_hash_element(const void *key, size_t key_len, const void *p,
memcpy(he->key, key, key_len);
he->key_len = key_len;
he->ptr = (void *) p;
- he->dtor = dtor;
}
return he;
}
#define FETCH_LIST(x,y,z) &x->table[x->hash_func(y, z, x->slots)]
-void *Curl_hash_add2(struct Curl_hash *h, void *key, size_t key_len, void *p,
- Curl_hash_elem_dtor dtor)
+/* Insert the data in the hash. If there already was a match in the hash, that
+ * data is replaced. This function also "lazily" allocates the table if
+ * needed, as it isn't done in the _init function (anymore).
+ *
+ * @unittest: 1305
+ * @unittest: 1602
+ * @unittest: 1603
+ */
+void *
+Curl_hash_add(struct Curl_hash *h, void *key, size_t key_len, void *p)
{
struct Curl_hash_element *he;
- struct Curl_llist_node *le;
+ struct Curl_llist_element *le;
struct Curl_llist *l;
DEBUGASSERT(h);
DEBUGASSERT(h->slots);
- DEBUGASSERT(h->init == HASHINIT);
if(!h->table) {
- size_t i;
+ int i;
h->table = malloc(h->slots * sizeof(struct Curl_llist));
if(!h->table)
return NULL; /* OOM */
@@ -126,18 +121,18 @@ void *Curl_hash_add2(struct Curl_hash *h, void *key, size_t key_len, void *p,
l = FETCH_LIST(h, key, key_len);
- for(le = Curl_llist_head(l); le; le = Curl_node_next(le)) {
- he = (struct Curl_hash_element *) Curl_node_elem(le);
+ for(le = l->head; le; le = le->next) {
+ he = (struct Curl_hash_element *) le->ptr;
if(h->comp_func(he->key, he->key_len, key, key_len)) {
- Curl_node_uremove(le, (void *)h);
+ Curl_llist_remove(l, le, (void *)h);
--h->size;
break;
}
}
- he = mk_hash_element(key, key_len, p, dtor);
+ he = mk_hash_element(key, key_len, p);
if(he) {
- Curl_llist_append(l, he, &he->list);
+ Curl_llist_insert_next(l, l->tail, he, &he->list);
++h->size;
return p; /* return the new entry */
}
@@ -145,20 +140,6 @@ void *Curl_hash_add2(struct Curl_hash *h, void *key, size_t key_len, void *p,
return NULL; /* failure */
}
-/* Insert the data in the hash. If there already was a match in the hash, that
- * data is replaced. This function also "lazily" allocates the table if
- * needed, as it is not done in the _init function (anymore).
- *
- * @unittest: 1305
- * @unittest: 1602
- * @unittest: 1603
- */
-void *
-Curl_hash_add(struct Curl_hash *h, void *key, size_t key_len, void *p)
-{
- return Curl_hash_add2(h, key, key_len, p, NULL);
-}
-
/* Remove the identified hash entry.
* Returns non-zero on failure.
*
@@ -166,17 +147,18 @@ Curl_hash_add(struct Curl_hash *h, void *key, size_t key_len, void *p)
*/
int Curl_hash_delete(struct Curl_hash *h, void *key, size_t key_len)
{
+ struct Curl_llist_element *le;
+ struct Curl_llist *l;
+
DEBUGASSERT(h);
DEBUGASSERT(h->slots);
- DEBUGASSERT(h->init == HASHINIT);
if(h->table) {
- struct Curl_llist_node *le;
- struct Curl_llist *l = FETCH_LIST(h, key, key_len);
+ l = FETCH_LIST(h, key, key_len);
- for(le = Curl_llist_head(l); le; le = Curl_node_next(le)) {
- struct Curl_hash_element *he = Curl_node_elem(le);
+ for(le = l->head; le; le = le->next) {
+ struct Curl_hash_element *he = le->ptr;
if(h->comp_func(he->key, he->key_len, key, key_len)) {
- Curl_node_uremove(le, (void *) h);
+ Curl_llist_remove(l, le, (void *) h);
--h->size;
return 0;
}
@@ -192,15 +174,15 @@ int Curl_hash_delete(struct Curl_hash *h, void *key, size_t key_len)
void *
Curl_hash_pick(struct Curl_hash *h, void *key, size_t key_len)
{
+ struct Curl_llist_element *le;
+ struct Curl_llist *l;
+
DEBUGASSERT(h);
- DEBUGASSERT(h->init == HASHINIT);
if(h->table) {
- struct Curl_llist_node *le;
- struct Curl_llist *l;
DEBUGASSERT(h->slots);
l = FETCH_LIST(h, key, key_len);
- for(le = Curl_llist_head(l); le; le = Curl_node_next(le)) {
- struct Curl_hash_element *he = Curl_node_elem(le);
+ for(le = l->head; le; le = le->next) {
+ struct Curl_hash_element *he = le->ptr;
if(h->comp_func(he->key, he->key_len, key, key_len)) {
return he->ptr;
}
@@ -210,6 +192,25 @@ Curl_hash_pick(struct Curl_hash *h, void *key, size_t key_len)
return NULL;
}
+#if defined(DEBUGBUILD) && defined(AGGRESSIVE_TEST)
+void
+Curl_hash_apply(Curl_hash *h, void *user,
+ void (*cb)(void *user, void *ptr))
+{
+ struct Curl_llist_element *le;
+ int i;
+
+ for(i = 0; i < h->slots; ++i) {
+ for(le = (h->table[i])->head;
+ le;
+ le = le->next) {
+ Curl_hash_element *el = le->ptr;
+ cb(user, el->ptr);
+ }
+ }
+}
+#endif
+
/* Destroys all the entries in the given hash and resets its attributes,
* prepping the given hash for [static|dynamic] deallocation.
*
@@ -220,9 +221,8 @@ Curl_hash_pick(struct Curl_hash *h, void *key, size_t key_len)
void
Curl_hash_destroy(struct Curl_hash *h)
{
- DEBUGASSERT(h->init == HASHINIT);
if(h->table) {
- size_t i;
+ int i;
for(i = 0; i < h->slots; ++i) {
Curl_llist_destroy(&h->table[i], (void *) h);
}
@@ -242,33 +242,28 @@ Curl_hash_clean(struct Curl_hash *h)
Curl_hash_clean_with_criterium(h, NULL, NULL);
}
-size_t Curl_hash_count(struct Curl_hash *h)
-{
- DEBUGASSERT(h->init == HASHINIT);
- return h->size;
-}
-
/* Cleans all entries that pass the comp function criteria. */
void
Curl_hash_clean_with_criterium(struct Curl_hash *h, void *user,
int (*comp)(void *, void *))
{
- size_t i;
+ struct Curl_llist_element *le;
+ struct Curl_llist_element *lnext;
+ struct Curl_llist *list;
+ int i;
if(!h || !h->table)
return;
- DEBUGASSERT(h->init == HASHINIT);
for(i = 0; i < h->slots; ++i) {
- struct Curl_llist *list = &h->table[i];
- struct Curl_llist_node *le =
- Curl_llist_head(list); /* get first list entry */
+ list = &h->table[i];
+ le = list->head; /* get first list entry */
while(le) {
- struct Curl_hash_element *he = Curl_node_elem(le);
- struct Curl_llist_node *lnext = Curl_node_next(le);
+ struct Curl_hash_element *he = le->ptr;
+ lnext = le->next;
/* ask the callback function if we shall remove this entry or not */
if(!comp || comp(user, he->ptr)) {
- Curl_node_uremove(le, (void *) h);
+ Curl_llist_remove(list, le, (void *) h);
--h->size; /* one less entry in the hash now */
}
le = lnext;
@@ -283,9 +278,8 @@ size_t Curl_hash_str(void *key, size_t key_length, size_t slots_num)
size_t h = 5381;
while(key_str < end) {
- size_t j = (size_t)*key_str++;
h += h << 5;
- h ^= j;
+ h ^= *key_str++;
}
return (h % slots_num);
@@ -303,34 +297,29 @@ size_t Curl_str_key_compare(void *k1, size_t key1_len,
void Curl_hash_start_iterate(struct Curl_hash *hash,
struct Curl_hash_iterator *iter)
{
- DEBUGASSERT(hash->init == HASHINIT);
iter->hash = hash;
iter->slot_index = 0;
iter->current_element = NULL;
-#ifdef DEBUGBUILD
- iter->init = ITERINIT;
-#endif
}
struct Curl_hash_element *
Curl_hash_next_element(struct Curl_hash_iterator *iter)
{
- struct Curl_hash *h;
- DEBUGASSERT(iter->init == ITERINIT);
- h = iter->hash;
+ struct Curl_hash *h = iter->hash;
+
if(!h->table)
return NULL; /* empty hash, nothing to return */
/* Get the next element in the current list, if any */
if(iter->current_element)
- iter->current_element = Curl_node_next(iter->current_element);
+ iter->current_element = iter->current_element->next;
/* If we have reached the end of the list, find the next one */
if(!iter->current_element) {
- size_t i;
+ int i;
for(i = iter->slot_index; i < h->slots; i++) {
- if(Curl_llist_head(&h->table[i])) {
- iter->current_element = Curl_llist_head(&h->table[i]);
+ if(h->table[i].head) {
+ iter->current_element = h->table[i].head;
iter->slot_index = i + 1;
break;
}
@@ -338,7 +327,7 @@ Curl_hash_next_element(struct Curl_hash_iterator *iter)
}
if(iter->current_element) {
- struct Curl_hash_element *he = Curl_node_elem(iter->current_element);
+ struct Curl_hash_element *he = iter->current_element->ptr;
return he;
}
return NULL;
@@ -350,7 +339,7 @@ void Curl_hash_print(struct Curl_hash *h,
{
struct Curl_hash_iterator iter;
struct Curl_hash_element *he;
- size_t last_index = ~0;
+ int last_index = -1;
if(!h)
return;
@@ -363,7 +352,7 @@ void Curl_hash_print(struct Curl_hash *h,
while(he) {
if(iter.slot_index != last_index) {
fprintf(stderr, "index %d:", iter.slot_index);
- if(last_index != ~0) {
+ if(last_index >= 0) {
fprintf(stderr, "\n");
}
last_index = iter.slot_index;
@@ -379,25 +368,3 @@ void Curl_hash_print(struct Curl_hash *h,
fprintf(stderr, "\n");
}
#endif
-
-void Curl_hash_offt_init(struct Curl_hash *h,
- size_t slots,
- Curl_hash_dtor dtor)
-{
- Curl_hash_init(h, slots, Curl_hash_str, Curl_str_key_compare, dtor);
-}
-
-void *Curl_hash_offt_set(struct Curl_hash *h, curl_off_t id, void *elem)
-{
- return Curl_hash_add(h, &id, sizeof(id), elem);
-}
-
-int Curl_hash_offt_remove(struct Curl_hash *h, curl_off_t id)
-{
- return Curl_hash_delete(h, &id, sizeof(id));
-}
-
-void *Curl_hash_offt_get(struct Curl_hash *h, curl_off_t id)
-{
- return Curl_hash_pick(h, &id, sizeof(id));
-}
diff --git a/contrib/libs/curl/lib/hash.h b/contrib/libs/curl/lib/hash.h
index b160395024..9cfffc25b0 100644
--- a/contrib/libs/curl/lib/hash.h
+++ b/contrib/libs/curl/lib/hash.h
@@ -54,49 +54,36 @@ struct Curl_hash {
/* Comparator function to compare keys */
comp_function comp_func;
Curl_hash_dtor dtor;
- size_t slots;
+ int slots;
size_t size;
-#ifdef DEBUGBUILD
- int init;
-#endif
};
-typedef void (*Curl_hash_elem_dtor)(void *key, size_t key_len, void *p);
-
struct Curl_hash_element {
- struct Curl_llist_node list;
+ struct Curl_llist_element list;
void *ptr;
- Curl_hash_elem_dtor dtor;
size_t key_len;
-#ifdef DEBUGBUILD
- int init;
-#endif
char key[1]; /* allocated memory following the struct */
};
struct Curl_hash_iterator {
struct Curl_hash *hash;
- size_t slot_index;
- struct Curl_llist_node *current_element;
-#ifdef DEBUGBUILD
- int init;
-#endif
+ int slot_index;
+ struct Curl_llist_element *current_element;
};
void Curl_hash_init(struct Curl_hash *h,
- size_t slots,
+ int slots,
hash_function hfunc,
comp_function comparator,
Curl_hash_dtor dtor);
void *Curl_hash_add(struct Curl_hash *h, void *key, size_t key_len, void *p);
-void *Curl_hash_add2(struct Curl_hash *h, void *key, size_t key_len, void *p,
- Curl_hash_elem_dtor dtor);
int Curl_hash_delete(struct Curl_hash *h, void *key, size_t key_len);
void *Curl_hash_pick(struct Curl_hash *, void *key, size_t key_len);
-
+void Curl_hash_apply(struct Curl_hash *h, void *user,
+ void (*cb)(void *user, void *ptr));
+#define Curl_hash_count(h) ((h)->size)
void Curl_hash_destroy(struct Curl_hash *h);
-size_t Curl_hash_count(struct Curl_hash *h);
void Curl_hash_clean(struct Curl_hash *h);
void Curl_hash_clean_with_criterium(struct Curl_hash *h, void *user,
int (*comp)(void *, void *));
@@ -111,13 +98,5 @@ Curl_hash_next_element(struct Curl_hash_iterator *iter);
void Curl_hash_print(struct Curl_hash *h,
void (*func)(void *));
-/* Hash for `curl_off_t` as key */
-void Curl_hash_offt_init(struct Curl_hash *h, size_t slots,
- Curl_hash_dtor dtor);
-
-void *Curl_hash_offt_set(struct Curl_hash *h, curl_off_t id, void *elem);
-int Curl_hash_offt_remove(struct Curl_hash *h, curl_off_t id);
-void *Curl_hash_offt_get(struct Curl_hash *h, curl_off_t id);
-
#endif /* HEADER_CURL_HASH_H */
diff --git a/contrib/libs/curl/lib/headers.c b/contrib/libs/curl/lib/headers.c
index 7c60c07985..3ff4d5eb07 100644
--- a/contrib/libs/curl/lib/headers.c
+++ b/contrib/libs/curl/lib/headers.c
@@ -27,7 +27,6 @@
#include "urldata.h"
#include "strdup.h"
#include "strcase.h"
-#include "sendf.h"
#include "headers.h"
/* The last 3 #include files should be in this order */
@@ -42,7 +41,7 @@
static void copy_header_external(struct Curl_header_store *hs,
size_t index,
size_t amount,
- struct Curl_llist_node *e,
+ struct Curl_llist_element *e,
struct curl_header *hout)
{
struct curl_header *h = hout;
@@ -54,7 +53,7 @@ static void copy_header_external(struct Curl_header_store *hs,
impossible for applications to do == comparisons, as that would otherwise
be very tempting and then lead to the reserved bits not being reserved
anymore. */
- h->origin = (unsigned int)(hs->type | (1<<27));
+ h->origin = hs->type | (1<<27);
h->anchor = e;
}
@@ -66,8 +65,8 @@ CURLHcode curl_easy_header(CURL *easy,
int request,
struct curl_header **hout)
{
- struct Curl_llist_node *e;
- struct Curl_llist_node *e_pick = NULL;
+ struct Curl_llist_element *e;
+ struct Curl_llist_element *e_pick = NULL;
struct Curl_easy *data = easy;
size_t match = 0;
size_t amount = 0;
@@ -85,8 +84,8 @@ CURLHcode curl_easy_header(CURL *easy,
request = data->state.requests;
/* we need a first round to count amount of this header */
- for(e = Curl_llist_head(&data->state.httphdrs); e; e = Curl_node_next(e)) {
- hs = Curl_node_elem(e);
+ for(e = data->state.httphdrs.head; e; e = e->next) {
+ hs = e->ptr;
if(strcasecompare(hs->name, name) &&
(hs->type & type) &&
(hs->request == request)) {
@@ -104,8 +103,8 @@ CURLHcode curl_easy_header(CURL *easy,
/* if the last or only occurrence is what's asked for, then we know it */
hs = pick;
else {
- for(e = Curl_llist_head(&data->state.httphdrs); e; e = Curl_node_next(e)) {
- hs = Curl_node_elem(e);
+ for(e = data->state.httphdrs.head; e; e = e->next) {
+ hs = e->ptr;
if(strcasecompare(hs->name, name) &&
(hs->type & type) &&
(hs->request == request) &&
@@ -114,7 +113,7 @@ CURLHcode curl_easy_header(CURL *easy,
break;
}
}
- if(!e) /* this should not happen */
+ if(!e) /* this shouldn't happen */
return CURLHE_MISSING;
}
/* this is the name we want */
@@ -131,8 +130,8 @@ struct curl_header *curl_easy_nextheader(CURL *easy,
struct curl_header *prev)
{
struct Curl_easy *data = easy;
- struct Curl_llist_node *pick;
- struct Curl_llist_node *e;
+ struct Curl_llist_element *pick;
+ struct Curl_llist_element *e;
struct Curl_header_store *hs;
size_t amount = 0;
size_t index = 0;
@@ -147,18 +146,18 @@ struct curl_header *curl_easy_nextheader(CURL *easy,
if(!pick)
/* something is wrong */
return NULL;
- pick = Curl_node_next(pick);
+ pick = pick->next;
}
else
- pick = Curl_llist_head(&data->state.httphdrs);
+ pick = data->state.httphdrs.head;
if(pick) {
/* make sure it is the next header of the desired type */
do {
- hs = Curl_node_elem(pick);
+ hs = pick->ptr;
if((hs->type & type) && (hs->request == request))
break;
- pick = Curl_node_next(pick);
+ pick = pick->next;
} while(pick);
}
@@ -166,12 +165,12 @@ struct curl_header *curl_easy_nextheader(CURL *easy,
/* no more headers available */
return NULL;
- hs = Curl_node_elem(pick);
+ hs = pick->ptr;
/* count number of occurrences of this name within the mask and figure out
the index for the currently selected entry */
- for(e = Curl_llist_head(&data->state.httphdrs); e; e = Curl_node_next(e)) {
- struct Curl_header_store *check = Curl_node_elem(e);
+ for(e = data->state.httphdrs.head; e; e = e->next) {
+ struct Curl_header_store *check = e->ptr;
if(strcasecompare(hs->name, check->name) &&
(check->request == request) &&
(check->type & type))
@@ -186,7 +185,7 @@ struct curl_header *curl_easy_nextheader(CURL *easy,
}
static CURLcode namevalue(char *header, size_t hlen, unsigned int type,
- char **name, char **value)
+ char **name, char **value)
{
char *end = header + hlen - 1; /* point to the last byte */
DEBUGASSERT(hlen);
@@ -247,13 +246,13 @@ static CURLcode unfold_value(struct Curl_easy *data, const char *value,
/* since this header block might move in the realloc below, it needs to
first be unlinked from the list and then re-added again after the
realloc */
- Curl_node_remove(&hs->node);
+ Curl_llist_remove(&data->state.httphdrs, &hs->node, NULL);
/* new size = struct + new value length + old name+value length */
newhs = Curl_saferealloc(hs, sizeof(*hs) + vlen + oalloc + 1);
if(!newhs)
return CURLE_OUT_OF_MEMORY;
- /* ->name and ->value point into ->buffer (to keep the header allocation
+ /* ->name' and ->value point into ->buffer (to keep the header allocation
in a single memory block), which now potentially have moved. Adjust
them. */
newhs->name = newhs->buffer;
@@ -264,7 +263,8 @@ static CURLcode unfold_value(struct Curl_easy *data, const char *value,
newhs->value[olen + vlen] = 0; /* null-terminate at newline */
/* insert this node into the list of headers */
- Curl_llist_append(&data->state.httphdrs, newhs, &newhs->node);
+ Curl_llist_insert_next(&data->state.httphdrs, data->state.httphdrs.tail,
+ newhs, &newhs->node);
data->state.prevhead = newhs;
return CURLE_OK;
}
@@ -292,17 +292,16 @@ CURLcode Curl_headers_push(struct Curl_easy *data, const char *header,
if(!end) {
end = strchr(header, '\n');
if(!end)
- /* neither CR nor LF as terminator is not a valid header */
- return CURLE_WEIRD_SERVER_REPLY;
+ return CURLE_BAD_FUNCTION_ARGUMENT;
}
- hlen = end - header;
+ hlen = end - header + 1;
if((header[0] == ' ') || (header[0] == '\t')) {
if(data->state.prevhead)
/* line folding, append value to the previous header's value */
return unfold_value(data, header, hlen);
else {
- /* cannot unfold without a previous header. Instead of erroring, just
+ /* Can't unfold without a previous header. Instead of erroring, just
pass the leading blanks. */
while(hlen && ISBLANK(*header)) {
header++;
@@ -320,100 +319,47 @@ CURLcode Curl_headers_push(struct Curl_easy *data, const char *header,
hs->buffer[hlen] = 0; /* nul terminate */
result = namevalue(hs->buffer, hlen, type, &name, &value);
- if(!result) {
- hs->name = name;
- hs->value = value;
- hs->type = type;
- hs->request = data->state.requests;
-
- /* insert this node into the list of headers */
- Curl_llist_append(&data->state.httphdrs, hs, &hs->node);
- data->state.prevhead = hs;
- }
- else
- free(hs);
+ if(result)
+ goto fail;
+
+ hs->name = name;
+ hs->value = value;
+ hs->type = type;
+ hs->request = data->state.requests;
+
+ /* insert this node into the list of headers */
+ Curl_llist_insert_next(&data->state.httphdrs, data->state.httphdrs.tail,
+ hs, &hs->node);
+ data->state.prevhead = hs;
+ return CURLE_OK;
+fail:
+ free(hs);
return result;
}
/*
- * Curl_headers_reset(). Reset the headers subsystem.
+ * Curl_headers_init(). Init the headers subsystem.
*/
-static void headers_reset(struct Curl_easy *data)
+static void headers_init(struct Curl_easy *data)
{
Curl_llist_init(&data->state.httphdrs, NULL);
data->state.prevhead = NULL;
}
-struct hds_cw_collect_ctx {
- struct Curl_cwriter super;
-};
-
-static CURLcode hds_cw_collect_write(struct Curl_easy *data,
- struct Curl_cwriter *writer, int type,
- const char *buf, size_t blen)
-{
- if((type & CLIENTWRITE_HEADER) && !(type & CLIENTWRITE_STATUS)) {
- unsigned char htype = (unsigned char)
- (type & CLIENTWRITE_CONNECT ? CURLH_CONNECT :
- (type & CLIENTWRITE_1XX ? CURLH_1XX :
- (type & CLIENTWRITE_TRAILER ? CURLH_TRAILER :
- CURLH_HEADER)));
- CURLcode result = Curl_headers_push(data, buf, htype);
- CURL_TRC_WRITE(data, "header_collect pushed(type=%x, len=%zu) -> %d",
- htype, blen, result);
- if(result)
- return result;
- }
- return Curl_cwriter_write(data, writer->next, type, buf, blen);
-}
-
-static const struct Curl_cwtype hds_cw_collect = {
- "hds-collect",
- NULL,
- Curl_cwriter_def_init,
- hds_cw_collect_write,
- Curl_cwriter_def_close,
- sizeof(struct hds_cw_collect_ctx)
-};
-
-CURLcode Curl_headers_init(struct Curl_easy *data)
-{
- struct Curl_cwriter *writer;
- CURLcode result;
-
- if(data->conn && (data->conn->handler->protocol & PROTO_FAMILY_HTTP)) {
- /* avoid installing it twice */
- if(Curl_cwriter_get_by_name(data, hds_cw_collect.name))
- return CURLE_OK;
-
- result = Curl_cwriter_create(&writer, data, &hds_cw_collect,
- CURL_CW_PROTOCOL);
- if(result)
- return result;
-
- result = Curl_cwriter_add(data, writer);
- if(result) {
- Curl_cwriter_free(data, writer);
- return result;
- }
- }
- return CURLE_OK;
-}
-
/*
* Curl_headers_cleanup(). Free all stored headers and associated memory.
*/
CURLcode Curl_headers_cleanup(struct Curl_easy *data)
{
- struct Curl_llist_node *e;
- struct Curl_llist_node *n;
+ struct Curl_llist_element *e;
+ struct Curl_llist_element *n;
- for(e = Curl_llist_head(&data->state.httphdrs); e; e = n) {
- struct Curl_header_store *hs = Curl_node_elem(e);
- n = Curl_node_next(e);
+ for(e = data->state.httphdrs.head; e; e = n) {
+ struct Curl_header_store *hs = e->ptr;
+ n = e->next;
free(hs);
}
- headers_reset(data);
+ headers_init(data);
return CURLE_OK;
}
diff --git a/contrib/libs/curl/lib/headers.h b/contrib/libs/curl/lib/headers.h
index e11fe9804e..a5229ea22f 100644
--- a/contrib/libs/curl/lib/headers.h
+++ b/contrib/libs/curl/lib/headers.h
@@ -28,7 +28,7 @@
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_HEADERS_API)
struct Curl_header_store {
- struct Curl_llist_node node;
+ struct Curl_llist_element node;
char *name; /* points into 'buffer' */
char *value; /* points into 'buffer */
int request; /* 0 is the first request, then 1.. 2.. */
@@ -37,12 +37,6 @@ struct Curl_header_store {
};
/*
- * Initialize header collecting for a transfer.
- * Will add a client writer that catches CLIENTWRITE_HEADER writes.
- */
-CURLcode Curl_headers_init(struct Curl_easy *data);
-
-/*
* Curl_headers_push() gets passed a full header to store.
*/
CURLcode Curl_headers_push(struct Curl_easy *data, const char *header,
@@ -54,7 +48,6 @@ CURLcode Curl_headers_push(struct Curl_easy *data, const char *header,
CURLcode Curl_headers_cleanup(struct Curl_easy *data);
#else
-#define Curl_headers_init(x) CURLE_OK
#define Curl_headers_push(x,y,z) CURLE_OK
#define Curl_headers_cleanup(x) Curl_nop_stmt
#endif
diff --git a/contrib/libs/curl/lib/hmac.c b/contrib/libs/curl/lib/hmac.c
index 90f37f0bff..4019b67f8e 100644
--- a/contrib/libs/curl/lib/hmac.c
+++ b/contrib/libs/curl/lib/hmac.c
@@ -42,7 +42,7 @@
* Generic HMAC algorithm.
*
* This module computes HMAC digests based on any hash function. Parameters
- * and computing procedures are setup dynamically at HMAC computation context
+ * and computing procedures are set-up dynamically at HMAC computation context
* initialization.
*/
diff --git a/contrib/libs/curl/lib/hostasyn.c b/contrib/libs/curl/lib/hostasyn.c
index 4d6a8e8596..faf01c5f4c 100644
--- a/contrib/libs/curl/lib/hostasyn.c
+++ b/contrib/libs/curl/lib/hostasyn.c
@@ -67,10 +67,11 @@ CURLcode Curl_addrinfo_callback(struct Curl_easy *data,
int status,
struct Curl_addrinfo *ai)
{
+ struct connectdata *conn = data->conn;
struct Curl_dns_entry *dns = NULL;
CURLcode result = CURLE_OK;
- data->state.async.status = status;
+ conn->resolve_async.status = status;
if(CURL_ASYNC_SUCCESS == status) {
if(ai) {
@@ -78,8 +79,8 @@ CURLcode Curl_addrinfo_callback(struct Curl_easy *data,
Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
dns = Curl_cache_addr(data, ai,
- data->state.async.hostname, 0,
- data->state.async.port, FALSE);
+ conn->resolve_async.hostname, 0,
+ conn->resolve_async.port);
if(data->share)
Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
@@ -94,12 +95,12 @@ CURLcode Curl_addrinfo_callback(struct Curl_easy *data,
}
}
- data->state.async.dns = dns;
+ conn->resolve_async.dns = dns;
/* Set async.done TRUE last in this function since it may be used multi-
threaded and once this is TRUE the other thread may read fields from the
async struct */
- data->state.async.done = TRUE;
+ conn->resolve_async.done = TRUE;
/* IPv4: The input hostent struct will be freed by ares when we return from
this function */
diff --git a/contrib/libs/curl/lib/hostip.c b/contrib/libs/curl/lib/hostip.c
index 18dea56923..813ea33c2d 100644
--- a/contrib/libs/curl/lib/hostip.c
+++ b/contrib/libs/curl/lib/hostip.c
@@ -84,8 +84,8 @@
* source file are these:
*
* CURLRES_IPV6 - this host has getaddrinfo() and family, and thus we use
- * that. The host may not be able to resolve IPv6, but we do not really have to
- * take that into account. Hosts that are not IPv6-enabled have CURLRES_IPV4
+ * that. The host may not be able to resolve IPv6, but we don't really have to
+ * take that into account. Hosts that aren't IPv6-enabled have CURLRES_IPV4
* defined.
*
* CURLRES_ARES - is defined if libcurl is built to use c-ares for
@@ -115,7 +115,7 @@
* CURLRES_* defines based on the config*.h and curl_setup.h defines.
*/
-static void hostcache_unlink_entry(void *entry);
+static void freednsentry(void *freethis);
#ifndef CURL_DISABLE_VERBOSE_STRINGS
static void show_resolve_info(struct Curl_easy *data,
@@ -144,7 +144,7 @@ void Curl_printable_address(const struct Curl_addrinfo *ai, char *buf,
(void)Curl_inet_ntop(ai->ai_family, (const void *)ipaddr4, buf, bufsize);
break;
}
-#ifdef USE_IPV6
+#ifdef ENABLE_IPV6
case AF_INET6: {
const struct sockaddr_in6 *sa6 = (const void *)ai->ai_addr;
const struct in6_addr *ipaddr6 = &sa6->sin6_addr;
@@ -167,18 +167,23 @@ create_hostcache_id(const char *name,
int port, char *ptr, size_t buflen)
{
size_t len = nlen ? nlen : strlen(name);
+ size_t olen = 0;
DEBUGASSERT(buflen >= MAX_HOSTCACHE_LEN);
if(len > (buflen - 7))
len = buflen - 7;
/* store and lower case the name */
- Curl_strntolower(ptr, name, len);
- return msnprintf(&ptr[len], 7, ":%u", port) + len;
+ while(len--) {
+ *ptr++ = Curl_raw_tolower(*name++);
+ olen++;
+ }
+ olen += msnprintf(ptr, 7, ":%u", port);
+ return olen;
}
struct hostcache_prune_data {
time_t now;
time_t oldest; /* oldest time in cache not pruned. */
- int max_age_sec;
+ int cache_timeout;
};
/*
@@ -189,16 +194,16 @@ struct hostcache_prune_data {
* cache.
*/
static int
-hostcache_entry_is_stale(void *datap, void *hc)
+hostcache_timestamp_remove(void *datap, void *hc)
{
struct hostcache_prune_data *prune =
(struct hostcache_prune_data *) datap;
- struct Curl_dns_entry *dns = (struct Curl_dns_entry *) hc;
+ struct Curl_dns_entry *c = (struct Curl_dns_entry *) hc;
- if(dns->timestamp) {
+ if(c->timestamp) {
/* age in seconds */
- time_t age = prune->now - dns->timestamp;
- if(age >= prune->max_age_sec)
+ time_t age = prune->now - c->timestamp;
+ if(age >= prune->cache_timeout)
return TRUE;
if(age > prune->oldest)
prune->oldest = age;
@@ -216,13 +221,13 @@ hostcache_prune(struct Curl_hash *hostcache, int cache_timeout,
{
struct hostcache_prune_data user;
- user.max_age_sec = cache_timeout;
+ user.cache_timeout = cache_timeout;
user.now = now;
user.oldest = 0;
Curl_hash_clean_with_criterium(hostcache,
(void *) &user,
- hostcache_entry_is_stale);
+ hostcache_timestamp_remove);
return user.oldest;
}
@@ -238,13 +243,13 @@ void Curl_hostcache_prune(struct Curl_easy *data)
int timeout = data->set.dns_cache_timeout;
if(!data->dns.hostcache)
- /* NULL hostcache means we cannot do it */
+ /* NULL hostcache means we can't do it */
return;
if(data->share)
Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
- now = time(NULL);
+ time(&now);
do {
/* Remove outdated and unused entries from the hostcache */
@@ -257,8 +262,7 @@ void Curl_hostcache_prune(struct Curl_easy *data)
/* if the cache size is still too big, use the oldest age as new
prune limit */
- } while(timeout &&
- (Curl_hash_count(data->dns.hostcache) > MAX_DNS_CACHE_SIZE));
+ } while(timeout && (data->dns.hostcache->size > MAX_DNS_CACHE_SIZE));
if(data->share)
Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
@@ -284,14 +288,14 @@ static struct Curl_dns_entry *fetch_addr(struct Curl_easy *data,
size_t entry_len = create_hostcache_id(hostname, 0, port,
entry_id, sizeof(entry_id));
- /* See if it is already in our dns cache */
+ /* See if its already in our dns cache */
dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len + 1);
/* No entry found in cache, check if we might have a wildcard entry */
if(!dns && data->state.wildcard_resolve) {
entry_len = create_hostcache_id("*", 1, port, entry_id, sizeof(entry_id));
- /* See if it is already in our dns cache */
+ /* See if it's already in our dns cache */
dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len + 1);
}
@@ -299,11 +303,11 @@ static struct Curl_dns_entry *fetch_addr(struct Curl_easy *data,
/* See whether the returned entry is stale. Done before we release lock */
struct hostcache_prune_data user;
- user.now = time(NULL);
- user.max_age_sec = data->set.dns_cache_timeout;
+ time(&user.now);
+ user.cache_timeout = data->set.dns_cache_timeout;
user.oldest = 0;
- if(hostcache_entry_is_stale(&user, dns)) {
+ if(hostcache_timestamp_remove(&user, dns)) {
infof(data, "Hostname in DNS cache was stale, zapped");
dns = NULL; /* the memory deallocation is being handled by the hash */
Curl_hash_delete(data->dns.hostcache, entry_id, entry_len + 1);
@@ -330,7 +334,7 @@ static struct Curl_dns_entry *fetch_addr(struct Curl_easy *data,
}
if(!found) {
- infof(data, "Hostname in DNS cache does not have needed family, zapped");
+ infof(data, "Hostname in DNS cache doesn't have needed family, zapped");
dns = NULL; /* the memory deallocation is being handled by the hash */
Curl_hash_delete(data->dns.hostcache, entry_id, entry_len + 1);
}
@@ -349,8 +353,8 @@ static struct Curl_dns_entry *fetch_addr(struct Curl_easy *data,
*
* Returns the Curl_dns_entry entry pointer or NULL if not in the cache.
*
- * The returned data *MUST* be "released" with Curl_resolv_unlink() after
- * use, or we will leak memory!
+ * The returned data *MUST* be "unlocked" with Curl_resolv_unlock() after
+ * use, or we'll leak memory!
*/
struct Curl_dns_entry *
Curl_fetch_addr(struct Curl_easy *data,
@@ -365,7 +369,7 @@ Curl_fetch_addr(struct Curl_easy *data,
dns = fetch_addr(data, hostname, port);
if(dns)
- dns->refcount++; /* we use it! */
+ dns->inuse++; /* we use it! */
if(data->share)
Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
@@ -429,8 +433,8 @@ UNITTEST CURLcode Curl_shuffle_addr(struct Curl_easy *data,
if(Curl_rand(data, (unsigned char *)rnd, rnd_size) == CURLE_OK) {
struct Curl_addrinfo *swap_tmp;
for(i = num_addrs - 1; i > 0; i--) {
- swap_tmp = nodes[rnd[i] % (unsigned int)(i + 1)];
- nodes[rnd[i] % (unsigned int)(i + 1)] = nodes[i];
+ swap_tmp = nodes[rnd[i] % (i + 1)];
+ nodes[rnd[i] % (i + 1)] = nodes[i];
nodes[i] = swap_tmp;
}
@@ -469,8 +473,7 @@ Curl_cache_addr(struct Curl_easy *data,
struct Curl_addrinfo *addr,
const char *hostname,
size_t hostlen, /* length or zero */
- int port,
- bool permanent)
+ int port)
{
char entry_id[MAX_HOSTCACHE_LEN];
size_t entry_len;
@@ -498,15 +501,11 @@ Curl_cache_addr(struct Curl_easy *data,
entry_len = create_hostcache_id(hostname, hostlen, port,
entry_id, sizeof(entry_id));
- dns->refcount = 1; /* the cache has the first reference */
+ dns->inuse = 1; /* the cache has the first reference */
dns->addr = addr; /* this is the address(es) */
- if(permanent)
- dns->timestamp = 0; /* an entry that never goes stale */
- else {
- dns->timestamp = time(NULL);
- if(dns->timestamp == 0)
- dns->timestamp = 1;
- }
+ time(&dns->timestamp);
+ if(dns->timestamp == 0)
+ dns->timestamp = 1; /* zero indicates permanent CURLOPT_RESOLVE entry */
dns->hostport = port;
if(hostlen)
memcpy(dns->hostname, hostname, hostlen);
@@ -520,11 +519,11 @@ Curl_cache_addr(struct Curl_easy *data,
}
dns = dns2;
- dns->refcount++; /* mark entry as in-use */
+ dns->inuse++; /* mark entry as in-use */
return dns;
}
-#ifdef USE_IPV6
+#ifdef ENABLE_IPV6
/* return a static IPv6 ::1 for the name */
static struct Curl_addrinfo *get_localhost6(int port, const char *name)
{
@@ -542,8 +541,8 @@ static struct Curl_addrinfo *get_localhost6(int port, const char *name)
sa6.sin6_port = htons(port16);
sa6.sin6_flowinfo = 0;
sa6.sin6_scope_id = 0;
-
- (void)Curl_inet_pton(AF_INET6, "::1", ipv6);
+ if(Curl_inet_pton(AF_INET6, "::1", ipv6) < 1)
+ return NULL;
memcpy(&sa6.sin6_addr, ipv6, sizeof(ipv6));
ca->ai_flags = 0;
@@ -601,14 +600,14 @@ static struct Curl_addrinfo *get_localhost(int port, const char *name)
return ca6;
}
-#ifdef USE_IPV6
+#ifdef ENABLE_IPV6
/*
* Curl_ipv6works() returns TRUE if IPv6 seems to work.
*/
bool Curl_ipv6works(struct Curl_easy *data)
{
if(data) {
- /* the nature of most system is that IPv6 status does not come and go
+ /* the nature of most system is that IPv6 status doesn't come and go
during a program's lifetime so we only probe the first time and then we
have the info kept for fast reuse */
DEBUGASSERT(data);
@@ -624,7 +623,7 @@ bool Curl_ipv6works(struct Curl_easy *data)
/* probe to see if we have a working IPv6 stack */
curl_socket_t s = socket(PF_INET6, SOCK_DGRAM, 0);
if(s == CURL_SOCKET_BAD)
- /* an IPv6 address was requested but we cannot get/use one */
+ /* an IPv6 address was requested but we can't get/use one */
ipv6_works = 0;
else {
ipv6_works = 1;
@@ -633,7 +632,7 @@ bool Curl_ipv6works(struct Curl_easy *data)
return (ipv6_works>0)?TRUE:FALSE;
}
}
-#endif /* USE_IPV6 */
+#endif /* ENABLE_IPV6 */
/*
* Curl_host_is_ipnum() returns TRUE if the given string is a numerical IPv4
@@ -642,11 +641,11 @@ bool Curl_ipv6works(struct Curl_easy *data)
bool Curl_host_is_ipnum(const char *hostname)
{
struct in_addr in;
-#ifdef USE_IPV6
+#ifdef ENABLE_IPV6
struct in6_addr in6;
#endif
if(Curl_inet_pton(AF_INET, hostname, &in) > 0
-#ifdef USE_IPV6
+#ifdef ENABLE_IPV6
|| Curl_inet_pton(AF_INET6, hostname, &in6) > 0
#endif
)
@@ -668,12 +667,12 @@ static bool tailmatch(const char *full, const char *part)
/*
* Curl_resolv() is the main name resolve function within libcurl. It resolves
* a name and returns a pointer to the entry in the 'entry' argument (if one
- * is provided). This function might return immediately if we are using asynch
+ * is provided). This function might return immediately if we're using asynch
* resolves. See the return codes.
*
* The cache entry we return will get its 'inuse' counter increased when this
- * function is used. You MUST call Curl_resolv_unlink() later (when you are
- * done using this struct) to decrease the reference counter again.
+ * function is used. You MUST call Curl_resolv_unlock() later (when you're
+ * done using this struct) to decrease the counter again.
*
* Return codes:
*
@@ -714,7 +713,7 @@ enum resolve_t Curl_resolv(struct Curl_easy *data,
if(dns) {
infof(data, "Hostname %s was found in DNS cache", hostname);
- dns->refcount++; /* we use it! */
+ dns->inuse++; /* we use it! */
rc = CURLRESOLV_RESOLVED;
}
@@ -742,7 +741,7 @@ enum resolve_t Curl_resolv(struct Curl_easy *data,
Curl_set_in_callback(data, true);
st = data->set.resolver_start(
#ifdef USE_CURL_ASYNC
- data->state.async.resolver,
+ conn->resolve_async.resolver,
#else
NULL,
#endif
@@ -755,24 +754,18 @@ enum resolve_t Curl_resolv(struct Curl_easy *data,
#ifndef USE_RESOLVE_ON_IPS
/* First check if this is an IPv4 address string */
- if(Curl_inet_pton(AF_INET, hostname, &in) > 0) {
+ if(Curl_inet_pton(AF_INET, hostname, &in) > 0)
/* This is a dotted IP address 123.123.123.123-style */
addr = Curl_ip2addr(AF_INET, &in, hostname, port);
- if(!addr)
- return CURLRESOLV_ERROR;
- }
-#ifdef USE_IPV6
- else {
+#ifdef ENABLE_IPV6
+ if(!addr) {
struct in6_addr in6;
/* check if this is an IPv6 address string */
- if(Curl_inet_pton(AF_INET6, hostname, &in6) > 0) {
+ if(Curl_inet_pton(AF_INET6, hostname, &in6) > 0)
/* This is an IPv6 address literal */
addr = Curl_ip2addr(AF_INET6, &in6, hostname, port);
- if(!addr)
- return CURLRESOLV_ERROR;
- }
}
-#endif /* USE_IPV6 */
+#endif /* ENABLE_IPV6 */
#else /* if USE_RESOLVE_ON_IPS */
#ifndef CURL_DISABLE_DOH
@@ -780,7 +773,7 @@ enum resolve_t Curl_resolv(struct Curl_easy *data,
if(Curl_inet_pton(AF_INET, hostname, &in) > 0)
/* This is a dotted IP address 123.123.123.123-style */
ipnum = TRUE;
-#ifdef USE_IPV6
+#ifdef ENABLE_IPV6
else {
struct in6_addr in6;
/* check if this is an IPv6 address string */
@@ -788,7 +781,7 @@ enum resolve_t Curl_resolv(struct Curl_easy *data,
/* This is an IPv6 address literal */
ipnum = TRUE;
}
-#endif /* USE_IPV6 */
+#endif /* ENABLE_IPV6 */
#endif /* CURL_DISABLE_DOH */
#endif /* !USE_RESOLVE_ON_IPS */
@@ -819,7 +812,7 @@ enum resolve_t Curl_resolv(struct Curl_easy *data,
if(respwait) {
/* the response to our resolve call will come asynchronously at
a later time, good or bad */
- /* First, check that we have not received the info by now */
+ /* First, check that we haven't received the info by now */
result = Curl_resolv_check(data, &dns);
if(result) /* error detected */
return CURLRESOLV_ERROR;
@@ -834,7 +827,7 @@ enum resolve_t Curl_resolv(struct Curl_easy *data,
Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
/* we got a response, store it in the cache */
- dns = Curl_cache_addr(data, addr, hostname, 0, port, FALSE);
+ dns = Curl_cache_addr(data, addr, hostname, 0, port);
if(data->share)
Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
@@ -857,7 +850,7 @@ enum resolve_t Curl_resolv(struct Curl_easy *data,
#ifdef USE_ALARM_TIMEOUT
/*
* This signal handler jumps back into the main libcurl code and continues
- * execution. This effectively causes the remainder of the application to run
+ * execution. This effectively causes the remainder of the application to run
* within a signal handler which is nonportable and could lead to problems.
*/
CURL_NORETURN static
@@ -870,12 +863,12 @@ void alarmfunc(int sig)
/*
* Curl_resolv_timeout() is the same as Curl_resolv() but specifies a
- * timeout. This function might return immediately if we are using asynch
+ * timeout. This function might return immediately if we're using asynch
* resolves. See the return codes.
*
* The cache entry we return will get its 'inuse' counter increased when this
- * function is used. You MUST call Curl_resolv_unlink() later (when you are
- * done using this struct) to decrease the reference counter again.
+ * function is used. You MUST call Curl_resolv_unlock() later (when you're
+ * done using this struct) to decrease the counter again.
*
* If built with a synchronous resolver and use of signals is not
* disabled by the application, then a nonzero timeout will cause a
@@ -940,7 +933,7 @@ enum resolve_t Curl_resolv_timeout(struct Curl_easy *data,
will generate a signal and we will siglongjmp() from that here.
This technique has problems (see alarmfunc).
This should be the last thing we do before calling Curl_resolv(),
- as otherwise we would have to worry about variables that get modified
+ as otherwise we'd have to worry about variables that get modified
before we invoke Curl_resolv() (and thus use "volatile"). */
curl_simple_lock_lock(&curl_jmpenv_lock);
@@ -961,7 +954,7 @@ enum resolve_t Curl_resolv_timeout(struct Curl_easy *data,
keep_copysig = TRUE; /* yes, we have a copy */
sigact.sa_handler = alarmfunc;
#ifdef SA_RESTART
- /* HP-UX does not have SA_RESTART but defaults to that behavior! */
+ /* HPUX doesn't have SA_RESTART but defaults to that behavior! */
sigact.sa_flags &= ~SA_RESTART;
#endif
/* now set the new struct */
@@ -1028,7 +1021,7 @@ clean_up:
((alarm_set >= 0x80000000) && (prev_alarm < 0x80000000)) ) {
/* if the alarm time-left reached zero or turned "negative" (counted
with unsigned values), we should fire off a SIGALRM here, but we
- will not, and zero would be to switch it off so we never set it to
+ won't, and zero would be to switch it off so we never set it to
less than 1! */
alarm(1);
rc = CURLRESOLV_TIMEDOUT;
@@ -1043,20 +1036,18 @@ clean_up:
}
/*
- * Curl_resolv_unlink() releases a reference to the given cached DNS entry.
- * When the reference count reaches 0, the entry is destroyed. It is important
- * that only one unlink is made for each Curl_resolv() call.
+ * Curl_resolv_unlock() unlocks the given cached DNS entry. When this has been
+ * made, the struct may be destroyed due to pruning. It is important that only
+ * one unlock is made for each Curl_resolv() call.
*
* May be called with 'data' == NULL for global cache.
*/
-void Curl_resolv_unlink(struct Curl_easy *data, struct Curl_dns_entry **pdns)
+void Curl_resolv_unlock(struct Curl_easy *data, struct Curl_dns_entry *dns)
{
- struct Curl_dns_entry *dns = *pdns;
- *pdns = NULL;
if(data && data->share)
Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
- hostcache_unlink_entry(dns);
+ freednsentry(dns);
if(data && data->share)
Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
@@ -1065,31 +1056,14 @@ void Curl_resolv_unlink(struct Curl_easy *data, struct Curl_dns_entry **pdns)
/*
* File-internal: release cache dns entry reference, free if inuse drops to 0
*/
-static void hostcache_unlink_entry(void *entry)
+static void freednsentry(void *freethis)
{
- struct Curl_dns_entry *dns = (struct Curl_dns_entry *) entry;
- DEBUGASSERT(dns && (dns->refcount>0));
+ struct Curl_dns_entry *dns = (struct Curl_dns_entry *) freethis;
+ DEBUGASSERT(dns && (dns->inuse>0));
- dns->refcount--;
- if(dns->refcount == 0) {
+ dns->inuse--;
+ if(dns->inuse == 0) {
Curl_freeaddrinfo(dns->addr);
-#ifdef USE_HTTPSRR
- if(dns->hinfo) {
- if(dns->hinfo->target)
- free(dns->hinfo->target);
- if(dns->hinfo->alpns)
- free(dns->hinfo->alpns);
- if(dns->hinfo->ipv4hints)
- free(dns->hinfo->ipv4hints);
- if(dns->hinfo->echconfiglist)
- free(dns->hinfo->echconfiglist);
- if(dns->hinfo->ipv6hints)
- free(dns->hinfo->ipv6hints);
- if(dns->hinfo->val)
- free(dns->hinfo->val);
- free(dns->hinfo);
- }
-#endif
free(dns);
}
}
@@ -1097,10 +1071,10 @@ static void hostcache_unlink_entry(void *entry)
/*
* Curl_init_dnscache() inits a new DNS cache.
*/
-void Curl_init_dnscache(struct Curl_hash *hash, size_t size)
+void Curl_init_dnscache(struct Curl_hash *hash, int size)
{
Curl_hash_init(hash, size, Curl_hash_str, Curl_str_key_compare,
- hostcache_unlink_entry);
+ freednsentry);
}
/*
@@ -1158,7 +1132,7 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
if(data->share)
Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
- /* delete entry, ignore if it did not exist */
+ /* delete entry, ignore if it didn't exist */
Curl_hash_delete(data->dns.hostcache, entry_id, entry_len + 1);
if(data->share)
@@ -1230,7 +1204,7 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
memcpy(address, addr_begin, alen);
address[alen] = '\0';
-#ifndef USE_IPV6
+#ifndef ENABLE_IPV6
if(strchr(address, ':')) {
infof(data, "Ignoring resolve address '%s', missing IPv6 support.",
address);
@@ -1272,7 +1246,7 @@ err:
if(data->share)
Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
- /* See if it is already in our dns cache */
+ /* See if it's already in our dns cache */
dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len + 1);
if(dns) {
@@ -1293,11 +1267,13 @@ err:
}
/* put this new host in the cache */
- dns = Curl_cache_addr(data, head, host_begin, hlen, port, permanent);
+ dns = Curl_cache_addr(data, head, host_begin, hlen, port);
if(dns) {
+ if(permanent)
+ dns->timestamp = 0; /* mark as permanent */
/* release the returned reference; the cache itself will keep the
* entry alive: */
- dns->refcount--;
+ dns->inuse--;
}
if(data->share)
@@ -1368,7 +1344,7 @@ static void show_resolve_info(struct Curl_easy *data,
if(!result)
result = Curl_dyn_add(d, buf);
if(result) {
- infof(data, "too many IP, cannot show");
+ infof(data, "too many IP, can't show");
goto fail;
}
}
@@ -1439,9 +1415,9 @@ CURLcode Curl_once_resolved(struct Curl_easy *data, bool *protocol_done)
struct connectdata *conn = data->conn;
#ifdef USE_CURL_ASYNC
- if(data->state.async.dns) {
- conn->dns_entry = data->state.async.dns;
- data->state.async.dns = NULL;
+ if(conn->resolve_async.dns) {
+ conn->dns_entry = conn->resolve_async.dns;
+ conn->resolve_async.dns = NULL;
}
#endif
@@ -1449,7 +1425,8 @@ CURLcode Curl_once_resolved(struct Curl_easy *data, bool *protocol_done)
if(result) {
Curl_detach_connection(data);
- Curl_cpool_disconnect(data, conn, TRUE);
+ Curl_conncache_remove_conn(data, conn, TRUE);
+ Curl_disconnect(data, conn, TRUE);
}
return result;
}
@@ -1462,11 +1439,11 @@ CURLcode Curl_once_resolved(struct Curl_easy *data, bool *protocol_done)
#ifdef USE_CURL_ASYNC
CURLcode Curl_resolver_error(struct Curl_easy *data)
{
+ struct connectdata *conn = data->conn;
const char *host_or_proxy;
CURLcode result;
#ifndef CURL_DISABLE_PROXY
- struct connectdata *conn = data->conn;
if(conn->bits.httpproxy) {
host_or_proxy = "proxy";
result = CURLE_COULDNT_RESOLVE_PROXY;
@@ -1479,7 +1456,7 @@ CURLcode Curl_resolver_error(struct Curl_easy *data)
}
failf(data, "Could not resolve %s: %s", host_or_proxy,
- data->state.async.hostname);
+ conn->resolve_async.hostname);
return result;
}
diff --git a/contrib/libs/curl/lib/hostip.h b/contrib/libs/curl/lib/hostip.h
index b1c5ecb2e1..fb53a5776b 100644
--- a/contrib/libs/curl/lib/hostip.h
+++ b/contrib/libs/curl/lib/hostip.h
@@ -32,10 +32,6 @@
#include <setjmp.h>
-#ifdef USE_HTTPSRR
-# include <stdint.h>
-#endif
-
/* Allocate enough memory to hold the full name information structs and
* everything. OSF1 is known to require at least 8872 bytes. The buffer
* required for storing all possible aliases and IP numbers is according to
@@ -62,48 +58,15 @@ struct connectdata;
*/
struct Curl_hash *Curl_global_host_cache_init(void);
-#ifdef USE_HTTPSRR
-
-#define CURL_MAXLEN_host_name 253
-
-struct Curl_https_rrinfo {
- size_t len; /* raw encoded length */
- unsigned char *val; /* raw encoded octets */
- /*
- * fields from HTTPS RR, with the mandatory fields
- * first (priority, target), then the others in the
- * order of the keytag numbers defined at
- * https://datatracker.ietf.org/doc/html/rfc9460#section-14.3.2
- */
- uint16_t priority;
- char *target;
- char *alpns; /* keytag = 1 */
- bool no_def_alpn; /* keytag = 2 */
- /*
- * we do not support ports (keytag = 3) as we do not support
- * port-switching yet
- */
- unsigned char *ipv4hints; /* keytag = 4 */
- size_t ipv4hints_len;
- unsigned char *echconfiglist; /* keytag = 5 */
- size_t echconfiglist_len;
- unsigned char *ipv6hints; /* keytag = 6 */
- size_t ipv6hints_len;
-};
-#endif
-
struct Curl_dns_entry {
struct Curl_addrinfo *addr;
-#ifdef USE_HTTPSRR
- struct Curl_https_rrinfo *hinfo;
-#endif
- /* timestamp == 0 -- permanent CURLOPT_RESOLVE entry (does not time out) */
+ /* timestamp == 0 -- permanent CURLOPT_RESOLVE entry (doesn't time out) */
time_t timestamp;
- /* reference counter, entry is freed on reaching 0 */
- size_t refcount;
+ /* use-counter, use Curl_resolv_unlock to release reference */
+ long inuse;
/* hostname port number that resolved to addr. */
int hostport;
- /* hostname that resolved to addr. may be NULL (Unix domain sockets). */
+ /* hostname that resolved to addr. may be NULL (unix domain sockets). */
char hostname[1];
};
@@ -113,8 +76,8 @@ bool Curl_host_is_ipnum(const char *hostname);
* Curl_resolv() returns an entry with the info for the specified host
* and port.
*
- * The returned data *MUST* be "released" with Curl_resolv_unlink() after
- * use, or we will leak memory!
+ * The returned data *MUST* be "unlocked" with Curl_resolv_unlock() after
+ * use, or we'll leak memory!
*/
/* return codes */
enum resolve_t {
@@ -133,7 +96,7 @@ enum resolve_t Curl_resolv_timeout(struct Curl_easy *data,
struct Curl_dns_entry **dnsentry,
timediff_t timeoutms);
-#ifdef USE_IPV6
+#ifdef ENABLE_IPV6
/*
* Curl_ipv6works() returns TRUE if IPv6 seems to work.
*/
@@ -161,12 +124,12 @@ struct Curl_addrinfo *Curl_getaddrinfo(struct Curl_easy *data,
int *waitp);
-/* unlink a dns entry, potentially shared with a cache */
-void Curl_resolv_unlink(struct Curl_easy *data,
- struct Curl_dns_entry **pdns);
+/* unlock a previously resolved dns entry */
+void Curl_resolv_unlock(struct Curl_easy *data,
+ struct Curl_dns_entry *dns);
/* init a new dns cache */
-void Curl_init_dnscache(struct Curl_hash *hash, size_t hashsize);
+void Curl_init_dnscache(struct Curl_hash *hash, int hashsize);
/* prune old entries from the DNS cache */
void Curl_hostcache_prune(struct Curl_easy *data);
@@ -199,8 +162,8 @@ void Curl_printable_address(const struct Curl_addrinfo *ip,
*
* Returns the Curl_dns_entry entry pointer or NULL if not in the cache.
*
- * The returned data *MUST* be "released" with Curl_resolv_unlink() after
- * use, or we will leak memory!
+ * The returned data *MUST* be "unlocked" with Curl_resolv_unlock() after
+ * use, or we'll leak memory!
*/
struct Curl_dns_entry *
Curl_fetch_addr(struct Curl_easy *data,
@@ -209,13 +172,12 @@ Curl_fetch_addr(struct Curl_easy *data,
/*
* Curl_cache_addr() stores a 'Curl_addrinfo' struct in the DNS cache.
- * @param permanent iff TRUE, entry will never become stale
+ *
* Returns the Curl_dns_entry entry pointer or NULL if the storage failed.
*/
struct Curl_dns_entry *
Curl_cache_addr(struct Curl_easy *data, struct Curl_addrinfo *addr,
- const char *hostname, size_t hostlen, int port,
- bool permanent);
+ const char *hostname, size_t hostlen, int port);
#ifndef INADDR_NONE
#define CURL_INADDR_NONE (in_addr_t) ~0
diff --git a/contrib/libs/curl/lib/hostip4.c b/contrib/libs/curl/lib/hostip4.c
index 3bfea48d4f..9140180ffd 100644
--- a/contrib/libs/curl/lib/hostip4.c
+++ b/contrib/libs/curl/lib/hostip4.c
@@ -62,7 +62,7 @@ bool Curl_ipvalid(struct Curl_easy *data, struct connectdata *conn)
{
(void)data;
if(conn->ip_version == CURL_IPRESOLVE_V6)
- /* An IPv6 address was requested and we cannot get/use one */
+ /* An IPv6 address was requested and we can't get/use one */
return FALSE;
return TRUE; /* OK, proceed */
@@ -82,7 +82,7 @@ bool Curl_ipvalid(struct Curl_easy *data, struct connectdata *conn)
* detect which one this platform supports in the configure script and set up
* the HAVE_GETHOSTBYNAME_R_3, HAVE_GETHOSTBYNAME_R_5 or
* HAVE_GETHOSTBYNAME_R_6 defines accordingly. Note that HAVE_GETADDRBYNAME
- * has the corresponding rules. This is primarily on *nix. Note that some Unix
+ * has the corresponding rules. This is primarily on *nix. Note that some unix
* flavours have thread-safe versions of the plain gethostbyname() etc.
*
*/
@@ -193,8 +193,8 @@ struct Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname,
* small. Previous versions are known to return ERANGE for the same
* problem.
*
- * This would not be such a big problem if older versions would not
- * sometimes return EAGAIN on a common failure case. Alas, we cannot
+ * This wouldn't be such a big problem if older versions wouldn't
+ * sometimes return EAGAIN on a common failure case. Alas, we can't
* assume that EAGAIN *or* ERANGE means ERANGE for any given version of
* glibc.
*
@@ -210,9 +210,9 @@ struct Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname,
* gethostbyname_r() in glibc:
*
* In glibc 2.2.5 the interface is different (this has also been
- * discovered in glibc 2.1.1-6 as shipped by Redhat 6). What I cannot
+ * discovered in glibc 2.1.1-6 as shipped by Redhat 6). What I can't
* explain, is that tests performed on glibc 2.2.4-34 and 2.2.4-32
- * (shipped/upgraded by Redhat 7.2) do not show this behavior!
+ * (shipped/upgraded by Redhat 7.2) don't show this behavior!
*
* In this "buggy" version, the return code is -1 on error and 'errno'
* is set to the ERANGE or EAGAIN code. Note that 'errno' is not a
@@ -221,9 +221,9 @@ struct Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname,
if(!h) /* failure */
#elif defined(HAVE_GETHOSTBYNAME_R_3)
- /* AIX, Digital UNIX/Tru64, HP-UX 10, more? */
+ /* AIX, Digital Unix/Tru64, HPUX 10, more? */
- /* For AIX 4.3 or later, we do not use gethostbyname_r() at all, because of
+ /* For AIX 4.3 or later, we don't use gethostbyname_r() at all, because of
* the plain fact that it does not return unique full buffers on each
* call, but instead several of the pointers in the hostent structs will
* point to the same actual data! This have the unfortunate down-side that
@@ -237,7 +237,7 @@ struct Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname,
*
* Troels Walsted Hansen helped us work this out on March 3rd, 2003.
*
- * [*] = much later we have found out that it is not at all "completely
+ * [*] = much later we've found out that it isn't at all "completely
* thread-safe", but at least the gethostbyname() function is.
*/
@@ -253,7 +253,7 @@ struct Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname,
(struct hostent *)buf,
(struct hostent_data *)((char *)buf +
sizeof(struct hostent)));
- h_errnop = SOCKERRNO; /* we do not deal with this, but set it anyway */
+ h_errnop = SOCKERRNO; /* we don't deal with this, but set it anyway */
}
else
res = -1; /* failure, too smallish buffer size */
@@ -263,8 +263,8 @@ struct Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname,
h = buf; /* result expected in h */
/* This is the worst kind of the different gethostbyname_r() interfaces.
- * Since we do not know how big buffer this particular lookup required,
- * we cannot realloc down the huge alloc without doing closer analysis of
+ * Since we don't know how big buffer this particular lookup required,
+ * we can't realloc down the huge alloc without doing closer analysis of
* the returned data. Thus, we always use CURL_HOSTENT_SIZE for every
* name lookup. Fixing this would require an extra malloc() and then
* calling Curl_addrinfo_copy() that subsequent realloc()s down the new
@@ -280,7 +280,7 @@ struct Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname,
#else /* (HAVE_GETADDRINFO && HAVE_GETADDRINFO_THREADSAFE) ||
HAVE_GETHOSTBYNAME_R */
/*
- * Here is code for platforms that do not have a thread safe
+ * Here is code for platforms that don't have a thread safe
* getaddrinfo() nor gethostbyname_r() function or for which
* gethostbyname() is the preferred one.
*/
diff --git a/contrib/libs/curl/lib/hostip6.c b/contrib/libs/curl/lib/hostip6.c
index c16ddfe58d..18969a7a7d 100644
--- a/contrib/libs/curl/lib/hostip6.c
+++ b/contrib/libs/curl/lib/hostip6.c
@@ -124,7 +124,7 @@ struct Curl_addrinfo *Curl_getaddrinfo(struct Curl_easy *data,
#ifndef USE_RESOLVE_ON_IPS
/*
* The AI_NUMERICHOST must not be set to get synthesized IPv6 address from
- * an IPv4 address on iOS and macOS.
+ * an IPv4 address on iOS and Mac OS X.
*/
if((1 == Curl_inet_pton(AF_INET, hostname, addrbuf)) ||
(1 == Curl_inet_pton(AF_INET6, hostname, addrbuf))) {
diff --git a/contrib/libs/curl/lib/hsts.c b/contrib/libs/curl/lib/hsts.c
index a5c216f6de..9314be294b 100644
--- a/contrib/libs/curl/lib/hsts.c
+++ b/contrib/libs/curl/lib/hsts.c
@@ -54,7 +54,7 @@
#define MAX_HSTS_DATELENSTR "64"
#define UNLIMITED "unlimited"
-#if defined(DEBUGBUILD) || defined(UNITTESTS)
+#ifdef DEBUGBUILD
/* to play well with debug builds, we can *set* a fixed time this will
return */
time_t deltatime; /* allow for "adjustments" for unit test purposes */
@@ -94,11 +94,11 @@ void Curl_hsts_cleanup(struct hsts **hp)
{
struct hsts *h = *hp;
if(h) {
- struct Curl_llist_node *e;
- struct Curl_llist_node *n;
- for(e = Curl_llist_head(&h->list); e; e = n) {
- struct stsentry *sts = Curl_node_elem(e);
- n = Curl_node_next(e);
+ struct Curl_llist_element *e;
+ struct Curl_llist_element *n;
+ for(e = h->list.head; e; e = n) {
+ struct stsentry *sts = e->ptr;
+ n = e->next;
hsts_free(sts);
}
free(h->filename);
@@ -107,11 +107,18 @@ void Curl_hsts_cleanup(struct hsts **hp)
}
}
+static struct stsentry *hsts_entry(void)
+{
+ return calloc(1, sizeof(struct stsentry));
+}
+
static CURLcode hsts_create(struct hsts *h,
const char *hostname,
bool subdomains,
curl_off_t expires)
{
+ struct stsentry *sts;
+ char *duphost;
size_t hlen;
DEBUGASSERT(h);
DEBUGASSERT(hostname);
@@ -120,23 +127,24 @@ static CURLcode hsts_create(struct hsts *h,
if(hlen && (hostname[hlen - 1] == '.'))
/* strip off any trailing dot */
--hlen;
- if(hlen) {
- char *duphost;
- struct stsentry *sts = calloc(1, sizeof(struct stsentry));
- if(!sts)
- return CURLE_OUT_OF_MEMORY;
-
- duphost = Curl_memdup0(hostname, hlen);
- if(!duphost) {
- free(sts);
- return CURLE_OUT_OF_MEMORY;
- }
+ if(!hlen)
+ /* no host name left */
+ return CURLE_BAD_FUNCTION_ARGUMENT;
- sts->host = duphost;
- sts->expires = expires;
- sts->includeSubDomains = subdomains;
- Curl_llist_append(&h->list, sts, &sts->node);
+ sts = hsts_entry();
+ if(!sts)
+ return CURLE_OUT_OF_MEMORY;
+
+ duphost = Curl_strndup(hostname, hlen);
+ if(!duphost) {
+ free(sts);
+ return CURLE_OUT_OF_MEMORY;
}
+
+ sts->host = duphost;
+ sts->expires = expires;
+ sts->includeSubDomains = subdomains;
+ Curl_llist_insert_next(&h->list, h->list.tail, sts, &sts->node);
return CURLE_OK;
}
@@ -215,7 +223,7 @@ CURLcode Curl_hsts_parse(struct hsts *h, const char *hostname,
/* remove the entry if present verbatim (without subdomain match) */
sts = Curl_hsts(h, hostname, FALSE);
if(sts) {
- Curl_node_remove(&sts->node);
+ Curl_llist_remove(&h->list, &sts->node, NULL);
hsts_free(sts);
}
return CURLE_OK;
@@ -241,7 +249,7 @@ CURLcode Curl_hsts_parse(struct hsts *h, const char *hostname,
}
/*
- * Return TRUE if the given hostname is currently an HSTS one.
+ * Return TRUE if the given host name is currently an HSTS one.
*
* The 'subdomain' argument tells the function if subdomain matching should be
* attempted.
@@ -253,8 +261,8 @@ struct stsentry *Curl_hsts(struct hsts *h, const char *hostname,
char buffer[MAX_HSTS_HOSTLEN + 1];
time_t now = time(NULL);
size_t hlen = strlen(hostname);
- struct Curl_llist_node *e;
- struct Curl_llist_node *n;
+ struct Curl_llist_element *e;
+ struct Curl_llist_element *n;
if((hlen > MAX_HSTS_HOSTLEN) || !hlen)
return NULL;
@@ -265,12 +273,12 @@ struct stsentry *Curl_hsts(struct hsts *h, const char *hostname,
buffer[hlen] = 0;
hostname = buffer;
- for(e = Curl_llist_head(&h->list); e; e = n) {
- struct stsentry *sts = Curl_node_elem(e);
- n = Curl_node_next(e);
+ for(e = h->list.head; e; e = n) {
+ struct stsentry *sts = e->ptr;
+ n = e->next;
if(sts->expires <= now) {
/* remove expired entries */
- Curl_node_remove(&sts->node);
+ Curl_llist_remove(&h->list, &sts->node, NULL);
hsts_free(sts);
continue;
}
@@ -353,8 +361,8 @@ static CURLcode hsts_out(struct stsentry *sts, FILE *fp)
CURLcode Curl_hsts_save(struct Curl_easy *data, struct hsts *h,
const char *file)
{
- struct Curl_llist_node *e;
- struct Curl_llist_node *n;
+ struct Curl_llist_element *e;
+ struct Curl_llist_element *n;
CURLcode result = CURLE_OK;
FILE *out;
char *tempstore = NULL;
@@ -368,7 +376,7 @@ CURLcode Curl_hsts_save(struct Curl_easy *data, struct hsts *h,
file = h->filename;
if((h->flags & CURLHSTS_READONLYFILE) || !file || !file[0])
- /* marked as read-only, no file or zero length filename */
+ /* marked as read-only, no file or zero length file name */
goto skipsave;
result = Curl_fopen(data, file, &out, &tempstore);
@@ -376,9 +384,9 @@ CURLcode Curl_hsts_save(struct Curl_easy *data, struct hsts *h,
fputs("# Your HSTS cache. https://curl.se/docs/hsts.html\n"
"# This file was generated by libcurl! Edit at your own risk.\n",
out);
- for(e = Curl_llist_head(&h->list); e; e = n) {
- struct stsentry *sts = Curl_node_elem(e);
- n = Curl_node_next(e);
+ for(e = h->list.head; e; e = n) {
+ struct stsentry *sts = e->ptr;
+ n = e->next;
result = hsts_out(sts, out);
if(result)
break;
@@ -393,14 +401,14 @@ CURLcode Curl_hsts_save(struct Curl_easy *data, struct hsts *h,
free(tempstore);
skipsave:
if(data->set.hsts_write) {
- /* if there is a write callback */
+ /* if there's a write callback */
struct curl_index i; /* count */
- i.total = Curl_llist_count(&h->list);
+ i.total = h->list.size;
i.index = 0;
- for(e = Curl_llist_head(&h->list); e; e = n) {
- struct stsentry *sts = Curl_node_elem(e);
+ for(e = h->list.head; e; e = n) {
+ struct stsentry *sts = e->ptr;
bool stop;
- n = Curl_node_next(e);
+ n = e->next;
result = hsts_push(data, &i, sts, &stop);
if(result || stop)
break;
@@ -440,7 +448,7 @@ static CURLcode hsts_add(struct hsts *h, char *line)
if(!e)
result = hsts_create(h, p, subdomain, expires);
else {
- /* the same hostname, use the largest expire time */
+ /* the same host name, use the largest expire time */
if(expires > e->expires)
e->expires = expires;
}
@@ -473,7 +481,6 @@ static CURLcode hsts_pull(struct Curl_easy *data, struct hsts *h)
if(sc == CURLSTS_OK) {
time_t expires;
CURLcode result;
- DEBUGASSERT(e.name[0]);
if(!e.name[0])
/* bail out if no name was stored */
return CURLE_BAD_FUNCTION_ARGUMENT;
@@ -506,9 +513,10 @@ static CURLcode hsts_pull(struct Curl_easy *data, struct hsts *h)
static CURLcode hsts_load(struct hsts *h, const char *file)
{
CURLcode result = CURLE_OK;
+ char *line = NULL;
FILE *fp;
- /* we need a private copy of the filename so that the hsts cache file
+ /* we need a private copy of the file name so that the hsts cache file
name survives an easy handle reset */
free(h->filename);
h->filename = strdup(file);
@@ -517,25 +525,28 @@ static CURLcode hsts_load(struct hsts *h, const char *file)
fp = fopen(file, FOPEN_READTEXT);
if(fp) {
- struct dynbuf buf;
- Curl_dyn_init(&buf, MAX_HSTS_LINE);
- while(Curl_get_line(&buf, fp)) {
- char *lineptr = Curl_dyn_ptr(&buf);
+ line = malloc(MAX_HSTS_LINE);
+ if(!line)
+ goto fail;
+ while(Curl_get_line(line, MAX_HSTS_LINE, fp)) {
+ char *lineptr = line;
while(*lineptr && ISBLANK(*lineptr))
lineptr++;
- /*
- * Skip empty or commented lines, since we know the line will have a
- * trailing newline from Curl_get_line we can treat length 1 as empty.
- */
- if((*lineptr == '#') || strlen(lineptr) <= 1)
+ if(*lineptr == '#')
+ /* skip commented lines */
continue;
hsts_add(h, lineptr);
}
- Curl_dyn_free(&buf); /* free the line buffer */
+ free(line); /* free the line buffer */
fclose(fp);
}
return result;
+
+fail:
+ Curl_safefree(h->filename);
+ fclose(fp);
+ return CURLE_OUT_OF_MEMORY;
}
/*
diff --git a/contrib/libs/curl/lib/hsts.h b/contrib/libs/curl/lib/hsts.h
index 1c544f97bd..d3431a5d7a 100644
--- a/contrib/libs/curl/lib/hsts.h
+++ b/contrib/libs/curl/lib/hsts.h
@@ -29,18 +29,18 @@
#include <curl/curl.h>
#include "llist.h"
-#if defined(DEBUGBUILD) || defined(UNITTESTS)
+#ifdef DEBUGBUILD
extern time_t deltatime;
#endif
struct stsentry {
- struct Curl_llist_node node;
+ struct Curl_llist_element node;
const char *host;
bool includeSubDomains;
curl_off_t expires; /* the timestamp of this entry's expiry */
};
-/* The HSTS cache. Needs to be able to tailmatch hostnames. */
+/* The HSTS cache. Needs to be able to tailmatch host names. */
struct hsts {
struct Curl_llist list;
char *filename;
diff --git a/contrib/libs/curl/lib/http.c b/contrib/libs/curl/lib/http.c
index 6f91f1fc41..e88af07a7d 100644
--- a/contrib/libs/curl/lib/http.c
+++ b/contrib/libs/curl/lib/http.c
@@ -65,6 +65,7 @@
#include "vquic/vquic.h"
#include "http_digest.h"
#include "http_ntlm.h"
+#include "curl_ntlm_wb.h"
#include "http_negotiate.h"
#include "http_aws_sigv4.h"
#include "url.h"
@@ -72,7 +73,6 @@
#include "hostip.h"
#include "dynhds.h"
#include "http.h"
-#include "headers.h"
#include "select.h"
#include "parsedate.h" /* for the week day and month names */
#include "strtoofft.h"
@@ -100,17 +100,24 @@
* Forward declarations.
*/
-static bool http_should_fail(struct Curl_easy *data, int httpcode);
-static bool http_exp100_is_waiting(struct Curl_easy *data);
-static CURLcode http_exp100_add_reader(struct Curl_easy *data);
-static void http_exp100_send_anyway(struct Curl_easy *data);
+static int http_getsock_do(struct Curl_easy *data,
+ struct connectdata *conn,
+ curl_socket_t *socks);
+static bool http_should_fail(struct Curl_easy *data);
+
+static CURLcode http_setup_conn(struct Curl_easy *data,
+ struct connectdata *conn);
+#ifdef USE_WEBSOCKETS
+static CURLcode ws_setup_conn(struct Curl_easy *data,
+ struct connectdata *conn);
+#endif
/*
* HTTP handler interface.
*/
const struct Curl_handler Curl_handler_http = {
- "http", /* scheme */
- Curl_http_setup_conn, /* setup_connection */
+ "HTTP", /* scheme */
+ http_setup_conn, /* setup_connection */
Curl_http, /* do_it */
Curl_http_done, /* done */
ZERO_NULL, /* do_more */
@@ -118,12 +125,11 @@ const struct Curl_handler Curl_handler_http = {
ZERO_NULL, /* connecting */
ZERO_NULL, /* doing */
ZERO_NULL, /* proto_getsock */
- Curl_http_getsock_do, /* doing_getsock */
+ http_getsock_do, /* doing_getsock */
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
ZERO_NULL, /* disconnect */
- Curl_http_write_resp, /* write_resp */
- Curl_http_write_resp_hd, /* write_resp_hd */
+ ZERO_NULL, /* readwrite */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_HTTP, /* defport */
@@ -133,13 +139,39 @@ const struct Curl_handler Curl_handler_http = {
PROTOPT_USERPWDCTRL
};
+#ifdef USE_WEBSOCKETS
+const struct Curl_handler Curl_handler_ws = {
+ "WS", /* scheme */
+ ws_setup_conn, /* setup_connection */
+ Curl_http, /* do_it */
+ Curl_http_done, /* done */
+ ZERO_NULL, /* do_more */
+ Curl_http_connect, /* connect_it */
+ ZERO_NULL, /* connecting */
+ ZERO_NULL, /* doing */
+ ZERO_NULL, /* proto_getsock */
+ http_getsock_do, /* doing_getsock */
+ ZERO_NULL, /* domore_getsock */
+ ZERO_NULL, /* perform_getsock */
+ Curl_ws_disconnect, /* disconnect */
+ ZERO_NULL, /* readwrite */
+ ZERO_NULL, /* connection_check */
+ ZERO_NULL, /* attach connection */
+ PORT_HTTP, /* defport */
+ CURLPROTO_WS, /* protocol */
+ CURLPROTO_HTTP, /* family */
+ PROTOPT_CREDSPERREQUEST | /* flags */
+ PROTOPT_USERPWDCTRL
+};
+#endif
+
#ifdef USE_SSL
/*
* HTTPS handler interface.
*/
const struct Curl_handler Curl_handler_https = {
- "https", /* scheme */
- Curl_http_setup_conn, /* setup_connection */
+ "HTTPS", /* scheme */
+ http_setup_conn, /* setup_connection */
Curl_http, /* do_it */
Curl_http_done, /* done */
ZERO_NULL, /* do_more */
@@ -147,12 +179,11 @@ const struct Curl_handler Curl_handler_https = {
NULL, /* connecting */
ZERO_NULL, /* doing */
NULL, /* proto_getsock */
- Curl_http_getsock_do, /* doing_getsock */
+ http_getsock_do, /* doing_getsock */
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
ZERO_NULL, /* disconnect */
- Curl_http_write_resp, /* write_resp */
- Curl_http_write_resp_hd, /* write_resp_hd */
+ ZERO_NULL, /* readwrite */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_HTTPS, /* defport */
@@ -162,13 +193,47 @@ const struct Curl_handler Curl_handler_https = {
PROTOPT_USERPWDCTRL
};
+#ifdef USE_WEBSOCKETS
+const struct Curl_handler Curl_handler_wss = {
+ "WSS", /* scheme */
+ ws_setup_conn, /* setup_connection */
+ Curl_http, /* do_it */
+ Curl_http_done, /* done */
+ ZERO_NULL, /* do_more */
+ Curl_http_connect, /* connect_it */
+ NULL, /* connecting */
+ ZERO_NULL, /* doing */
+ NULL, /* proto_getsock */
+ http_getsock_do, /* doing_getsock */
+ ZERO_NULL, /* domore_getsock */
+ ZERO_NULL, /* perform_getsock */
+ Curl_ws_disconnect, /* disconnect */
+ ZERO_NULL, /* readwrite */
+ ZERO_NULL, /* connection_check */
+ ZERO_NULL, /* attach connection */
+ PORT_HTTPS, /* defport */
+ CURLPROTO_WSS, /* protocol */
+ CURLPROTO_HTTP, /* family */
+ PROTOPT_SSL | PROTOPT_CREDSPERREQUEST | /* flags */
+ PROTOPT_USERPWDCTRL
+};
+#endif
+
#endif
-CURLcode Curl_http_setup_conn(struct Curl_easy *data,
- struct connectdata *conn)
+static CURLcode http_setup_conn(struct Curl_easy *data,
+ struct connectdata *conn)
{
/* allocate the HTTP-specific struct for the Curl_easy, only to survive
during this request */
+ struct HTTP *http;
+ DEBUGASSERT(data->req.p.http == NULL);
+
+ http = calloc(1, sizeof(struct HTTP));
+ if(!http)
+ return CURLE_OUT_OF_MEMORY;
+
+ data->req.p.http = http;
connkeep(conn, "HTTP default");
if(data->state.httpwant == CURL_HTTP_VERSION_3ONLY) {
@@ -180,6 +245,16 @@ CURLcode Curl_http_setup_conn(struct Curl_easy *data,
return CURLE_OK;
}
+#ifdef USE_WEBSOCKETS
+static CURLcode ws_setup_conn(struct Curl_easy *data,
+ struct connectdata *conn)
+{
+ /* websockets is 1.1 only (for now) */
+ data->state.httpwant = CURL_HTTP_VERSION_1_1;
+ return http_setup_conn(data, conn);
+}
+#endif
+
#ifndef CURL_DISABLE_PROXY
/*
* checkProxyHeaders() checks the linked list of custom proxy headers
@@ -222,6 +297,7 @@ char *Curl_copy_header_value(const char *header)
{
const char *start;
const char *end;
+ char *value;
size_t len;
/* Find the end of the header name */
@@ -237,6 +313,8 @@ char *Curl_copy_header_value(const char *header)
while(*start && ISSPACE(*start))
start++;
+ /* data is in the host encoding so
+ use '\r' and '\n' instead of 0x0d and 0x0a */
end = strchr(start, '\r');
if(!end)
end = strchr(start, '\n');
@@ -252,7 +330,14 @@ char *Curl_copy_header_value(const char *header)
/* get length of the type */
len = end - start + 1;
- return Curl_memdup0(start, len);
+ value = malloc(len + 1);
+ if(!value)
+ return NULL;
+
+ memcpy(value, start, len);
+ value[len] = 0; /* null-terminate */
+
+ return value;
}
#ifndef CURL_DISABLE_HTTP_AUTH
@@ -377,6 +462,8 @@ static bool pickoneauth(struct auth *pick, unsigned long mask)
#endif
else if(avail & CURLAUTH_NTLM)
pick->picked = CURLAUTH_NTLM;
+ else if(avail & CURLAUTH_NTLM_WB)
+ pick->picked = CURLAUTH_NTLM_WB;
#ifndef CURL_DISABLE_BASIC_AUTH
else if(avail & CURLAUTH_BASIC)
pick->picked = CURLAUTH_BASIC;
@@ -397,85 +484,150 @@ static bool pickoneauth(struct auth *pick, unsigned long mask)
/*
* http_perhapsrewind()
*
- * The current request needs to be done again - maybe due to a follow
- * or authentication negotiation. Check if:
- * 1) a rewind of the data sent to the server is necessary
- * 2) the current transfer should continue or be stopped early
+ * If we are doing POST or PUT {
+ * If we have more data to send {
+ * If we are doing NTLM {
+ * Keep sending since we must not disconnect
+ * }
+ * else {
+ * If there is more than just a little data left to send, close
+ * the current connection by force.
+ * }
+ * }
+ * If we have sent any data {
+ * If we don't have track of all the data {
+ * call app to tell it to rewind
+ * }
+ * else {
+ * rewind internally so that the operation can restart fine
+ * }
+ * }
+ * }
*/
static CURLcode http_perhapsrewind(struct Curl_easy *data,
struct connectdata *conn)
{
- curl_off_t bytessent = data->req.writebytecount;
- curl_off_t expectsend = Curl_creader_total_length(data);
- curl_off_t upload_remain = (expectsend >= 0)? (expectsend - bytessent) : -1;
- bool little_upload_remains = (upload_remain >= 0 && upload_remain < 2000);
- bool needs_rewind = Curl_creader_needs_rewind(data);
- /* By default, we would like to abort the transfer when little or unknown
- * amount remains. This may be overridden by authentications further
- * below! */
- bool abort_upload = (!data->req.upload_done && !little_upload_remains);
- const char *ongoing_auth = NULL;
-
- /* We need a rewind before uploading client read data again. The
- * checks below just influence of the upload is to be continued
- * or aborted early.
- * This depends on how much remains to be sent and in what state
- * the authentication is. Some auth schemes such as NTLM do not work
- * for a new connection. */
- if(needs_rewind) {
- infof(data, "Need to rewind upload for next request");
- Curl_creader_set_rewind(data, TRUE);
- }
-
- if(conn->bits.close)
- /* If we already decided to close this connection, we cannot veto. */
+ struct HTTP *http = data->req.p.http;
+ curl_off_t bytessent;
+ curl_off_t expectsend = -1; /* default is unknown */
+
+ if(!http)
+ /* If this is still NULL, we have not reach very far and we can safely
+ skip this rewinding stuff */
return CURLE_OK;
- if(abort_upload) {
- /* We'd like to abort the upload - but should we? */
+ switch(data->state.httpreq) {
+ case HTTPREQ_GET:
+ case HTTPREQ_HEAD:
+ return CURLE_OK;
+ default:
+ break;
+ }
+
+ bytessent = data->req.writebytecount;
+
+ if(conn->bits.authneg) {
+ /* This is a state where we are known to be negotiating and we don't send
+ any data then. */
+ expectsend = 0;
+ }
+ else if(!conn->bits.protoconnstart) {
+ /* HTTP CONNECT in progress: there is no body */
+ expectsend = 0;
+ }
+ else {
+ /* figure out how much data we are expected to send */
+ switch(data->state.httpreq) {
+ case HTTPREQ_POST:
+ case HTTPREQ_PUT:
+ if(data->state.infilesize != -1)
+ expectsend = data->state.infilesize;
+ break;
+ case HTTPREQ_POST_FORM:
+ case HTTPREQ_POST_MIME:
+ expectsend = http->postsize;
+ break;
+ default:
+ break;
+ }
+ }
+
+ data->state.rewindbeforesend = FALSE; /* default */
+
+ if((expectsend == -1) || (expectsend > bytessent)) {
#if defined(USE_NTLM)
+ /* There is still data left to send */
if((data->state.authproxy.picked == CURLAUTH_NTLM) ||
- (data->state.authhost.picked == CURLAUTH_NTLM)) {
- ongoing_auth = "NTML";
- if((conn->http_ntlm_state != NTLMSTATE_NONE) ||
+ (data->state.authhost.picked == CURLAUTH_NTLM) ||
+ (data->state.authproxy.picked == CURLAUTH_NTLM_WB) ||
+ (data->state.authhost.picked == CURLAUTH_NTLM_WB)) {
+ if(((expectsend - bytessent) < 2000) ||
+ (conn->http_ntlm_state != NTLMSTATE_NONE) ||
(conn->proxy_ntlm_state != NTLMSTATE_NONE)) {
- /* The NTLM-negotiation has started, keep on sending.
- * Need to do further work on same connection */
- abort_upload = FALSE;
+ /* The NTLM-negotiation has started *OR* there is just a little (<2K)
+ data left to send, keep on sending. */
+
+ /* rewind data when completely done sending! */
+ if(!conn->bits.authneg && (conn->writesockfd != CURL_SOCKET_BAD)) {
+ data->state.rewindbeforesend = TRUE;
+ infof(data, "Rewind stream before next send");
+ }
+
+ return CURLE_OK;
}
+
+ if(conn->bits.close)
+ /* this is already marked to get closed */
+ return CURLE_OK;
+
+ infof(data, "NTLM send, close instead of sending %"
+ CURL_FORMAT_CURL_OFF_T " bytes",
+ (curl_off_t)(expectsend - bytessent));
}
#endif
#if defined(USE_SPNEGO)
/* There is still data left to send */
if((data->state.authproxy.picked == CURLAUTH_NEGOTIATE) ||
(data->state.authhost.picked == CURLAUTH_NEGOTIATE)) {
- ongoing_auth = "NEGOTIATE";
- if((conn->http_negotiate_state != GSS_AUTHNONE) ||
+ if(((expectsend - bytessent) < 2000) ||
+ (conn->http_negotiate_state != GSS_AUTHNONE) ||
(conn->proxy_negotiate_state != GSS_AUTHNONE)) {
- /* The NEGOTIATE-negotiation has started, keep on sending.
- * Need to do further work on same connection */
- abort_upload = FALSE;
+ /* The NEGOTIATE-negotiation has started *OR*
+ there is just a little (<2K) data left to send, keep on sending. */
+
+ /* rewind data when completely done sending! */
+ if(!conn->bits.authneg && (conn->writesockfd != CURL_SOCKET_BAD)) {
+ data->state.rewindbeforesend = TRUE;
+ infof(data, "Rewind stream before next send");
+ }
+
+ return CURLE_OK;
}
+
+ if(conn->bits.close)
+ /* this is already marked to get closed */
+ return CURLE_OK;
+
+ infof(data, "NEGOTIATE send, close instead of sending %"
+ CURL_FORMAT_CURL_OFF_T " bytes",
+ (curl_off_t)(expectsend - bytessent));
}
#endif
- }
- if(abort_upload) {
- if(upload_remain >= 0)
- infof(data, "%s%sclose instead of sending %" FMT_OFF_T " more bytes",
- ongoing_auth? ongoing_auth : "",
- ongoing_auth? " send, " : "",
- upload_remain);
- else
- infof(data, "%s%sclose instead of sending unknown amount "
- "of more bytes",
- ongoing_auth? ongoing_auth : "",
- ongoing_auth? " send, " : "");
- /* We decided to abort the ongoing transfer */
+ /* This is not NEGOTIATE/NTLM or many bytes left to send: close */
streamclose(conn, "Mid-auth HTTP and much data left to send");
- /* FIXME: questionable manipulation here, can we do this differently? */
- data->req.size = 0; /* do not download any more than 0 bytes */
+ data->req.size = 0; /* don't download any more than 0 bytes */
+
+ /* There still is data left to send, but this connection is marked for
+ closure so we can safely do the rewind right now */
+ }
+
+ if(bytessent) {
+ /* mark for rewind since if we already sent something */
+ data->state.rewindbeforesend = TRUE;
+ infof(data, "Please rewind output before next send");
}
+
return CURLE_OK;
}
@@ -506,7 +658,7 @@ CURLcode Curl_http_auth_act(struct Curl_easy *data)
if((data->state.aptr.user || data->set.str[STRING_BEARER]) &&
((data->req.httpcode == 401) ||
- (data->req.authneg && data->req.httpcode < 300))) {
+ (conn->bits.authneg && data->req.httpcode < 300))) {
pickhost = pickoneauth(&data->state.authhost, authmask);
if(!pickhost)
data->state.authproblem = TRUE;
@@ -520,7 +672,7 @@ CURLcode Curl_http_auth_act(struct Curl_easy *data)
#ifndef CURL_DISABLE_PROXY
if(conn->bits.proxy_user_passwd &&
((data->req.httpcode == 407) ||
- (data->req.authneg && data->req.httpcode < 300))) {
+ (conn->bits.authneg && data->req.httpcode < 300))) {
pickproxy = pickoneauth(&data->state.authproxy,
authmask & ~CURLAUTH_BEARER);
if(!pickproxy)
@@ -529,10 +681,13 @@ CURLcode Curl_http_auth_act(struct Curl_easy *data)
#endif
if(pickhost || pickproxy) {
- result = http_perhapsrewind(data, conn);
- if(result)
- return result;
-
+ if((data->state.httpreq != HTTPREQ_GET) &&
+ (data->state.httpreq != HTTPREQ_HEAD) &&
+ !data->state.rewindbeforesend) {
+ result = http_perhapsrewind(data, conn);
+ if(result)
+ return result;
+ }
/* In case this is GSS auth, the newurl field is already allocated so
we must make sure to free it before allocating a new one. As figured
out in bug #2284386 */
@@ -543,11 +698,11 @@ CURLcode Curl_http_auth_act(struct Curl_easy *data)
}
else if((data->req.httpcode < 300) &&
(!data->state.authhost.done) &&
- data->req.authneg) {
+ conn->bits.authneg) {
/* no (known) authentication available,
authentication is not "done" yet and
no authentication seems to be required and
- we did not try HEAD or GET */
+ we didn't try HEAD or GET */
if((data->state.httpreq != HTTPREQ_GET) &&
(data->state.httpreq != HTTPREQ_HEAD)) {
data->req.newurl = strdup(data->state.url); /* clone URL */
@@ -556,7 +711,7 @@ CURLcode Curl_http_auth_act(struct Curl_easy *data)
data->state.authhost.done = TRUE;
}
}
- if(http_should_fail(data, data->req.httpcode)) {
+ if(http_should_fail(data)) {
failf(data, "The requested URL returned error: %d",
data->req.httpcode);
result = CURLE_HTTP_RETURNED_ERROR;
@@ -613,6 +768,15 @@ output_auth_headers(struct Curl_easy *data,
}
else
#endif
+#if defined(USE_NTLM) && defined(NTLM_WB_ENABLED)
+ if(authstatus->picked == CURLAUTH_NTLM_WB) {
+ auth = "NTLM_WB";
+ result = Curl_output_ntlm_wb(data, conn, proxy);
+ if(result)
+ return result;
+ }
+ else
+#endif
#ifndef CURL_DISABLE_DIGEST_AUTH
if(authstatus->picked == CURLAUTH_DIGEST) {
auth = "Digest";
@@ -737,13 +901,13 @@ Curl_http_output_auth(struct Curl_easy *data,
if(authhost->want && !authhost->picked)
/* The app has selected one or more methods, but none has been picked
so far by a server round-trip. Then we set the picked one to the
- want one, and if this is one single bit it will be used instantly. */
+ want one, and if this is one single bit it'll be used instantly. */
authhost->picked = authhost->want;
if(authproxy->want && !authproxy->picked)
/* The app has selected one or more methods, but none has been picked so
far by a proxy round-trip. Then we set the picked one to the want one,
- and if this is one single bit it will be used instantly. */
+ and if this is one single bit it'll be used instantly. */
authproxy->picked = authproxy->want;
#ifndef CURL_DISABLE_PROXY
@@ -758,7 +922,7 @@ Curl_http_output_auth(struct Curl_easy *data,
#else
(void)proxytunnel;
#endif /* CURL_DISABLE_PROXY */
- /* we have no proxy so let's pretend we are done authenticating
+ /* we have no proxy so let's pretend we're done authenticating
with it */
authproxy->done = TRUE;
@@ -779,10 +943,10 @@ Curl_http_output_auth(struct Curl_easy *data,
(httpreq != HTTPREQ_HEAD)) {
/* Auth is required and we are not authenticated yet. Make a PUT or POST
with content-length zero as a "probe". */
- data->req.authneg = TRUE;
+ conn->bits.authneg = TRUE;
}
else
- data->req.authneg = FALSE;
+ conn->bits.authneg = FALSE;
return result;
}
@@ -902,15 +1066,31 @@ CURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy,
/* NTLM support requires the SSL crypto libs */
if(checkprefix("NTLM", auth) && is_valid_auth_separator(auth[4])) {
if((authp->avail & CURLAUTH_NTLM) ||
+ (authp->avail & CURLAUTH_NTLM_WB) ||
Curl_auth_is_ntlm_supported()) {
*availp |= CURLAUTH_NTLM;
authp->avail |= CURLAUTH_NTLM;
- if(authp->picked == CURLAUTH_NTLM) {
+ if(authp->picked == CURLAUTH_NTLM ||
+ authp->picked == CURLAUTH_NTLM_WB) {
/* NTLM authentication is picked and activated */
CURLcode result = Curl_input_ntlm(data, proxy, auth);
if(!result) {
data->state.authproblem = FALSE;
+#ifdef NTLM_WB_ENABLED
+ if(authp->picked == CURLAUTH_NTLM_WB) {
+ *availp &= ~CURLAUTH_NTLM;
+ authp->avail &= ~CURLAUTH_NTLM;
+ *availp |= CURLAUTH_NTLM_WB;
+ authp->avail |= CURLAUTH_NTLM_WB;
+
+ result = Curl_input_ntlm_wb(data, conn, proxy, auth);
+ if(result) {
+ infof(data, "Authentication problem. Ignoring this.");
+ data->state.authproblem = TRUE;
+ }
+ }
+#endif
}
else {
infof(data, "Authentication problem. Ignoring this.");
@@ -932,7 +1112,7 @@ CURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy,
authp->avail |= CURLAUTH_DIGEST;
/* We call this function on input Digest headers even if Digest
- * authentication is not activated yet, as we need to store the
+ * authentication isn't activated yet, as we need to store the
* incoming data from this header in case we are going to use
* Digest */
result = Curl_input_digest(data, proxy, auth);
@@ -951,7 +1131,7 @@ CURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy,
authp->avail |= CURLAUTH_BASIC;
if(authp->picked == CURLAUTH_BASIC) {
/* We asked for Basic authentication but got a 40X back
- anyway, which basically means our name+password is not
+ anyway, which basically means our name+password isn't
valid. */
authp->avail = CURLAUTH_NONE;
infof(data, "Authentication problem. Ignoring this.");
@@ -967,7 +1147,7 @@ CURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy,
authp->avail |= CURLAUTH_BEARER;
if(authp->picked == CURLAUTH_BEARER) {
/* We asked for Bearer authentication but got a 40X back
- anyway, which basically means our token is not valid. */
+ anyway, which basically means our token isn't valid. */
authp->avail = CURLAUTH_NONE;
infof(data, "Authentication problem. Ignoring this.");
data->state.authproblem = TRUE;
@@ -987,7 +1167,7 @@ CURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy,
/* there may be multiple methods on one line, so keep reading */
while(*auth && *auth != ',') /* read up to the next comma */
auth++;
- if(*auth == ',') /* if we are on a comma, skip it */
+ if(*auth == ',') /* if we're on a comma, skip it */
auth++;
while(*auth && ISSPACE(*auth))
auth++;
@@ -997,21 +1177,24 @@ CURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy,
}
/**
- * http_should_fail() determines whether an HTTP response code has gotten us
+ * http_should_fail() determines whether an HTTP response has gotten us
* into an error state or not.
*
* @retval FALSE communications should continue
*
* @retval TRUE communications should not continue
*/
-static bool http_should_fail(struct Curl_easy *data, int httpcode)
+static bool http_should_fail(struct Curl_easy *data)
{
+ int httpcode;
DEBUGASSERT(data);
DEBUGASSERT(data->conn);
+ httpcode = data->req.httpcode;
+
/*
- ** If we have not been asked to fail on error,
- ** do not fail.
+ ** If we haven't been asked to fail on error,
+ ** don't fail.
*/
if(!data->set.http_fail_on_error)
return FALSE;
@@ -1031,7 +1214,7 @@ static bool http_should_fail(struct Curl_easy *data, int httpcode)
return FALSE;
/*
- ** Any code >= 400 that is not 401 or 407 is always
+ ** Any code >= 400 that's not 401 or 407 is always
** a terminal error
*/
if((httpcode != 401) && (httpcode != 407))
@@ -1043,19 +1226,22 @@ static bool http_should_fail(struct Curl_easy *data, int httpcode)
DEBUGASSERT((httpcode == 401) || (httpcode == 407));
/*
- ** Examine the current authentication state to see if this is an error. The
- ** idea is for this function to get called after processing all the headers
- ** in a response message. So, if we have been to asked to authenticate a
- ** particular stage, and we have done it, we are OK. If we are already
- ** completely authenticated, it is not OK to get another 401 or 407.
+ ** Examine the current authentication state to see if this
+ ** is an error. The idea is for this function to get
+ ** called after processing all the headers in a response
+ ** message. So, if we've been to asked to authenticate a
+ ** particular stage, and we've done it, we're OK. But, if
+ ** we're already completely authenticated, it's not OK to
+ ** get another 401 or 407.
**
- ** It is possible for authentication to go stale such that the client needs
- ** to reauthenticate. Once that info is available, use it here.
+ ** It is possible for authentication to go stale such that
+ ** the client needs to reauthenticate. Once that info is
+ ** available, use it here.
*/
/*
- ** Either we are not authenticating, or we are supposed to be authenticating
- ** something else. This is an error.
+ ** Either we're not authenticating, or we're supposed to
+ ** be authenticating something else. This is an error.
*/
if((httpcode == 401) && !data->state.aptr.user)
return TRUE;
@@ -1068,6 +1254,274 @@ static bool http_should_fail(struct Curl_easy *data, int httpcode)
}
/*
+ * readmoredata() is a "fread() emulation" to provide POST and/or request
+ * data. It is used when a huge POST is to be made and the entire chunk wasn't
+ * sent in the first send(). This function will then be called from the
+ * transfer.c loop when more data is to be sent to the peer.
+ *
+ * Returns the amount of bytes it filled the buffer with.
+ */
+static size_t readmoredata(char *buffer,
+ size_t size,
+ size_t nitems,
+ void *userp)
+{
+ struct HTTP *http = (struct HTTP *)userp;
+ struct Curl_easy *data = http->backup.data;
+ size_t fullsize = size * nitems;
+
+ if(!http->postsize)
+ /* nothing to return */
+ return 0;
+
+ /* make sure that an HTTP request is never sent away chunked! */
+ data->req.forbidchunk = (http->sending == HTTPSEND_REQUEST)?TRUE:FALSE;
+
+ if(data->set.max_send_speed &&
+ (data->set.max_send_speed < (curl_off_t)fullsize) &&
+ (data->set.max_send_speed < http->postsize))
+ /* speed limit */
+ fullsize = (size_t)data->set.max_send_speed;
+
+ else if(http->postsize <= (curl_off_t)fullsize) {
+ memcpy(buffer, http->postdata, (size_t)http->postsize);
+ fullsize = (size_t)http->postsize;
+
+ if(http->backup.postsize) {
+ /* move backup data into focus and continue on that */
+ http->postdata = http->backup.postdata;
+ http->postsize = http->backup.postsize;
+ data->state.fread_func = http->backup.fread_func;
+ data->state.in = http->backup.fread_in;
+
+ http->sending++; /* move one step up */
+
+ http->backup.postsize = 0;
+ }
+ else
+ http->postsize = 0;
+
+ return fullsize;
+ }
+
+ memcpy(buffer, http->postdata, fullsize);
+ http->postdata += fullsize;
+ http->postsize -= fullsize;
+
+ return fullsize;
+}
+
+/*
+ * Curl_buffer_send() sends a header buffer and frees all associated
+ * memory. Body data may be appended to the header data if desired.
+ *
+ * Returns CURLcode
+ */
+CURLcode Curl_buffer_send(struct dynbuf *in,
+ struct Curl_easy *data,
+ struct HTTP *http,
+ /* add the number of sent bytes to this
+ counter */
+ curl_off_t *bytes_written,
+ /* how much of the buffer contains body data */
+ curl_off_t included_body_bytes,
+ int sockindex)
+{
+ ssize_t amount;
+ CURLcode result;
+ char *ptr;
+ size_t size;
+ struct connectdata *conn = data->conn;
+ size_t sendsize;
+ size_t headersize;
+
+ DEBUGASSERT(sockindex <= SECONDARYSOCKET && sockindex >= 0);
+
+ /* The looping below is required since we use non-blocking sockets, but due
+ to the circumstances we will just loop and try again and again etc */
+
+ ptr = Curl_dyn_ptr(in);
+ size = Curl_dyn_len(in);
+
+ headersize = size - (size_t)included_body_bytes; /* the initial part that
+ isn't body is header */
+
+ DEBUGASSERT(size > (size_t)included_body_bytes);
+
+ if((conn->handler->flags & PROTOPT_SSL
+#ifndef CURL_DISABLE_PROXY
+ || IS_HTTPS_PROXY(conn->http_proxy.proxytype)
+#endif
+ )
+ && conn->httpversion < 20) {
+ /* Make sure this doesn't send more body bytes than what the max send
+ speed says. The request bytes do not count to the max speed.
+ */
+ if(data->set.max_send_speed &&
+ (included_body_bytes > data->set.max_send_speed)) {
+ curl_off_t overflow = included_body_bytes - data->set.max_send_speed;
+ DEBUGASSERT((size_t)overflow < size);
+ sendsize = size - (size_t)overflow;
+ }
+ else
+ sendsize = size;
+
+ /* OpenSSL is very picky and we must send the SAME buffer pointer to the
+ library when we attempt to re-send this buffer. Sending the same data
+ is not enough, we must use the exact same address. For this reason, we
+ must copy the data to the uploadbuffer first, since that is the buffer
+ we will be using if this send is retried later.
+ */
+ result = Curl_get_upload_buffer(data);
+ if(result) {
+ /* malloc failed, free memory and return to the caller */
+ Curl_dyn_free(in);
+ return result;
+ }
+ /* We never send more than upload_buffer_size bytes in one single chunk
+ when we speak HTTPS, as if only a fraction of it is sent now, this data
+ needs to fit into the normal read-callback buffer later on and that
+ buffer is using this size.
+ */
+ if(sendsize > (size_t)data->set.upload_buffer_size)
+ sendsize = (size_t)data->set.upload_buffer_size;
+
+ memcpy(data->state.ulbuf, ptr, sendsize);
+ ptr = data->state.ulbuf;
+ }
+ else {
+#ifdef CURLDEBUG
+ /* Allow debug builds to override this logic to force short initial
+ sends
+ */
+ char *p = getenv("CURL_SMALLREQSEND");
+ if(p) {
+ size_t altsize = (size_t)strtoul(p, NULL, 10);
+ if(altsize)
+ sendsize = CURLMIN(size, altsize);
+ else
+ sendsize = size;
+ }
+ else
+#endif
+ {
+ /* Make sure this doesn't send more body bytes than what the max send
+ speed says. The request bytes do not count to the max speed.
+ */
+ if(data->set.max_send_speed &&
+ (included_body_bytes > data->set.max_send_speed)) {
+ curl_off_t overflow = included_body_bytes - data->set.max_send_speed;
+ DEBUGASSERT((size_t)overflow < size);
+ sendsize = size - (size_t)overflow;
+ }
+ else
+ sendsize = size;
+ }
+
+ /* We currently cannot send more that this for http here:
+ * - if sending blocks, it return 0 as amount
+ * - we then whisk aside the `in` into the `http` struct
+ * and install our own `data->state.fread_func` that
+ * on subsequent calls reads `in` empty.
+ * - when the whisked away `in` is empty, the `fread_func`
+ * is restored to its original state.
+ * The problem is that `fread_func` can only return
+ * `upload_buffer_size` lengths. If the send we do here
+ * is larger and blocks, we do re-sending with smaller
+ * amounts of data and connection filters do not like
+ * that.
+ */
+ if(http && (sendsize > (size_t)data->set.upload_buffer_size))
+ sendsize = (size_t)data->set.upload_buffer_size;
+ }
+
+ result = Curl_nwrite(data, sockindex, ptr, sendsize, &amount);
+
+ if(!result) {
+ /*
+ * Note that we may not send the entire chunk at once, and we have a set
+ * number of data bytes at the end of the big buffer (out of which we may
+ * only send away a part).
+ */
+ /* how much of the header that was sent */
+ size_t headlen = (size_t)amount>headersize ? headersize : (size_t)amount;
+ size_t bodylen = amount - headlen;
+
+ /* this data _may_ contain binary stuff */
+ Curl_debug(data, CURLINFO_HEADER_OUT, ptr, headlen);
+ if(bodylen)
+ /* there was body data sent beyond the initial header part, pass that on
+ to the debug callback too */
+ Curl_debug(data, CURLINFO_DATA_OUT, ptr + headlen, bodylen);
+
+ /* 'amount' can never be a very large value here so typecasting it so a
+ signed 31 bit value should not cause problems even if ssize_t is
+ 64bit */
+ *bytes_written += (long)amount;
+
+ if(http) {
+ /* if we sent a piece of the body here, up the byte counter for it
+ accordingly */
+ data->req.writebytecount += bodylen;
+ Curl_pgrsSetUploadCounter(data, data->req.writebytecount);
+
+ if((size_t)amount != size) {
+ /* The whole request could not be sent in one system call. We must
+ queue it up and send it later when we get the chance. We must not
+ loop here and wait until it might work again. */
+
+ size -= amount;
+
+ ptr = Curl_dyn_ptr(in) + amount;
+
+ /* backup the currently set pointers */
+ http->backup.fread_func = data->state.fread_func;
+ http->backup.fread_in = data->state.in;
+ http->backup.postdata = http->postdata;
+ http->backup.postsize = http->postsize;
+ http->backup.data = data;
+
+ /* set the new pointers for the request-sending */
+ data->state.fread_func = (curl_read_callback)readmoredata;
+ data->state.in = (void *)http;
+ http->postdata = ptr;
+ http->postsize = (curl_off_t)size;
+
+ /* this much data is remaining header: */
+ data->req.pendingheader = headersize - headlen;
+
+ http->send_buffer = *in; /* copy the whole struct */
+ http->sending = HTTPSEND_REQUEST;
+ return CURLE_OK;
+ }
+ http->sending = HTTPSEND_BODY;
+ /* the full buffer was sent, clean up and return */
+ }
+ else {
+ if((size_t)amount != size)
+ /* We have no continue-send mechanism now, fail. This can only happen
+ when this function is used from the CONNECT sending function. We
+ currently (stupidly) assume that the whole request is always sent
+ away in the first single chunk.
+
+ This needs FIXing.
+ */
+ return CURLE_SEND_ERROR;
+ }
+ }
+ Curl_dyn_free(in);
+
+ /* no remaining header data */
+ data->req.pendingheader = 0;
+ return result;
+}
+
+/* end of the add_buffer functions */
+/* ------------------------------------------------------------------------- */
+
+
+
+/*
* Curl_compareheader()
*
* Returns TRUE if 'headerline' contains the 'header' with given 'content'.
@@ -1094,7 +1548,7 @@ Curl_compareheader(const char *headerline, /* line to check */
DEBUGASSERT(content);
if(!strncasecompare(headerline, header, hlen))
- return FALSE; /* does not start with header */
+ return FALSE; /* doesn't start with header */
/* pass the header */
start = &headerline[hlen];
@@ -1106,11 +1560,11 @@ Curl_compareheader(const char *headerline, /* line to check */
/* find the end of the header line */
end = strchr(start, '\r'); /* lines end with CRLF */
if(!end) {
- /* in case there is a non-standard compliant line here */
+ /* in case there's a non-standard compliant line here */
end = strchr(start, '\n');
if(!end)
- /* hm, there is no line ending here, use the zero byte! */
+ /* hm, there's no line ending here, use the zero byte! */
end = strchr(start, '\0');
}
@@ -1141,11 +1595,11 @@ CURLcode Curl_http_connect(struct Curl_easy *data, bool *done)
}
/* this returns the socket to wait for in the DO and DOING state for the multi
- interface and then we are always _sending_ a request and thus we wait for
+ interface and then we're always _sending_ a request and thus we wait for
the single socket to become writable only */
-int Curl_http_getsock_do(struct Curl_easy *data,
- struct connectdata *conn,
- curl_socket_t *socks)
+static int http_getsock_do(struct Curl_easy *data,
+ struct connectdata *conn,
+ curl_socket_t *socks)
{
/* write mode */
(void)conn;
@@ -1162,14 +1616,24 @@ CURLcode Curl_http_done(struct Curl_easy *data,
CURLcode status, bool premature)
{
struct connectdata *conn = data->conn;
+ struct HTTP *http = data->req.p.http;
- /* Clear multipass flag. If authentication is not done yet, then it will get
+ /* Clear multipass flag. If authentication isn't done yet, then it will get
* a chance to be set back to true when we output the next auth header */
data->state.authhost.multipass = FALSE;
data->state.authproxy.multipass = FALSE;
+ /* set the proper values (possibly modified on POST) */
+ conn->seek_func = data->set.seek_func; /* restore */
+ conn->seek_client = data->set.seek_client; /* restore */
+
+ if(!http)
+ return CURLE_OK;
+
+ Curl_dyn_free(&http->send_buffer);
Curl_dyn_reset(&data->state.headerb);
Curl_hyper_done(data);
+ Curl_ws_done(data);
if(status)
return status;
@@ -1181,8 +1645,8 @@ CURLcode Curl_http_done(struct Curl_easy *data,
(data->req.bytecount +
data->req.headerbytecount -
data->req.deductheadercount) <= 0) {
- /* If this connection is not simply closed to be retried, AND nothing was
- read from the HTTP server (that counts), this cannot be right so we
+ /* If this connection isn't simply closed to be retried, AND nothing was
+ read from the HTTP server (that counts), this can't be right so we
return an error here */
failf(data, "Empty reply from server");
/* Mark it as closed to avoid the "left intact" message */
@@ -1229,12 +1693,83 @@ static const char *get_http_string(const struct Curl_easy *data,
}
#endif
+/* check and possibly add an Expect: header */
+static CURLcode expect100(struct Curl_easy *data,
+ struct connectdata *conn,
+ struct dynbuf *req)
+{
+ CURLcode result = CURLE_OK;
+ if(!data->state.disableexpect && Curl_use_http_1_1plus(data, conn) &&
+ (conn->httpversion < 20)) {
+ /* if not doing HTTP 1.0 or version 2, or disabled explicitly, we add an
+ Expect: 100-continue to the headers which actually speeds up post
+ operations (as there is one packet coming back from the web server) */
+ const char *ptr = Curl_checkheaders(data, STRCONST("Expect"));
+ if(ptr) {
+ data->state.expect100header =
+ Curl_compareheader(ptr, STRCONST("Expect:"), STRCONST("100-continue"));
+ }
+ else {
+ result = Curl_dyn_addn(req, STRCONST("Expect: 100-continue\r\n"));
+ if(!result)
+ data->state.expect100header = TRUE;
+ }
+ }
+
+ return result;
+}
+
enum proxy_use {
HEADER_SERVER, /* direct to server */
HEADER_PROXY, /* regular request to proxy */
HEADER_CONNECT /* sending CONNECT to a proxy */
};
+/* used to compile the provided trailers into one buffer
+ will return an error code if one of the headers is
+ not formatted correctly */
+CURLcode Curl_http_compile_trailers(struct curl_slist *trailers,
+ struct dynbuf *b,
+ struct Curl_easy *handle)
+{
+ char *ptr = NULL;
+ CURLcode result = CURLE_OK;
+ const char *endofline_native = NULL;
+ const char *endofline_network = NULL;
+
+ if(
+#ifdef CURL_DO_LINEEND_CONV
+ (handle->state.prefer_ascii) ||
+#endif
+ (handle->set.crlf)) {
+ /* \n will become \r\n later on */
+ endofline_native = "\n";
+ endofline_network = "\x0a";
+ }
+ else {
+ endofline_native = "\r\n";
+ endofline_network = "\x0d\x0a";
+ }
+
+ while(trailers) {
+ /* only add correctly formatted trailers */
+ ptr = strchr(trailers->data, ':');
+ if(ptr && *(ptr + 1) == ' ') {
+ result = Curl_dyn_add(b, trailers->data);
+ if(result)
+ return result;
+ result = Curl_dyn_add(b, endofline_native);
+ if(result)
+ return result;
+ }
+ else
+ infof(handle, "Malformatted trailing header, skipping trailer");
+ trailers = trailers->next;
+ }
+ result = Curl_dyn_add(b, endofline_network);
+ return result;
+}
+
static bool hd_name_eq(const char *n1, size_t n1len,
const char *n2, size_t n2len)
{
@@ -1341,7 +1876,7 @@ CURLcode Curl_dynhds_add_custom(struct Curl_easy *data,
DEBUGASSERT(name && value);
if(data->state.aptr.host &&
- /* a Host: header was sent already, do not pass on any custom Host:
+ /* a Host: header was sent already, don't pass on any custom Host:
header as that will produce *two* in the same request! */
hd_name_eq(name, namelen, STRCONST("Host:")))
;
@@ -1353,19 +1888,19 @@ CURLcode Curl_dynhds_add_custom(struct Curl_easy *data,
/* this header is sent later */
hd_name_eq(name, namelen, STRCONST("Content-Type:")))
;
- else if(data->req.authneg &&
- /* while doing auth neg, do not allow the custom length since
+ else if(conn->bits.authneg &&
+ /* while doing auth neg, don't allow the custom length since
we will force length zero then */
hd_name_eq(name, namelen, STRCONST("Content-Length:")))
;
else if(data->state.aptr.te &&
- /* when asking for Transfer-Encoding, do not pass on a custom
+ /* when asking for Transfer-Encoding, don't pass on a custom
Connection: */
hd_name_eq(name, namelen, STRCONST("Connection:")))
;
else if((conn->httpversion >= 20) &&
hd_name_eq(name, namelen, STRCONST("Transfer-Encoding:")))
- /* HTTP/2 does not support chunked requests */
+ /* HTTP/2 doesn't support chunked requests */
;
else if((hd_name_eq(name, namelen, STRCONST("Authorization:")) ||
hd_name_eq(name, namelen, STRCONST("Cookie:"))) &&
@@ -1487,9 +2022,8 @@ CURLcode Curl_add_custom_headers(struct Curl_easy *data,
char *compare = semicolonp ? semicolonp : headers->data;
if(data->state.aptr.host &&
- /* a Host: header was sent already, do not pass on any custom
- Host: header as that will produce *two* in the same
- request! */
+ /* a Host: header was sent already, don't pass on any custom Host:
+ header as that will produce *two* in the same request! */
checkprefix("Host:", compare))
;
else if(data->state.httpreq == HTTPREQ_POST_FORM &&
@@ -1500,19 +2034,19 @@ CURLcode Curl_add_custom_headers(struct Curl_easy *data,
/* this header is sent later */
checkprefix("Content-Type:", compare))
;
- else if(data->req.authneg &&
- /* while doing auth neg, do not allow the custom length since
+ else if(conn->bits.authneg &&
+ /* while doing auth neg, don't allow the custom length since
we will force length zero then */
checkprefix("Content-Length:", compare))
;
else if(data->state.aptr.te &&
- /* when asking for Transfer-Encoding, do not pass on a custom
+ /* when asking for Transfer-Encoding, don't pass on a custom
Connection: */
checkprefix("Connection:", compare))
;
else if((conn->httpversion >= 20) &&
checkprefix("Transfer-Encoding:", compare))
- /* HTTP/2 does not support chunked requests */
+ /* HTTP/2 doesn't support chunked requests */
;
else if((checkprefix("Authorization:", compare) ||
checkprefix("Cookie:", compare)) &&
@@ -1569,7 +2103,6 @@ CURLcode Curl_add_timecondition(struct Curl_easy *data,
switch(data->set.timecondition) {
default:
- DEBUGF(infof(data, "invalid time condition"));
return CURLE_BAD_FUNCTION_ARGUMENT;
case CURL_TIMECOND_IFMODSINCE:
@@ -1704,10 +2237,10 @@ CURLcode Curl_http_host(struct Curl_easy *data, struct connectdata *conn)
if(ptr && (!data->state.this_is_a_follow ||
strcasecompare(data->state.first_host, conn->host.name))) {
#if !defined(CURL_DISABLE_COOKIES)
- /* If we have a given custom Host: header, we extract the hostname in
+ /* If we have a given custom Host: header, we extract the host name in
order to possibly use it for cookie reasons later on. We only allow the
custom Host: header if this is NOT a redirect, as setting Host: in the
- redirected request is being out on thin ice. Except if the hostname
+ redirected request is being out on thin ice. Except if the host name
is the same as the first one! */
char *cookiehost = Curl_copy_header_value(ptr);
if(!cookiehost)
@@ -1738,22 +2271,22 @@ CURLcode Curl_http_host(struct Curl_easy *data, struct connectdata *conn)
}
#endif
- if(!strcasecompare("Host:", ptr)) {
+ if(strcmp("Host:", ptr)) {
aptr->host = aprintf("Host:%s\r\n", &ptr[5]);
if(!aptr->host)
return CURLE_OUT_OF_MEMORY;
}
}
else {
- /* When building Host: headers, we must put the hostname within
- [brackets] if the hostname is a plain IPv6-address. RFC2732-style. */
+ /* When building Host: headers, we must put the host name within
+ [brackets] if the host name is a plain IPv6-address. RFC2732-style. */
const char *host = conn->host.name;
if(((conn->given->protocol&(CURLPROTO_HTTPS|CURLPROTO_WSS)) &&
(conn->remote_port == PORT_HTTPS)) ||
((conn->given->protocol&(CURLPROTO_HTTP|CURLPROTO_WS)) &&
(conn->remote_port == PORT_HTTP)) )
- /* if(HTTPS on port 443) OR (HTTP on port 80) then do not include
+ /* if(HTTPS on port 443) OR (HTTP on port 80) then don't include
the port number in the host string */
aptr->host = aprintf("Host: %s%s%s\r\n", conn->bits.ipv6_ip?"[":"",
host, conn->bits.ipv6_ip?"]":"");
@@ -1763,7 +2296,7 @@ CURLcode Curl_http_host(struct Curl_easy *data, struct connectdata *conn)
conn->remote_port);
if(!aptr->host)
- /* without Host: we cannot make a nice request */
+ /* without Host: we can't make a nice request */
return CURLE_OUT_OF_MEMORY;
}
return CURLE_OK;
@@ -1791,7 +2324,7 @@ CURLcode Curl_http_target(struct Curl_easy *data,
/* The path sent to the proxy is in fact the entire URL. But if the remote
host is a IDN-name, we must make sure that the request we produce only
- uses the encoded hostname! */
+ uses the encoded host name! */
/* and no fragment part */
CURLUcode uc;
@@ -1814,7 +2347,7 @@ CURLcode Curl_http_target(struct Curl_easy *data,
}
if(strcasecompare("http", data->state.up.scheme)) {
- /* when getting HTTP, we do not want the userinfo the URL */
+ /* when getting HTTP, we don't want the userinfo the URL */
uc = curl_url_set(h, CURLUPART_USER, NULL, 0);
if(uc) {
curl_url_cleanup(h);
@@ -1826,7 +2359,9 @@ CURLcode Curl_http_target(struct Curl_easy *data,
return CURLE_OUT_OF_MEMORY;
}
}
- /* Extract the URL to use in the request. */
+ /* Extract the URL to use in the request. Store in STRING_TEMP_URL for
+ clean-up reasons if the function returns before the free() further
+ down. */
uc = curl_url_get(h, CURLUPART_URL, &url, CURLU_NO_DEFAULT_PORT);
if(uc) {
curl_url_cleanup(h);
@@ -1835,7 +2370,7 @@ CURLcode Curl_http_target(struct Curl_easy *data,
curl_url_cleanup(h);
- /* target or URL */
+ /* target or url */
result = Curl_dyn_add(r, data->set.str[STRING_TARGET]?
data->set.str[STRING_TARGET]:url);
free(url);
@@ -1881,17 +2416,18 @@ CURLcode Curl_http_target(struct Curl_easy *data,
return result;
}
-#if !defined(CURL_DISABLE_MIME) || !defined(CURL_DISABLE_FORM_API)
-static CURLcode set_post_reader(struct Curl_easy *data, Curl_HttpReq httpreq)
+CURLcode Curl_http_body(struct Curl_easy *data, struct connectdata *conn,
+ Curl_HttpReq httpreq, const char **tep)
{
- CURLcode result;
+ CURLcode result = CURLE_OK;
+ const char *ptr;
+ struct HTTP *http = data->req.p.http;
+ http->postsize = 0;
switch(httpreq) {
-#ifndef CURL_DISABLE_MIME
case HTTPREQ_POST_MIME:
data->state.mimepost = &data->set.mimepost;
break;
-#endif
#ifndef CURL_DISABLE_FORM_API
case HTTPREQ_POST_FORM:
/* Convert the form structure into a mime structure, then keep
@@ -1913,188 +2449,55 @@ static CURLcode set_post_reader(struct Curl_easy *data, Curl_HttpReq httpreq)
#endif
default:
data->state.mimepost = NULL;
- break;
}
- switch(httpreq) {
- case HTTPREQ_POST_FORM:
- case HTTPREQ_POST_MIME:
- /* This is form posting using mime data. */
#ifndef CURL_DISABLE_MIME
- if(data->state.mimepost) {
- const char *cthdr = Curl_checkheaders(data, STRCONST("Content-Type"));
-
- /* Read and seek body only. */
- data->state.mimepost->flags |= MIME_BODY_ONLY;
-
- /* Prepare the mime structure headers & set content type. */
+ if(data->state.mimepost) {
+ const char *cthdr = Curl_checkheaders(data, STRCONST("Content-Type"));
- if(cthdr)
- for(cthdr += 13; *cthdr == ' '; cthdr++)
- ;
- else if(data->state.mimepost->kind == MIMEKIND_MULTIPART)
- cthdr = "multipart/form-data";
+ /* Read and seek body only. */
+ data->state.mimepost->flags |= MIME_BODY_ONLY;
- curl_mime_headers(data->state.mimepost, data->set.headers, 0);
- result = Curl_mime_prepare_headers(data, data->state.mimepost, cthdr,
- NULL, MIMESTRATEGY_FORM);
- if(result)
- return result;
- curl_mime_headers(data->state.mimepost, NULL, 0);
- result = Curl_creader_set_mime(data, data->state.mimepost);
- if(result)
- return result;
- }
- else
-#endif
- {
- result = Curl_creader_set_null(data);
- }
- data->state.infilesize = Curl_creader_total_length(data);
- return result;
-
- default:
- return Curl_creader_set_null(data);
- }
- /* never reached */
-}
-#endif
-
-static CURLcode set_reader(struct Curl_easy *data, Curl_HttpReq httpreq)
-{
- CURLcode result = CURLE_OK;
- curl_off_t postsize = data->state.infilesize;
+ /* Prepare the mime structure headers & set content type. */
- DEBUGASSERT(data->conn);
+ if(cthdr)
+ for(cthdr += 13; *cthdr == ' '; cthdr++)
+ ;
+ else if(data->state.mimepost->kind == MIMEKIND_MULTIPART)
+ cthdr = "multipart/form-data";
- if(data->req.authneg) {
- return Curl_creader_set_null(data);
+ curl_mime_headers(data->state.mimepost, data->set.headers, 0);
+ result = Curl_mime_prepare_headers(data, data->state.mimepost, cthdr,
+ NULL, MIMESTRATEGY_FORM);
+ curl_mime_headers(data->state.mimepost, NULL, 0);
+ if(!result)
+ result = Curl_mime_rewind(data->state.mimepost);
+ if(result)
+ return result;
+ http->postsize = Curl_mime_size(data->state.mimepost);
}
-
- switch(httpreq) {
- case HTTPREQ_PUT: /* Let's PUT the data to the server! */
- if(!postsize)
- result = Curl_creader_set_null(data);
- else
- result = Curl_creader_set_fread(data, postsize);
- return result;
-
-#if !defined(CURL_DISABLE_MIME) || !defined(CURL_DISABLE_FORM_API)
- case HTTPREQ_POST_FORM:
- case HTTPREQ_POST_MIME:
- return set_post_reader(data, httpreq);
#endif
- case HTTPREQ_POST:
- /* this is the simple POST, using x-www-form-urlencoded style */
- /* the size of the post body */
- if(!postsize) {
- result = Curl_creader_set_null(data);
- }
- else if(data->set.postfields) {
- if(postsize > 0)
- result = Curl_creader_set_buf(data, data->set.postfields,
- (size_t)postsize);
- else
- result = Curl_creader_set_null(data);
- }
- else {
- /* we read the bytes from the callback. In case "chunked" encoding
- * is forced by the application, we disregard `postsize`. This is
- * a backward compatibility decision to earlier versions where
- * chunking disregarded this. See issue #13229. */
- bool chunked = FALSE;
- char *ptr = Curl_checkheaders(data, STRCONST("Transfer-Encoding"));
- if(ptr) {
- /* Some kind of TE is requested, check if 'chunked' is chosen */
- chunked = Curl_compareheader(ptr, STRCONST("Transfer-Encoding:"),
- STRCONST("chunked"));
- }
- result = Curl_creader_set_fread(data, chunked? -1 : postsize);
- }
- return result;
-
- default:
- /* HTTP GET/HEAD download, has no body, needs no Content-Length */
- data->state.infilesize = 0;
- return Curl_creader_set_null(data);
- }
- /* not reached */
-}
-
-static CURLcode http_resume(struct Curl_easy *data, Curl_HttpReq httpreq)
-{
- if((HTTPREQ_POST == httpreq || HTTPREQ_PUT == httpreq) &&
- data->state.resume_from) {
- /**********************************************************************
- * Resuming upload in HTTP means that we PUT or POST and that we have
- * got a resume_from value set. The resume value has already created
- * a Range: header that will be passed along. We need to "fast forward"
- * the file the given number of bytes and decrease the assume upload
- * file size before we continue this venture in the dark lands of HTTP.
- * Resuming mime/form posting at an offset > 0 has no sense and is ignored.
- *********************************************************************/
-
- if(data->state.resume_from < 0) {
- /*
- * This is meant to get the size of the present remote-file by itself.
- * We do not support this now. Bail out!
- */
- data->state.resume_from = 0;
- }
-
- if(data->state.resume_from && !data->req.authneg) {
- /* only act on the first request */
- CURLcode result;
- result = Curl_creader_resume_from(data, data->state.resume_from);
- if(result) {
- failf(data, "Unable to resume from offset %" FMT_OFF_T,
- data->state.resume_from);
- return result;
- }
- }
- }
- return CURLE_OK;
-}
-
-CURLcode Curl_http_req_set_reader(struct Curl_easy *data,
- Curl_HttpReq httpreq,
- const char **tep)
-{
- CURLcode result = CURLE_OK;
- const char *ptr;
-
- result = set_reader(data, httpreq);
- if(result)
- return result;
-
- result = http_resume(data, httpreq);
- if(result)
- return result;
-
ptr = Curl_checkheaders(data, STRCONST("Transfer-Encoding"));
if(ptr) {
/* Some kind of TE is requested, check if 'chunked' is chosen */
data->req.upload_chunky =
Curl_compareheader(ptr,
STRCONST("Transfer-Encoding:"), STRCONST("chunked"));
- if(data->req.upload_chunky &&
- Curl_use_http_1_1plus(data, data->conn) &&
- (data->conn->httpversion >= 20)) {
- infof(data, "suppressing chunked transfer encoding on connection "
- "using HTTP version 2 or higher");
- data->req.upload_chunky = FALSE;
- }
}
else {
- curl_off_t req_clen = Curl_creader_total_length(data);
-
- if(req_clen < 0) {
- /* indeterminate request content length */
- if(Curl_use_http_1_1plus(data, data->conn)) {
- /* On HTTP/1.1, enable chunked, on HTTP/2 and later we do not
- * need it */
- data->req.upload_chunky = (data->conn->httpversion < 20);
+ if((conn->handler->protocol & PROTO_FAMILY_HTTP) &&
+ (((httpreq == HTTPREQ_POST_MIME || httpreq == HTTPREQ_POST_FORM) &&
+ http->postsize < 0) ||
+ ((data->state.upload || httpreq == HTTPREQ_POST) &&
+ data->state.infilesize == -1))) {
+ if(conn->bits.authneg)
+ /* don't enable chunked during auth neg */
+ ;
+ else if(Curl_use_http_1_1plus(data, conn)) {
+ if(conn->httpversion < 20)
+ /* HTTP, upload, unknown file size and not HTTP 1.0 */
+ data->req.upload_chunky = TRUE;
}
else {
failf(data, "Chunky upload is not supported by HTTP 1.0");
@@ -2112,127 +2515,330 @@ CURLcode Curl_http_req_set_reader(struct Curl_easy *data,
return result;
}
-static CURLcode addexpect(struct Curl_easy *data, struct dynbuf *r,
- bool *announced_exp100)
+static CURLcode addexpect(struct Curl_easy *data, struct connectdata *conn,
+ struct dynbuf *r)
{
- CURLcode result;
- char *ptr;
-
- *announced_exp100 = FALSE;
+ data->state.expect100header = FALSE;
/* Avoid Expect: 100-continue if Upgrade: is used */
- if(data->req.upgr101 != UPGR101_INIT)
- return CURLE_OK;
-
- /* For really small puts we do not use Expect: headers at all, and for
- the somewhat bigger ones we allow the app to disable it. Just make
- sure that the expect100header is always set to the preferred value
- here. */
- ptr = Curl_checkheaders(data, STRCONST("Expect"));
- if(ptr) {
- *announced_exp100 =
- Curl_compareheader(ptr, STRCONST("Expect:"), STRCONST("100-continue"));
- }
- else if(!data->state.disableexpect &&
- Curl_use_http_1_1plus(data, data->conn) &&
- (data->conn->httpversion < 20)) {
- /* if not doing HTTP 1.0 or version 2, or disabled explicitly, we add an
- Expect: 100-continue to the headers which actually speeds up post
- operations (as there is one packet coming back from the web server) */
- curl_off_t client_len = Curl_creader_client_length(data);
- if(client_len > EXPECT_100_THRESHOLD || client_len < 0) {
- result = Curl_dyn_addn(r, STRCONST("Expect: 100-continue\r\n"));
- if(result)
- return result;
- *announced_exp100 = TRUE;
+ if(data->req.upgr101 == UPGR101_INIT) {
+ struct HTTP *http = data->req.p.http;
+ /* For really small puts we don't use Expect: headers at all, and for
+ the somewhat bigger ones we allow the app to disable it. Just make
+ sure that the expect100header is always set to the preferred value
+ here. */
+ char *ptr = Curl_checkheaders(data, STRCONST("Expect"));
+ if(ptr) {
+ data->state.expect100header =
+ Curl_compareheader(ptr, STRCONST("Expect:"),
+ STRCONST("100-continue"));
}
+ else if(http->postsize > EXPECT_100_THRESHOLD || http->postsize < 0)
+ return expect100(data, conn, r);
}
return CURLE_OK;
}
-CURLcode Curl_http_req_complete(struct Curl_easy *data,
- struct dynbuf *r, Curl_HttpReq httpreq)
+CURLcode Curl_http_bodysend(struct Curl_easy *data, struct connectdata *conn,
+ struct dynbuf *r, Curl_HttpReq httpreq)
{
+#ifndef USE_HYPER
+ /* Hyper always handles the body separately */
+ curl_off_t included_body = 0;
+#else
+ /* from this point down, this function should not be used */
+#define Curl_buffer_send(a,b,c,d,e,f) CURLE_OK
+#endif
CURLcode result = CURLE_OK;
- curl_off_t req_clen;
- bool announced_exp100 = FALSE;
+ struct HTTP *http = data->req.p.http;
- DEBUGASSERT(data->conn);
-#ifndef USE_HYPER
- if(data->req.upload_chunky) {
- result = Curl_httpchunk_add_reader(data);
+ switch(httpreq) {
+ case HTTPREQ_PUT: /* Let's PUT the data to the server! */
+
+ if(conn->bits.authneg)
+ http->postsize = 0;
+ else
+ http->postsize = data->state.infilesize;
+
+ if((http->postsize != -1) && !data->req.upload_chunky &&
+ (conn->bits.authneg ||
+ !Curl_checkheaders(data, STRCONST("Content-Length")))) {
+ /* only add Content-Length if not uploading chunked */
+ result = Curl_dyn_addf(r, "Content-Length: %" CURL_FORMAT_CURL_OFF_T
+ "\r\n", http->postsize);
+ if(result)
+ return result;
+ }
+
+ result = addexpect(data, conn, r);
if(result)
return result;
- }
-#endif
- /* Get the request body length that has been set up */
- req_clen = Curl_creader_total_length(data);
- switch(httpreq) {
- case HTTPREQ_PUT:
- case HTTPREQ_POST:
-#if !defined(CURL_DISABLE_MIME) || !defined(CURL_DISABLE_FORM_API)
+ /* end of headers */
+ result = Curl_dyn_addn(r, STRCONST("\r\n"));
+ if(result)
+ return result;
+
+ /* set the upload size to the progress meter */
+ Curl_pgrsSetUploadSize(data, http->postsize);
+
+ /* this sends the buffer and frees all the buffer resources */
+ result = Curl_buffer_send(r, data, data->req.p.http,
+ &data->info.request_size, 0,
+ FIRSTSOCKET);
+ if(result)
+ failf(data, "Failed sending PUT request");
+ else
+ /* prepare for transfer */
+ Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE,
+ http->postsize?FIRSTSOCKET:-1);
+ if(result)
+ return result;
+ break;
+
case HTTPREQ_POST_FORM:
case HTTPREQ_POST_MIME:
-#endif
+ /* This is form posting using mime data. */
+ if(conn->bits.authneg) {
+ /* nothing to post! */
+ result = Curl_dyn_addn(r, STRCONST("Content-Length: 0\r\n\r\n"));
+ if(result)
+ return result;
+
+ result = Curl_buffer_send(r, data, data->req.p.http,
+ &data->info.request_size, 0,
+ FIRSTSOCKET);
+ if(result)
+ failf(data, "Failed sending POST request");
+ else
+ /* setup variables for the upcoming transfer */
+ Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE, -1);
+ break;
+ }
+
+ data->state.infilesize = http->postsize;
+
/* We only set Content-Length and allow a custom Content-Length if
- we do not upload data chunked, as RFC2616 forbids us to set both
- kinds of headers (Transfer-Encoding: chunked and Content-Length).
- We do not override a custom "Content-Length" header, but during
- authentication negotiation that header is suppressed.
- */
- if(req_clen >= 0 && !data->req.upload_chunky &&
- (data->req.authneg ||
- !Curl_checkheaders(data, STRCONST("Content-Length")))) {
+ we don't upload data chunked, as RFC2616 forbids us to set both
+ kinds of headers (Transfer-Encoding: chunked and Content-Length) */
+ if(http->postsize != -1 && !data->req.upload_chunky &&
+ (!Curl_checkheaders(data, STRCONST("Content-Length")))) {
/* we allow replacing this header if not during auth negotiation,
- although it is not very wise to actually set your own */
- result = Curl_dyn_addf(r, "Content-Length: %" FMT_OFF_T "\r\n",
- req_clen);
+ although it isn't very wise to actually set your own */
+ result = Curl_dyn_addf(r,
+ "Content-Length: %" CURL_FORMAT_CURL_OFF_T
+ "\r\n", http->postsize);
+ if(result)
+ return result;
}
- if(result)
- goto out;
#ifndef CURL_DISABLE_MIME
/* Output mime-generated headers. */
- if(data->state.mimepost &&
- ((httpreq == HTTPREQ_POST_FORM) || (httpreq == HTTPREQ_POST_MIME))) {
+ {
struct curl_slist *hdr;
for(hdr = data->state.mimepost->curlheaders; hdr; hdr = hdr->next) {
result = Curl_dyn_addf(r, "%s\r\n", hdr->data);
if(result)
- goto out;
+ return result;
}
}
#endif
- if(httpreq == HTTPREQ_POST) {
- if(!Curl_checkheaders(data, STRCONST("Content-Type"))) {
- result = Curl_dyn_addn(r, STRCONST("Content-Type: application/"
- "x-www-form-urlencoded\r\n"));
+
+ result = addexpect(data, conn, r);
+ if(result)
+ return result;
+
+ /* make the request end in a true CRLF */
+ result = Curl_dyn_addn(r, STRCONST("\r\n"));
+ if(result)
+ return result;
+
+ /* set the upload size to the progress meter */
+ Curl_pgrsSetUploadSize(data, http->postsize);
+
+ /* Read from mime structure. */
+ data->state.fread_func = (curl_read_callback) Curl_mime_read;
+ data->state.in = (void *) data->state.mimepost;
+ http->sending = HTTPSEND_BODY;
+
+ /* this sends the buffer and frees all the buffer resources */
+ result = Curl_buffer_send(r, data, data->req.p.http,
+ &data->info.request_size, 0,
+ FIRSTSOCKET);
+ if(result)
+ failf(data, "Failed sending POST request");
+ else
+ /* prepare for transfer */
+ Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE,
+ http->postsize?FIRSTSOCKET:-1);
+ if(result)
+ return result;
+
+ break;
+
+ case HTTPREQ_POST:
+ /* this is the simple POST, using x-www-form-urlencoded style */
+
+ if(conn->bits.authneg)
+ http->postsize = 0;
+ else
+ /* the size of the post body */
+ http->postsize = data->state.infilesize;
+
+ /* We only set Content-Length and allow a custom Content-Length if
+ we don't upload data chunked, as RFC2616 forbids us to set both
+ kinds of headers (Transfer-Encoding: chunked and Content-Length) */
+ if((http->postsize != -1) && !data->req.upload_chunky &&
+ (conn->bits.authneg ||
+ !Curl_checkheaders(data, STRCONST("Content-Length")))) {
+ /* we allow replacing this header if not during auth negotiation,
+ although it isn't very wise to actually set your own */
+ result = Curl_dyn_addf(r, "Content-Length: %" CURL_FORMAT_CURL_OFF_T
+ "\r\n", http->postsize);
+ if(result)
+ return result;
+ }
+
+ if(!Curl_checkheaders(data, STRCONST("Content-Type"))) {
+ result = Curl_dyn_addn(r, STRCONST("Content-Type: application/"
+ "x-www-form-urlencoded\r\n"));
+ if(result)
+ return result;
+ }
+
+ result = addexpect(data, conn, r);
+ if(result)
+ return result;
+
+#ifndef USE_HYPER
+ /* With Hyper the body is always passed on separately */
+ if(data->set.postfields) {
+ if(!data->state.expect100header &&
+ (http->postsize < MAX_INITIAL_POST_SIZE)) {
+ /* if we don't use expect: 100 AND
+ postsize is less than MAX_INITIAL_POST_SIZE
+
+ then append the post data to the HTTP request header. This limit
+ is no magic limit but only set to prevent really huge POSTs to
+ get the data duplicated with malloc() and family. */
+
+ /* end of headers! */
+ result = Curl_dyn_addn(r, STRCONST("\r\n"));
if(result)
- goto out;
+ return result;
+
+ if(!data->req.upload_chunky) {
+ /* We're not sending it 'chunked', append it to the request
+ already now to reduce the number of send() calls */
+ result = Curl_dyn_addn(r, data->set.postfields,
+ (size_t)http->postsize);
+ included_body = http->postsize;
+ }
+ else {
+ if(http->postsize) {
+ char chunk[16];
+ /* Append the POST data chunky-style */
+ msnprintf(chunk, sizeof(chunk), "%x\r\n", (int)http->postsize);
+ result = Curl_dyn_add(r, chunk);
+ if(!result) {
+ included_body = http->postsize + strlen(chunk);
+ result = Curl_dyn_addn(r, data->set.postfields,
+ (size_t)http->postsize);
+ if(!result)
+ result = Curl_dyn_addn(r, STRCONST("\r\n"));
+ included_body += 2;
+ }
+ }
+ if(!result) {
+ result = Curl_dyn_addn(r, STRCONST("\x30\x0d\x0a\x0d\x0a"));
+ /* 0 CR LF CR LF */
+ included_body += 5;
+ }
+ }
+ if(result)
+ return result;
+ /* Make sure the progress information is accurate */
+ Curl_pgrsSetUploadSize(data, http->postsize);
+ }
+ else {
+ /* A huge POST coming up, do data separate from the request */
+ http->postdata = data->set.postfields;
+ http->sending = HTTPSEND_BODY;
+ http->backup.data = data;
+ data->state.fread_func = (curl_read_callback)readmoredata;
+ data->state.in = (void *)http;
+
+ /* set the upload size to the progress meter */
+ Curl_pgrsSetUploadSize(data, http->postsize);
+
+ /* end of headers! */
+ result = Curl_dyn_addn(r, STRCONST("\r\n"));
+ if(result)
+ return result;
}
}
- result = addexpect(data, r, &announced_exp100);
+ else
+#endif
+ {
+ /* end of headers! */
+ result = Curl_dyn_addn(r, STRCONST("\r\n"));
+ if(result)
+ return result;
+
+ if(data->req.upload_chunky && conn->bits.authneg) {
+ /* Chunky upload is selected and we're negotiating auth still, send
+ end-of-data only */
+ result = Curl_dyn_addn(r, (char *)STRCONST("\x30\x0d\x0a\x0d\x0a"));
+ /* 0 CR LF CR LF */
+ if(result)
+ return result;
+ }
+
+ else if(data->state.infilesize) {
+ /* set the upload size to the progress meter */
+ Curl_pgrsSetUploadSize(data, http->postsize?http->postsize:-1);
+
+ /* set the pointer to mark that we will send the post body using the
+ read callback, but only if we're not in authenticate negotiation */
+ if(!conn->bits.authneg)
+ http->postdata = (char *)&http->postdata;
+ }
+ }
+ /* issue the request */
+ result = Curl_buffer_send(r, data, data->req.p.http,
+ &data->info.request_size, included_body,
+ FIRSTSOCKET);
+
if(result)
- goto out;
+ failf(data, "Failed sending HTTP POST request");
+ else
+ Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE,
+ http->postdata?FIRSTSOCKET:-1);
break;
+
default:
- break;
- }
+ result = Curl_dyn_addn(r, STRCONST("\r\n"));
+ if(result)
+ return result;
- /* end of headers */
- result = Curl_dyn_addn(r, STRCONST("\r\n"));
- if(!result) {
- Curl_pgrsSetUploadSize(data, req_clen);
- if(announced_exp100)
- result = http_exp100_add_reader(data);
+ /* issue the request */
+ result = Curl_buffer_send(r, data, data->req.p.http,
+ &data->info.request_size, 0,
+ FIRSTSOCKET);
+ if(result)
+ failf(data, "Failed sending HTTP request");
+#ifdef USE_WEBSOCKETS
+ else if((conn->handler->protocol & (CURLPROTO_WS|CURLPROTO_WSS)) &&
+ !(data->set.connect_only))
+ /* Set up the transfer for two-way since without CONNECT_ONLY set, this
+ request probably wants to send data too post upgrade */
+ Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE, FIRSTSOCKET);
+#endif
+ else
+ /* HTTP GET/HEAD download: */
+ Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE, -1);
}
-out:
- if(!result) {
- /* setup variables for the upcoming transfer */
- Curl_xfer_setup1(data, CURL_XFER_SENDRECV, -1, TRUE);
- }
return result;
}
@@ -2319,7 +2925,7 @@ CURLcode Curl_http_range(struct Curl_easy *data,
{
if(data->state.use_range) {
/*
- * A range is selected. We use different headers whether we are downloading
+ * A range is selected. We use different headers whether we're downloading
* or uploading and we always let customized headers override our internal
* ones if any such are specified.
*/
@@ -2332,37 +2938,36 @@ CURLcode Curl_http_range(struct Curl_easy *data,
}
else if((httpreq == HTTPREQ_POST || httpreq == HTTPREQ_PUT) &&
!Curl_checkheaders(data, STRCONST("Content-Range"))) {
- curl_off_t req_clen = Curl_creader_total_length(data);
+
/* if a line like this was already allocated, free the previous one */
free(data->state.aptr.rangeline);
if(data->set.set_resume_from < 0) {
- /* Upload resume was asked for, but we do not know the size of the
+ /* Upload resume was asked for, but we don't know the size of the
remote part so we tell the server (and act accordingly) that we
upload the whole file (again) */
data->state.aptr.rangeline =
- aprintf("Content-Range: bytes 0-%" FMT_OFF_T "/%" FMT_OFF_T "\r\n",
- req_clen - 1, req_clen);
+ aprintf("Content-Range: bytes 0-%" CURL_FORMAT_CURL_OFF_T
+ "/%" CURL_FORMAT_CURL_OFF_T "\r\n",
+ data->state.infilesize - 1, data->state.infilesize);
}
else if(data->state.resume_from) {
/* This is because "resume" was selected */
- /* TODO: not sure if we want to send this header during authentication
- * negotiation, but test1084 checks for it. In which case we have a
- * "null" client reader installed that gives an unexpected length. */
- curl_off_t total_len = data->req.authneg?
- data->state.infilesize :
- (data->state.resume_from + req_clen);
+ curl_off_t total_expected_size =
+ data->state.resume_from + data->state.infilesize;
data->state.aptr.rangeline =
- aprintf("Content-Range: bytes %s%" FMT_OFF_T "/%" FMT_OFF_T "\r\n",
- data->state.range, total_len-1, total_len);
+ aprintf("Content-Range: bytes %s%" CURL_FORMAT_CURL_OFF_T
+ "/%" CURL_FORMAT_CURL_OFF_T "\r\n",
+ data->state.range, total_expected_size-1,
+ total_expected_size);
}
else {
/* Range was selected and then we just pass the incoming range and
append total size */
data->state.aptr.rangeline =
- aprintf("Content-Range: bytes %s/%" FMT_OFF_T "\r\n",
- data->state.range, req_clen);
+ aprintf("Content-Range: bytes %s/%" CURL_FORMAT_CURL_OFF_T "\r\n",
+ data->state.range, data->state.infilesize);
}
if(!data->state.aptr.rangeline)
return CURLE_OUT_OF_MEMORY;
@@ -2371,20 +2976,101 @@ CURLcode Curl_http_range(struct Curl_easy *data,
return CURLE_OK;
}
-CURLcode Curl_http_firstwrite(struct Curl_easy *data)
+CURLcode Curl_http_resume(struct Curl_easy *data,
+ struct connectdata *conn,
+ Curl_HttpReq httpreq)
+{
+ if((HTTPREQ_POST == httpreq || HTTPREQ_PUT == httpreq) &&
+ data->state.resume_from) {
+ /**********************************************************************
+ * Resuming upload in HTTP means that we PUT or POST and that we have
+ * got a resume_from value set. The resume value has already created
+ * a Range: header that will be passed along. We need to "fast forward"
+ * the file the given number of bytes and decrease the assume upload
+ * file size before we continue this venture in the dark lands of HTTP.
+ * Resuming mime/form posting at an offset > 0 has no sense and is ignored.
+ *********************************************************************/
+
+ if(data->state.resume_from < 0) {
+ /*
+ * This is meant to get the size of the present remote-file by itself.
+ * We don't support this now. Bail out!
+ */
+ data->state.resume_from = 0;
+ }
+
+ if(data->state.resume_from && !data->state.followlocation) {
+ /* only act on the first request */
+
+ /* Now, let's read off the proper amount of bytes from the
+ input. */
+ int seekerr = CURL_SEEKFUNC_CANTSEEK;
+ if(conn->seek_func) {
+ Curl_set_in_callback(data, true);
+ seekerr = conn->seek_func(conn->seek_client, data->state.resume_from,
+ SEEK_SET);
+ Curl_set_in_callback(data, false);
+ }
+
+ if(seekerr != CURL_SEEKFUNC_OK) {
+ curl_off_t passed = 0;
+
+ if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
+ failf(data, "Could not seek stream");
+ return CURLE_READ_ERROR;
+ }
+ /* when seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */
+ do {
+ size_t readthisamountnow =
+ (data->state.resume_from - passed > data->set.buffer_size) ?
+ (size_t)data->set.buffer_size :
+ curlx_sotouz(data->state.resume_from - passed);
+
+ size_t actuallyread =
+ data->state.fread_func(data->state.buffer, 1, readthisamountnow,
+ data->state.in);
+
+ passed += actuallyread;
+ if((actuallyread == 0) || (actuallyread > readthisamountnow)) {
+ /* this checks for greater-than only to make sure that the
+ CURL_READFUNC_ABORT return code still aborts */
+ failf(data, "Could only read %" CURL_FORMAT_CURL_OFF_T
+ " bytes from the input", passed);
+ return CURLE_READ_ERROR;
+ }
+ } while(passed < data->state.resume_from);
+ }
+
+ /* now, decrease the size of the read */
+ if(data->state.infilesize>0) {
+ data->state.infilesize -= data->state.resume_from;
+
+ if(data->state.infilesize <= 0) {
+ failf(data, "File already completely uploaded");
+ return CURLE_PARTIAL_FILE;
+ }
+ }
+ /* we've passed, proceed as normal */
+ }
+ }
+ return CURLE_OK;
+}
+
+CURLcode Curl_http_firstwrite(struct Curl_easy *data,
+ struct connectdata *conn,
+ bool *done)
{
- struct connectdata *conn = data->conn;
struct SingleRequest *k = &data->req;
if(data->req.newurl) {
if(conn->bits.close) {
/* Abort after the headers if "follow Location" is set
- and we are set to close anyway. */
+ and we're set to close anyway. */
k->keepon &= ~KEEP_RECV;
- k->done = TRUE;
+ *done = TRUE;
return CURLE_OK;
}
- /* We have a new URL to load, but since we want to be able to reuse this
+ /* We have a new url to load, but since we want to be able to reuse this
connection properly, we read the full response in "ignore more" */
k->ignorebody = TRUE;
infof(data, "Ignoring the response-body");
@@ -2395,19 +3081,19 @@ CURLcode Curl_http_firstwrite(struct Curl_easy *data)
if(k->size == data->state.resume_from) {
/* The resume point is at the end of file, consider this fine even if it
- does not allow resume from here. */
+ doesn't allow resume from here. */
infof(data, "The entire document is already downloaded");
streamclose(conn, "already downloaded");
/* Abort download */
k->keepon &= ~KEEP_RECV;
- k->done = TRUE;
+ *done = TRUE;
return CURLE_OK;
}
- /* we wanted to resume a download, although the server does not seem to
- * support this and we did this with a GET (if it was not a GET we did a
+ /* we wanted to resume a download, although the server doesn't seem to
+ * support this and we did this with a GET (if it wasn't a GET we did a
* POST or PUT resume) */
- failf(data, "HTTP server does not seem to support "
+ failf(data, "HTTP server doesn't seem to support "
"byte ranges. Cannot resume.");
return CURLE_RANGE_ERROR;
}
@@ -2418,8 +3104,8 @@ CURLcode Curl_http_firstwrite(struct Curl_easy *data)
action for an HTTP/1.1 client */
if(!Curl_meets_timecondition(data, k->timeofdoc)) {
- k->done = TRUE;
- /* We are simulating an HTTP 304 from server so we return
+ *done = TRUE;
+ /* We're simulating an HTTP 304 from server so we return
what should have been returned from the server */
data->info.httpcode = 304;
infof(data, "Simulate an HTTP 304 response");
@@ -2441,7 +3127,7 @@ CURLcode Curl_transferencode(struct Curl_easy *data)
/* When we are to insert a TE: header in the request, we must also insert
TE in a Connection: header, so we need to merge the custom provided
Connection: header and prevent the original to get sent. Note that if
- the user has inserted his/her own TE: header we do not do this magic
+ the user has inserted his/her own TE: header we don't do this magic
but then assume that the user will handle it all! */
char *cptr = Curl_checkheaders(data, STRCONST("Connection"));
#define TE_HEADER "TE: gzip\r\n"
@@ -2476,6 +3162,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
{
struct connectdata *conn = data->conn;
CURLcode result = CURLE_OK;
+ struct HTTP *http;
Curl_HttpReq httpreq;
const char *te = ""; /* transfer-encoding */
const char *request;
@@ -2500,7 +3187,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
) {
result = Curl_http2_switch(data, conn, FIRSTSOCKET);
if(result)
- goto fail;
+ return result;
}
else
#endif
@@ -2515,25 +3202,21 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
DEBUGF(infof(data, "HTTP/2 over clean TCP"));
result = Curl_http2_switch(data, conn, FIRSTSOCKET);
if(result)
- goto fail;
+ return result;
}
break;
}
- /* Add collecting of headers written to client. For a new connection,
- * we might have done that already, but reuse
- * or multiplex needs it here as well. */
- result = Curl_headers_init(data);
- if(result)
- goto fail;
+ http = data->req.p.http;
+ DEBUGASSERT(http);
result = Curl_http_host(data, conn);
if(result)
- goto fail;
+ return result;
result = Curl_http_useragent(data);
if(result)
- goto fail;
+ return result;
Curl_http_method(data, conn, &request, &httpreq);
@@ -2549,7 +3232,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
(pq ? pq : data->state.up.path), FALSE);
free(pq);
if(result)
- goto fail;
+ return result;
}
Curl_safefree(data->state.aptr.ref);
@@ -2574,19 +3257,23 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
/* we only consider transfer-encoding magic if libz support is built-in */
result = Curl_transferencode(data);
if(result)
- goto fail;
+ return result;
#endif
- result = Curl_http_req_set_reader(data, httpreq, &te);
+ result = Curl_http_body(data, conn, httpreq, &te);
if(result)
- goto fail;
+ return result;
p_accept = Curl_checkheaders(data,
STRCONST("Accept"))?NULL:"Accept: */*\r\n";
+ result = Curl_http_resume(data, conn, httpreq);
+ if(result)
+ return result;
+
result = Curl_http_range(data, httpreq);
if(result)
- goto fail;
+ return result;
httpstring = get_http_string(data, conn);
@@ -2604,7 +3291,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
result = Curl_http_target(data, conn, &req);
if(result) {
Curl_dyn_free(&req);
- goto fail;
+ return result;
}
#ifndef CURL_DISABLE_ALTSVC
@@ -2635,12 +3322,8 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
httpstring,
(data->state.aptr.host?data->state.aptr.host:""),
-#ifndef CURL_DISABLE_PROXY
data->state.aptr.proxyuserpwd?
data->state.aptr.proxyuserpwd:"",
-#else
- "",
-#endif
data->state.aptr.userpwd?data->state.aptr.userpwd:"",
(data->state.use_range && data->state.aptr.rangeline)?
data->state.aptr.rangeline:"",
@@ -2674,20 +3357,18 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
/* clear userpwd and proxyuserpwd to avoid reusing old credentials
* from reused connections */
Curl_safefree(data->state.aptr.userpwd);
-#ifndef CURL_DISABLE_PROXY
Curl_safefree(data->state.aptr.proxyuserpwd);
-#endif
free(altused);
if(result) {
Curl_dyn_free(&req);
- goto fail;
+ return result;
}
if(!(conn->handler->flags&PROTOPT_SSL) &&
conn->httpversion < 20 &&
(data->state.httpwant == CURL_HTTP_VERSION_2)) {
- /* append HTTP2 upgrade magic stuff to the HTTP request if it is not done
+ /* append HTTP2 upgrade magic stuff to the HTTP request if it isn't done
over SSL */
result = Curl_http2_request_upgrade(&req, data);
if(result) {
@@ -2707,23 +3388,52 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
result = Curl_add_custom_headers(data, FALSE, &req);
if(!result) {
- /* req_send takes ownership of the 'req' memory on success */
- result = Curl_http_req_complete(data, &req, httpreq);
- if(!result)
- result = Curl_req_send(data, &req);
+ http->postdata = NULL; /* nothing to post at this point */
+ if((httpreq == HTTPREQ_GET) ||
+ (httpreq == HTTPREQ_HEAD))
+ Curl_pgrsSetUploadSize(data, 0); /* nothing */
+
+ /* bodysend takes ownership of the 'req' memory on success */
+ result = Curl_http_bodysend(data, conn, &req, httpreq);
+ }
+ if(result) {
+ Curl_dyn_free(&req);
+ return result;
+ }
+
+ if((http->postsize > -1) &&
+ (http->postsize <= data->req.writebytecount) &&
+ (http->sending != HTTPSEND_REQUEST))
+ data->req.upload_done = TRUE;
+
+ if(data->req.writebytecount) {
+ /* if a request-body has been sent off, we make sure this progress is noted
+ properly */
+ Curl_pgrsSetUploadCounter(data, data->req.writebytecount);
+ if(Curl_pgrsUpdate(data))
+ result = CURLE_ABORTED_BY_CALLBACK;
+
+ if(!http->postsize) {
+ /* already sent the entire request body, mark the "upload" as
+ complete */
+ infof(data, "upload completely sent off: %" CURL_FORMAT_CURL_OFF_T
+ " out of %" CURL_FORMAT_CURL_OFF_T " bytes",
+ data->req.writebytecount, http->postsize);
+ data->req.upload_done = TRUE;
+ data->req.keepon &= ~KEEP_SEND; /* we're done writing */
+ data->req.exp100 = EXP100_SEND_DATA; /* already sent */
+ Curl_expire_done(data, EXPIRE_100_TIMEOUT);
+ }
}
- Curl_dyn_free(&req);
- if(result)
- goto fail;
+
+ if(data->req.upload_done)
+ Curl_conn_ev_data_done_send(data);
if((conn->httpversion >= 20) && data->req.upload_chunky)
/* upload_chunky was set above to set up the request in a chunky fashion,
but is disabled here again to avoid that the chunked encoded version is
actually used when sending the request body over h2 */
data->req.upload_chunky = FALSE;
-fail:
- if(CURLE_TOO_LARGE == result)
- failf(data, "HTTP request too large");
return result;
}
@@ -2799,378 +3509,325 @@ checkprotoprefix(struct Curl_easy *data, struct connectdata *conn,
return checkhttpprefix(data, s, len);
}
-/* HTTP header has field name `n` (a string constant) */
-#define HD_IS(hd, hdlen, n) \
- (((hdlen) >= (sizeof(n)-1)) && curl_strnequal((n), (hd), (sizeof(n)-1)))
-
-#define HD_VAL(hd, hdlen, n) \
- ((((hdlen) >= (sizeof(n)-1)) && \
- curl_strnequal((n), (hd), (sizeof(n)-1)))? (hd + (sizeof(n)-1)) : NULL)
-
-/* HTTP header has field name `n` (a string constant) and contains `v`
- * (a string constant) in its value(s) */
-#define HD_IS_AND_SAYS(hd, hdlen, n, v) \
- (HD_IS(hd, hdlen, n) && \
- ((hdlen) > ((sizeof(n)-1) + (sizeof(v)-1))) && \
- Curl_compareheader(hd, STRCONST(n), STRCONST(v)))
-
/*
* Curl_http_header() parses a single response header.
*/
-CURLcode Curl_http_header(struct Curl_easy *data,
- const char *hd, size_t hdlen)
+CURLcode Curl_http_header(struct Curl_easy *data, struct connectdata *conn,
+ char *headp)
{
- struct connectdata *conn = data->conn;
CURLcode result;
struct SingleRequest *k = &data->req;
- const char *v;
-
- switch(hd[0]) {
- case 'a':
- case 'A':
-#ifndef CURL_DISABLE_ALTSVC
- v = (data->asi &&
- ((data->conn->handler->flags & PROTOPT_SSL) ||
-#ifdef DEBUGBUILD
- /* allow debug builds to circumvent the HTTPS restriction */
- getenv("CURL_ALTSVC_HTTP")
-#else
- 0
-#endif
- ))? HD_VAL(hd, hdlen, "Alt-Svc:") : NULL;
- if(v) {
- /* the ALPN of the current request */
- enum alpnid id = (conn->httpversion == 30)? ALPN_h3 :
- (conn->httpversion == 20) ? ALPN_h2 : ALPN_h1;
- return Curl_altsvc_parse(data, data->asi, v, id, conn->host.name,
- curlx_uitous((unsigned int)conn->remote_port));
+ /* Check for Content-Length: header lines to get size */
+ if(!k->http_bodyless &&
+ !data->set.ignorecl && checkprefix("Content-Length:", headp)) {
+ curl_off_t contentlength;
+ CURLofft offt = curlx_strtoofft(headp + strlen("Content-Length:"),
+ NULL, 10, &contentlength);
+
+ if(offt == CURL_OFFT_OK) {
+ k->size = contentlength;
+ k->maxdownload = k->size;
}
-#endif
- break;
- case 'c':
- case 'C':
- /* Check for Content-Length: header lines to get size */
- v = (!k->http_bodyless && !data->set.ignorecl)?
- HD_VAL(hd, hdlen, "Content-Length:") : NULL;
- if(v) {
- curl_off_t contentlength;
- CURLofft offt = curlx_strtoofft(v, NULL, 10, &contentlength);
-
- if(offt == CURL_OFFT_OK) {
- k->size = contentlength;
- k->maxdownload = k->size;
- }
- else if(offt == CURL_OFFT_FLOW) {
- /* out of range */
- if(data->set.max_filesize) {
- failf(data, "Maximum file size exceeded");
- return CURLE_FILESIZE_EXCEEDED;
- }
- streamclose(conn, "overflow content-length");
- infof(data, "Overflow Content-Length: value");
- }
- else {
- /* negative or just rubbish - bad HTTP */
- failf(data, "Invalid Content-Length: value");
- return CURLE_WEIRD_SERVER_REPLY;
+ else if(offt == CURL_OFFT_FLOW) {
+ /* out of range */
+ if(data->set.max_filesize) {
+ failf(data, "Maximum file size exceeded");
+ return CURLE_FILESIZE_EXCEEDED;
}
- return CURLE_OK;
+ streamclose(conn, "overflow content-length");
+ infof(data, "Overflow Content-Length: value");
}
- v = (!k->http_bodyless && data->set.str[STRING_ENCODING])?
- HD_VAL(hd, hdlen, "Content-Encoding:") : NULL;
- if(v) {
- /*
- * Process Content-Encoding. Look for the values: identity,
- * gzip, deflate, compress, x-gzip and x-compress. x-gzip and
- * x-compress are the same as gzip and compress. (Sec 3.5 RFC
- * 2616). zlib cannot handle compress. However, errors are
- * handled further down when the response body is processed
- */
- return Curl_build_unencoding_stack(data, v, FALSE);
+ else {
+ /* negative or just rubbish - bad HTTP */
+ failf(data, "Invalid Content-Length: value");
+ return CURLE_WEIRD_SERVER_REPLY;
}
- /* check for Content-Type: header lines to get the MIME-type */
- v = HD_VAL(hd, hdlen, "Content-Type:");
- if(v) {
- char *contenttype = Curl_copy_header_value(hd);
- if(!contenttype)
- return CURLE_OUT_OF_MEMORY;
- if(!*contenttype)
- /* ignore empty data */
- free(contenttype);
- else {
- Curl_safefree(data->info.contenttype);
- data->info.contenttype = contenttype;
- }
- return CURLE_OK;
+ }
+ /* check for Content-Type: header lines to get the MIME-type */
+ else if(checkprefix("Content-Type:", headp)) {
+ char *contenttype = Curl_copy_header_value(headp);
+ if(!contenttype)
+ return CURLE_OUT_OF_MEMORY;
+ if(!*contenttype)
+ /* ignore empty data */
+ free(contenttype);
+ else {
+ Curl_safefree(data->info.contenttype);
+ data->info.contenttype = contenttype;
}
- if(HD_IS_AND_SAYS(hd, hdlen, "Connection:", "close")) {
- /*
- * [RFC 2616, section 8.1.2.1]
- * "Connection: close" is HTTP/1.1 language and means that
- * the connection will close when this request has been
- * served.
- */
- streamclose(conn, "Connection: close used");
- return CURLE_OK;
+ }
+#ifndef CURL_DISABLE_PROXY
+ else if((conn->httpversion == 10) &&
+ conn->bits.httpproxy &&
+ Curl_compareheader(headp,
+ STRCONST("Proxy-Connection:"),
+ STRCONST("keep-alive"))) {
+ /*
+ * When an HTTP/1.0 reply comes when using a proxy, the
+ * 'Proxy-Connection: keep-alive' line tells us the
+ * connection will be kept alive for our pleasure.
+ * Default action for 1.0 is to close.
+ */
+ connkeep(conn, "Proxy-Connection keep-alive"); /* don't close */
+ infof(data, "HTTP/1.0 proxy connection set to keep alive");
+ }
+ else if((conn->httpversion == 11) &&
+ conn->bits.httpproxy &&
+ Curl_compareheader(headp,
+ STRCONST("Proxy-Connection:"),
+ STRCONST("close"))) {
+ /*
+ * We get an HTTP/1.1 response from a proxy and it says it'll
+ * close down after this transfer.
+ */
+ connclose(conn, "Proxy-Connection: asked to close after done");
+ infof(data, "HTTP/1.1 proxy connection set close");
+ }
+#endif
+ else if((conn->httpversion == 10) &&
+ Curl_compareheader(headp,
+ STRCONST("Connection:"),
+ STRCONST("keep-alive"))) {
+ /*
+ * An HTTP/1.0 reply with the 'Connection: keep-alive' line
+ * tells us the connection will be kept alive for our
+ * pleasure. Default action for 1.0 is to close.
+ *
+ * [RFC2068, section 19.7.1] */
+ connkeep(conn, "Connection keep-alive");
+ infof(data, "HTTP/1.0 connection set to keep alive");
+ }
+ else if(Curl_compareheader(headp,
+ STRCONST("Connection:"), STRCONST("close"))) {
+ /*
+ * [RFC 2616, section 8.1.2.1]
+ * "Connection: close" is HTTP/1.1 language and means that
+ * the connection will close when this request has been
+ * served.
+ */
+ streamclose(conn, "Connection: close used");
+ }
+ else if(!k->http_bodyless && checkprefix("Transfer-Encoding:", headp)) {
+ /* One or more encodings. We check for chunked and/or a compression
+ algorithm. */
+ /*
+ * [RFC 2616, section 3.6.1] A 'chunked' transfer encoding
+ * means that the server will send a series of "chunks". Each
+ * chunk starts with line with info (including size of the
+ * coming block) (terminated with CRLF), then a block of data
+ * with the previously mentioned size. There can be any amount
+ * of chunks, and a chunk-data set to zero signals the
+ * end-of-chunks. */
+
+ result = Curl_build_unencoding_stack(data,
+ headp + strlen("Transfer-Encoding:"),
+ TRUE);
+ if(result)
+ return result;
+ if(!k->chunk && data->set.http_transfer_encoding) {
+ /* if this isn't chunked, only close can signal the end of this transfer
+ as Content-Length is said not to be trusted for transfer-encoding! */
+ connclose(conn, "HTTP/1.1 transfer-encoding without chunks");
+ k->ignore_cl = TRUE;
}
- if((conn->httpversion == 10) &&
- HD_IS_AND_SAYS(hd, hdlen, "Connection:", "keep-alive")) {
- /*
- * An HTTP/1.0 reply with the 'Connection: keep-alive' line
- * tells us the connection will be kept alive for our
- * pleasure. Default action for 1.0 is to close.
- *
- * [RFC2068, section 19.7.1] */
- connkeep(conn, "Connection keep-alive");
- infof(data, "HTTP/1.0 connection set to keep alive");
- return CURLE_OK;
+ }
+ else if(!k->http_bodyless && checkprefix("Content-Encoding:", headp) &&
+ data->set.str[STRING_ENCODING]) {
+ /*
+ * Process Content-Encoding. Look for the values: identity,
+ * gzip, deflate, compress, x-gzip and x-compress. x-gzip and
+ * x-compress are the same as gzip and compress. (Sec 3.5 RFC
+ * 2616). zlib cannot handle compress. However, errors are
+ * handled further down when the response body is processed
+ */
+ result = Curl_build_unencoding_stack(data,
+ headp + strlen("Content-Encoding:"),
+ FALSE);
+ if(result)
+ return result;
+ }
+ else if(checkprefix("Retry-After:", headp)) {
+ /* Retry-After = HTTP-date / delay-seconds */
+ curl_off_t retry_after = 0; /* zero for unknown or "now" */
+ /* Try it as a decimal number, if it works it is not a date */
+ (void)curlx_strtoofft(headp + strlen("Retry-After:"),
+ NULL, 10, &retry_after);
+ if(!retry_after) {
+ time_t date = Curl_getdate_capped(headp + strlen("Retry-After:"));
+ if(-1 != date)
+ /* convert date to number of seconds into the future */
+ retry_after = date - time(NULL);
}
- v = !k->http_bodyless? HD_VAL(hd, hdlen, "Content-Range:") : NULL;
- if(v) {
- /* Content-Range: bytes [num]-
- Content-Range: bytes: [num]-
- Content-Range: [num]-
- Content-Range: [asterisk]/[total]
-
- The second format was added since Sun's webserver
- JavaWebServer/1.1.1 obviously sends the header this way!
- The third added since some servers use that!
- The fourth means the requested range was unsatisfied.
- */
-
- const char *ptr = v;
-
- /* Move forward until first digit or asterisk */
- while(*ptr && !ISDIGIT(*ptr) && *ptr != '*')
- ptr++;
-
- /* if it truly stopped on a digit */
- if(ISDIGIT(*ptr)) {
- if(!curlx_strtoofft(ptr, NULL, 10, &k->offset)) {
- if(data->state.resume_from == k->offset)
- /* we asked for a resume and we got it */
- k->content_range = TRUE;
- }
+ data->info.retry_after = retry_after; /* store it */
+ }
+ else if(!k->http_bodyless && checkprefix("Content-Range:", headp)) {
+ /* Content-Range: bytes [num]-
+ Content-Range: bytes: [num]-
+ Content-Range: [num]-
+ Content-Range: [asterisk]/[total]
+
+ The second format was added since Sun's webserver
+ JavaWebServer/1.1.1 obviously sends the header this way!
+ The third added since some servers use that!
+ The fourth means the requested range was unsatisfied.
+ */
+
+ char *ptr = headp + strlen("Content-Range:");
+
+ /* Move forward until first digit or asterisk */
+ while(*ptr && !ISDIGIT(*ptr) && *ptr != '*')
+ ptr++;
+
+ /* if it truly stopped on a digit */
+ if(ISDIGIT(*ptr)) {
+ if(!curlx_strtoofft(ptr, NULL, 10, &k->offset)) {
+ if(data->state.resume_from == k->offset)
+ /* we asked for a resume and we got it */
+ k->content_range = TRUE;
}
- else if(k->httpcode < 300)
- data->state.resume_from = 0; /* get everything */
- }
- break;
- case 'l':
- case 'L':
- v = (!k->http_bodyless &&
- (data->set.timecondition || data->set.get_filetime))?
- HD_VAL(hd, hdlen, "Last-Modified:") : NULL;
- if(v) {
- k->timeofdoc = Curl_getdate_capped(v);
- if(data->set.get_filetime)
- data->info.filetime = k->timeofdoc;
- return CURLE_OK;
}
- if((k->httpcode >= 300 && k->httpcode < 400) &&
- HD_IS(hd, hdlen, "Location:") &&
- !data->req.location) {
- /* this is the URL that the server advises us to use instead */
- char *location = Curl_copy_header_value(hd);
- if(!location)
- return CURLE_OUT_OF_MEMORY;
- if(!*location)
- /* ignore empty data */
- free(location);
- else {
- data->req.location = location;
+ else if(k->httpcode < 300)
+ data->state.resume_from = 0; /* get everything */
+ }
+#if !defined(CURL_DISABLE_COOKIES)
+ else if(data->cookies && data->state.cookie_engine &&
+ checkprefix("Set-Cookie:", headp)) {
+ /* If there is a custom-set Host: name, use it here, or else use real peer
+ host name. */
+ const char *host = data->state.aptr.cookiehost?
+ data->state.aptr.cookiehost:conn->host.name;
+ const bool secure_context =
+ conn->handler->protocol&(CURLPROTO_HTTPS|CURLPROTO_WSS) ||
+ strcasecompare("localhost", host) ||
+ !strcmp(host, "127.0.0.1") ||
+ !strcmp(host, "::1") ? TRUE : FALSE;
+
+ Curl_share_lock(data, CURL_LOCK_DATA_COOKIE,
+ CURL_LOCK_ACCESS_SINGLE);
+ Curl_cookie_add(data, data->cookies, TRUE, FALSE,
+ headp + strlen("Set-Cookie:"), host,
+ data->state.up.path, secure_context);
+ Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
+ }
+#endif
+ else if(!k->http_bodyless && checkprefix("Last-Modified:", headp) &&
+ (data->set.timecondition || data->set.get_filetime) ) {
+ k->timeofdoc = Curl_getdate_capped(headp + strlen("Last-Modified:"));
+ if(data->set.get_filetime)
+ data->info.filetime = k->timeofdoc;
+ }
+ else if((checkprefix("WWW-Authenticate:", headp) &&
+ (401 == k->httpcode)) ||
+ (checkprefix("Proxy-authenticate:", headp) &&
+ (407 == k->httpcode))) {
+
+ bool proxy = (k->httpcode == 407) ? TRUE : FALSE;
+ char *auth = Curl_copy_header_value(headp);
+ if(!auth)
+ return CURLE_OUT_OF_MEMORY;
- if(data->set.http_follow_location) {
- DEBUGASSERT(!data->req.newurl);
- data->req.newurl = strdup(data->req.location); /* clone */
- if(!data->req.newurl)
- return CURLE_OUT_OF_MEMORY;
+ result = Curl_http_input_auth(data, proxy, auth);
- /* some cases of POST and PUT etc needs to rewind the data
- stream at this point */
- result = http_perhapsrewind(data, conn);
- if(result)
- return result;
+ free(auth);
- /* mark the next request as a followed location: */
- data->state.this_is_a_follow = TRUE;
- }
- }
- }
- break;
- case 'p':
- case 'P':
-#ifndef CURL_DISABLE_PROXY
- v = HD_VAL(hd, hdlen, "Proxy-Connection:");
- if(v) {
- if((conn->httpversion == 10) && conn->bits.httpproxy &&
- HD_IS_AND_SAYS(hd, hdlen, "Proxy-Connection:", "keep-alive")) {
- /*
- * When an HTTP/1.0 reply comes when using a proxy, the
- * 'Proxy-Connection: keep-alive' line tells us the
- * connection will be kept alive for our pleasure.
- * Default action for 1.0 is to close.
- */
- connkeep(conn, "Proxy-Connection keep-alive"); /* do not close */
- infof(data, "HTTP/1.0 proxy connection set to keep alive");
- }
- else if((conn->httpversion == 11) && conn->bits.httpproxy &&
- HD_IS_AND_SAYS(hd, hdlen, "Proxy-Connection:", "close")) {
- /*
- * We get an HTTP/1.1 response from a proxy and it says it will
- * close down after this transfer.
- */
- connclose(conn, "Proxy-Connection: asked to close after done");
- infof(data, "HTTP/1.1 proxy connection set close");
- }
- return CURLE_OK;
- }
-#endif
- if((407 == k->httpcode) && HD_IS(hd, hdlen, "Proxy-authenticate:")) {
- char *auth = Curl_copy_header_value(hd);
- if(!auth)
- return CURLE_OUT_OF_MEMORY;
- result = Curl_http_input_auth(data, TRUE, auth);
- free(auth);
+ if(result)
return result;
- }
+ }
#ifdef USE_SPNEGO
- if(HD_IS(hd, hdlen, "Persistent-Auth:")) {
- struct negotiatedata *negdata = &conn->negotiate;
- struct auth *authp = &data->state.authhost;
- if(authp->picked == CURLAUTH_NEGOTIATE) {
- char *persistentauth = Curl_copy_header_value(hd);
- if(!persistentauth)
- return CURLE_OUT_OF_MEMORY;
- negdata->noauthpersist = checkprefix("false", persistentauth)?
- TRUE:FALSE;
- negdata->havenoauthpersist = TRUE;
- infof(data, "Negotiate: noauthpersist -> %d, header part: %s",
- negdata->noauthpersist, persistentauth);
- free(persistentauth);
- }
+ else if(checkprefix("Persistent-Auth:", headp)) {
+ struct negotiatedata *negdata = &conn->negotiate;
+ struct auth *authp = &data->state.authhost;
+ if(authp->picked == CURLAUTH_NEGOTIATE) {
+ char *persistentauth = Curl_copy_header_value(headp);
+ if(!persistentauth)
+ return CURLE_OUT_OF_MEMORY;
+ negdata->noauthpersist = checkprefix("false", persistentauth)?
+ TRUE:FALSE;
+ negdata->havenoauthpersist = TRUE;
+ infof(data, "Negotiate: noauthpersist -> %d, header part: %s",
+ negdata->noauthpersist, persistentauth);
+ free(persistentauth);
}
+ }
#endif
- break;
- case 'r':
- case 'R':
- v = HD_VAL(hd, hdlen, "Retry-After:");
- if(v) {
- /* Retry-After = HTTP-date / delay-seconds */
- curl_off_t retry_after = 0; /* zero for unknown or "now" */
- /* Try it as a decimal number, if it works it is not a date */
- (void)curlx_strtoofft(v, NULL, 10, &retry_after);
- if(!retry_after) {
- time_t date = Curl_getdate_capped(v);
- if(-1 != date)
- /* convert date to number of seconds into the future */
- retry_after = date - time(NULL);
+ else if((k->httpcode >= 300 && k->httpcode < 400) &&
+ checkprefix("Location:", headp) &&
+ !data->req.location) {
+ /* this is the URL that the server advises us to use instead */
+ char *location = Curl_copy_header_value(headp);
+ if(!location)
+ return CURLE_OUT_OF_MEMORY;
+ if(!*location)
+ /* ignore empty data */
+ free(location);
+ else {
+ data->req.location = location;
+
+ if(data->set.http_follow_location) {
+ DEBUGASSERT(!data->req.newurl);
+ data->req.newurl = strdup(data->req.location); /* clone */
+ if(!data->req.newurl)
+ return CURLE_OUT_OF_MEMORY;
+
+ /* some cases of POST and PUT etc needs to rewind the data
+ stream at this point */
+ result = http_perhapsrewind(data, conn);
+ if(result)
+ return result;
+
+ /* mark the next request as a followed location: */
+ data->state.this_is_a_follow = TRUE;
}
- data->info.retry_after = retry_after; /* store it */
- return CURLE_OK;
}
- break;
- case 's':
- case 'S':
-#if !defined(CURL_DISABLE_COOKIES)
- v = (data->cookies && data->state.cookie_engine)?
- HD_VAL(hd, hdlen, "Set-Cookie:") : NULL;
- if(v) {
- /* If there is a custom-set Host: name, use it here, or else use
- * real peer hostname. */
- const char *host = data->state.aptr.cookiehost?
- data->state.aptr.cookiehost:conn->host.name;
- const bool secure_context =
- conn->handler->protocol&(CURLPROTO_HTTPS|CURLPROTO_WSS) ||
- strcasecompare("localhost", host) ||
- !strcmp(host, "127.0.0.1") ||
- !strcmp(host, "::1") ? TRUE : FALSE;
+ }
- Curl_share_lock(data, CURL_LOCK_DATA_COOKIE,
- CURL_LOCK_ACCESS_SINGLE);
- Curl_cookie_add(data, data->cookies, TRUE, FALSE, v, host,
- data->state.up.path, secure_context);
- Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
- return CURLE_OK;
- }
-#endif
#ifndef CURL_DISABLE_HSTS
- /* If enabled, the header is incoming and this is over HTTPS */
- v = (data->hsts &&
- ((conn->handler->flags & PROTOPT_SSL) ||
-#ifdef DEBUGBUILD
+ /* If enabled, the header is incoming and this is over HTTPS */
+ else if(data->hsts && checkprefix("Strict-Transport-Security:", headp) &&
+ ((conn->handler->flags & PROTOPT_SSL) ||
+#ifdef CURLDEBUG
/* allow debug builds to circumvent the HTTPS restriction */
getenv("CURL_HSTS_HTTP")
#else
0
#endif
- )
- )? HD_VAL(hd, hdlen, "Strict-Transport-Security:") : NULL;
- if(v) {
- CURLcode check =
- Curl_hsts_parse(data->hsts, conn->host.name, v);
- if(check)
- infof(data, "Illegal STS header skipped");
+ )) {
+ CURLcode check =
+ Curl_hsts_parse(data->hsts, conn->host.name,
+ headp + strlen("Strict-Transport-Security:"));
+ if(check)
+ infof(data, "Illegal STS header skipped");
#ifdef DEBUGBUILD
- else
- infof(data, "Parsed STS header fine (%zu entries)",
- Curl_llist_count(&data->hsts->list));
+ else
+ infof(data, "Parsed STS header fine (%zu entries)",
+ data->hsts->list.size);
#endif
- }
+ }
#endif
- break;
- case 't':
- case 'T':
- /* RFC 9112, ch. 6.1
- * "Transfer-Encoding MAY be sent in a response to a HEAD request or
- * in a 304 (Not Modified) response (Section 15.4.5 of [HTTP]) to a
- * GET request, neither of which includes a message body, to indicate
- * that the origin server would have applied a transfer coding to the
- * message body if the request had been an unconditional GET."
- *
- * Read: in these cases the 'Transfer-Encoding' does not apply
- * to any data following the response headers. Do not add any decoders.
- */
- v = (!k->http_bodyless &&
- (data->state.httpreq != HTTPREQ_HEAD) &&
- (k->httpcode != 304))?
- HD_VAL(hd, hdlen, "Transfer-Encoding:") : NULL;
- if(v) {
- /* One or more encodings. We check for chunked and/or a compression
- algorithm. */
- result = Curl_build_unencoding_stack(data, v, TRUE);
- if(result)
- return result;
- if(!k->chunk && data->set.http_transfer_encoding) {
- /* if this is not chunked, only close can signal the end of this
- * transfer as Content-Length is said not to be trusted for
- * transfer-encoding! */
- connclose(conn, "HTTP/1.1 transfer-encoding without chunks");
- k->ignore_cl = TRUE;
- }
- return CURLE_OK;
- }
- v = HD_VAL(hd, hdlen, "Trailer:");
- if(v) {
- data->req.resp_trailer = TRUE;
- return CURLE_OK;
- }
- break;
- case 'w':
- case 'W':
- if((401 == k->httpcode) && HD_IS(hd, hdlen, "WWW-Authenticate:")) {
- char *auth = Curl_copy_header_value(hd);
- if(!auth)
- return CURLE_OUT_OF_MEMORY;
- result = Curl_http_input_auth(data, FALSE, auth);
- free(auth);
+#ifndef CURL_DISABLE_ALTSVC
+ /* If enabled, the header is incoming and this is over HTTPS */
+ else if(data->asi && checkprefix("Alt-Svc:", headp) &&
+ ((conn->handler->flags & PROTOPT_SSL) ||
+#ifdef CURLDEBUG
+ /* allow debug builds to circumvent the HTTPS restriction */
+ getenv("CURL_ALTSVC_HTTP")
+#else
+ 0
+#endif
+ )) {
+ /* the ALPN of the current request */
+ enum alpnid id = (conn->httpversion == 30)? ALPN_h3 :
+ (conn->httpversion == 20) ? ALPN_h2 : ALPN_h1;
+ result = Curl_altsvc_parse(data, data->asi,
+ headp + strlen("Alt-Svc:"),
+ id, conn->host.name,
+ curlx_uitous((unsigned int)conn->remote_port));
+ if(result)
return result;
- }
- break;
}
-
- if(conn->handler->protocol & CURLPROTO_RTSP) {
- result = Curl_rtsp_parseheader(data, hd);
+#endif
+ else if(conn->handler->protocol & CURLPROTO_RTSP) {
+ result = Curl_rtsp_parseheader(data, headp);
if(result)
return result;
}
@@ -3181,48 +3838,25 @@ CURLcode Curl_http_header(struct Curl_easy *data,
* Called after the first HTTP response line (the status line) has been
* received and parsed.
*/
+
CURLcode Curl_http_statusline(struct Curl_easy *data,
struct connectdata *conn)
{
struct SingleRequest *k = &data->req;
-
- switch(k->httpversion) {
- case 10:
- case 11:
-#ifdef USE_HTTP2
- case 20:
-#endif
-#ifdef USE_HTTP3
- case 30:
-#endif
- /* no major version switch mid-connection */
- if(conn->httpversion &&
- (k->httpversion/10 != conn->httpversion/10)) {
- failf(data, "Version mismatch (from HTTP/%u to HTTP/%u)",
- conn->httpversion/10, k->httpversion/10);
- return CURLE_UNSUPPORTED_PROTOCOL;
- }
- break;
- default:
- failf(data, "Unsupported HTTP version (%u.%d) in response",
- k->httpversion/10, k->httpversion%10);
- return CURLE_UNSUPPORTED_PROTOCOL;
- }
-
data->info.httpcode = k->httpcode;
- data->info.httpversion = k->httpversion;
- conn->httpversion = (unsigned char)k->httpversion;
- if(!data->state.httpversion || data->state.httpversion > k->httpversion)
+ data->info.httpversion = conn->httpversion;
+ if(!data->state.httpversion ||
+ data->state.httpversion > conn->httpversion)
/* store the lowest server version we encounter */
- data->state.httpversion = (unsigned char)k->httpversion;
+ data->state.httpversion = conn->httpversion;
/*
- * This code executes as part of processing the header. As a
- * result, it is not totally clear how to interpret the
+ * This code executes as part of processing the header. As a
+ * result, it's not totally clear how to interpret the
* response code yet as that depends on what other headers may
- * be present. 401 and 407 may be errors, but may be OK
- * depending on how authentication is working. Other codes
+ * be present. 401 and 407 may be errors, but may be OK
+ * depending on how authentication is working. Other codes
* are definitely errors, so give up here.
*/
if(data->state.resume_from && data->state.httpreq == HTTPREQ_GET &&
@@ -3232,16 +3866,25 @@ CURLcode Curl_http_statusline(struct Curl_easy *data,
k->ignorebody = TRUE; /* Avoid appending error msg to good data. */
}
- if(k->httpversion == 10) {
+ if(conn->httpversion == 10) {
/* Default action for HTTP/1.0 must be to close, unless
we get one of those fancy headers that tell us the
server keeps it open for us! */
infof(data, "HTTP 1.0, assume close after body");
connclose(conn, "HTTP/1.0 close after body");
}
- else if(k->httpversion == 20 ||
+ else if(conn->httpversion == 20 ||
(k->upgr101 == UPGR101_H2 && k->httpcode == 101)) {
DEBUGF(infof(data, "HTTP/2 found, allow multiplexing"));
+ /* HTTP/2 cannot avoid multiplexing since it is a core functionality
+ of the protocol */
+ conn->bundle->multiuse = BUNDLE_MULTIPLEX;
+ }
+ else if(conn->httpversion >= 11 &&
+ !conn->bits.close) {
+ /* If HTTP version is >= 1.1 and connection is persistent */
+ DEBUGF(infof(data,
+ "HTTP 1.1 or later with persistent connection"));
}
k->http_bodyless = k->httpcode >= 100 && k->httpcode < 200;
@@ -3253,7 +3896,7 @@ CURLcode Curl_http_statusline(struct Curl_easy *data,
* fields. */
if(data->set.timecondition)
data->info.timecond = TRUE;
- FALLTHROUGH();
+ /* FALLTHROUGH */
case 204:
/* (quote from RFC2616, section 10.2.5): The server has
* fulfilled the request but does not need to return an
@@ -3271,7 +3914,7 @@ CURLcode Curl_http_statusline(struct Curl_easy *data,
}
/* Content-Length must be ignored if any Transfer-Encoding is present in the
- response. Refer to RFC 7230 section 3.3.3 and RFC2616 section 4.4. This is
+ response. Refer to RFC 7230 section 3.3.3 and RFC2616 section 4.4. This is
figured out here after all headers have been received but before the final
call to the user's header callback, so that a valid content length can be
retrieved by the user in the final call. */
@@ -3283,24 +3926,22 @@ CURLcode Curl_http_size(struct Curl_easy *data)
}
else if(k->size != -1) {
if(data->set.max_filesize &&
- !k->ignorebody &&
- (k->size > data->set.max_filesize)) {
+ k->size > data->set.max_filesize) {
failf(data, "Maximum file size exceeded");
return CURLE_FILESIZE_EXCEEDED;
}
- if(k->ignorebody)
- infof(data, "setting size while ignoring");
Curl_pgrsSetDownloadSize(data, k->size);
k->maxdownload = k->size;
}
return CURLE_OK;
}
-static CURLcode verify_header(struct Curl_easy *data,
- const char *hd, size_t hdlen)
+static CURLcode verify_header(struct Curl_easy *data)
{
struct SingleRequest *k = &data->req;
- char *ptr = memchr(hd, 0x00, hdlen);
+ const char *header = Curl_dyn_ptr(&data->state.headerb);
+ size_t hlen = Curl_dyn_len(&data->state.headerb);
+ char *ptr = memchr(header, 0x00, hlen);
if(ptr) {
/* this is bad, bail out */
failf(data, "Nul byte in header");
@@ -3309,11 +3950,11 @@ static CURLcode verify_header(struct Curl_easy *data,
if(k->headerline < 2)
/* the first "header" is the status-line and it has no colon */
return CURLE_OK;
- if(((hd[0] == ' ') || (hd[0] == '\t')) && k->headerline > 2)
- /* line folding, cannot happen on line 2 */
+ if(((header[0] == ' ') || (header[0] == '\t')) && k->headerline > 2)
+ /* line folding, can't happen on line 2 */
;
else {
- ptr = memchr(hd, ':', hdlen);
+ ptr = memchr(header, ':', hlen);
if(!ptr) {
/* this is bad, bail out */
failf(data, "Header without colon");
@@ -3350,686 +3991,596 @@ CURLcode Curl_bump_headersize(struct Curl_easy *data,
return CURLE_OK;
}
-static CURLcode http_write_header(struct Curl_easy *data,
- const char *hd, size_t hdlen)
+
+/*
+ * Read any HTTP header lines from the server and pass them to the client app.
+ */
+CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
+ struct connectdata *conn,
+ const char *buf, size_t blen,
+ size_t *pconsumed)
{
CURLcode result;
- int writetype;
-
- /* now, only output this if the header AND body are requested:
- */
- Curl_debug(data, CURLINFO_HEADER_IN, (char *)hd, hdlen);
-
- writetype = CLIENTWRITE_HEADER |
- ((data->req.httpcode/100 == 1) ? CLIENTWRITE_1XX : 0);
-
- result = Curl_client_write(data, writetype, hd, hdlen);
- if(result)
- return result;
+ struct SingleRequest *k = &data->req;
+ char *headp;
+ char *end_ptr;
- result = Curl_bump_headersize(data, hdlen, FALSE);
- if(result)
- return result;
+ /* header line within buffer loop */
+ *pconsumed = 0;
+ do {
+ size_t line_length;
+ int writetype;
- data->req.deductheadercount = (100 <= data->req.httpcode &&
- 199 >= data->req.httpcode)?
- data->req.headerbytecount:0;
- return result;
-}
+ /* data is in network encoding so use 0x0a instead of '\n' */
+ end_ptr = memchr(buf, 0x0a, blen);
-static CURLcode http_on_response(struct Curl_easy *data,
- const char *last_hd, size_t last_hd_len,
- const char *buf, size_t blen,
- size_t *pconsumed)
-{
- struct connectdata *conn = data->conn;
- CURLcode result = CURLE_OK;
- struct SingleRequest *k = &data->req;
+ if(!end_ptr) {
+ /* Not a complete header line within buffer, append the data to
+ the end of the headerbuff. */
+ result = Curl_dyn_addn(&data->state.headerb, buf, blen);
+ if(result)
+ return result;
+ *pconsumed += blen;
- (void)buf; /* not used without HTTP2 enabled */
- *pconsumed = 0;
+ if(!k->headerline) {
+ /* check if this looks like a protocol header */
+ statusline st =
+ checkprotoprefix(data, conn,
+ Curl_dyn_ptr(&data->state.headerb),
+ Curl_dyn_len(&data->state.headerb));
- if(k->upgr101 == UPGR101_RECEIVED) {
- /* supposedly upgraded to http2 now */
- if(conn->httpversion != 20)
- infof(data, "Lying server, not serving HTTP/2");
- }
+ if(st == STATUS_BAD) {
+ /* this is not the beginning of a protocol first header line */
+ k->header = FALSE;
+ k->badheader = TRUE;
+ streamclose(conn, "bad HTTP: No end-of-message indicator");
+ if(!data->set.http09_allowed) {
+ failf(data, "Received HTTP/0.9 when not allowed");
+ return CURLE_UNSUPPORTED_PROTOCOL;
+ }
+ goto out;
+ }
+ }
+ goto out; /* read more and try again */
+ }
- if(k->httpcode < 200 && last_hd) {
- /* Intermediate responses might trigger processing of more
- * responses, write the last header to the client before
- * proceeding. */
- result = http_write_header(data, last_hd, last_hd_len);
- last_hd = NULL; /* handled it */
+ /* decrease the size of the remaining (supposed) header line */
+ line_length = (end_ptr - buf) + 1;
+ result = Curl_dyn_addn(&data->state.headerb, buf, line_length);
if(result)
- goto out;
- }
+ return result;
- if(k->httpcode < 100) {
- failf(data, "Unsupported response code in HTTP response");
- result = CURLE_UNSUPPORTED_PROTOCOL;
- goto out;
- }
- else if(k->httpcode < 200) {
- /* "A user agent MAY ignore unexpected 1xx status responses."
- * By default, we expect to get more responses after this one. */
- k->header = TRUE;
- k->headerline = 0; /* restart the header line counter */
+ blen -= line_length;
+ buf += line_length;
+ *pconsumed += line_length;
- switch(k->httpcode) {
- case 100:
- /*
- * We have made an HTTP PUT or POST and this is 1.1-lingo
- * that tells us that the server is OK with this and ready
- * to receive the data.
- */
- Curl_http_exp100_got100(data);
- break;
- case 101:
- /* Switching Protocols only allowed from HTTP/1.1 */
+ /****
+ * We now have a FULL header line in 'headerb'.
+ *****/
- if(conn->httpversion != 11) {
- /* invalid for other HTTP versions */
- failf(data, "unexpected 101 response code");
- result = CURLE_WEIRD_SERVER_REPLY;
- goto out;
- }
- if(k->upgr101 == UPGR101_H2) {
- /* Switching to HTTP/2, where we will get more responses */
- infof(data, "Received 101, Switching to HTTP/2");
- k->upgr101 = UPGR101_RECEIVED;
- data->conn->bits.asks_multiplex = FALSE;
- /* We expect more response from HTTP/2 later */
- k->header = TRUE;
- k->headerline = 0; /* restart the header line counter */
- /* Any remaining `buf` bytes are already HTTP/2 and passed to
- * be processed. */
- result = Curl_http2_upgrade(data, conn, FIRSTSOCKET, buf, blen);
- if(result)
- goto out;
- *pconsumed += blen;
+ if(!k->headerline) {
+ /* the first read header */
+ statusline st = checkprotoprefix(data, conn,
+ Curl_dyn_ptr(&data->state.headerb),
+ Curl_dyn_len(&data->state.headerb));
+ if(st == STATUS_BAD) {
+ streamclose(conn, "bad HTTP: No end-of-message indicator");
+ /* this is not the beginning of a protocol first header line */
+ if(!data->set.http09_allowed) {
+ failf(data, "Received HTTP/0.9 when not allowed");
+ return CURLE_UNSUPPORTED_PROTOCOL;
+ }
+ k->header = FALSE;
+ if(blen)
+ /* since there's more, this is a partial bad header */
+ k->badheader = TRUE;
+ else {
+ /* this was all we read so it's all a bad header */
+ k->badheader = TRUE;
+ return CURLE_OK;
+ }
+ break;
}
+ }
+
+ /* headers are in network encoding so use 0x0a and 0x0d instead of '\n'
+ and '\r' */
+ headp = Curl_dyn_ptr(&data->state.headerb);
+ if((0x0a == *headp) || (0x0d == *headp)) {
+ size_t headerlen;
+ /* Zero-length header line means end of headers! */
+
+ if('\r' == *headp)
+ headp++; /* pass the \r byte */
+ if('\n' == *headp)
+ headp++; /* pass the \n byte */
+
+ if(100 <= k->httpcode && 199 >= k->httpcode) {
+ /* "A user agent MAY ignore unexpected 1xx status responses." */
+ switch(k->httpcode) {
+ case 100:
+ /*
+ * We have made an HTTP PUT or POST and this is 1.1-lingo
+ * that tells us that the server is OK with this and ready
+ * to receive the data.
+ * However, we'll get more headers now so we must get
+ * back into the header-parsing state!
+ */
+ k->header = TRUE;
+ k->headerline = 0; /* restart the header line counter */
+
+ /* if we did wait for this do enable write now! */
+ if(k->exp100 > EXP100_SEND_DATA) {
+ k->exp100 = EXP100_SEND_DATA;
+ k->keepon |= KEEP_SEND;
+ Curl_expire_done(data, EXPIRE_100_TIMEOUT);
+ }
+ break;
+ case 101:
+ /* Switching Protocols */
+ if(k->upgr101 == UPGR101_H2) {
+ /* Switching to HTTP/2 */
+ DEBUGASSERT(conn->httpversion < 20);
+ infof(data, "Received 101, Switching to HTTP/2");
+ k->upgr101 = UPGR101_RECEIVED;
+
+ /* we'll get more headers (HTTP/2 response) */
+ k->header = TRUE;
+ k->headerline = 0; /* restart the header line counter */
+
+ /* switch to http2 now. The bytes after response headers
+ are also processed here, otherwise they are lost. */
+ result = Curl_http2_upgrade(data, conn, FIRSTSOCKET, buf, blen);
+ if(result)
+ return result;
+ *pconsumed += blen;
+ blen = 0;
+ }
#ifdef USE_WEBSOCKETS
- else if(k->upgr101 == UPGR101_WS) {
- /* verify the response. Any passed `buf` bytes are already in
- * WebSockets format and taken in by the protocol handler. */
- result = Curl_ws_accept(data, buf, blen);
- if(result)
- goto out;
- *pconsumed += blen; /* ws accept handled the data */
- k->header = FALSE; /* we will not get more responses */
- if(data->set.connect_only)
- k->keepon &= ~KEEP_RECV; /* read no more content */
- }
+ else if(k->upgr101 == UPGR101_WS) {
+ /* verify the response */
+ result = Curl_ws_accept(data, buf, blen);
+ if(result)
+ return result;
+ k->header = FALSE; /* no more header to parse! */
+ if(data->set.connect_only) {
+ k->keepon &= ~KEEP_RECV; /* read no more content */
+ *pconsumed += blen;
+ blen = 0;
+ }
+ }
#endif
+ else {
+ /* Not switching to another protocol */
+ k->header = FALSE; /* no more header to parse! */
+ }
+ break;
+ default:
+ /* the status code 1xx indicates a provisional response, so
+ we'll get another set of headers */
+ k->header = TRUE;
+ k->headerline = 0; /* restart the header line counter */
+ break;
+ }
+ }
else {
- /* We silently accept this as the final response.
- * TODO: this looks, uhm, wrong. What are we switching to if we
- * did not ask for an Upgrade? Maybe the application provided an
- * `Upgrade: xxx` header? */
- k->header = FALSE;
+ if(k->upgr101 == UPGR101_H2) {
+ /* A requested upgrade was denied, poke the multi handle to possibly
+ allow a pending pipewait to continue */
+ Curl_multi_connchanged(data->multi);
+ }
+ k->header = FALSE; /* no more header to parse! */
+
+ if((k->size == -1) && !k->chunk && !conn->bits.close &&
+ (conn->httpversion == 11) &&
+ !(conn->handler->protocol & CURLPROTO_RTSP) &&
+ data->state.httpreq != HTTPREQ_HEAD) {
+ /* On HTTP 1.1, when connection is not to get closed, but no
+ Content-Length nor Transfer-Encoding chunked have been
+ received, according to RFC2616 section 4.4 point 5, we
+ assume that the server will close the connection to
+ signal the end of the document. */
+ infof(data, "no chunk, no close, no size. Assume close to "
+ "signal end");
+ streamclose(conn, "HTTP: No end-of-message indicator");
+ }
}
- break;
- default:
- /* The server may send us other 1xx responses, like informative
- * 103. This have no influence on request processing and we expect
- * to receive a final response eventually. */
- break;
- }
- goto out;
- }
- /* k->httpcode >= 200, final response */
- k->header = FALSE;
-
- if(k->upgr101 == UPGR101_H2) {
- /* A requested upgrade was denied, poke the multi handle to possibly
- allow a pending pipewait to continue */
- data->conn->bits.asks_multiplex = FALSE;
- Curl_multi_connchanged(data->multi);
- }
-
- if((k->size == -1) && !k->chunk && !conn->bits.close &&
- (conn->httpversion == 11) &&
- !(conn->handler->protocol & CURLPROTO_RTSP) &&
- data->state.httpreq != HTTPREQ_HEAD) {
- /* On HTTP 1.1, when connection is not to get closed, but no
- Content-Length nor Transfer-Encoding chunked have been
- received, according to RFC2616 section 4.4 point 5, we
- assume that the server will close the connection to
- signal the end of the document. */
- infof(data, "no chunk, no close, no size. Assume close to "
- "signal end");
- streamclose(conn, "HTTP: No end-of-message indicator");
- }
+ if(!k->header) {
+ result = Curl_http_size(data);
+ if(result)
+ return result;
+ }
- /* At this point we have some idea about the fate of the connection.
- If we are closing the connection it may result auth failure. */
+ /* At this point we have some idea about the fate of the connection.
+ If we are closing the connection it may result auth failure. */
#if defined(USE_NTLM)
- if(conn->bits.close &&
- (((data->req.httpcode == 401) &&
- (conn->http_ntlm_state == NTLMSTATE_TYPE2)) ||
- ((data->req.httpcode == 407) &&
- (conn->proxy_ntlm_state == NTLMSTATE_TYPE2)))) {
- infof(data, "Connection closure while negotiating auth (HTTP 1.0?)");
- data->state.authproblem = TRUE;
- }
+ if(conn->bits.close &&
+ (((data->req.httpcode == 401) &&
+ (conn->http_ntlm_state == NTLMSTATE_TYPE2)) ||
+ ((data->req.httpcode == 407) &&
+ (conn->proxy_ntlm_state == NTLMSTATE_TYPE2)))) {
+ infof(data, "Connection closure while negotiating auth (HTTP 1.0?)");
+ data->state.authproblem = TRUE;
+ }
#endif
#if defined(USE_SPNEGO)
- if(conn->bits.close &&
- (((data->req.httpcode == 401) &&
- (conn->http_negotiate_state == GSS_AUTHRECV)) ||
- ((data->req.httpcode == 407) &&
- (conn->proxy_negotiate_state == GSS_AUTHRECV)))) {
- infof(data, "Connection closure while negotiating auth (HTTP 1.0?)");
- data->state.authproblem = TRUE;
- }
- if((conn->http_negotiate_state == GSS_AUTHDONE) &&
- (data->req.httpcode != 401)) {
- conn->http_negotiate_state = GSS_AUTHSUCC;
- }
- if((conn->proxy_negotiate_state == GSS_AUTHDONE) &&
- (data->req.httpcode != 407)) {
- conn->proxy_negotiate_state = GSS_AUTHSUCC;
- }
+ if(conn->bits.close &&
+ (((data->req.httpcode == 401) &&
+ (conn->http_negotiate_state == GSS_AUTHRECV)) ||
+ ((data->req.httpcode == 407) &&
+ (conn->proxy_negotiate_state == GSS_AUTHRECV)))) {
+ infof(data, "Connection closure while negotiating auth (HTTP 1.0?)");
+ data->state.authproblem = TRUE;
+ }
+ if((conn->http_negotiate_state == GSS_AUTHDONE) &&
+ (data->req.httpcode != 401)) {
+ conn->http_negotiate_state = GSS_AUTHSUCC;
+ }
+ if((conn->proxy_negotiate_state == GSS_AUTHDONE) &&
+ (data->req.httpcode != 407)) {
+ conn->proxy_negotiate_state = GSS_AUTHSUCC;
+ }
#endif
-#ifdef USE_WEBSOCKETS
- /* All >=200 HTTP status codes are errors when wanting WebSockets */
- if(data->req.upgr101 == UPGR101_WS) {
- failf(data, "Refused WebSockets upgrade: %d", k->httpcode);
- result = CURLE_HTTP_RETURNED_ERROR;
- goto out;
- }
-#endif
+ /* now, only output this if the header AND body are requested:
+ */
+ writetype = CLIENTWRITE_HEADER |
+ ((k->httpcode/100 == 1) ? CLIENTWRITE_1XX : 0);
- /* Check if this response means the transfer errored. */
- if(http_should_fail(data, data->req.httpcode)) {
- failf(data, "The requested URL returned error: %d",
- k->httpcode);
- result = CURLE_HTTP_RETURNED_ERROR;
- goto out;
- }
+ headerlen = Curl_dyn_len(&data->state.headerb);
+ result = Curl_client_write(data, writetype,
+ Curl_dyn_ptr(&data->state.headerb),
+ headerlen);
+ if(result)
+ return result;
- /* Curl_http_auth_act() checks what authentication methods
- * that are available and decides which one (if any) to
- * use. It will set 'newurl' if an auth method was picked. */
- result = Curl_http_auth_act(data);
- if(result)
- goto out;
+ result = Curl_bump_headersize(data, headerlen, FALSE);
+ if(result)
+ return result;
- if(k->httpcode >= 300) {
- if((!data->req.authneg) && !conn->bits.close &&
- !Curl_creader_will_rewind(data)) {
/*
- * General treatment of errors when about to send data. Including :
- * "417 Expectation Failed", while waiting for 100-continue.
- *
- * The check for close above is done simply because of something
- * else has already deemed the connection to get closed then
- * something else should've considered the big picture and we
- * avoid this check.
- *
+ * When all the headers have been parsed, see if we should give
+ * up and return an error.
*/
+ if(http_should_fail(data)) {
+ failf(data, "The requested URL returned error: %d",
+ k->httpcode);
+ return CURLE_HTTP_RETURNED_ERROR;
+ }
- switch(data->state.httpreq) {
- case HTTPREQ_PUT:
- case HTTPREQ_POST:
- case HTTPREQ_POST_FORM:
- case HTTPREQ_POST_MIME:
- /* We got an error response. If this happened before the whole
- * request body has been sent we stop sending and mark the
- * connection for closure after we have read the entire response.
- */
- if(!Curl_req_done_sending(data)) {
- if((k->httpcode == 417) && Curl_http_exp100_is_selected(data)) {
- /* 417 Expectation Failed - try again without the Expect
- header */
- if(!k->writebytecount && http_exp100_is_waiting(data)) {
- infof(data, "Got HTTP failure 417 while waiting for a 100");
- }
- else {
- infof(data, "Got HTTP failure 417 while sending data");
- streamclose(conn,
- "Stop sending data before everything sent");
- result = http_perhapsrewind(data, conn);
- if(result)
- goto out;
- }
- data->state.disableexpect = TRUE;
- DEBUGASSERT(!data->req.newurl);
- data->req.newurl = strdup(data->state.url);
- Curl_req_abort_sending(data);
- }
- else if(data->set.http_keep_sending_on_error) {
- infof(data, "HTTP error before end of send, keep sending");
- http_exp100_send_anyway(data);
- }
- else {
- infof(data, "HTTP error before end of send, stop sending");
- streamclose(conn, "Stop sending data before everything sent");
- result = Curl_req_abort_sending(data);
- if(result)
- goto out;
- }
- }
- break;
-
- default: /* default label present to avoid compiler warnings */
- break;
+#ifdef USE_WEBSOCKETS
+ /* All non-101 HTTP status codes are bad when wanting to upgrade to
+ websockets */
+ if(data->req.upgr101 == UPGR101_WS) {
+ failf(data, "Refused WebSockets upgrade: %d", k->httpcode);
+ return CURLE_HTTP_RETURNED_ERROR;
}
- }
+#endif
- if(Curl_creader_will_rewind(data) && !Curl_req_done_sending(data)) {
- /* We rewind before next send, continue sending now */
- infof(data, "Keep sending data to get tossed away");
- k->keepon |= KEEP_SEND;
- }
- }
+ data->req.deductheadercount =
+ (100 <= k->httpcode && 199 >= k->httpcode)?data->req.headerbytecount:0;
- /* If we requested a "no body", this is a good time to get
- * out and return home.
- */
- if(data->req.no_body)
- k->download_done = TRUE;
-
- /* If max download size is *zero* (nothing) we already have
- nothing and can safely return ok now! But for HTTP/2, we would
- like to call http2_handle_stream_close to properly close a
- stream. In order to do this, we keep reading until we
- close the stream. */
- if(0 == k->maxdownload
- && !Curl_conn_is_http2(data, conn, FIRSTSOCKET)
- && !Curl_conn_is_http3(data, conn, FIRSTSOCKET))
- k->download_done = TRUE;
-
- /* final response without error, prepare to receive the body */
- result = Curl_http_firstwrite(data);
+ /* Curl_http_auth_act() checks what authentication methods
+ * that are available and decides which one (if any) to
+ * use. It will set 'newurl' if an auth method was picked. */
+ result = Curl_http_auth_act(data);
- if(!result)
- /* This is the last response that we get for the current request.
- * Check on the body size and determine if the response is complete.
- */
- result = Curl_http_size(data);
+ if(result)
+ return result;
-out:
- if(last_hd) {
- /* if not written yet, write it now */
- CURLcode r2 = http_write_header(data, last_hd, last_hd_len);
- if(!result)
- result = r2;
- }
- return result;
-}
+ if(k->httpcode >= 300) {
+ if((!conn->bits.authneg) && !conn->bits.close &&
+ !data->state.rewindbeforesend) {
+ /*
+ * General treatment of errors when about to send data. Including :
+ * "417 Expectation Failed", while waiting for 100-continue.
+ *
+ * The check for close above is done simply because of something
+ * else has already deemed the connection to get closed then
+ * something else should've considered the big picture and we
+ * avoid this check.
+ *
+ * rewindbeforesend indicates that something has told libcurl to
+ * continue sending even if it gets discarded
+ */
+
+ switch(data->state.httpreq) {
+ case HTTPREQ_PUT:
+ case HTTPREQ_POST:
+ case HTTPREQ_POST_FORM:
+ case HTTPREQ_POST_MIME:
+ /* We got an error response. If this happened before the whole
+ * request body has been sent we stop sending and mark the
+ * connection for closure after we've read the entire response.
+ */
+ Curl_expire_done(data, EXPIRE_100_TIMEOUT);
+ if(!k->upload_done) {
+ if((k->httpcode == 417) && data->state.expect100header) {
+ /* 417 Expectation Failed - try again without the Expect
+ header */
+ if(!k->writebytecount &&
+ k->exp100 == EXP100_AWAITING_CONTINUE) {
+ infof(data, "Got HTTP failure 417 while waiting for a 100");
+ }
+ else {
+ infof(data, "Got HTTP failure 417 while sending data");
+ streamclose(conn,
+ "Stop sending data before everything sent");
+ result = http_perhapsrewind(data, conn);
+ if(result)
+ return result;
+ }
+ data->state.disableexpect = TRUE;
+ DEBUGASSERT(!data->req.newurl);
+ data->req.newurl = strdup(data->state.url);
+ Curl_done_sending(data, k);
+ }
+ else if(data->set.http_keep_sending_on_error) {
+ infof(data, "HTTP error before end of send, keep sending");
+ if(k->exp100 > EXP100_SEND_DATA) {
+ k->exp100 = EXP100_SEND_DATA;
+ k->keepon |= KEEP_SEND;
+ }
+ }
+ else {
+ infof(data, "HTTP error before end of send, stop sending");
+ streamclose(conn, "Stop sending data before everything sent");
+ result = Curl_done_sending(data, k);
+ if(result)
+ return result;
+ k->upload_done = TRUE;
+ if(data->state.expect100header)
+ k->exp100 = EXP100_FAILED;
+ }
+ }
+ break;
-static CURLcode http_rw_hd(struct Curl_easy *data,
- const char *hd, size_t hdlen,
- const char *buf_remain, size_t blen,
- size_t *pconsumed)
-{
- CURLcode result = CURLE_OK;
- struct SingleRequest *k = &data->req;
- int writetype;
+ default: /* default label present to avoid compiler warnings */
+ break;
+ }
+ }
- *pconsumed = 0;
- if((0x0a == *hd) || (0x0d == *hd)) {
- /* Empty header line means end of headers! */
- struct dynbuf last_header;
- size_t consumed;
+ if(data->state.rewindbeforesend &&
+ (conn->writesockfd != CURL_SOCKET_BAD)) {
+ /* We rewind before next send, continue sending now */
+ infof(data, "Keep sending data to get tossed away");
+ k->keepon |= KEEP_SEND;
+ }
+ }
- Curl_dyn_init(&last_header, hdlen + 1);
- result = Curl_dyn_addn(&last_header, hd, hdlen);
- if(result)
- return result;
+ if(!k->header) {
+ /*
+ * really end-of-headers.
+ *
+ * If we requested a "no body", this is a good time to get
+ * out and return home.
+ */
+ if(data->req.no_body)
+ k->download_done = TRUE;
+#ifndef CURL_DISABLE_RTSP
+ else if((conn->handler->protocol & CURLPROTO_RTSP) &&
+ (data->set.rtspreq == RTSPREQ_DESCRIBE) &&
+ (k->size <= -1))
+ /* Respect section 4.4 of rfc2326: If the Content-Length header is
+ absent, a length 0 must be assumed. It will prevent libcurl from
+ hanging on DESCRIBE request that got refused for whatever
+ reason */
+ k->download_done = TRUE;
+#endif
- /* analyze the response to find out what to do. */
- /* Caveat: we clear anything in the header brigade, because a
- * response might switch HTTP version which may call use recursively.
- * Not nice, but that is currently the way of things. */
- Curl_dyn_reset(&data->state.headerb);
- result = http_on_response(data, Curl_dyn_ptr(&last_header),
- Curl_dyn_len(&last_header),
- buf_remain, blen, &consumed);
- *pconsumed += consumed;
- Curl_dyn_free(&last_header);
- return result;
- }
+ /* If max download size is *zero* (nothing) we already have
+ nothing and can safely return ok now! But for HTTP/2, we'd
+ like to call http2_handle_stream_close to properly close a
+ stream. In order to do this, we keep reading until we
+ close the stream. */
+ if(0 == k->maxdownload
+ && !Curl_conn_is_http2(data, conn, FIRSTSOCKET)
+ && !Curl_conn_is_http3(data, conn, FIRSTSOCKET))
+ k->download_done = TRUE;
+
+ Curl_debug(data, CURLINFO_HEADER_IN,
+ Curl_dyn_ptr(&data->state.headerb),
+ Curl_dyn_len(&data->state.headerb));
+ goto out; /* exit header line loop */
+ }
- /*
- * Checks for special headers coming up.
- */
+ /* We continue reading headers, reset the line-based header */
+ Curl_dyn_reset(&data->state.headerb);
+ continue;
+ }
- writetype = CLIENTWRITE_HEADER;
- if(!k->headerline++) {
- /* This is the first header, it MUST be the error code line
- or else we consider this to be the body right away! */
- bool fine_statusline = FALSE;
+ /*
+ * Checks for special headers coming up.
+ */
- k->httpversion = 0; /* Do not know yet */
- if(data->conn->handler->protocol & PROTO_FAMILY_HTTP) {
- /*
- * https://datatracker.ietf.org/doc/html/rfc7230#section-3.1.2
- *
- * The response code is always a three-digit number in HTTP as the spec
- * says. We allow any three-digit number here, but we cannot make
- * guarantees on future behaviors since it is not within the protocol.
- */
- const char *p = hd;
-
- while(*p && ISBLANK(*p))
- p++;
- if(!strncmp(p, "HTTP/", 5)) {
- p += 5;
- switch(*p) {
- case '1':
+ writetype = CLIENTWRITE_HEADER;
+ if(!k->headerline++) {
+ /* This is the first header, it MUST be the error code line
+ or else we consider this to be the body right away! */
+ bool fine_statusline = FALSE;
+ if(conn->handler->protocol & PROTO_FAMILY_HTTP) {
+ /*
+ * https://datatracker.ietf.org/doc/html/rfc7230#section-3.1.2
+ *
+ * The response code is always a three-digit number in HTTP as the spec
+ * says. We allow any three-digit number here, but we cannot make
+ * guarantees on future behaviors since it isn't within the protocol.
+ */
+ int httpversion = 0;
+ char *p = headp;
+
+ while(*p && ISBLANK(*p))
p++;
- if((p[0] == '.') && (p[1] == '0' || p[1] == '1')) {
- if(ISBLANK(p[2])) {
- k->httpversion = 10 + (p[1] - '0');
- p += 3;
- if(ISDIGIT(p[0]) && ISDIGIT(p[1]) && ISDIGIT(p[2])) {
- k->httpcode = (p[0] - '0') * 100 + (p[1] - '0') * 10 +
- (p[2] - '0');
+ if(!strncmp(p, "HTTP/", 5)) {
+ p += 5;
+ switch(*p) {
+ case '1':
+ p++;
+ if((p[0] == '.') && (p[1] == '0' || p[1] == '1')) {
+ if(ISBLANK(p[2])) {
+ httpversion = 10 + (p[1] - '0');
p += 3;
- if(ISSPACE(*p))
- fine_statusline = TRUE;
+ if(ISDIGIT(p[0]) && ISDIGIT(p[1]) && ISDIGIT(p[2])) {
+ k->httpcode = (p[0] - '0') * 100 + (p[1] - '0') * 10 +
+ (p[2] - '0');
+ p += 3;
+ if(ISSPACE(*p))
+ fine_statusline = TRUE;
+ }
}
}
+ if(!fine_statusline) {
+ failf(data, "Unsupported HTTP/1 subversion in response");
+ return CURLE_UNSUPPORTED_PROTOCOL;
+ }
+ break;
+ case '2':
+ case '3':
+ if(!ISBLANK(p[1]))
+ break;
+ httpversion = (*p - '0') * 10;
+ p += 2;
+ if(ISDIGIT(p[0]) && ISDIGIT(p[1]) && ISDIGIT(p[2])) {
+ k->httpcode = (p[0] - '0') * 100 + (p[1] - '0') * 10 +
+ (p[2] - '0');
+ p += 3;
+ if(!ISSPACE(*p))
+ break;
+ fine_statusline = TRUE;
+ }
+ break;
+ default: /* unsupported */
+ failf(data, "Unsupported HTTP version in response");
+ return CURLE_UNSUPPORTED_PROTOCOL;
}
- if(!fine_statusline) {
- failf(data, "Unsupported HTTP/1 subversion in response");
+ }
+
+ if(fine_statusline) {
+ if(k->httpcode < 100) {
+ failf(data, "Unsupported response code in HTTP response");
return CURLE_UNSUPPORTED_PROTOCOL;
}
- break;
- case '2':
- case '3':
- if(!ISBLANK(p[1]))
+ switch(httpversion) {
+ case 10:
+ case 11:
+#ifdef USE_HTTP2
+ case 20:
+#endif
+#ifdef ENABLE_QUIC
+ case 30:
+#endif
+ conn->httpversion = (unsigned char)httpversion;
break;
- k->httpversion = (*p - '0') * 10;
- p += 2;
- if(ISDIGIT(p[0]) && ISDIGIT(p[1]) && ISDIGIT(p[2])) {
- k->httpcode = (p[0] - '0') * 100 + (p[1] - '0') * 10 +
- (p[2] - '0');
- p += 3;
- if(!ISSPACE(*p))
- break;
- fine_statusline = TRUE;
+ default:
+ failf(data, "Unsupported HTTP version (%u.%d) in response",
+ httpversion/10, httpversion%10);
+ return CURLE_UNSUPPORTED_PROTOCOL;
}
- break;
- default: /* unsupported */
- failf(data, "Unsupported HTTP version in response");
- return CURLE_UNSUPPORTED_PROTOCOL;
- }
- }
- if(!fine_statusline) {
- /* If user has set option HTTP200ALIASES,
- compare header line against list of aliases
- */
- statusline check = checkhttpprefix(data, hd, hdlen);
- if(check == STATUS_DONE) {
- fine_statusline = TRUE;
- k->httpcode = 200;
- k->httpversion = 10;
+ if(k->upgr101 == UPGR101_RECEIVED) {
+ /* supposedly upgraded to http2 now */
+ if(conn->httpversion != 20)
+ infof(data, "Lying server, not serving HTTP/2");
+ }
+ if(conn->httpversion < 20) {
+ conn->bundle->multiuse = BUNDLE_NO_MULTIUSE;
+ }
+ }
+ else {
+ /* If user has set option HTTP200ALIASES,
+ compare header line against list of aliases
+ */
+ statusline check =
+ checkhttpprefix(data,
+ Curl_dyn_ptr(&data->state.headerb),
+ Curl_dyn_len(&data->state.headerb));
+ if(check == STATUS_DONE) {
+ fine_statusline = TRUE;
+ k->httpcode = 200;
+ conn->httpversion = 10;
+ }
}
}
- }
- else if(data->conn->handler->protocol & CURLPROTO_RTSP) {
- const char *p = hd;
- while(*p && ISBLANK(*p))
- p++;
- if(!strncmp(p, "RTSP/", 5)) {
- p += 5;
- if(ISDIGIT(*p)) {
+ else if(conn->handler->protocol & CURLPROTO_RTSP) {
+ char *p = headp;
+ while(*p && ISBLANK(*p))
p++;
- if((p[0] == '.') && ISDIGIT(p[1])) {
- if(ISBLANK(p[2])) {
- p += 3;
- if(ISDIGIT(p[0]) && ISDIGIT(p[1]) && ISDIGIT(p[2])) {
- k->httpcode = (p[0] - '0') * 100 + (p[1] - '0') * 10 +
- (p[2] - '0');
+ if(!strncmp(p, "RTSP/", 5)) {
+ p += 5;
+ if(ISDIGIT(*p)) {
+ p++;
+ if((p[0] == '.') && ISDIGIT(p[1])) {
+ if(ISBLANK(p[2])) {
p += 3;
- if(ISSPACE(*p)) {
- fine_statusline = TRUE;
- k->httpversion = 11; /* RTSP acts like HTTP 1.1 */
+ if(ISDIGIT(p[0]) && ISDIGIT(p[1]) && ISDIGIT(p[2])) {
+ k->httpcode = (p[0] - '0') * 100 + (p[1] - '0') * 10 +
+ (p[2] - '0');
+ p += 3;
+ if(ISSPACE(*p)) {
+ fine_statusline = TRUE;
+ conn->httpversion = 11; /* RTSP acts like HTTP 1.1 */
+ }
}
}
}
}
+ if(!fine_statusline)
+ return CURLE_WEIRD_SERVER_REPLY;
}
- if(!fine_statusline)
- return CURLE_WEIRD_SERVER_REPLY;
}
- }
- if(fine_statusline) {
- result = Curl_http_statusline(data, data->conn);
- if(result)
- return result;
- writetype |= CLIENTWRITE_STATUS;
- }
- else {
- k->header = FALSE; /* this is not a header line */
- return CURLE_WEIRD_SERVER_REPLY;
+ if(fine_statusline) {
+ result = Curl_http_statusline(data, conn);
+ if(result)
+ return result;
+ writetype |= CLIENTWRITE_STATUS;
+ }
+ else {
+ k->header = FALSE; /* this is not a header line */
+ break;
+ }
}
- }
-
- result = verify_header(data, hd, hdlen);
- if(result)
- return result;
-
- result = Curl_http_header(data, hd, hdlen);
- if(result)
- return result;
-
- /*
- * Taken in one (more) header. Write it to the client.
- */
- Curl_debug(data, CURLINFO_HEADER_IN, (char *)hd, hdlen);
- if(k->httpcode/100 == 1)
- writetype |= CLIENTWRITE_1XX;
- result = Curl_client_write(data, writetype, hd, hdlen);
- if(result)
- return result;
-
- result = Curl_bump_headersize(data, hdlen, FALSE);
- if(result)
- return result;
-
- return CURLE_OK;
-}
-
-/*
- * Read any HTTP header lines from the server and pass them to the client app.
- */
-static CURLcode http_parse_headers(struct Curl_easy *data,
- const char *buf, size_t blen,
- size_t *pconsumed)
-{
- struct connectdata *conn = data->conn;
- CURLcode result = CURLE_OK;
- struct SingleRequest *k = &data->req;
- char *end_ptr;
- bool leftover_body = FALSE;
-
- /* header line within buffer loop */
- *pconsumed = 0;
- while(blen && k->header) {
- size_t consumed;
+ result = verify_header(data);
+ if(result)
+ return result;
- end_ptr = memchr(buf, '\n', blen);
- if(!end_ptr) {
- /* Not a complete header line within buffer, append the data to
- the end of the headerbuff. */
- result = Curl_dyn_addn(&data->state.headerb, buf, blen);
- if(result)
- return result;
- *pconsumed += blen;
+ result = Curl_http_header(data, conn, headp);
+ if(result)
+ return result;
- if(!k->headerline) {
- /* check if this looks like a protocol header */
- statusline st =
- checkprotoprefix(data, conn,
- Curl_dyn_ptr(&data->state.headerb),
- Curl_dyn_len(&data->state.headerb));
+ /*
+ * End of header-checks. Write them to the client.
+ */
+ if(k->httpcode/100 == 1)
+ writetype |= CLIENTWRITE_1XX;
- if(st == STATUS_BAD) {
- /* this is not the beginning of a protocol first header line */
- k->header = FALSE;
- streamclose(conn, "bad HTTP: No end-of-message indicator");
- if(conn->httpversion >= 10) {
- failf(data, "Invalid status line");
- return CURLE_WEIRD_SERVER_REPLY;
- }
- if(!data->set.http09_allowed) {
- failf(data, "Received HTTP/0.9 when not allowed");
- return CURLE_UNSUPPORTED_PROTOCOL;
- }
- leftover_body = TRUE;
- goto out;
- }
- }
- goto out; /* read more and try again */
- }
+ Curl_debug(data, CURLINFO_HEADER_IN, headp,
+ Curl_dyn_len(&data->state.headerb));
- /* decrease the size of the remaining (supposed) header line */
- consumed = (end_ptr - buf) + 1;
- result = Curl_dyn_addn(&data->state.headerb, buf, consumed);
+ result = Curl_client_write(data, writetype, headp,
+ Curl_dyn_len(&data->state.headerb));
if(result)
return result;
- blen -= consumed;
- buf += consumed;
- *pconsumed += consumed;
- /****
- * We now have a FULL header line in 'headerb'.
- *****/
-
- if(!k->headerline) {
- /* the first read header */
- statusline st = checkprotoprefix(data, conn,
- Curl_dyn_ptr(&data->state.headerb),
- Curl_dyn_len(&data->state.headerb));
- if(st == STATUS_BAD) {
- streamclose(conn, "bad HTTP: No end-of-message indicator");
- /* this is not the beginning of a protocol first header line */
- if(conn->httpversion >= 10) {
- failf(data, "Invalid status line");
- return CURLE_WEIRD_SERVER_REPLY;
- }
- if(!data->set.http09_allowed) {
- failf(data, "Received HTTP/0.9 when not allowed");
- return CURLE_UNSUPPORTED_PROTOCOL;
- }
- k->header = FALSE;
- leftover_body = TRUE;
- goto out;
- }
- }
-
- result = http_rw_hd(data, Curl_dyn_ptr(&data->state.headerb),
- Curl_dyn_len(&data->state.headerb),
- buf, blen, &consumed);
- /* We are done with this line. We reset because response
- * processing might switch to HTTP/2 and that might call us
- * directly again. */
- Curl_dyn_reset(&data->state.headerb);
- if(consumed) {
- blen -= consumed;
- buf += consumed;
- *pconsumed += consumed;
- }
+ result = Curl_bump_headersize(data, Curl_dyn_len(&data->state.headerb),
+ FALSE);
if(result)
return result;
+
+ Curl_dyn_reset(&data->state.headerb);
}
+ while(blen);
/* We might have reached the end of the header part here, but
there might be a non-header part left in the end of the read
buffer. */
out:
- if(!k->header && !leftover_body) {
- Curl_dyn_free(&data->state.headerb);
- }
return CURLE_OK;
}
-CURLcode Curl_http_write_resp_hd(struct Curl_easy *data,
- const char *hd, size_t hdlen,
- bool is_eos)
-{
- CURLcode result;
- size_t consumed;
- char tmp = 0;
-
- result = http_rw_hd(data, hd, hdlen, &tmp, 0, &consumed);
- if(!result && is_eos) {
- result = Curl_client_write(data, (CLIENTWRITE_BODY|CLIENTWRITE_EOS),
- &tmp, 0);
- }
- return result;
-}
-
-/*
- * HTTP protocol `write_resp` implementation. Will parse headers
- * when not done yet and otherwise return without consuming data.
- */
-CURLcode Curl_http_write_resp_hds(struct Curl_easy *data,
- const char *buf, size_t blen,
- size_t *pconsumed)
-{
- if(!data->req.header) {
- *pconsumed = 0;
- return CURLE_OK;
- }
- else {
- CURLcode result;
-
- result = http_parse_headers(data, buf, blen, pconsumed);
- if(!result && !data->req.header) {
- if(!data->req.no_body && Curl_dyn_len(&data->state.headerb)) {
- /* leftover from parsing something that turned out not
- * to be a header, only happens if we allow for
- * HTTP/0.9 like responses */
- result = Curl_client_write(data, CLIENTWRITE_BODY,
- Curl_dyn_ptr(&data->state.headerb),
- Curl_dyn_len(&data->state.headerb));
- }
- Curl_dyn_free(&data->state.headerb);
- }
- return result;
- }
-}
-
-CURLcode Curl_http_write_resp(struct Curl_easy *data,
- const char *buf, size_t blen,
- bool is_eos)
-{
- CURLcode result;
- size_t consumed;
- int flags;
-
- result = Curl_http_write_resp_hds(data, buf, blen, &consumed);
- if(result || data->req.done)
- goto out;
-
- DEBUGASSERT(consumed <= blen);
- blen -= consumed;
- buf += consumed;
- /* either all was consumed in header parsing, or we have data left
- * and are done with headers, e.g. it is BODY data */
- DEBUGASSERT(!blen || !data->req.header);
- if(!data->req.header && (blen || is_eos)) {
- /* BODY data after header been parsed, write and consume */
- flags = CLIENTWRITE_BODY;
- if(is_eos)
- flags |= CLIENTWRITE_EOS;
- result = Curl_client_write(data, flags, (char *)buf, blen);
- }
-out:
- return result;
-}
/* Decode HTTP status code string. */
CURLcode Curl_http_decode_status(int *pstatus, const char *s, size_t len)
@@ -4066,7 +4617,7 @@ CURLcode Curl_http_req_make(struct httpreq **preq,
CURLcode result = CURLE_OUT_OF_MEMORY;
DEBUGASSERT(method);
- if(m_len + 1 > sizeof(req->method))
+ if(m_len + 1 >= sizeof(req->method))
return CURLE_BAD_FUNCTION_ARGUMENT;
req = calloc(1, sizeof(*req));
@@ -4074,17 +4625,17 @@ CURLcode Curl_http_req_make(struct httpreq **preq,
goto out;
memcpy(req->method, method, m_len);
if(scheme) {
- req->scheme = Curl_memdup0(scheme, s_len);
+ req->scheme = Curl_strndup(scheme, s_len);
if(!req->scheme)
goto out;
}
if(authority) {
- req->authority = Curl_memdup0(authority, a_len);
+ req->authority = Curl_strndup(authority, a_len);
if(!req->authority)
goto out;
}
if(path) {
- req->path = Curl_memdup0(path, p_len);
+ req->path = Curl_strndup(path, p_len);
if(!req->path)
goto out;
}
@@ -4222,7 +4773,7 @@ CURLcode Curl_http_req_make2(struct httpreq **preq,
CURLUcode uc;
DEBUGASSERT(method);
- if(m_len + 1 > sizeof(req->method))
+ if(m_len + 1 >= sizeof(req->method))
return CURLE_BAD_FUNCTION_ARGUMENT;
req = calloc(1, sizeof(*req));
@@ -4400,152 +4951,4 @@ void Curl_http_resp_free(struct http_resp *resp)
}
}
-struct cr_exp100_ctx {
- struct Curl_creader super;
- struct curltime start; /* time started waiting */
- enum expect100 state;
-};
-
-/* Expect: 100-continue client reader, blocking uploads */
-
-static void http_exp100_continue(struct Curl_easy *data,
- struct Curl_creader *reader)
-{
- struct cr_exp100_ctx *ctx = reader->ctx;
- if(ctx->state > EXP100_SEND_DATA) {
- ctx->state = EXP100_SEND_DATA;
- data->req.keepon |= KEEP_SEND;
- data->req.keepon &= ~KEEP_SEND_TIMED;
- Curl_expire_done(data, EXPIRE_100_TIMEOUT);
- }
-}
-
-static CURLcode cr_exp100_read(struct Curl_easy *data,
- struct Curl_creader *reader,
- char *buf, size_t blen,
- size_t *nread, bool *eos)
-{
- struct cr_exp100_ctx *ctx = reader->ctx;
- timediff_t ms;
-
- switch(ctx->state) {
- case EXP100_SENDING_REQUEST:
- if(!Curl_req_sendbuf_empty(data)) {
- /* The initial request data has not been fully sent yet. Do
- * not start the timer yet. */
- DEBUGF(infof(data, "cr_exp100_read, request not full sent yet"));
- *nread = 0;
- *eos = FALSE;
- return CURLE_OK;
- }
- /* We are now waiting for a reply from the server or
- * a timeout on our side IFF the request has been fully sent. */
- DEBUGF(infof(data, "cr_exp100_read, start AWAITING_CONTINUE, "
- "timeout %ldms", data->set.expect_100_timeout));
- ctx->state = EXP100_AWAITING_CONTINUE;
- ctx->start = Curl_now();
- Curl_expire(data, data->set.expect_100_timeout, EXPIRE_100_TIMEOUT);
- data->req.keepon &= ~KEEP_SEND;
- data->req.keepon |= KEEP_SEND_TIMED;
- *nread = 0;
- *eos = FALSE;
- return CURLE_OK;
- case EXP100_FAILED:
- DEBUGF(infof(data, "cr_exp100_read, expectation failed, error"));
- *nread = 0;
- *eos = FALSE;
- return CURLE_READ_ERROR;
- case EXP100_AWAITING_CONTINUE:
- ms = Curl_timediff(Curl_now(), ctx->start);
- if(ms < data->set.expect_100_timeout) {
- DEBUGF(infof(data, "cr_exp100_read, AWAITING_CONTINUE, not expired"));
- data->req.keepon &= ~KEEP_SEND;
- data->req.keepon |= KEEP_SEND_TIMED;
- *nread = 0;
- *eos = FALSE;
- return CURLE_OK;
- }
- /* we have waited long enough, continue anyway */
- http_exp100_continue(data, reader);
- infof(data, "Done waiting for 100-continue");
- FALLTHROUGH();
- default:
- DEBUGF(infof(data, "cr_exp100_read, pass through"));
- return Curl_creader_read(data, reader->next, buf, blen, nread, eos);
- }
-}
-
-static void cr_exp100_done(struct Curl_easy *data,
- struct Curl_creader *reader, int premature)
-{
- struct cr_exp100_ctx *ctx = reader->ctx;
- ctx->state = premature? EXP100_FAILED : EXP100_SEND_DATA;
- data->req.keepon &= ~KEEP_SEND_TIMED;
- Curl_expire_done(data, EXPIRE_100_TIMEOUT);
-}
-
-static const struct Curl_crtype cr_exp100 = {
- "cr-exp100",
- Curl_creader_def_init,
- cr_exp100_read,
- Curl_creader_def_close,
- Curl_creader_def_needs_rewind,
- Curl_creader_def_total_length,
- Curl_creader_def_resume_from,
- Curl_creader_def_rewind,
- Curl_creader_def_unpause,
- Curl_creader_def_is_paused,
- cr_exp100_done,
- sizeof(struct cr_exp100_ctx)
-};
-
-static CURLcode http_exp100_add_reader(struct Curl_easy *data)
-{
- struct Curl_creader *reader = NULL;
- CURLcode result;
-
- result = Curl_creader_create(&reader, data, &cr_exp100,
- CURL_CR_PROTOCOL);
- if(!result)
- result = Curl_creader_add(data, reader);
- if(!result) {
- struct cr_exp100_ctx *ctx = reader->ctx;
- ctx->state = EXP100_SENDING_REQUEST;
- }
-
- if(result && reader)
- Curl_creader_free(data, reader);
- return result;
-}
-
-void Curl_http_exp100_got100(struct Curl_easy *data)
-{
- struct Curl_creader *r = Curl_creader_get_by_type(data, &cr_exp100);
- if(r)
- http_exp100_continue(data, r);
-}
-
-static bool http_exp100_is_waiting(struct Curl_easy *data)
-{
- struct Curl_creader *r = Curl_creader_get_by_type(data, &cr_exp100);
- if(r) {
- struct cr_exp100_ctx *ctx = r->ctx;
- return (ctx->state == EXP100_AWAITING_CONTINUE);
- }
- return FALSE;
-}
-
-static void http_exp100_send_anyway(struct Curl_easy *data)
-{
- struct Curl_creader *r = Curl_creader_get_by_type(data, &cr_exp100);
- if(r)
- http_exp100_continue(data, r);
-}
-
-bool Curl_http_exp100_is_selected(struct Curl_easy *data)
-{
- struct Curl_creader *r = Curl_creader_get_by_type(data, &cr_exp100);
- return r? TRUE : FALSE;
-}
-
#endif /* CURL_DISABLE_HTTP */
diff --git a/contrib/libs/curl/lib/http.h b/contrib/libs/curl/lib/http.h
index bb5974d94d..56b091301f 100644
--- a/contrib/libs/curl/lib/http.h
+++ b/contrib/libs/curl/lib/http.h
@@ -44,7 +44,7 @@ typedef enum {
#ifndef CURL_DISABLE_HTTP
-#if defined(USE_HTTP3)
+#if defined(ENABLE_QUIC)
#include <stdint.h>
#endif
@@ -54,6 +54,14 @@ extern const struct Curl_handler Curl_handler_http;
extern const struct Curl_handler Curl_handler_https;
#endif
+#ifdef USE_WEBSOCKETS
+extern const struct Curl_handler Curl_handler_ws;
+
+#ifdef USE_SSL
+extern const struct Curl_handler Curl_handler_wss;
+#endif
+#endif /* websockets */
+
struct dynhds;
CURLcode Curl_bump_headersize(struct Curl_easy *data,
@@ -73,6 +81,13 @@ char *Curl_checkProxyheaders(struct Curl_easy *data,
const struct connectdata *conn,
const char *thisheader,
const size_t thislen);
+struct HTTP; /* see below */
+CURLcode Curl_buffer_send(struct dynbuf *in,
+ struct Curl_easy *data,
+ struct HTTP *http,
+ curl_off_t *bytes_written,
+ curl_off_t included_body_bytes,
+ int socketindex);
CURLcode Curl_add_timecondition(struct Curl_easy *data,
#ifndef USE_HYPER
@@ -93,6 +108,10 @@ CURLcode Curl_dynhds_add_custom(struct Curl_easy *data,
bool is_connect,
struct dynhds *hds);
+CURLcode Curl_http_compile_trailers(struct curl_slist *trailers,
+ struct dynbuf *buf,
+ struct Curl_easy *handle);
+
void Curl_http_method(struct Curl_easy *data, struct connectdata *conn,
const char **method, Curl_HttpReq *);
CURLcode Curl_http_useragent(struct Curl_easy *data);
@@ -101,14 +120,14 @@ CURLcode Curl_http_target(struct Curl_easy *data, struct connectdata *conn,
struct dynbuf *req);
CURLcode Curl_http_statusline(struct Curl_easy *data,
struct connectdata *conn);
-CURLcode Curl_http_header(struct Curl_easy *data,
- const char *hd, size_t hdlen);
+CURLcode Curl_http_header(struct Curl_easy *data, struct connectdata *conn,
+ char *headp);
CURLcode Curl_transferencode(struct Curl_easy *data);
-CURLcode Curl_http_req_set_reader(struct Curl_easy *data,
- Curl_HttpReq httpreq,
- const char **tep);
-CURLcode Curl_http_req_complete(struct Curl_easy *data,
- struct dynbuf *r, Curl_HttpReq httpreq);
+CURLcode Curl_http_body(struct Curl_easy *data, struct connectdata *conn,
+ Curl_HttpReq httpreq,
+ const char **teep);
+CURLcode Curl_http_bodysend(struct Curl_easy *data, struct connectdata *conn,
+ struct dynbuf *r, Curl_HttpReq httpreq);
bool Curl_use_http_1_1plus(const struct Curl_easy *data,
const struct connectdata *conn);
#ifndef CURL_DISABLE_COOKIES
@@ -118,24 +137,19 @@ CURLcode Curl_http_cookies(struct Curl_easy *data,
#else
#define Curl_http_cookies(a,b,c) CURLE_OK
#endif
+CURLcode Curl_http_resume(struct Curl_easy *data,
+ struct connectdata *conn,
+ Curl_HttpReq httpreq);
CURLcode Curl_http_range(struct Curl_easy *data,
Curl_HttpReq httpreq);
-CURLcode Curl_http_firstwrite(struct Curl_easy *data);
+CURLcode Curl_http_firstwrite(struct Curl_easy *data,
+ struct connectdata *conn,
+ bool *done);
/* protocol-specific functions set up to be called by the main engine */
-CURLcode Curl_http_setup_conn(struct Curl_easy *data,
- struct connectdata *conn);
CURLcode Curl_http(struct Curl_easy *data, bool *done);
CURLcode Curl_http_done(struct Curl_easy *data, CURLcode, bool premature);
CURLcode Curl_http_connect(struct Curl_easy *data, bool *done);
-int Curl_http_getsock_do(struct Curl_easy *data, struct connectdata *conn,
- curl_socket_t *socks);
-CURLcode Curl_http_write_resp(struct Curl_easy *data,
- const char *buf, size_t blen,
- bool is_eos);
-CURLcode Curl_http_write_resp_hd(struct Curl_easy *data,
- const char *hd, size_t hdlen,
- bool is_eos);
/* These functions are in http.c */
CURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy,
@@ -146,7 +160,7 @@ CURLcode Curl_http_auth_act(struct Curl_easy *data);
selected to use no auth at all. Ie, we actively select no auth, as opposed
to not having one selected. The other CURLAUTH_* defines are present in the
public curl/curl.h header. */
-#define CURLAUTH_PICKNONE (1<<30) /* do not use auth */
+#define CURLAUTH_PICKNONE (1<<30) /* don't use auth */
/* MAX_INITIAL_POST_SIZE indicates the number of bytes that will make the POST
data get included in the initial data chunk sent to the server. If the
@@ -178,20 +192,43 @@ CURLcode Curl_http_auth_act(struct Curl_easy *data);
version. This count includes CONNECT response headers. */
#define MAX_HTTP_RESP_HEADER_SIZE (300*1024)
-bool Curl_http_exp100_is_selected(struct Curl_easy *data);
-void Curl_http_exp100_got100(struct Curl_easy *data);
-
#endif /* CURL_DISABLE_HTTP */
/****************************************************************************
* HTTP unique setup
***************************************************************************/
+struct HTTP {
+ curl_off_t postsize; /* off_t to handle large file sizes */
+ const char *postdata;
+ struct back {
+ curl_read_callback fread_func; /* backup storage for fread pointer */
+ void *fread_in; /* backup storage for fread_in pointer */
+ const char *postdata;
+ curl_off_t postsize;
+ struct Curl_easy *data;
+ } backup;
+
+ enum {
+ HTTPSEND_NADA, /* init */
+ HTTPSEND_REQUEST, /* sending a request */
+ HTTPSEND_BODY /* sending body */
+ } sending;
+
+#ifndef CURL_DISABLE_HTTP
+ void *h2_ctx; /* HTTP/2 implementation context */
+ void *h3_ctx; /* HTTP/3 implementation context */
+ struct dynbuf send_buffer; /* used if the request couldn't be sent in one
+ chunk, points to an allocated send_buffer
+ struct */
+#endif
+};
CURLcode Curl_http_size(struct Curl_easy *data);
-CURLcode Curl_http_write_resp_hds(struct Curl_easy *data,
- const char *buf, size_t blen,
- size_t *pconsumed);
+CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
+ struct connectdata *conn,
+ const char *buf, size_t blen,
+ size_t *pconsumed);
/**
* Curl_http_output_auth() setups the authentication headers for the
@@ -235,7 +272,7 @@ struct httpreq {
};
/**
- * Create an HTTP request struct.
+ * Create a HTTP request struct.
*/
CURLcode Curl_http_req_make(struct httpreq **preq,
const char *method, size_t m_len,
@@ -285,7 +322,7 @@ struct http_resp {
};
/**
- * Create an HTTP response struct.
+ * Create a HTTP response struct.
*/
CURLcode Curl_http_resp_make(struct http_resp **presp,
int status,
diff --git a/contrib/libs/curl/lib/http1.c b/contrib/libs/curl/lib/http1.c
index d7e21fdcec..182234ca97 100644
--- a/contrib/libs/curl/lib/http1.c
+++ b/contrib/libs/curl/lib/http1.c
@@ -217,7 +217,7 @@ static CURLcode start_req(struct h1_req_parser *parser,
tmp[target_len] = '\0';
/* See if treating TARGET as an absolute URL makes sense */
if(Curl_is_absolute_url(tmp, NULL, 0, FALSE)) {
- unsigned int url_options;
+ int url_options;
url = curl_url();
if(!url) {
diff --git a/contrib/libs/curl/lib/http2.c b/contrib/libs/curl/lib/http2.c
index df3e6f0df3..f202b81d0c 100644
--- a/contrib/libs/curl/lib/http2.c
+++ b/contrib/libs/curl/lib/http2.c
@@ -29,7 +29,6 @@
#include <nghttp2/nghttp2.h>
#include "urldata.h"
#include "bufq.h"
-#include "hash.h"
#include "http1.h"
#include "http2.h"
#include "http.h"
@@ -69,44 +68,38 @@
/* buffer dimensioning:
* use 16K as chunk size, as that fits H2 DATA frames well */
#define H2_CHUNK_SIZE (16 * 1024)
-/* connection window size */
-#define H2_CONN_WINDOW_SIZE (10 * 1024 * 1024)
+/* this is how much we want "in flight" for a stream */
+#define H2_STREAM_WINDOW_SIZE (10 * 1024 * 1024)
/* on receiving from TLS, we prep for holding a full stream window */
-#define H2_NW_RECV_CHUNKS (H2_CONN_WINDOW_SIZE / H2_CHUNK_SIZE)
+#define H2_NW_RECV_CHUNKS (H2_STREAM_WINDOW_SIZE / H2_CHUNK_SIZE)
/* on send into TLS, we just want to accumulate small frames */
#define H2_NW_SEND_CHUNKS 1
-/* this is how much we want "in flight" for a stream, unthrottled */
-#define H2_STREAM_WINDOW_SIZE_MAX (10 * 1024 * 1024)
-/* this is how much we want "in flight" for a stream, initially, IFF
- * nghttp2 allows us to tweak the local window size. */
-#if NGHTTP2_HAS_SET_LOCAL_WINDOW_SIZE
-#define H2_STREAM_WINDOW_SIZE_INITIAL (64 * 1024)
-#else
-#define H2_STREAM_WINDOW_SIZE_INITIAL H2_STREAM_WINDOW_SIZE_MAX
-#endif
+/* stream recv/send chunks are a result of window / chunk sizes */
+#define H2_STREAM_RECV_CHUNKS (H2_STREAM_WINDOW_SIZE / H2_CHUNK_SIZE)
/* keep smaller stream upload buffer (default h2 window size) to have
* our progress bars and "upload done" reporting closer to reality */
#define H2_STREAM_SEND_CHUNKS ((64 * 1024) / H2_CHUNK_SIZE)
/* spare chunks we keep for a full window */
-#define H2_STREAM_POOL_SPARES (H2_CONN_WINDOW_SIZE / H2_CHUNK_SIZE)
+#define H2_STREAM_POOL_SPARES (H2_STREAM_WINDOW_SIZE / H2_CHUNK_SIZE)
-/* We need to accommodate the max number of streams with their window sizes on
- * the overall connection. Streams might become PAUSED which will block their
- * received QUOTA in the connection window. If we run out of space, the server
- * is blocked from sending us any data. See #10988 for an issue with this. */
-#define HTTP2_HUGE_WINDOW_SIZE (100 * H2_STREAM_WINDOW_SIZE_MAX)
+/* We need to accommodate the max number of streams with their window
+ * sizes on the overall connection. Streams might become PAUSED which
+ * will block their received QUOTA in the connection window. And if we
+ * run out of space, the server is blocked from sending us any data.
+ * See #10988 for an issue with this. */
+#define HTTP2_HUGE_WINDOW_SIZE (100 * H2_STREAM_WINDOW_SIZE)
#define H2_SETTINGS_IV_LEN 3
#define H2_BINSETTINGS_LEN 80
-static size_t populate_settings(nghttp2_settings_entry *iv,
- struct Curl_easy *data)
+static int populate_settings(nghttp2_settings_entry *iv,
+ struct Curl_easy *data)
{
iv[0].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS;
iv[0].value = Curl_multi_max_concurrent_streams(data->multi);
iv[1].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE;
- iv[1].value = H2_STREAM_WINDOW_SIZE_INITIAL;
+ iv[1].value = H2_STREAM_WINDOW_SIZE;
iv[2].settings_id = NGHTTP2_SETTINGS_ENABLE_PUSH;
iv[2].value = data->multi->push_cb != NULL;
@@ -118,7 +111,7 @@ static ssize_t populate_binsettings(uint8_t *binsettings,
struct Curl_easy *data)
{
nghttp2_settings_entry iv[H2_SETTINGS_IV_LEN];
- size_t ivlen;
+ int ivlen;
ivlen = populate_settings(iv, data);
/* this returns number of bytes it wrote or a negative number on error. */
@@ -128,25 +121,19 @@ static ssize_t populate_binsettings(uint8_t *binsettings,
struct cf_h2_ctx {
nghttp2_session *h2;
+ uint32_t max_concurrent_streams;
/* The easy handle used in the current filter call, cleared at return */
struct cf_call_data call_data;
struct bufq inbufq; /* network input */
struct bufq outbufq; /* network output */
struct bufc_pool stream_bufcp; /* spares for stream buffers */
- struct dynbuf scratch; /* scratch buffer for temp use */
- struct Curl_hash streams; /* hash of `data->mid` to `h2_stream_ctx` */
size_t drain_total; /* sum of all stream's UrlState drain */
- uint32_t max_concurrent_streams;
- uint32_t goaway_error; /* goaway error code from server */
- int32_t remote_max_sid; /* max id processed by server */
- int32_t local_max_sid; /* max id processed by us */
- BIT(initialized);
- BIT(via_h1_upgrade);
+ int32_t goaway_error;
+ int32_t last_stream_id;
BIT(conn_closed);
- BIT(rcvd_goaway);
- BIT(sent_goaway);
+ BIT(goaway);
BIT(enable_push);
BIT(nw_out_blocked);
};
@@ -156,38 +143,25 @@ struct cf_h2_ctx {
#define CF_CTX_CALL_DATA(cf) \
((struct cf_h2_ctx *)(cf)->ctx)->call_data
-static void h2_stream_hash_free(void *stream);
-
-static void cf_h2_ctx_init(struct cf_h2_ctx *ctx, bool via_h1_upgrade)
+static void cf_h2_ctx_clear(struct cf_h2_ctx *ctx)
{
- Curl_bufcp_init(&ctx->stream_bufcp, H2_CHUNK_SIZE, H2_STREAM_POOL_SPARES);
- Curl_bufq_initp(&ctx->inbufq, &ctx->stream_bufcp, H2_NW_RECV_CHUNKS, 0);
- Curl_bufq_initp(&ctx->outbufq, &ctx->stream_bufcp, H2_NW_SEND_CHUNKS, 0);
- Curl_dyn_init(&ctx->scratch, CURL_MAX_HTTP_HEADER);
- Curl_hash_offt_init(&ctx->streams, 63, h2_stream_hash_free);
- ctx->remote_max_sid = 2147483647;
- ctx->via_h1_upgrade = via_h1_upgrade;
- ctx->initialized = TRUE;
-}
+ struct cf_call_data save = ctx->call_data;
-static void cf_h2_ctx_free(struct cf_h2_ctx *ctx)
-{
- if(ctx && ctx->initialized) {
- Curl_bufq_free(&ctx->inbufq);
- Curl_bufq_free(&ctx->outbufq);
- Curl_bufcp_free(&ctx->stream_bufcp);
- Curl_dyn_free(&ctx->scratch);
- Curl_hash_clean(&ctx->streams);
- Curl_hash_destroy(&ctx->streams);
- memset(ctx, 0, sizeof(*ctx));
+ if(ctx->h2) {
+ nghttp2_session_del(ctx->h2);
}
- free(ctx);
+ Curl_bufq_free(&ctx->inbufq);
+ Curl_bufq_free(&ctx->outbufq);
+ Curl_bufcp_free(&ctx->stream_bufcp);
+ memset(ctx, 0, sizeof(*ctx));
+ ctx->call_data = save;
}
-static void cf_h2_ctx_close(struct cf_h2_ctx *ctx)
+static void cf_h2_ctx_free(struct cf_h2_ctx *ctx)
{
- if(ctx->h2) {
- nghttp2_session_del(ctx->h2);
+ if(ctx) {
+ cf_h2_ctx_clear(ctx);
+ free(ctx);
}
}
@@ -195,15 +169,18 @@ static CURLcode h2_progress_egress(struct Curl_cfilter *cf,
struct Curl_easy *data);
/**
- * All about the H2 internals of a stream
+ * All about the H3 internals of a stream
*/
-struct h2_stream_ctx {
+struct stream_ctx {
+ /*********** for HTTP/2 we store stream-local data here *************/
+ int32_t id; /* HTTP/2 protocol identifier for stream */
struct bufq recvbuf; /* response buffer */
struct bufq sendbuf; /* request buffer */
struct h1_req_parser h1; /* parsing the request */
struct dynhds resp_trailers; /* response trailer fields */
size_t resp_hds_len; /* amount of response header bytes in recvbuf */
- curl_off_t nrcvd_data; /* number of DATA bytes received */
+ size_t upload_blocked_len;
+ curl_off_t upload_left; /* number of request bytes left to upload */
char **push_headers; /* allocated array */
size_t push_headers_used; /* number of entries filled in */
@@ -211,198 +188,98 @@ struct h2_stream_ctx {
int status_code; /* HTTP response status code */
uint32_t error; /* stream error code */
- CURLcode xfer_result; /* Result of writing out response */
- int32_t local_window_size; /* the local recv window size */
- int32_t id; /* HTTP/2 protocol identifier for stream */
- BIT(resp_hds_complete); /* we have a complete, final response */
- BIT(closed); /* TRUE on stream close */
- BIT(reset); /* TRUE on stream reset */
- BIT(close_handled); /* TRUE if stream closure is handled by libcurl */
- BIT(bodystarted);
- BIT(body_eos); /* the complete body has been added to `sendbuf` and
- * is being/has been processed from there. */
+ uint32_t local_window_size; /* the local recv window size */
+ bool resp_hds_complete; /* we have a complete, final response */
+ bool closed; /* TRUE on stream close */
+ bool reset; /* TRUE on stream reset */
+ bool close_handled; /* TRUE if stream closure is handled by libcurl */
+ bool bodystarted;
+ bool send_closed; /* transfer is done sending, we might have still
+ buffered data in stream->sendbuf to upload. */
};
-#define H2_STREAM_CTX(ctx,data) ((struct h2_stream_ctx *)(\
- data? Curl_hash_offt_get(&(ctx)->streams, (data)->mid) : NULL))
-
-static struct h2_stream_ctx *h2_stream_ctx_create(struct cf_h2_ctx *ctx)
-{
- struct h2_stream_ctx *stream;
-
- (void)ctx;
- stream = calloc(1, sizeof(*stream));
- if(!stream)
- return NULL;
-
- stream->id = -1;
- Curl_bufq_initp(&stream->sendbuf, &ctx->stream_bufcp,
- H2_STREAM_SEND_CHUNKS, BUFQ_OPT_NONE);
- Curl_h1_req_parse_init(&stream->h1, H1_PARSE_DEFAULT_MAX_LINE_LEN);
- Curl_dynhds_init(&stream->resp_trailers, 0, DYN_HTTP_REQUEST);
- stream->resp_hds_len = 0;
- stream->bodystarted = FALSE;
- stream->status_code = -1;
- stream->closed = FALSE;
- stream->close_handled = FALSE;
- stream->error = NGHTTP2_NO_ERROR;
- stream->local_window_size = H2_STREAM_WINDOW_SIZE_INITIAL;
- stream->nrcvd_data = 0;
- return stream;
-}
-
-static void free_push_headers(struct h2_stream_ctx *stream)
-{
- size_t i;
- for(i = 0; i<stream->push_headers_used; i++)
- free(stream->push_headers[i]);
- Curl_safefree(stream->push_headers);
- stream->push_headers_used = 0;
-}
-
-static void h2_stream_ctx_free(struct h2_stream_ctx *stream)
-{
- Curl_bufq_free(&stream->sendbuf);
- Curl_h1_req_parse_free(&stream->h1);
- Curl_dynhds_free(&stream->resp_trailers);
- free_push_headers(stream);
- free(stream);
-}
-
-static void h2_stream_hash_free(void *stream)
-{
- DEBUGASSERT(stream);
- h2_stream_ctx_free((struct h2_stream_ctx *)stream);
-}
-
-#ifdef NGHTTP2_HAS_SET_LOCAL_WINDOW_SIZE
-static int32_t cf_h2_get_desired_local_win(struct Curl_cfilter *cf,
- struct Curl_easy *data)
-{
- (void)cf;
- if(data->set.max_recv_speed && data->set.max_recv_speed < INT32_MAX) {
- /* The transfer should only receive `max_recv_speed` bytes per second.
- * We restrict the stream's local window size, so that the server cannot
- * send us "too much" at a time.
- * This gets less precise the higher the latency. */
- return (int32_t)data->set.max_recv_speed;
- }
- return H2_STREAM_WINDOW_SIZE_MAX;
-}
-
-static CURLcode cf_h2_update_local_win(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- struct h2_stream_ctx *stream,
- bool paused)
-{
- struct cf_h2_ctx *ctx = cf->ctx;
- int32_t dwsize;
- int rv;
-
- dwsize = paused? 0 : cf_h2_get_desired_local_win(cf, data);
- if(dwsize != stream->local_window_size) {
- int32_t wsize = nghttp2_session_get_stream_effective_local_window_size(
- ctx->h2, stream->id);
- if(dwsize > wsize) {
- rv = nghttp2_submit_window_update(ctx->h2, NGHTTP2_FLAG_NONE,
- stream->id, dwsize - wsize);
- if(rv) {
- failf(data, "[%d] nghttp2_submit_window_update() failed: "
- "%s(%d)", stream->id, nghttp2_strerror(rv), rv);
- return CURLE_HTTP2;
- }
- stream->local_window_size = dwsize;
- CURL_TRC_CF(data, cf, "[%d] local window update by %d",
- stream->id, dwsize - wsize);
- }
- else {
- rv = nghttp2_session_set_local_window_size(ctx->h2, NGHTTP2_FLAG_NONE,
- stream->id, dwsize);
- if(rv) {
- failf(data, "[%d] nghttp2_session_set_local_window_size() failed: "
- "%s(%d)", stream->id, nghttp2_strerror(rv), rv);
- return CURLE_HTTP2;
- }
- stream->local_window_size = dwsize;
- CURL_TRC_CF(data, cf, "[%d] local window size now %d",
- stream->id, dwsize);
- }
- }
- return CURLE_OK;
-}
-
-#else /* NGHTTP2_HAS_SET_LOCAL_WINDOW_SIZE */
-
-static CURLcode cf_h2_update_local_win(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- struct h2_stream_ctx *stream,
- bool paused)
-{
- (void)cf;
- (void)data;
- (void)stream;
- (void)paused;
- return CURLE_OK;
-}
-#endif /* !NGHTTP2_HAS_SET_LOCAL_WINDOW_SIZE */
+#define H2_STREAM_CTX(d) ((struct stream_ctx *)(((d) && (d)->req.p.http)? \
+ ((struct HTTP *)(d)->req.p.http)->h2_ctx \
+ : NULL))
+#define H2_STREAM_LCTX(d) ((struct HTTP *)(d)->req.p.http)->h2_ctx
+#define H2_STREAM_ID(d) (H2_STREAM_CTX(d)? \
+ H2_STREAM_CTX(d)->id : -2)
/*
* Mark this transfer to get "drained".
*/
static void drain_stream(struct Curl_cfilter *cf,
struct Curl_easy *data,
- struct h2_stream_ctx *stream)
+ struct stream_ctx *stream)
{
unsigned char bits;
(void)cf;
bits = CURL_CSELECT_IN;
- if(!stream->closed &&
- (!stream->body_eos || !Curl_bufq_is_empty(&stream->sendbuf)))
+ if(!stream->send_closed &&
+ (stream->upload_left || stream->upload_blocked_len))
bits |= CURL_CSELECT_OUT;
- if(stream->closed || (data->state.select_bits != bits)) {
- CURL_TRC_CF(data, cf, "[%d] DRAIN select_bits=%x",
+ if(data->state.dselect_bits != bits) {
+ CURL_TRC_CF(data, cf, "[%d] DRAIN dselect_bits=%x",
stream->id, bits);
- data->state.select_bits = bits;
+ data->state.dselect_bits = bits;
Curl_expire(data, 0, EXPIRE_RUN_NOW);
}
}
static CURLcode http2_data_setup(struct Curl_cfilter *cf,
struct Curl_easy *data,
- struct h2_stream_ctx **pstream)
+ struct stream_ctx **pstream)
{
struct cf_h2_ctx *ctx = cf->ctx;
- struct h2_stream_ctx *stream;
+ struct stream_ctx *stream;
(void)cf;
DEBUGASSERT(data);
- stream = H2_STREAM_CTX(ctx, data);
+ if(!data->req.p.http) {
+ failf(data, "initialization failure, transfer not http initialized");
+ return CURLE_FAILED_INIT;
+ }
+ stream = H2_STREAM_CTX(data);
if(stream) {
*pstream = stream;
return CURLE_OK;
}
- stream = h2_stream_ctx_create(ctx);
+ stream = calloc(1, sizeof(*stream));
if(!stream)
return CURLE_OUT_OF_MEMORY;
- if(!Curl_hash_offt_set(&ctx->streams, data->mid, stream)) {
- h2_stream_ctx_free(stream);
- return CURLE_OUT_OF_MEMORY;
- }
+ stream->id = -1;
+ Curl_bufq_initp(&stream->sendbuf, &ctx->stream_bufcp,
+ H2_STREAM_SEND_CHUNKS, BUFQ_OPT_NONE);
+ Curl_bufq_initp(&stream->recvbuf, &ctx->stream_bufcp,
+ H2_STREAM_RECV_CHUNKS, BUFQ_OPT_SOFT_LIMIT);
+ Curl_h1_req_parse_init(&stream->h1, H1_PARSE_DEFAULT_MAX_LINE_LEN);
+ Curl_dynhds_init(&stream->resp_trailers, 0, DYN_HTTP_REQUEST);
+ stream->resp_hds_len = 0;
+ stream->bodystarted = FALSE;
+ stream->status_code = -1;
+ stream->closed = FALSE;
+ stream->close_handled = FALSE;
+ stream->error = NGHTTP2_NO_ERROR;
+ stream->local_window_size = H2_STREAM_WINDOW_SIZE;
+ stream->upload_left = 0;
+ H2_STREAM_LCTX(data) = stream;
*pstream = stream;
return CURLE_OK;
}
-static void http2_data_done(struct Curl_cfilter *cf, struct Curl_easy *data)
+static void http2_data_done(struct Curl_cfilter *cf,
+ struct Curl_easy *data, bool premature)
{
struct cf_h2_ctx *ctx = cf->ctx;
- struct h2_stream_ctx *stream = H2_STREAM_CTX(ctx, data);
+ struct stream_ctx *stream = H2_STREAM_CTX(data);
DEBUGASSERT(ctx);
- if(!stream || !ctx->initialized)
+ (void)premature;
+ if(!stream)
return;
if(ctx->h2) {
@@ -416,16 +293,41 @@ static void http2_data_done(struct Curl_cfilter *cf, struct Curl_easy *data)
stream->id);
stream->closed = TRUE;
stream->reset = TRUE;
+ stream->send_closed = TRUE;
nghttp2_submit_rst_stream(ctx->h2, NGHTTP2_FLAG_NONE,
stream->id, NGHTTP2_STREAM_CLOSED);
flush_egress = TRUE;
}
+ if(!Curl_bufq_is_empty(&stream->recvbuf)) {
+ /* Anything in the recvbuf is still being counted
+ * in stream and connection window flow control. Need
+ * to free that space or the connection window might get
+ * exhausted eventually. */
+ nghttp2_session_consume(ctx->h2, stream->id,
+ Curl_bufq_len(&stream->recvbuf));
+ /* give WINDOW_UPATE a chance to be sent, but ignore any error */
+ flush_egress = TRUE;
+ }
if(flush_egress)
nghttp2_session_send(ctx->h2);
}
- Curl_hash_offt_remove(&ctx->streams, data->mid);
+ Curl_bufq_free(&stream->sendbuf);
+ Curl_bufq_free(&stream->recvbuf);
+ Curl_h1_req_parse_free(&stream->h1);
+ Curl_dynhds_free(&stream->resp_trailers);
+ if(stream->push_headers) {
+ /* if they weren't used and then freed before */
+ for(; stream->push_headers_used > 0; --stream->push_headers_used) {
+ free(stream->push_headers[stream->push_headers_used - 1]);
+ }
+ free(stream->push_headers);
+ stream->push_headers = NULL;
+ }
+
+ free(stream);
+ H2_STREAM_LCTX(data) = NULL;
}
static int h2_client_new(struct Curl_cfilter *cf,
@@ -468,8 +370,8 @@ static ssize_t nw_out_writer(void *writer_ctx,
struct Curl_easy *data = CF_DATA_CURRENT(cf);
if(data) {
- ssize_t nwritten = Curl_conn_cf_send(cf->next, data, (const char *)buf,
- buflen, FALSE, err);
+ ssize_t nwritten = Curl_conn_cf_send(cf->next, data,
+ (const char *)buf, buflen, err);
if(nwritten > 0)
CURL_TRC_CF(data, cf, "[0] egress: wrote %zd bytes", nwritten);
return nwritten;
@@ -501,17 +403,24 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
static int error_callback(nghttp2_session *session, const char *msg,
size_t len, void *userp);
-static CURLcode cf_h2_ctx_open(struct Curl_cfilter *cf,
- struct Curl_easy *data)
+/*
+ * Initialize the cfilter context
+ */
+static CURLcode cf_h2_ctx_init(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ bool via_h1_upgrade)
{
struct cf_h2_ctx *ctx = cf->ctx;
- struct h2_stream_ctx *stream;
+ struct stream_ctx *stream;
CURLcode result = CURLE_OUT_OF_MEMORY;
int rc;
nghttp2_session_callbacks *cbs = NULL;
DEBUGASSERT(!ctx->h2);
- DEBUGASSERT(ctx->initialized);
+ Curl_bufcp_init(&ctx->stream_bufcp, H2_CHUNK_SIZE, H2_STREAM_POOL_SPARES);
+ Curl_bufq_initp(&ctx->inbufq, &ctx->stream_bufcp, H2_NW_RECV_CHUNKS, 0);
+ Curl_bufq_initp(&ctx->outbufq, &ctx->stream_bufcp, H2_NW_SEND_CHUNKS, 0);
+ ctx->last_stream_id = 2147483647;
rc = nghttp2_session_callbacks_new(&cbs);
if(rc) {
@@ -540,7 +449,7 @@ static CURLcode cf_h2_ctx_open(struct Curl_cfilter *cf,
}
ctx->max_concurrent_streams = DEFAULT_MAX_CONCURRENT_STREAMS;
- if(ctx->via_h1_upgrade) {
+ if(via_h1_upgrade) {
/* HTTP/1.1 Upgrade issued. H2 Settings have already been submitted
* in the H1 request and we upgrade from there. This stream
* is opened implicitly as #1. */
@@ -560,7 +469,7 @@ static CURLcode cf_h2_ctx_open(struct Curl_cfilter *cf,
DEBUGASSERT(stream);
stream->id = 1;
/* queue SETTINGS frame (again) */
- rc = nghttp2_session_upgrade2(ctx->h2, binsettings, (size_t)binlen,
+ rc = nghttp2_session_upgrade2(ctx->h2, binsettings, binlen,
data->state.httpreq == HTTPREQ_HEAD,
NULL);
if(rc) {
@@ -581,7 +490,7 @@ static CURLcode cf_h2_ctx_open(struct Curl_cfilter *cf,
}
else {
nghttp2_settings_entry iv[H2_SETTINGS_IV_LEN];
- size_t ivlen;
+ int ivlen;
ivlen = populate_settings(iv, data);
rc = nghttp2_submit_settings(ctx->h2, NGHTTP2_FLAG_NONE,
@@ -606,7 +515,7 @@ static CURLcode cf_h2_ctx_open(struct Curl_cfilter *cf,
/* all set, traffic will be send on connect */
result = CURLE_OK;
CURL_TRC_CF(data, cf, "[0] created h2 session%s",
- ctx->via_h1_upgrade? " (via h1 upgrade)" : "");
+ via_h1_upgrade? " (via h1 upgrade)" : "");
out:
if(cbs)
@@ -686,8 +595,8 @@ static bool http2_connisalive(struct Curl_cfilter *cf, struct Curl_easy *data,
return FALSE;
if(*input_pending) {
- /* This happens before we have sent off a request and the connection is
- not in use by any other transfer, there should not be any data here,
+ /* This happens before we've sent off a request and the connection is
+ not in use by any other transfer, there shouldn't be any data here,
only "protocol frames" */
CURLcode result;
ssize_t nread = -1;
@@ -809,7 +718,6 @@ static ssize_t send_callback(nghttp2_session *h2,
the struct are hidden from the user. */
struct curl_pushheaders {
struct Curl_easy *data;
- struct h2_stream_ctx *stream;
const nghttp2_push_promise *frame;
};
@@ -823,8 +731,9 @@ char *curl_pushheader_bynum(struct curl_pushheaders *h, size_t num)
if(!h || !GOOD_EASY_HANDLE(h->data))
return NULL;
else {
- if(h->stream && num < h->stream->push_headers_used)
- return h->stream->push_headers[num];
+ struct stream_ctx *stream = H2_STREAM_CTX(h->data);
+ if(stream && num < stream->push_headers_used)
+ return stream->push_headers[num];
}
return NULL;
}
@@ -834,7 +743,7 @@ char *curl_pushheader_bynum(struct curl_pushheaders *h, size_t num)
*/
char *curl_pushheader_byname(struct curl_pushheaders *h, const char *header)
{
- struct h2_stream_ctx *stream;
+ struct stream_ctx *stream;
size_t len;
size_t i;
/* Verify that we got a good easy handle in the push header struct,
@@ -847,7 +756,7 @@ char *curl_pushheader_byname(struct curl_pushheaders *h, const char *header)
!strcmp(header, ":") || strchr(header + 1, ':'))
return NULL;
- stream = h->stream;
+ stream = H2_STREAM_CTX(h->data);
if(!stream)
return NULL;
@@ -868,9 +777,18 @@ static struct Curl_easy *h2_duphandle(struct Curl_cfilter *cf,
{
struct Curl_easy *second = curl_easy_duphandle(data);
if(second) {
- struct h2_stream_ctx *second_stream;
- http2_data_setup(cf, second, &second_stream);
- second->state.priority.weight = data->state.priority.weight;
+ /* setup the request struct */
+ struct HTTP *http = calloc(1, sizeof(struct HTTP));
+ if(!http) {
+ (void)Curl_close(&second);
+ }
+ else {
+ struct stream_ctx *second_stream;
+
+ second->req.p.http = http;
+ http2_data_setup(cf, second, &second_stream);
+ second->state.priority.weight = data->state.priority.weight;
+ }
}
return second;
}
@@ -898,7 +816,7 @@ static int set_transfer_url(struct Curl_easy *data,
v = curl_pushheader_byname(hp, HTTP_PSEUDO_AUTHORITY);
if(v) {
- uc = Curl_url_set_authority(u, v);
+ uc = Curl_url_set_authority(u, v, CURLU_DISALLOW_USER);
if(uc) {
rc = 2;
goto fail;
@@ -932,7 +850,10 @@ fail:
static void discard_newhandle(struct Curl_cfilter *cf,
struct Curl_easy *newhandle)
{
- http2_data_done(cf, newhandle);
+ if(!newhandle->req.p.http) {
+ http2_data_done(cf, newhandle, TRUE);
+ newhandle->req.p.http = NULL;
+ }
(void)Curl_close(&newhandle);
}
@@ -946,11 +867,12 @@ static int push_promise(struct Curl_cfilter *cf,
CURL_TRC_CF(data, cf, "[%d] PUSH_PROMISE received",
frame->promised_stream_id);
if(data->multi->push_cb) {
- struct h2_stream_ctx *stream;
- struct h2_stream_ctx *newstream;
+ struct stream_ctx *stream;
+ struct stream_ctx *newstream;
struct curl_pushheaders heads;
CURLMcode rc;
CURLcode result;
+ size_t i;
/* clone the parent */
struct Curl_easy *newhandle = h2_duphandle(cf, data);
if(!newhandle) {
@@ -959,10 +881,12 @@ static int push_promise(struct Curl_cfilter *cf,
goto fail;
}
+ heads.data = data;
+ heads.frame = frame;
/* ask the application */
CURL_TRC_CF(data, cf, "Got PUSH_PROMISE, ask application");
- stream = H2_STREAM_CTX(ctx, data);
+ stream = H2_STREAM_CTX(data);
if(!stream) {
failf(data, "Internal NULL stream");
discard_newhandle(cf, newhandle);
@@ -970,10 +894,6 @@ static int push_promise(struct Curl_cfilter *cf,
goto fail;
}
- heads.data = data;
- heads.stream = stream;
- heads.frame = frame;
-
rv = set_transfer_url(newhandle, &heads);
if(rv) {
discard_newhandle(cf, newhandle);
@@ -997,7 +917,11 @@ static int push_promise(struct Curl_cfilter *cf,
Curl_set_in_callback(data, false);
/* free the headers again */
- free_push_headers(stream);
+ for(i = 0; i<stream->push_headers_used; i++)
+ free(stream->push_headers[i]);
+ free(stream->push_headers);
+ stream->push_headers = NULL;
+ stream->push_headers_used = 0;
if(rv) {
DEBUGASSERT((rv > CURL_PUSH_OK) && (rv <= CURL_PUSH_ERROROUT));
@@ -1030,10 +954,6 @@ static int push_promise(struct Curl_cfilter *cf,
rv = CURL_PUSH_DENY;
goto fail;
}
-
- /* success, remember max stream id processed */
- if(newstream->id > ctx->local_max_sid)
- ctx->local_max_sid = newstream->id;
}
else {
CURL_TRC_CF(data, cf, "Got PUSH_PROMISE, ignore it");
@@ -1043,43 +963,22 @@ fail:
return rv;
}
-static void h2_xfer_write_resp_hd(struct Curl_cfilter *cf,
+static CURLcode recvbuf_write_hds(struct Curl_cfilter *cf,
struct Curl_easy *data,
- struct h2_stream_ctx *stream,
- const char *buf, size_t blen, bool eos)
-{
-
- /* If we already encountered an error, skip further writes */
- if(!stream->xfer_result) {
- stream->xfer_result = Curl_xfer_write_resp_hd(data, buf, blen, eos);
- if(!stream->xfer_result && !eos)
- stream->xfer_result = cf_h2_update_local_win(cf, data, stream, FALSE);
- if(stream->xfer_result)
- CURL_TRC_CF(data, cf, "[%d] error %d writing %zu bytes of headers",
- stream->id, stream->xfer_result, blen);
- }
-}
-
-static void h2_xfer_write_resp(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- struct h2_stream_ctx *stream,
- const char *buf, size_t blen, bool eos)
+ const char *buf, size_t blen)
{
+ struct stream_ctx *stream = H2_STREAM_CTX(data);
+ ssize_t nwritten;
+ CURLcode result;
- /* If we already encountered an error, skip further writes */
- if(!stream->xfer_result)
- stream->xfer_result = Curl_xfer_write_resp(data, buf, blen, eos);
- if(!stream->xfer_result && !eos)
- stream->xfer_result = cf_h2_update_local_win(cf, data, stream, FALSE);
- /* If the transfer write is errored, we do not want any more data */
- if(stream->xfer_result) {
- struct cf_h2_ctx *ctx = cf->ctx;
- CURL_TRC_CF(data, cf, "[%d] error %d writing %zu bytes of data, "
- "RST-ing stream",
- stream->id, stream->xfer_result, blen);
- nghttp2_submit_rst_stream(ctx->h2, 0, stream->id,
- (uint32_t)NGHTTP2_ERR_CALLBACK_FAILURE);
- }
+ (void)cf;
+ nwritten = Curl_bufq_write(&stream->recvbuf,
+ (const unsigned char *)buf, blen, &result);
+ if(nwritten < 0)
+ return result;
+ stream->resp_hds_len += (size_t)nwritten;
+ DEBUGASSERT((size_t)nwritten == blen);
+ return CURLE_OK;
}
static CURLcode on_stream_frame(struct Curl_cfilter *cf,
@@ -1087,8 +986,10 @@ static CURLcode on_stream_frame(struct Curl_cfilter *cf,
const nghttp2_frame *frame)
{
struct cf_h2_ctx *ctx = cf->ctx;
- struct h2_stream_ctx *stream = H2_STREAM_CTX(ctx, data);
+ struct stream_ctx *stream = H2_STREAM_CTX(data);
int32_t stream_id = frame->hd.stream_id;
+ CURLcode result;
+ size_t rbuflen;
int rv;
if(!stream) {
@@ -1098,8 +999,9 @@ static CURLcode on_stream_frame(struct Curl_cfilter *cf,
switch(frame->hd.type) {
case NGHTTP2_DATA:
- CURL_TRC_CF(data, cf, "[%d] DATA, window=%d/%d",
- stream_id,
+ rbuflen = Curl_bufq_len(&stream->recvbuf);
+ CURL_TRC_CF(data, cf, "[%d] DATA, buffered=%zu, window=%d/%d",
+ stream_id, rbuflen,
nghttp2_session_get_stream_effective_recv_data_length(
ctx->h2, stream->id),
nghttp2_session_get_stream_effective_local_window_size(
@@ -1116,10 +1018,24 @@ static CURLcode on_stream_frame(struct Curl_cfilter *cf,
if(frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
drain_stream(cf, data, stream);
}
+ else if(rbuflen > stream->local_window_size) {
+ int32_t wsize = nghttp2_session_get_stream_local_window_size(
+ ctx->h2, stream->id);
+ if(wsize > 0 && (uint32_t)wsize != stream->local_window_size) {
+ /* H2 flow control is not absolute, as the server might not have the
+ * same view, yet. When we receive more than we want, we enforce
+ * the local window size again to make nghttp2 send WINDOW_UPATEs
+ * accordingly. */
+ nghttp2_session_set_local_window_size(ctx->h2,
+ NGHTTP2_FLAG_NONE,
+ stream->id,
+ stream->local_window_size);
+ }
+ }
break;
case NGHTTP2_HEADERS:
if(stream->bodystarted) {
- /* Only valid HEADERS after body started is trailer HEADERS. We
+ /* Only valid HEADERS after body started is trailer HEADERS. We
buffer them in on_header callback. */
break;
}
@@ -1136,7 +1052,9 @@ static CURLcode on_stream_frame(struct Curl_cfilter *cf,
stream->status_code = -1;
}
- h2_xfer_write_resp_hd(cf, data, stream, STRCONST("\r\n"), stream->closed);
+ result = recvbuf_write_hds(cf, data, STRCONST("\r\n"));
+ if(result)
+ return result;
if(stream->status_code / 100 != 1) {
stream->resp_hds_complete = TRUE;
@@ -1164,19 +1082,13 @@ static CURLcode on_stream_frame(struct Curl_cfilter *cf,
if(frame->rst_stream.error_code) {
stream->reset = TRUE;
}
+ stream->send_closed = TRUE;
drain_stream(cf, data, stream);
break;
case NGHTTP2_WINDOW_UPDATE:
- if(CURL_WANT_SEND(data) && Curl_bufq_is_empty(&stream->sendbuf)) {
- /* need more data, force processing of transfer */
+ if(CURL_WANT_SEND(data)) {
drain_stream(cf, data, stream);
}
- else if(!Curl_bufq_is_empty(&stream->sendbuf)) {
- /* resume the potentially suspended stream */
- rv = nghttp2_session_resume_data(ctx->h2, stream->id);
- if(nghttp2_is_fatal(rv))
- return CURLE_SEND_ERROR;
- }
break;
default:
break;
@@ -1321,7 +1233,7 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
* servers send an explicit WINDOW_UPDATE, but not all seem to do that.
* To be safe, we UNHOLD a stream in order not to stall. */
if(CURL_WANT_SEND(data)) {
- struct h2_stream_ctx *stream = H2_STREAM_CTX(ctx, data);
+ struct stream_ctx *stream = H2_STREAM_CTX(data);
if(stream)
drain_stream(cf, data, stream);
}
@@ -1329,12 +1241,12 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
break;
}
case NGHTTP2_GOAWAY:
- ctx->rcvd_goaway = TRUE;
+ ctx->goaway = TRUE;
ctx->goaway_error = frame->goaway.error_code;
- ctx->remote_max_sid = frame->goaway.last_stream_id;
+ ctx->last_stream_id = frame->goaway.last_stream_id;
if(data) {
- infof(data, "received GOAWAY, error=%u, last_stream=%u",
- ctx->goaway_error, ctx->remote_max_sid);
+ infof(data, "received GOAWAY, error=%d, last_stream=%u",
+ ctx->goaway_error, ctx->last_stream_id);
Curl_multi_connchanged(data->multi);
}
break;
@@ -1358,9 +1270,10 @@ static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags,
const uint8_t *mem, size_t len, void *userp)
{
struct Curl_cfilter *cf = userp;
- struct cf_h2_ctx *ctx = cf->ctx;
- struct h2_stream_ctx *stream;
+ struct stream_ctx *stream;
struct Curl_easy *data_s;
+ ssize_t nwritten;
+ CURLcode result;
(void)flags;
DEBUGASSERT(stream_id); /* should never be a zero stream ID here */
@@ -1379,14 +1292,22 @@ static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags,
return 0;
}
- stream = H2_STREAM_CTX(ctx, data_s);
+ stream = H2_STREAM_CTX(data_s);
if(!stream)
return NGHTTP2_ERR_CALLBACK_FAILURE;
- h2_xfer_write_resp(cf, data_s, stream, (char *)mem, len, FALSE);
+ nwritten = Curl_bufq_write(&stream->recvbuf, mem, len, &result);
+ if(nwritten < 0) {
+ if(result != CURLE_AGAIN)
+ return NGHTTP2_ERR_CALLBACK_FAILURE;
+
+ nwritten = 0;
+ }
+
+ /* if we receive data for another handle, wake that up */
+ drain_stream(cf, data_s, stream);
- nghttp2_session_consume(ctx->h2, stream_id, len);
- stream->nrcvd_data += (curl_off_t)len;
+ DEBUGASSERT((size_t)nwritten == len);
return 0;
}
@@ -1394,14 +1315,14 @@ static int on_stream_close(nghttp2_session *session, int32_t stream_id,
uint32_t error_code, void *userp)
{
struct Curl_cfilter *cf = userp;
- struct cf_h2_ctx *ctx = cf->ctx;
struct Curl_easy *data_s, *call_data = CF_DATA_CURRENT(cf);
- struct h2_stream_ctx *stream;
+ struct stream_ctx *stream;
int rv;
(void)session;
DEBUGASSERT(call_data);
- /* stream id 0 is the connection, do not look there for streams. */
+ /* get the stream from the hash based on Stream ID, stream ID zero is for
+ connection-oriented stuff */
data_s = stream_id?
nghttp2_session_get_stream_user_data(session, stream_id) : NULL;
if(!data_s) {
@@ -1418,7 +1339,7 @@ static int on_stream_close(nghttp2_session *session, int32_t stream_id,
(void)nghttp2_session_set_stream_user_data(session, stream_id, 0);
return NGHTTP2_ERR_CALLBACK_FAILURE;
}
- stream = H2_STREAM_CTX(ctx, data_s);
+ stream = H2_STREAM_CTX(data_s);
if(!stream) {
CURL_TRC_CF(data_s, cf,
"[%d] on_stream_close, GOOD easy but no stream", stream_id);
@@ -1429,6 +1350,7 @@ static int on_stream_close(nghttp2_session *session, int32_t stream_id,
stream->error = error_code;
if(stream->error) {
stream->reset = TRUE;
+ stream->send_closed = TRUE;
}
if(stream->error)
@@ -1452,8 +1374,7 @@ static int on_begin_headers(nghttp2_session *session,
const nghttp2_frame *frame, void *userp)
{
struct Curl_cfilter *cf = userp;
- struct cf_h2_ctx *ctx = cf->ctx;
- struct h2_stream_ctx *stream;
+ struct stream_ctx *stream;
struct Curl_easy *data_s = NULL;
(void)cf;
@@ -1466,7 +1387,7 @@ static int on_begin_headers(nghttp2_session *session,
return 0;
}
- stream = H2_STREAM_CTX(ctx, data_s);
+ stream = H2_STREAM_CTX(data_s);
if(!stream || !stream->bodystarted) {
return 0;
}
@@ -1482,8 +1403,7 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
void *userp)
{
struct Curl_cfilter *cf = userp;
- struct cf_h2_ctx *ctx = cf->ctx;
- struct h2_stream_ctx *stream;
+ struct stream_ctx *stream;
struct Curl_easy *data_s;
int32_t stream_id = frame->hd.stream_id;
CURLcode result;
@@ -1498,7 +1418,7 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
internal error more than anything else! */
return NGHTTP2_ERR_CALLBACK_FAILURE;
- stream = H2_STREAM_CTX(ctx, data_s);
+ stream = H2_STREAM_CTX(data_s);
if(!stream) {
failf(data_s, "Internal NULL stream");
return NGHTTP2_ERR_CALLBACK_FAILURE;
@@ -1539,7 +1459,7 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
stream->push_headers = malloc(stream->push_headers_alloc *
sizeof(char *));
if(!stream->push_headers)
- return NGHTTP2_ERR_CALLBACK_FAILURE;
+ return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
stream->push_headers_used = 0;
}
else if(stream->push_headers_used ==
@@ -1548,15 +1468,15 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
if(stream->push_headers_alloc > 1000) {
/* this is beyond crazy many headers, bail out */
failf(data_s, "Too many PUSH_PROMISE headers");
- free_push_headers(stream);
- return NGHTTP2_ERR_CALLBACK_FAILURE;
+ Curl_safefree(stream->push_headers);
+ return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
}
stream->push_headers_alloc *= 2;
- headp = realloc(stream->push_headers,
- stream->push_headers_alloc * sizeof(char *));
+ headp = Curl_saferealloc(stream->push_headers,
+ stream->push_headers_alloc * sizeof(char *));
if(!headp) {
- free_push_headers(stream);
- return NGHTTP2_ERR_CALLBACK_FAILURE;
+ stream->push_headers = NULL;
+ return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
}
stream->push_headers = headp;
}
@@ -1592,15 +1512,14 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
result = Curl_headers_push(data_s, buffer, CURLH_PSEUDO);
if(result)
return NGHTTP2_ERR_CALLBACK_FAILURE;
- Curl_dyn_reset(&ctx->scratch);
- result = Curl_dyn_addn(&ctx->scratch, STRCONST("HTTP/2 "));
- if(!result)
- result = Curl_dyn_addn(&ctx->scratch, value, valuelen);
- if(!result)
- result = Curl_dyn_addn(&ctx->scratch, STRCONST(" \r\n"));
- if(!result)
- h2_xfer_write_resp_hd(cf, data_s, stream, Curl_dyn_ptr(&ctx->scratch),
- Curl_dyn_len(&ctx->scratch), FALSE);
+ result = recvbuf_write_hds(cf, data_s, STRCONST("HTTP/2 "));
+ if(result)
+ return NGHTTP2_ERR_CALLBACK_FAILURE;
+ result = recvbuf_write_hds(cf, data_s, (const char *)value, valuelen);
+ if(result)
+ return NGHTTP2_ERR_CALLBACK_FAILURE;
+ /* the space character after the status code is mandatory */
+ result = recvbuf_write_hds(cf, data_s, STRCONST(" \r\n"));
if(result)
return NGHTTP2_ERR_CALLBACK_FAILURE;
/* if we receive data for another handle, wake that up */
@@ -1615,17 +1534,16 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
/* nghttp2 guarantees that namelen > 0, and :status was already
received, and this is not pseudo-header field . */
/* convert to an HTTP1-style header */
- Curl_dyn_reset(&ctx->scratch);
- result = Curl_dyn_addn(&ctx->scratch, (const char *)name, namelen);
- if(!result)
- result = Curl_dyn_addn(&ctx->scratch, STRCONST(": "));
- if(!result)
- result = Curl_dyn_addn(&ctx->scratch, (const char *)value, valuelen);
- if(!result)
- result = Curl_dyn_addn(&ctx->scratch, STRCONST("\r\n"));
- if(!result)
- h2_xfer_write_resp_hd(cf, data_s, stream, Curl_dyn_ptr(&ctx->scratch),
- Curl_dyn_len(&ctx->scratch), FALSE);
+ result = recvbuf_write_hds(cf, data_s, (const char *)name, namelen);
+ if(result)
+ return NGHTTP2_ERR_CALLBACK_FAILURE;
+ result = recvbuf_write_hds(cf, data_s, STRCONST(": "));
+ if(result)
+ return NGHTTP2_ERR_CALLBACK_FAILURE;
+ result = recvbuf_write_hds(cf, data_s, (const char *)value, valuelen);
+ if(result)
+ return NGHTTP2_ERR_CALLBACK_FAILURE;
+ result = recvbuf_write_hds(cf, data_s, STRCONST("\r\n"));
if(result)
return NGHTTP2_ERR_CALLBACK_FAILURE;
/* if we receive data for another handle, wake that up */
@@ -1646,28 +1564,28 @@ static ssize_t req_body_read_callback(nghttp2_session *session,
void *userp)
{
struct Curl_cfilter *cf = userp;
- struct cf_h2_ctx *ctx = cf->ctx;
struct Curl_easy *data_s;
- struct h2_stream_ctx *stream = NULL;
+ struct stream_ctx *stream = NULL;
CURLcode result;
ssize_t nread;
(void)source;
(void)cf;
- if(!stream_id)
- return NGHTTP2_ERR_INVALID_ARGUMENT;
-
- /* get the stream from the hash based on Stream ID, stream ID zero is for
- connection-oriented stuff */
- data_s = nghttp2_session_get_stream_user_data(session, stream_id);
- if(!data_s)
- /* Receiving a Stream ID not in the hash should not happen, this is an
- internal error more than anything else! */
- return NGHTTP2_ERR_CALLBACK_FAILURE;
+ if(stream_id) {
+ /* get the stream from the hash based on Stream ID, stream ID zero is for
+ connection-oriented stuff */
+ data_s = nghttp2_session_get_stream_user_data(session, stream_id);
+ if(!data_s)
+ /* Receiving a Stream ID not in the hash should not happen, this is an
+ internal error more than anything else! */
+ return NGHTTP2_ERR_CALLBACK_FAILURE;
- stream = H2_STREAM_CTX(ctx, data_s);
- if(!stream)
- return NGHTTP2_ERR_CALLBACK_FAILURE;
+ stream = H2_STREAM_CTX(data_s);
+ if(!stream)
+ return NGHTTP2_ERR_CALLBACK_FAILURE;
+ }
+ else
+ return NGHTTP2_ERR_INVALID_ARGUMENT;
nread = Curl_bufq_read(&stream->sendbuf, buf, length, &result);
if(nread < 0) {
@@ -1676,14 +1594,19 @@ static ssize_t req_body_read_callback(nghttp2_session *session,
nread = 0;
}
- CURL_TRC_CF(data_s, cf, "[%d] req_body_read(len=%zu) eos=%d -> %zd, %d",
- stream_id, length, stream->body_eos, nread, result);
+ if(nread > 0 && stream->upload_left != -1)
+ stream->upload_left -= nread;
- if(stream->body_eos && Curl_bufq_is_empty(&stream->sendbuf)) {
+ CURL_TRC_CF(data_s, cf, "[%d] req_body_read(len=%zu) left=%"
+ CURL_FORMAT_CURL_OFF_T " -> %zd, %d",
+ stream_id, length, stream->upload_left, nread, result);
+
+ if(stream->upload_left == 0)
*data_flags = NGHTTP2_DATA_FLAG_EOF;
- return nread;
- }
- return (nread == 0)? NGHTTP2_ERR_DEFERRED : nread;
+ else if(nread == 0)
+ return NGHTTP2_ERR_DEFERRED;
+
+ return nread;
}
#if !defined(CURL_DISABLE_VERBOSE_STRINGS)
@@ -1720,7 +1643,7 @@ CURLcode Curl_http2_request_upgrade(struct dynbuf *req,
return CURLE_FAILED_INIT;
}
- result = Curl_base64url_encode((const char *)binsettings, (size_t)binlen,
+ result = Curl_base64url_encode((const char *)binsettings, binlen,
&base64, &blen);
if(result) {
Curl_dyn_free(req);
@@ -1735,14 +1658,40 @@ CURLcode Curl_http2_request_upgrade(struct dynbuf *req,
free(base64);
k->upgr101 = UPGR101_H2;
- data->conn->bits.asks_multiplex = TRUE;
return result;
}
+static CURLcode http2_data_done_send(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
+{
+ struct cf_h2_ctx *ctx = cf->ctx;
+ CURLcode result = CURLE_OK;
+ struct stream_ctx *stream = H2_STREAM_CTX(data);
+
+ if(!ctx || !ctx->h2 || !stream)
+ goto out;
+
+ CURL_TRC_CF(data, cf, "[%d] data done send", stream->id);
+ if(!stream->send_closed) {
+ stream->send_closed = TRUE;
+ if(stream->upload_left) {
+ /* we now know that everything that is buffered is all there is. */
+ stream->upload_left = Curl_bufq_len(&stream->sendbuf);
+ /* resume sending here to trigger the callback to get called again so
+ that it can signal EOF to nghttp2 */
+ (void)nghttp2_session_resume_data(ctx->h2, stream->id);
+ drain_stream(cf, data, stream);
+ }
+ }
+
+out:
+ return result;
+}
+
static ssize_t http2_handle_stream_close(struct Curl_cfilter *cf,
struct Curl_easy *data,
- struct h2_stream_ctx *stream,
+ struct stream_ctx *stream,
CURLcode *err)
{
ssize_t rv = 0;
@@ -1750,21 +1699,12 @@ static ssize_t http2_handle_stream_close(struct Curl_cfilter *cf,
if(stream->error == NGHTTP2_REFUSED_STREAM) {
CURL_TRC_CF(data, cf, "[%d] REFUSED_STREAM, try again on a new "
"connection", stream->id);
- connclose(cf->conn, "REFUSED_STREAM"); /* do not use this anymore */
+ connclose(cf->conn, "REFUSED_STREAM"); /* don't use this anymore */
data->state.refused_stream = TRUE;
*err = CURLE_RECV_ERROR; /* trigger Curl_retry_request() later */
return -1;
}
else if(stream->error != NGHTTP2_NO_ERROR) {
- if(stream->resp_hds_complete && data->req.no_body) {
- CURL_TRC_CF(data, cf, "[%d] error after response headers, but we did "
- "not want a body anyway, ignore: %s (err %u)",
- stream->id, nghttp2_http2_strerror(stream->error),
- stream->error);
- stream->close_handled = TRUE;
- *err = CURLE_OK;
- goto out;
- }
failf(data, "HTTP/2 stream %u was not closed cleanly: %s (err %u)",
stream->id, nghttp2_http2_strerror(stream->error),
stream->error);
@@ -1773,7 +1713,7 @@ static ssize_t http2_handle_stream_close(struct Curl_cfilter *cf,
}
else if(stream->reset) {
failf(data, "HTTP/2 stream %u was reset", stream->id);
- *err = data->req.bytecount? CURLE_PARTIAL_FILE : CURLE_HTTP2;
+ *err = stream->bodystarted? CURLE_PARTIAL_FILE : CURLE_RECV_ERROR;
return -1;
}
@@ -1843,12 +1783,11 @@ static int sweight_in_effect(const struct Curl_easy *data)
* struct.
*/
-static void h2_pri_spec(struct cf_h2_ctx *ctx,
- struct Curl_easy *data,
+static void h2_pri_spec(struct Curl_easy *data,
nghttp2_priority_spec *pri_spec)
{
struct Curl_data_priority *prio = &data->set.priority;
- struct h2_stream_ctx *depstream = H2_STREAM_CTX(ctx, prio->parent);
+ struct stream_ctx *depstream = H2_STREAM_CTX(prio->parent);
int32_t depstream_id = depstream? depstream->id:0;
nghttp2_priority_spec_init(pri_spec, depstream_id,
sweight_wanted(data),
@@ -1857,7 +1796,7 @@ static void h2_pri_spec(struct cf_h2_ctx *ctx,
}
/*
- * Check if there is been an update in the priority /
+ * Check if there's been an update in the priority /
* dependency settings and if so it submits a PRIORITY frame with the updated
* info.
* Flush any out data pending in the network buffer.
@@ -1866,7 +1805,7 @@ static CURLcode h2_progress_egress(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
struct cf_h2_ctx *ctx = cf->ctx;
- struct h2_stream_ctx *stream = H2_STREAM_CTX(ctx, data);
+ struct stream_ctx *stream = H2_STREAM_CTX(data);
int rv = 0;
if(stream && stream->id > 0 &&
@@ -1876,7 +1815,7 @@ static CURLcode h2_progress_egress(struct Curl_cfilter *cf,
/* send new weight and/or dependency */
nghttp2_priority_spec pri_spec;
- h2_pri_spec(ctx, data, &pri_spec);
+ h2_pri_spec(data, &pri_spec);
CURL_TRC_CF(data, cf, "[%d] Queuing PRIORITY", stream->id);
DEBUGASSERT(stream->id != -1);
rv = nghttp2_submit_priority(ctx->h2, NGHTTP2_FLAG_NONE,
@@ -1899,31 +1838,40 @@ out:
}
static ssize_t stream_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
- struct h2_stream_ctx *stream,
+ struct stream_ctx *stream,
char *buf, size_t len, CURLcode *err)
{
struct cf_h2_ctx *ctx = cf->ctx;
ssize_t nread = -1;
- (void)buf;
*err = CURLE_AGAIN;
- if(stream->xfer_result) {
- CURL_TRC_CF(data, cf, "[%d] xfer write failed", stream->id);
- *err = stream->xfer_result;
- nread = -1;
+ if(!Curl_bufq_is_empty(&stream->recvbuf)) {
+ nread = Curl_bufq_read(&stream->recvbuf,
+ (unsigned char *)buf, len, err);
+ if(nread < 0)
+ goto out;
+ DEBUGASSERT(nread > 0);
}
- else if(stream->closed) {
- CURL_TRC_CF(data, cf, "[%d] returning CLOSE", stream->id);
- nread = http2_handle_stream_close(cf, data, stream, err);
+
+ if(nread < 0) {
+ if(stream->closed) {
+ CURL_TRC_CF(data, cf, "[%d] returning CLOSE", stream->id);
+ nread = http2_handle_stream_close(cf, data, stream, err);
+ }
+ else if(stream->reset ||
+ (ctx->conn_closed && Curl_bufq_is_empty(&ctx->inbufq)) ||
+ (ctx->goaway && ctx->last_stream_id < stream->id)) {
+ CURL_TRC_CF(data, cf, "[%d] returning ERR", stream->id);
+ *err = stream->bodystarted? CURLE_PARTIAL_FILE : CURLE_RECV_ERROR;
+ nread = -1;
+ }
}
- else if(stream->reset ||
- (ctx->conn_closed && Curl_bufq_is_empty(&ctx->inbufq)) ||
- (ctx->rcvd_goaway && ctx->remote_max_sid < stream->id)) {
- CURL_TRC_CF(data, cf, "[%d] returning ERR", stream->id);
- *err = data->req.bytecount? CURLE_PARTIAL_FILE : CURLE_HTTP2;
+ else if(nread == 0) {
+ *err = CURLE_AGAIN;
nread = -1;
}
+out:
if(nread < 0 && *err != CURLE_AGAIN)
CURL_TRC_CF(data, cf, "[%d] stream_recv(len=%zu) -> %zd, %d",
stream->id, len, nread, *err);
@@ -1931,11 +1879,10 @@ static ssize_t stream_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
}
static CURLcode h2_progress_ingress(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- size_t data_max_bytes)
+ struct Curl_easy *data)
{
struct cf_h2_ctx *ctx = cf->ctx;
- struct h2_stream_ctx *stream;
+ struct stream_ctx *stream;
CURLcode result = CURLE_OK;
ssize_t nread;
@@ -1951,18 +1898,17 @@ static CURLcode h2_progress_ingress(struct Curl_cfilter *cf,
* it is time to stop due to connection close or us not processing
* all network input */
while(!ctx->conn_closed && Curl_bufq_is_empty(&ctx->inbufq)) {
- stream = H2_STREAM_CTX(ctx, data);
- if(stream && (stream->closed || !data_max_bytes)) {
+ stream = H2_STREAM_CTX(data);
+ if(stream && (stream->closed || Curl_bufq_is_full(&stream->recvbuf))) {
/* We would like to abort here and stop processing, so that
* the transfer loop can handle the data/close here. However,
* this may leave data in underlying buffers that will not
* be consumed. */
if(!cf->next || !cf->next->cft->has_data_pending(cf->next, data))
- drain_stream(cf, data, stream);
- break;
+ break;
}
- nread = Curl_bufq_sipn(&ctx->inbufq, 0, nw_in_reader, cf, &result);
+ nread = Curl_bufq_slurp(&ctx->inbufq, nw_in_reader, cf, &result);
if(nread < 0) {
if(result != CURLE_AGAIN) {
failf(data, "Failed receiving HTTP2 data: %d(%s)", result,
@@ -1977,22 +1923,18 @@ static CURLcode h2_progress_ingress(struct Curl_cfilter *cf,
break;
}
else {
- CURL_TRC_CF(data, cf, "[0] ingress: read %zd bytes", nread);
- data_max_bytes = (data_max_bytes > (size_t)nread)?
- (data_max_bytes - (size_t)nread) : 0;
+ CURL_TRC_CF(data, cf, "[0] ingress: read %zd bytes",
+ nread);
}
if(h2_process_pending_input(cf, data, &result))
return result;
- CURL_TRC_CF(data, cf, "[0] progress ingress: inbufg=%zu",
- Curl_bufq_len(&ctx->inbufq));
}
if(ctx->conn_closed && Curl_bufq_is_empty(&ctx->inbufq)) {
connclose(cf->conn, "GOAWAY received");
}
- CURL_TRC_CF(data, cf, "[0] progress ingress: done");
return CURLE_OK;
}
@@ -2000,7 +1942,7 @@ static ssize_t cf_h2_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
char *buf, size_t len, CURLcode *err)
{
struct cf_h2_ctx *ctx = cf->ctx;
- struct h2_stream_ctx *stream = H2_STREAM_CTX(ctx, data);
+ struct stream_ctx *stream = H2_STREAM_CTX(data);
ssize_t nread = -1;
CURLcode result;
struct cf_call_data save;
@@ -2010,8 +1952,9 @@ static ssize_t cf_h2_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
* (unlikely) or the transfer has been done, cleaned up its resources, but
* a read() is called anyway. It is not clear what the calling sequence
* is for such a case. */
- failf(data, "http/2 recv on a transfer never opened "
- "or already cleared, mid=%" FMT_OFF_T, data->mid);
+ failf(data, "[%zd-%zd], http/2 recv on a transfer never opened "
+ "or already cleared", (ssize_t)data->id,
+ (ssize_t)cf->conn->connection_id);
*err = CURLE_HTTP2;
return -1;
}
@@ -2023,7 +1966,7 @@ static ssize_t cf_h2_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
goto out;
if(nread < 0) {
- *err = h2_progress_ingress(cf, data, len);
+ *err = h2_progress_ingress(cf, data);
if(*err)
goto out;
@@ -2057,19 +2000,20 @@ static ssize_t cf_h2_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
out:
result = h2_progress_egress(cf, data);
if(result == CURLE_AGAIN) {
- /* pending data to send, need to be called again. Ideally, we
- * monitor the socket for POLLOUT, but when not SENDING
- * any more, we force processing of the transfer. */
- if(!CURL_WANT_SEND(data))
- drain_stream(cf, data, stream);
+ /* pending data to send, need to be called again. Ideally, we'd
+ * monitor the socket for POLLOUT, but we might not be in SENDING
+ * transfer state any longer and are unable to make this happen.
+ */
+ drain_stream(cf, data, stream);
}
else if(result) {
*err = result;
nread = -1;
}
CURL_TRC_CF(data, cf, "[%d] cf_recv(len=%zu) -> %zd %d, "
- "window=%d/%d, connection %d/%d",
+ "buffered=%zu, window=%d/%d, connection %d/%d",
stream->id, len, nread, *err,
+ Curl_bufq_len(&stream->recvbuf),
nghttp2_session_get_stream_effective_recv_data_length(
ctx->h2, stream->id),
nghttp2_session_get_stream_effective_local_window_size(
@@ -2081,60 +2025,12 @@ out:
return nread;
}
-static ssize_t cf_h2_body_send(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- struct h2_stream_ctx *stream,
- const void *buf, size_t blen, bool eos,
- CURLcode *err)
-{
- struct cf_h2_ctx *ctx = cf->ctx;
- ssize_t nwritten;
-
- if(stream->closed) {
- if(stream->resp_hds_complete) {
- /* Server decided to close the stream after having sent us a final
- * response. This is valid if it is not interested in the request
- * body. This happens on 30x or 40x responses.
- * We silently discard the data sent, since this is not a transport
- * error situation. */
- CURL_TRC_CF(data, cf, "[%d] discarding data"
- "on closed stream with response", stream->id);
- if(eos)
- stream->body_eos = TRUE;
- *err = CURLE_OK;
- return (ssize_t)blen;
- }
- /* Server closed before we got a response, this is an error */
- infof(data, "stream %u closed", stream->id);
- *err = CURLE_SEND_ERROR;
- return -1;
- }
-
- nwritten = Curl_bufq_write(&stream->sendbuf, buf, blen, err);
- if(nwritten < 0)
- return -1;
-
- if(eos && (blen == (size_t)nwritten))
- stream->body_eos = TRUE;
-
- if(eos || !Curl_bufq_is_empty(&stream->sendbuf)) {
- /* resume the potentially suspended stream */
- int rv = nghttp2_session_resume_data(ctx->h2, stream->id);
- if(nghttp2_is_fatal(rv)) {
- *err = CURLE_SEND_ERROR;
- return -1;
- }
- }
- return nwritten;
-}
-
-static ssize_t h2_submit(struct h2_stream_ctx **pstream,
+static ssize_t h2_submit(struct stream_ctx **pstream,
struct Curl_cfilter *cf, struct Curl_easy *data,
- const void *buf, size_t len,
- bool eos, CURLcode *err)
+ const void *buf, size_t len, CURLcode *err)
{
struct cf_h2_ctx *ctx = cf->ctx;
- struct h2_stream_ctx *stream = NULL;
+ struct stream_ctx *stream = NULL;
struct dynhds h2_headers;
nghttp2_nv *nva = NULL;
const void *body = NULL;
@@ -2176,7 +2072,7 @@ static ssize_t h2_submit(struct h2_stream_ctx **pstream,
goto out;
}
- h2_pri_spec(ctx, data, &pri_spec);
+ h2_pri_spec(data, &pri_spec);
if(!nghttp2_session_check_request_allowed(ctx->h2))
CURL_TRC_CF(data, cf, "send request NOT allowed (via nghttp2)");
@@ -2185,12 +2081,19 @@ static ssize_t h2_submit(struct h2_stream_ctx **pstream,
case HTTPREQ_POST_FORM:
case HTTPREQ_POST_MIME:
case HTTPREQ_PUT:
+ if(data->state.infilesize != -1)
+ stream->upload_left = data->state.infilesize;
+ else
+ /* data sending without specifying the data amount up front */
+ stream->upload_left = -1; /* unknown */
+
data_prd.read_callback = req_body_read_callback;
data_prd.source.ptr = NULL;
stream_id = nghttp2_submit_request(ctx->h2, &pri_spec, nva, nheader,
&data_prd, data);
break;
default:
+ stream->upload_left = 0; /* no request body */
stream_id = nghttp2_submit_request(ctx->h2, &pri_spec, nva, nheader,
NULL, data);
}
@@ -2225,21 +2128,32 @@ static ssize_t h2_submit(struct h2_stream_ctx **pstream,
}
stream->id = stream_id;
+ stream->local_window_size = H2_STREAM_WINDOW_SIZE;
+ if(data->set.max_recv_speed) {
+ /* We are asked to only receive `max_recv_speed` bytes per second.
+ * Let's limit our stream window size around that, otherwise the server
+ * will send in large bursts only. We make the window 50% larger to
+ * allow for data in flight and avoid stalling. */
+ curl_off_t n = (((data->set.max_recv_speed - 1) / H2_CHUNK_SIZE) + 1);
+ n += CURLMAX((n/2), 1);
+ if(n < (H2_STREAM_WINDOW_SIZE / H2_CHUNK_SIZE) &&
+ n < (UINT_MAX / H2_CHUNK_SIZE)) {
+ stream->local_window_size = (uint32_t)n * H2_CHUNK_SIZE;
+ }
+ }
body = (const char *)buf + nwritten;
bodylen = len - nwritten;
- if(bodylen || eos) {
- ssize_t n = cf_h2_body_send(cf, data, stream, body, bodylen, eos, err);
- if(n >= 0)
- nwritten += n;
- else if(*err == CURLE_AGAIN)
- *err = CURLE_OK;
- else if(*err != CURLE_AGAIN) {
+ if(bodylen) {
+ /* We have request body to send in DATA frame */
+ ssize_t n = Curl_bufq_write(&stream->sendbuf, body, bodylen, err);
+ if(n < 0) {
*err = CURLE_SEND_ERROR;
nwritten = -1;
goto out;
}
+ nwritten += n;
}
out:
@@ -2252,63 +2166,129 @@ out:
}
static ssize_t cf_h2_send(struct Curl_cfilter *cf, struct Curl_easy *data,
- const void *buf, size_t len, bool eos,
- CURLcode *err)
+ const void *buf, size_t len, CURLcode *err)
{
struct cf_h2_ctx *ctx = cf->ctx;
- struct h2_stream_ctx *stream = H2_STREAM_CTX(ctx, data);
+ struct stream_ctx *stream = H2_STREAM_CTX(data);
struct cf_call_data save;
+ int rv;
ssize_t nwritten;
CURLcode result;
+ int blocked = 0, was_blocked = 0;
CF_DATA_SAVE(save, cf, data);
- if(!stream || stream->id == -1) {
- nwritten = h2_submit(&stream, cf, data, buf, len, eos, err);
- if(nwritten < 0) {
+ if(stream && stream->id != -1) {
+ if(stream->upload_blocked_len) {
+ /* the data in `buf` has already been submitted or added to the
+ * buffers, but have been EAGAINed on the last invocation. */
+ /* TODO: this assertion triggers in OSSFuzz runs and it is not
+ * clear why. Disable for now to let OSSFuzz continue its tests. */
+ DEBUGASSERT(len >= stream->upload_blocked_len);
+ if(len < stream->upload_blocked_len) {
+ /* Did we get called again with a smaller `len`? This should not
+ * happen. We are not prepared to handle that. */
+ failf(data, "HTTP/2 send again with decreased length (%zd vs %zd)",
+ len, stream->upload_blocked_len);
+ *err = CURLE_HTTP2;
+ nwritten = -1;
+ goto out;
+ }
+ nwritten = (ssize_t)stream->upload_blocked_len;
+ stream->upload_blocked_len = 0;
+ was_blocked = 1;
+ }
+ else if(stream->closed) {
+ if(stream->resp_hds_complete) {
+ /* Server decided to close the stream after having sent us a findl
+ * response. This is valid if it is not interested in the request
+ * body. This happens on 30x or 40x responses.
+ * We silently discard the data sent, since this is not a transport
+ * error situation. */
+ CURL_TRC_CF(data, cf, "[%d] discarding data"
+ "on closed stream with response", stream->id);
+ *err = CURLE_OK;
+ nwritten = (ssize_t)len;
+ goto out;
+ }
+ infof(data, "stream %u closed", stream->id);
+ *err = CURLE_SEND_ERROR;
+ nwritten = -1;
goto out;
}
- DEBUGASSERT(stream);
+ else {
+ /* If stream_id != -1, we have dispatched request HEADERS and
+ * optionally request body, and now are going to send or sending
+ * more request body in DATA frame */
+ nwritten = Curl_bufq_write(&stream->sendbuf, buf, len, err);
+ if(nwritten < 0 && *err != CURLE_AGAIN)
+ goto out;
+ }
+
+ if(!Curl_bufq_is_empty(&stream->sendbuf)) {
+ /* req body data is buffered, resume the potentially suspended stream */
+ rv = nghttp2_session_resume_data(ctx->h2, stream->id);
+ if(nghttp2_is_fatal(rv)) {
+ *err = CURLE_SEND_ERROR;
+ nwritten = -1;
+ goto out;
+ }
+ }
}
- else if(stream->body_eos) {
- /* We already wrote this, but CURLE_AGAINed the call due to not
- * being able to flush stream->sendbuf. Make a 0-length write
- * to trigger flushing again.
- * If this works, we report to have written `len` bytes. */
- DEBUGASSERT(eos);
- nwritten = cf_h2_body_send(cf, data, stream, buf, 0, eos, err);
- CURL_TRC_CF(data, cf, "[%d] cf_body_send last CHUNK -> %zd, %d, eos=%d",
- stream->id, nwritten, *err, eos);
+ else {
+ nwritten = h2_submit(&stream, cf, data, buf, len, err);
if(nwritten < 0) {
goto out;
}
- nwritten = len;
- }
- else {
- nwritten = cf_h2_body_send(cf, data, stream, buf, len, eos, err);
- CURL_TRC_CF(data, cf, "[%d] cf_body_send(len=%zu) -> %zd, %d, eos=%d",
- stream->id, len, nwritten, *err, eos);
+ DEBUGASSERT(stream);
}
/* Call the nghttp2 send loop and flush to write ALL buffered data,
* headers and/or request body completely out to the network */
result = h2_progress_egress(cf, data);
-
/* if the stream has been closed in egress handling (nghttp2 does that
* when it does not like the headers, for example */
- if(stream && stream->closed) {
+ if(stream && stream->closed && !was_blocked) {
infof(data, "stream %u closed", stream->id);
*err = CURLE_SEND_ERROR;
nwritten = -1;
goto out;
}
- else if(result && (result != CURLE_AGAIN)) {
+ else if(result == CURLE_AGAIN) {
+ blocked = 1;
+ }
+ else if(result) {
*err = result;
nwritten = -1;
goto out;
}
-
- if(should_close_session(ctx)) {
+ else if(stream && !Curl_bufq_is_empty(&stream->sendbuf)) {
+ /* although we wrote everything that nghttp2 wants to send now,
+ * there is data left in our stream send buffer unwritten. This may
+ * be due to the stream's HTTP/2 flow window being exhausted. */
+ blocked = 1;
+ }
+
+ if(stream && blocked && nwritten > 0) {
+ /* Unable to send all data, due to connection blocked or H2 window
+ * exhaustion. Data is left in our stream buffer, or nghttp2's internal
+ * frame buffer or our network out buffer. */
+ size_t rwin = nghttp2_session_get_stream_remote_window_size(ctx->h2,
+ stream->id);
+ /* Whatever the cause, we need to return CURL_EAGAIN for this call.
+ * We have unwritten state that needs us being invoked again and EAGAIN
+ * is the only way to ensure that. */
+ stream->upload_blocked_len = nwritten;
+ CURL_TRC_CF(data, cf, "[%d] cf_send(len=%zu) BLOCK: win %u/%zu "
+ "blocked_len=%zu",
+ stream->id, len,
+ nghttp2_session_get_remote_window_size(ctx->h2), rwin,
+ nwritten);
+ *err = CURLE_AGAIN;
+ nwritten = -1;
+ goto out;
+ }
+ else if(should_close_session(ctx)) {
/* nghttp2 thinks this session is done. If the stream has not been
* closed, this is an error state for out transfer */
if(stream->closed) {
@@ -2324,10 +2304,11 @@ static ssize_t cf_h2_send(struct Curl_cfilter *cf, struct Curl_easy *data,
out:
if(stream) {
CURL_TRC_CF(data, cf, "[%d] cf_send(len=%zu) -> %zd, %d, "
- "eos=%d, h2 windows %d-%d (stream-conn), "
+ "upload_left=%" CURL_FORMAT_CURL_OFF_T ", "
+ "h2 windows %d-%d (stream-conn), "
"buffers %zu-%zu (stream-conn)",
stream->id, len, nwritten, *err,
- stream->body_eos,
+ stream->upload_left,
nghttp2_session_get_stream_remote_window_size(
ctx->h2, stream->id),
nghttp2_session_get_remote_window_size(ctx->h2),
@@ -2345,64 +2326,18 @@ out:
return nwritten;
}
-static CURLcode cf_h2_flush(struct Curl_cfilter *cf,
- struct Curl_easy *data)
-{
- struct cf_h2_ctx *ctx = cf->ctx;
- struct h2_stream_ctx *stream = H2_STREAM_CTX(ctx, data);
- struct cf_call_data save;
- CURLcode result = CURLE_OK;
-
- CF_DATA_SAVE(save, cf, data);
- if(stream && !Curl_bufq_is_empty(&stream->sendbuf)) {
- /* resume the potentially suspended stream */
- int rv = nghttp2_session_resume_data(ctx->h2, stream->id);
- if(nghttp2_is_fatal(rv)) {
- result = CURLE_SEND_ERROR;
- goto out;
- }
- }
-
- result = h2_progress_egress(cf, data);
-
-out:
- if(stream) {
- CURL_TRC_CF(data, cf, "[%d] flush -> %d, "
- "h2 windows %d-%d (stream-conn), "
- "buffers %zu-%zu (stream-conn)",
- stream->id, result,
- nghttp2_session_get_stream_remote_window_size(
- ctx->h2, stream->id),
- nghttp2_session_get_remote_window_size(ctx->h2),
- Curl_bufq_len(&stream->sendbuf),
- Curl_bufq_len(&ctx->outbufq));
- }
- else {
- CURL_TRC_CF(data, cf, "flush -> %d, "
- "connection-window=%d, nw_send_buffer(%zu)",
- result, nghttp2_session_get_remote_window_size(ctx->h2),
- Curl_bufq_len(&ctx->outbufq));
- }
- CF_DATA_RESTORE(cf, save);
- return result;
-}
-
static void cf_h2_adjust_pollset(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct easy_pollset *ps)
{
struct cf_h2_ctx *ctx = cf->ctx;
- struct cf_call_data save;
- curl_socket_t sock;
- bool want_recv, want_send;
-
- if(!ctx->h2)
- return;
+ bool want_recv = CURL_WANT_RECV(data);
+ bool want_send = CURL_WANT_SEND(data);
- sock = Curl_conn_cf_get_socket(cf, data);
- Curl_pollset_check(data, ps, sock, &want_recv, &want_send);
- if(want_recv || want_send) {
- struct h2_stream_ctx *stream = H2_STREAM_CTX(ctx, data);
+ if(ctx->h2 && (want_recv || want_send)) {
+ struct stream_ctx *stream = H2_STREAM_CTX(data);
+ curl_socket_t sock = Curl_conn_cf_get_socket(cf, data);
+ struct cf_call_data save;
bool c_exhaust, s_exhaust;
CF_DATA_SAVE(save, cf, data);
@@ -2412,21 +2347,11 @@ static void cf_h2_adjust_pollset(struct Curl_cfilter *cf,
stream->id);
want_recv = (want_recv || c_exhaust || s_exhaust);
want_send = (!s_exhaust && want_send) ||
- (!c_exhaust && nghttp2_session_want_write(ctx->h2)) ||
- !Curl_bufq_is_empty(&ctx->outbufq);
+ (!c_exhaust && nghttp2_session_want_write(ctx->h2));
Curl_pollset_set(data, ps, sock, want_recv, want_send);
CF_DATA_RESTORE(cf, save);
}
- else if(ctx->sent_goaway && !cf->shutdown) {
- /* shutdown in progress */
- CF_DATA_SAVE(save, cf, data);
- want_send = nghttp2_session_want_write(ctx->h2) ||
- !Curl_bufq_is_empty(&ctx->outbufq);
- want_recv = nghttp2_session_want_read(ctx->h2);
- Curl_pollset_set(data, ps, sock, want_recv, want_send);
- CF_DATA_RESTORE(cf, save);
- }
}
static CURLcode cf_h2_connect(struct Curl_cfilter *cf,
@@ -2452,14 +2377,13 @@ static CURLcode cf_h2_connect(struct Curl_cfilter *cf,
*done = FALSE;
CF_DATA_SAVE(save, cf, data);
- DEBUGASSERT(ctx->initialized);
if(!ctx->h2) {
- result = cf_h2_ctx_open(cf, data);
+ result = cf_h2_ctx_init(cf, data, FALSE);
if(result)
goto out;
}
- result = h2_progress_ingress(cf, data, H2_CHUNK_SIZE);
+ result = h2_progress_ingress(cf, data);
if(result)
goto out;
@@ -2489,9 +2413,8 @@ static void cf_h2_close(struct Curl_cfilter *cf, struct Curl_easy *data)
struct cf_call_data save;
CF_DATA_SAVE(save, cf, data);
- cf_h2_ctx_close(ctx);
+ cf_h2_ctx_clear(ctx);
CF_DATA_RESTORE(cf, save);
- cf->connected = FALSE;
}
if(cf->next)
cf->next->cft->do_close(cf->next, data);
@@ -2508,68 +2431,30 @@ static void cf_h2_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
}
}
-static CURLcode cf_h2_shutdown(struct Curl_cfilter *cf,
- struct Curl_easy *data, bool *done)
-{
- struct cf_h2_ctx *ctx = cf->ctx;
- struct cf_call_data save;
- CURLcode result;
- int rv;
-
- if(!cf->connected || !ctx->h2 || cf->shutdown || ctx->conn_closed) {
- *done = TRUE;
- return CURLE_OK;
- }
-
- CF_DATA_SAVE(save, cf, data);
-
- if(!ctx->sent_goaway) {
- rv = nghttp2_submit_goaway(ctx->h2, NGHTTP2_FLAG_NONE,
- ctx->local_max_sid, 0,
- (const uint8_t *)"shutdown",
- sizeof("shutdown"));
- if(rv) {
- failf(data, "nghttp2_submit_goaway() failed: %s(%d)",
- nghttp2_strerror(rv), rv);
- result = CURLE_SEND_ERROR;
- goto out;
- }
- ctx->sent_goaway = TRUE;
- }
- /* GOAWAY submitted, process egress and ingress until nghttp2 is done. */
- result = CURLE_OK;
- if(nghttp2_session_want_write(ctx->h2) ||
- !Curl_bufq_is_empty(&ctx->outbufq))
- result = h2_progress_egress(cf, data);
- if(!result && nghttp2_session_want_read(ctx->h2))
- result = h2_progress_ingress(cf, data, 0);
-
- if(result == CURLE_AGAIN)
- result = CURLE_OK;
-
- *done = (ctx->conn_closed ||
- (!result && !nghttp2_session_want_write(ctx->h2) &&
- !nghttp2_session_want_read(ctx->h2) &&
- Curl_bufq_is_empty(&ctx->outbufq)));
-
-out:
- CF_DATA_RESTORE(cf, save);
- cf->shutdown = (result || *done);
- return result;
-}
-
static CURLcode http2_data_pause(struct Curl_cfilter *cf,
struct Curl_easy *data,
bool pause)
{
+#ifdef NGHTTP2_HAS_SET_LOCAL_WINDOW_SIZE
struct cf_h2_ctx *ctx = cf->ctx;
- struct h2_stream_ctx *stream = H2_STREAM_CTX(ctx, data);
+ struct stream_ctx *stream = H2_STREAM_CTX(data);
DEBUGASSERT(data);
if(ctx && ctx->h2 && stream) {
- CURLcode result = cf_h2_update_local_win(cf, data, stream, pause);
- if(result)
- return result;
+ uint32_t window = pause? 0 : stream->local_window_size;
+
+ int rv = nghttp2_session_set_local_window_size(ctx->h2,
+ NGHTTP2_FLAG_NONE,
+ stream->id,
+ window);
+ if(rv) {
+ failf(data, "nghttp2_session_set_local_window_size() failed: %s(%d)",
+ nghttp2_strerror(rv), rv);
+ return CURLE_HTTP2;
+ }
+
+ if(!pause)
+ drain_stream(cf, data, stream);
/* attempt to send the window update */
(void)h2_progress_egress(cf, data);
@@ -2583,9 +2468,21 @@ static CURLcode http2_data_pause(struct Curl_cfilter *cf,
drain_stream(cf, data, stream);
Curl_expire(data, 0, EXPIRE_RUN_NOW);
}
- CURL_TRC_CF(data, cf, "[%d] stream now %spaused", stream->id,
- pause? "" : "un");
+ DEBUGF(infof(data, "Set HTTP/2 window size to %u for stream %u",
+ window, stream->id));
+
+#ifdef DEBUGBUILD
+ {
+ /* read out the stream local window again */
+ uint32_t window2 =
+ nghttp2_session_get_stream_local_window_size(ctx->h2,
+ stream->id);
+ DEBUGF(infof(data, "HTTP/2 window size is now %u for stream %u",
+ window2, stream->id));
+ }
+#endif
}
+#endif
return CURLE_OK;
}
@@ -2605,14 +2502,14 @@ static CURLcode cf_h2_cntrl(struct Curl_cfilter *cf,
case CF_CTRL_DATA_PAUSE:
result = http2_data_pause(cf, data, (arg1 != 0));
break;
- case CF_CTRL_FLUSH:
- result = cf_h2_flush(cf, data);
+ case CF_CTRL_DATA_DONE_SEND:
+ result = http2_data_done_send(cf, data);
break;
case CF_CTRL_DATA_DETACH:
- http2_data_done(cf, data);
+ http2_data_done(cf, data, TRUE);
break;
case CF_CTRL_DATA_DONE:
- http2_data_done(cf, data);
+ http2_data_done(cf, data, arg1 != 0);
break;
default:
break;
@@ -2625,10 +2522,11 @@ static bool cf_h2_data_pending(struct Curl_cfilter *cf,
const struct Curl_easy *data)
{
struct cf_h2_ctx *ctx = cf->ctx;
- struct h2_stream_ctx *stream = H2_STREAM_CTX(ctx, data);
+ struct stream_ctx *stream = H2_STREAM_CTX(data);
if(ctx && (!Curl_bufq_is_empty(&ctx->inbufq)
- || (stream && !Curl_bufq_is_empty(&stream->sendbuf))))
+ || (stream && !Curl_bufq_is_empty(&stream->sendbuf))
+ || (stream && !Curl_bufq_is_empty(&stream->recvbuf))))
return TRUE;
return cf->next? cf->next->cft->has_data_pending(cf->next, data) : FALSE;
}
@@ -2684,20 +2582,6 @@ static CURLcode cf_h2_query(struct Curl_cfilter *cf,
*pres1 = (effective_max > INT_MAX)? INT_MAX : (int)effective_max;
CF_DATA_RESTORE(cf, save);
return CURLE_OK;
- case CF_QUERY_STREAM_ERROR: {
- struct h2_stream_ctx *stream = H2_STREAM_CTX(ctx, data);
- *pres1 = stream? (int)stream->error : 0;
- return CURLE_OK;
- }
- case CF_QUERY_NEED_FLUSH: {
- struct h2_stream_ctx *stream = H2_STREAM_CTX(ctx, data);
- if(!Curl_bufq_is_empty(&ctx->outbufq) ||
- (stream && !Curl_bufq_is_empty(&stream->sendbuf))) {
- *pres1 = TRUE;
- return CURLE_OK;
- }
- break;
- }
default:
break;
}
@@ -2713,7 +2597,6 @@ struct Curl_cftype Curl_cft_nghttp2 = {
cf_h2_destroy,
cf_h2_connect,
cf_h2_close,
- cf_h2_shutdown,
Curl_cf_def_get_host,
cf_h2_adjust_pollset,
cf_h2_data_pending,
@@ -2728,8 +2611,7 @@ struct Curl_cftype Curl_cft_nghttp2 = {
static CURLcode http2_cfilter_add(struct Curl_cfilter **pcf,
struct Curl_easy *data,
struct connectdata *conn,
- int sockindex,
- bool via_h1_upgrade)
+ int sockindex)
{
struct Curl_cfilter *cf = NULL;
struct cf_h2_ctx *ctx;
@@ -2739,14 +2621,13 @@ static CURLcode http2_cfilter_add(struct Curl_cfilter **pcf,
ctx = calloc(1, sizeof(*ctx));
if(!ctx)
goto out;
- cf_h2_ctx_init(ctx, via_h1_upgrade);
result = Curl_cf_create(&cf, &Curl_cft_nghttp2, ctx);
if(result)
goto out;
- ctx = NULL;
Curl_conn_cf_add(data, conn, sockindex, cf);
+ result = CURLE_OK;
out:
if(result)
@@ -2756,8 +2637,7 @@ out:
}
static CURLcode http2_cfilter_insert_after(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- bool via_h1_upgrade)
+ struct Curl_easy *data)
{
struct Curl_cfilter *cf_h2 = NULL;
struct cf_h2_ctx *ctx;
@@ -2767,14 +2647,13 @@ static CURLcode http2_cfilter_insert_after(struct Curl_cfilter *cf,
ctx = calloc(1, sizeof(*ctx));
if(!ctx)
goto out;
- cf_h2_ctx_init(ctx, via_h1_upgrade);
result = Curl_cf_create(&cf_h2, &Curl_cft_nghttp2, ctx);
if(result)
goto out;
- ctx = NULL;
Curl_conn_cf_insert_after(cf, cf_h2);
+ result = CURLE_OK;
out:
if(result)
@@ -2811,7 +2690,7 @@ bool Curl_http2_may_switch(struct Curl_easy *data,
data->state.httpwant == CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE) {
#ifndef CURL_DISABLE_PROXY
if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) {
- /* We do not support HTTP/2 proxies yet. Also it is debatable
+ /* We don't support HTTP/2 proxies yet. Also it's debatable
whether or not this setting should apply to HTTP/2 proxies. */
infof(data, "Ignoring HTTP/2 prior knowledge due to proxy");
return FALSE;
@@ -2829,14 +2708,19 @@ CURLcode Curl_http2_switch(struct Curl_easy *data,
CURLcode result;
DEBUGASSERT(!Curl_conn_is_http2(data, conn, sockindex));
+ DEBUGF(infof(data, "switching to HTTP/2"));
- result = http2_cfilter_add(&cf, data, conn, sockindex, FALSE);
+ result = http2_cfilter_add(&cf, data, conn, sockindex);
if(result)
return result;
- CURL_TRC_CF(data, cf, "switching connection to HTTP/2");
- conn->httpversion = 20; /* we know we are on HTTP/2 now */
+ result = cf_h2_ctx_init(cf, data, FALSE);
+ if(result)
+ return result;
+
+ conn->httpversion = 20; /* we know we're on HTTP/2 now */
conn->bits.multiplex = TRUE; /* at least potentially multiplexed */
+ conn->bundle->multiuse = BUNDLE_MULTIPLEX;
Curl_multi_connchanged(data->multi);
if(cf->next) {
@@ -2853,13 +2737,18 @@ CURLcode Curl_http2_switch_at(struct Curl_cfilter *cf, struct Curl_easy *data)
DEBUGASSERT(!Curl_cf_is_http2(cf, data));
- result = http2_cfilter_insert_after(cf, data, FALSE);
+ result = http2_cfilter_insert_after(cf, data);
if(result)
return result;
cf_h2 = cf->next;
- cf->conn->httpversion = 20; /* we know we are on HTTP/2 now */
+ result = cf_h2_ctx_init(cf_h2, data, FALSE);
+ if(result)
+ return result;
+
+ cf->conn->httpversion = 20; /* we know we're on HTTP/2 now */
cf->conn->bits.multiplex = TRUE; /* at least potentially multiplexed */
+ cf->conn->bundle->multiuse = BUNDLE_MULTIPLEX;
Curl_multi_connchanged(data->multi);
if(cf_h2->next) {
@@ -2878,16 +2767,20 @@ CURLcode Curl_http2_upgrade(struct Curl_easy *data,
CURLcode result;
DEBUGASSERT(!Curl_conn_is_http2(data, conn, sockindex));
+ DEBUGF(infof(data, "upgrading to HTTP/2"));
DEBUGASSERT(data->req.upgr101 == UPGR101_RECEIVED);
- result = http2_cfilter_add(&cf, data, conn, sockindex, TRUE);
+ result = http2_cfilter_add(&cf, data, conn, sockindex);
if(result)
return result;
- CURL_TRC_CF(data, cf, "upgrading connection to HTTP/2");
DEBUGASSERT(cf->cft == &Curl_cft_nghttp2);
ctx = cf->ctx;
+ result = cf_h2_ctx_init(cf, data, TRUE);
+ if(result)
+ return result;
+
if(nread > 0) {
/* Remaining data from the protocol switch reply is already using
* the switched protocol, ie. HTTP/2. We add that to the network
@@ -2910,8 +2803,9 @@ CURLcode Curl_http2_upgrade(struct Curl_easy *data,
" after upgrade: len=%zu", nread);
}
- conn->httpversion = 20; /* we know we are on HTTP/2 now */
+ conn->httpversion = 20; /* we know we're on HTTP/2 now */
conn->bits.multiplex = TRUE; /* at least potentially multiplexed */
+ conn->bundle->multiuse = BUNDLE_MULTIPLEX;
Curl_multi_connchanged(data->multi);
if(cf->next) {
@@ -2925,11 +2819,8 @@ CURLcode Curl_http2_upgrade(struct Curl_easy *data,
CURLE_HTTP2_STREAM error! */
bool Curl_h2_http_1_1_error(struct Curl_easy *data)
{
- if(Curl_conn_is_http2(data, data->conn, FIRSTSOCKET)) {
- int err = Curl_conn_get_stream_error(data, data->conn, FIRSTSOCKET);
- return (err == NGHTTP2_HTTP_1_1_REQUIRED);
- }
- return FALSE;
+ struct stream_ctx *stream = H2_STREAM_CTX(data);
+ return (stream && stream->error == NGHTTP2_HTTP_1_1_REQUIRED);
}
#else /* !USE_NGHTTP2 */
diff --git a/contrib/libs/curl/lib/http_aws_sigv4.c b/contrib/libs/curl/lib/http_aws_sigv4.c
index 3874993e9e..b673055f30 100644
--- a/contrib/libs/curl/lib/http_aws_sigv4.c
+++ b/contrib/libs/curl/lib/http_aws_sigv4.c
@@ -60,11 +60,11 @@
#define TIMESTAMP_SIZE 17
/* hex-encoded with trailing null */
-#define SHA256_HEX_LENGTH (2 * CURL_SHA256_DIGEST_LENGTH + 1)
+#define SHA256_HEX_LENGTH (2 * SHA256_DIGEST_LENGTH + 1)
static void sha256_to_hex(char *dst, unsigned char *sha)
{
- Curl_hexencode(sha, CURL_SHA256_DIGEST_LENGTH,
+ Curl_hexencode(sha, SHA256_DIGEST_LENGTH,
(unsigned char *)dst, SHA256_HEX_LENGTH);
}
@@ -129,37 +129,6 @@ static void trim_headers(struct curl_slist *head)
/* string been x-PROVIDER-date:TIMESTAMP, I need +1 for ':' */
#define DATE_FULL_HDR_LEN (DATE_HDR_KEY_LEN + TIMESTAMP_SIZE + 1)
-/* alphabetically compare two headers by their name, expecting
- headers to use ':' at this point */
-static int compare_header_names(const char *a, const char *b)
-{
- const char *colon_a;
- const char *colon_b;
- size_t len_a;
- size_t len_b;
- size_t min_len;
- int cmp;
-
- colon_a = strchr(a, ':');
- colon_b = strchr(b, ':');
-
- DEBUGASSERT(colon_a);
- DEBUGASSERT(colon_b);
-
- len_a = colon_a ? (size_t)(colon_a - a) : strlen(a);
- len_b = colon_b ? (size_t)(colon_b - b) : strlen(b);
-
- min_len = (len_a < len_b) ? len_a : len_b;
-
- cmp = strncmp(a, b, min_len);
-
- /* return the shorter of the two if one is shorter */
- if(!cmp)
- return (int)(len_a - len_b);
-
- return cmp;
-}
-
/* timestamp should point to a buffer of at last TIMESTAMP_SIZE bytes */
static CURLcode make_headers(struct Curl_easy *data,
const char *hostname,
@@ -189,7 +158,10 @@ static CURLcode make_headers(struct Curl_easy *data,
msnprintf(date_full_hdr, DATE_FULL_HDR_LEN,
"x-%s-date:%s", provider1, timestamp);
- if(!Curl_checkheaders(data, STRCONST("Host"))) {
+ if(Curl_checkheaders(data, STRCONST("Host"))) {
+ head = NULL;
+ }
+ else {
char full_host[FULL_HOST_LEN + 1];
if(data->state.aptr.host) {
@@ -271,11 +243,11 @@ static CURLcode make_headers(struct Curl_easy *data,
if(!tmp_head)
goto fail;
head = tmp_head;
- *date_header = aprintf("%s: %s\r\n", date_hdr_key, timestamp);
+ *date_header = curl_maprintf("%s: %s\r\n", date_hdr_key, timestamp);
}
else {
char *value;
- char *endp;
+
value = strchr(*date_header, ':');
if(!value) {
*date_header = NULL;
@@ -284,27 +256,18 @@ static CURLcode make_headers(struct Curl_easy *data,
++value;
while(ISBLANK(*value))
++value;
- endp = value;
- while(*endp && ISALNUM(*endp))
- ++endp;
- /* 16 bytes => "19700101T000000Z" */
- if((endp - value) == TIMESTAMP_SIZE - 1) {
- memcpy(timestamp, value, TIMESTAMP_SIZE - 1);
- timestamp[TIMESTAMP_SIZE - 1] = 0;
- }
- else
- /* bad timestamp length */
- timestamp[0] = 0;
+ strncpy(timestamp, value, TIMESTAMP_SIZE - 1);
+ timestamp[TIMESTAMP_SIZE - 1] = 0;
*date_header = NULL;
}
- /* alpha-sort by header name in a case sensitive manner */
+ /* alpha-sort in a case sensitive manner */
do {
again = 0;
for(l = head; l; l = l->next) {
struct curl_slist *next = l->next;
- if(next && compare_header_names(l->data, next->data) > 0) {
+ if(next && strcmp(l->data, next->data) > 0) {
char *tmp = l->data;
l->data = next->data;
@@ -454,76 +417,6 @@ static int compare_func(const void *a, const void *b)
#define MAX_QUERYPAIRS 64
-/**
- * found_equals have a double meaning,
- * detect if an equal have been found when called from canon_query,
- * and mark that this function is called to compute the path,
- * if found_equals is NULL.
- */
-static CURLcode canon_string(const char *q, size_t len,
- struct dynbuf *dq, bool *found_equals)
-{
- CURLcode result = CURLE_OK;
-
- for(; len && !result; q++, len--) {
- if(ISALNUM(*q))
- result = Curl_dyn_addn(dq, q, 1);
- else {
- switch(*q) {
- case '-':
- case '.':
- case '_':
- case '~':
- /* allowed as-is */
- result = Curl_dyn_addn(dq, q, 1);
- break;
- case '%':
- /* uppercase the following if hexadecimal */
- if(ISXDIGIT(q[1]) && ISXDIGIT(q[2])) {
- char tmp[3]="%";
- tmp[1] = Curl_raw_toupper(q[1]);
- tmp[2] = Curl_raw_toupper(q[2]);
- result = Curl_dyn_addn(dq, tmp, 3);
- q += 2;
- len -= 2;
- }
- else
- /* '%' without a following two-digit hex, encode it */
- result = Curl_dyn_addn(dq, "%25", 3);
- break;
- default: {
- const char hex[] = "0123456789ABCDEF";
- char out[3]={'%'};
-
- if(!found_equals) {
- /* if found_equals is NULL assuming, been in path */
- if(*q == '/') {
- /* allowed as if */
- result = Curl_dyn_addn(dq, q, 1);
- break;
- }
- }
- else {
- /* allowed as-is */
- if(*q == '=') {
- result = Curl_dyn_addn(dq, q, 1);
- *found_equals = true;
- break;
- }
- }
- /* URL encode */
- out[1] = hex[((unsigned char)*q)>>4];
- out[2] = hex[*q & 0xf];
- result = Curl_dyn_addn(dq, out, 3);
- break;
- }
- }
- }
- }
- return result;
-}
-
-
static CURLcode canon_query(struct Curl_easy *data,
const char *query, struct dynbuf *dq)
{
@@ -561,11 +454,54 @@ static CURLcode canon_query(struct Curl_easy *data,
ap = &array[0];
for(i = 0; !result && (i < entry); i++, ap++) {
+ size_t len;
const char *q = ap->p;
bool found_equals = false;
if(!ap->len)
continue;
- result = canon_string(q, ap->len, dq, &found_equals);
+ for(len = ap->len; len && !result; q++, len--) {
+ if(ISALNUM(*q))
+ result = Curl_dyn_addn(dq, q, 1);
+ else {
+ switch(*q) {
+ case '-':
+ case '.':
+ case '_':
+ case '~':
+ /* allowed as-is */
+ result = Curl_dyn_addn(dq, q, 1);
+ break;
+ case '=':
+ /* allowed as-is */
+ result = Curl_dyn_addn(dq, q, 1);
+ found_equals = true;
+ break;
+ case '%':
+ /* uppercase the following if hexadecimal */
+ if(ISXDIGIT(q[1]) && ISXDIGIT(q[2])) {
+ char tmp[3]="%";
+ tmp[1] = Curl_raw_toupper(q[1]);
+ tmp[2] = Curl_raw_toupper(q[2]);
+ result = Curl_dyn_addn(dq, tmp, 3);
+ q += 2;
+ len -= 2;
+ }
+ else
+ /* '%' without a following two-digit hex, encode it */
+ result = Curl_dyn_addn(dq, "%25", 3);
+ break;
+ default: {
+ /* URL encode */
+ const char hex[] = "0123456789ABCDEF";
+ char out[3]={'%'};
+ out[1] = hex[((unsigned char)*q)>>4];
+ out[2] = hex[*q & 0xf];
+ result = Curl_dyn_addn(dq, out, 3);
+ break;
+ }
+ }
+ }
+ }
if(!result && !found_equals) {
/* queries without value still need an equals */
result = Curl_dyn_addn(dq, "=", 1);
@@ -598,13 +534,12 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
struct dynbuf canonical_headers;
struct dynbuf signed_headers;
struct dynbuf canonical_query;
- struct dynbuf canonical_path;
char *date_header = NULL;
Curl_HttpReq httpreq;
const char *method = NULL;
char *payload_hash = NULL;
size_t payload_hash_len = 0;
- unsigned char sha_hash[CURL_SHA256_DIGEST_LENGTH];
+ unsigned char sha_hash[SHA256_DIGEST_LENGTH];
char sha_hex[SHA256_HEX_LENGTH];
char content_sha256_hdr[CONTENT_SHA256_HDR_LEN + 2] = ""; /* add \r\n */
char *canonical_request = NULL;
@@ -613,8 +548,8 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
char *str_to_sign = NULL;
const char *user = data->state.aptr.user ? data->state.aptr.user : "";
char *secret = NULL;
- unsigned char sign0[CURL_SHA256_DIGEST_LENGTH] = {0};
- unsigned char sign1[CURL_SHA256_DIGEST_LENGTH] = {0};
+ unsigned char sign0[SHA256_DIGEST_LENGTH] = {0};
+ unsigned char sign1[SHA256_DIGEST_LENGTH] = {0};
char *auth_headers = NULL;
DEBUGASSERT(!proxy);
@@ -629,7 +564,6 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
Curl_dyn_init(&canonical_headers, CURL_MAX_HTTP_HEADER);
Curl_dyn_init(&canonical_query, CURL_MAX_HTTP_HEADER);
Curl_dyn_init(&signed_headers, CURL_MAX_HTTP_HEADER);
- Curl_dyn_init(&canonical_path, CURL_MAX_HTTP_HEADER);
/*
* Parameters parsing
@@ -651,7 +585,7 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
":%" MAX_SIGV4_LEN_TXT "s",
provider0, provider1, region, service);
if(!provider0[0]) {
- failf(data, "first aws-sigv4 provider cannot be empty");
+ failf(data, "first aws-sigv4 provider can't be empty");
result = CURLE_BAD_FUNCTION_ARGUMENT;
goto fail;
}
@@ -671,7 +605,7 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
result = CURLE_URL_MALFORMAT;
goto fail;
}
- memcpy(service, hostname, len);
+ strncpy(service, hostname, len);
service[len] = '\0';
infof(data, "aws_sigv4: picked service %s from host", service);
@@ -690,7 +624,7 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
result = CURLE_URL_MALFORMAT;
goto fail;
}
- memcpy(region, reg, len);
+ strncpy(region, reg, len);
region[len] = '\0';
infof(data, "aws_sigv4: picked region %s from host", region);
}
@@ -725,10 +659,10 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
if(force_timestamp)
clock = 0;
else
- clock = time(NULL);
+ time(&clock);
}
#else
- clock = time(NULL);
+ time(&clock);
#endif
result = Curl_gmtime(clock, &tm);
if(result) {
@@ -758,27 +692,22 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
result = canon_query(data, data->state.up.query, &canonical_query);
if(result)
goto fail;
-
- result = canon_string(data->state.up.path, strlen(data->state.up.path),
- &canonical_path, NULL);
- if(result)
- goto fail;
result = CURLE_OUT_OF_MEMORY;
canonical_request =
- aprintf("%s\n" /* HTTPRequestMethod */
- "%s\n" /* CanonicalURI */
- "%s\n" /* CanonicalQueryString */
- "%s\n" /* CanonicalHeaders */
- "%s\n" /* SignedHeaders */
- "%.*s", /* HashedRequestPayload in hex */
- method,
- Curl_dyn_ptr(&canonical_path),
- Curl_dyn_ptr(&canonical_query) ?
- Curl_dyn_ptr(&canonical_query) : "",
- Curl_dyn_ptr(&canonical_headers),
- Curl_dyn_ptr(&signed_headers),
- (int)payload_hash_len, payload_hash);
+ curl_maprintf("%s\n" /* HTTPRequestMethod */
+ "%s\n" /* CanonicalURI */
+ "%s\n" /* CanonicalQueryString */
+ "%s\n" /* CanonicalHeaders */
+ "%s\n" /* SignedHeaders */
+ "%.*s", /* HashedRequestPayload in hex */
+ method,
+ data->state.up.path,
+ Curl_dyn_ptr(&canonical_query) ?
+ Curl_dyn_ptr(&canonical_query) : "",
+ Curl_dyn_ptr(&canonical_headers),
+ Curl_dyn_ptr(&signed_headers),
+ (int)payload_hash_len, payload_hash);
if(!canonical_request)
goto fail;
@@ -786,12 +715,12 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
/* provider 0 lowercase */
Curl_strntolower(provider0, provider0, strlen(provider0));
- request_type = aprintf("%s4_request", provider0);
+ request_type = curl_maprintf("%s4_request", provider0);
if(!request_type)
goto fail;
- credential_scope = aprintf("%s/%s/%s/%s",
- date, region, service, request_type);
+ credential_scope = curl_maprintf("%s/%s/%s/%s",
+ date, region, service, request_type);
if(!credential_scope)
goto fail;
@@ -808,22 +737,22 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
* Google allows using RSA key instead of HMAC, so this code might change
* in the future. For now we only support HMAC.
*/
- str_to_sign = aprintf("%s4-HMAC-SHA256\n" /* Algorithm */
- "%s\n" /* RequestDateTime */
- "%s\n" /* CredentialScope */
- "%s", /* HashedCanonicalRequest in hex */
- provider0,
- timestamp,
- credential_scope,
- sha_hex);
+ str_to_sign = curl_maprintf("%s4-HMAC-SHA256\n" /* Algorithm */
+ "%s\n" /* RequestDateTime */
+ "%s\n" /* CredentialScope */
+ "%s", /* HashedCanonicalRequest in hex */
+ provider0,
+ timestamp,
+ credential_scope,
+ sha_hex);
if(!str_to_sign) {
goto fail;
}
/* provider 0 uppercase */
- secret = aprintf("%s4%s", provider0,
- data->state.aptr.passwd ?
- data->state.aptr.passwd : "");
+ secret = curl_maprintf("%s4%s", provider0,
+ data->state.aptr.passwd ?
+ data->state.aptr.passwd : "");
if(!secret)
goto fail;
@@ -836,24 +765,24 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
sha256_to_hex(sha_hex, sign0);
/* provider 0 uppercase */
- auth_headers = aprintf("Authorization: %s4-HMAC-SHA256 "
- "Credential=%s/%s, "
- "SignedHeaders=%s, "
- "Signature=%s\r\n"
- /*
- * date_header is added here, only if it was not
- * user-specified (using CURLOPT_HTTPHEADER).
- * date_header includes \r\n
- */
- "%s"
- "%s", /* optional sha256 header includes \r\n */
- provider0,
- user,
- credential_scope,
- Curl_dyn_ptr(&signed_headers),
- sha_hex,
- date_header ? date_header : "",
- content_sha256_hdr);
+ auth_headers = curl_maprintf("Authorization: %s4-HMAC-SHA256 "
+ "Credential=%s/%s, "
+ "SignedHeaders=%s, "
+ "Signature=%s\r\n"
+ /*
+ * date_header is added here, only if it wasn't
+ * user-specified (using CURLOPT_HTTPHEADER).
+ * date_header includes \r\n
+ */
+ "%s"
+ "%s", /* optional sha256 header includes \r\n */
+ provider0,
+ user,
+ credential_scope,
+ Curl_dyn_ptr(&signed_headers),
+ sha_hex,
+ date_header ? date_header : "",
+ content_sha256_hdr);
if(!auth_headers) {
goto fail;
}
@@ -865,7 +794,6 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
fail:
Curl_dyn_free(&canonical_query);
- Curl_dyn_free(&canonical_path);
Curl_dyn_free(&canonical_headers);
Curl_dyn_free(&signed_headers);
free(canonical_request);
diff --git a/contrib/libs/curl/lib/http_chunks.c b/contrib/libs/curl/lib/http_chunks.c
index c228eb4f9b..acdb108634 100644
--- a/contrib/libs/curl/lib/http_chunks.c
+++ b/contrib/libs/curl/lib/http_chunks.c
@@ -27,13 +27,10 @@
#ifndef CURL_DISABLE_HTTP
#include "urldata.h" /* it includes http_chunks.h */
-#include "curl_printf.h"
-#include "curl_trc.h"
#include "sendf.h" /* for the client write stuff */
#include "dynbuf.h"
#include "content_encoding.h"
#include "http.h"
-#include "multiif.h"
#include "strtoofft.h"
#include "warnless.h"
@@ -78,67 +75,47 @@
*/
-void Curl_httpchunk_init(struct Curl_easy *data, struct Curl_chunker *ch,
- bool ignore_body)
+void Curl_httpchunk_init(struct Curl_easy *data)
{
- (void)data;
- ch->hexindex = 0; /* start at 0 */
- ch->state = CHUNK_HEX; /* we get hex first! */
- ch->last_code = CHUNKE_OK;
- Curl_dyn_init(&ch->trailer, DYN_H1_TRAILER);
- ch->ignore_body = ignore_body;
+ struct connectdata *conn = data->conn;
+ struct Curl_chunker *chunk = &conn->chunk;
+ chunk->hexindex = 0; /* start at 0 */
+ chunk->state = CHUNK_HEX; /* we get hex first! */
+ Curl_dyn_init(&conn->trailer, DYN_H1_TRAILER);
}
-void Curl_httpchunk_reset(struct Curl_easy *data, struct Curl_chunker *ch,
- bool ignore_body)
-{
- (void)data;
- ch->hexindex = 0; /* start at 0 */
- ch->state = CHUNK_HEX; /* we get hex first! */
- ch->last_code = CHUNKE_OK;
- Curl_dyn_reset(&ch->trailer);
- ch->ignore_body = ignore_body;
-}
-
-void Curl_httpchunk_free(struct Curl_easy *data, struct Curl_chunker *ch)
-{
- (void)data;
- Curl_dyn_free(&ch->trailer);
-}
-
-bool Curl_httpchunk_is_done(struct Curl_easy *data, struct Curl_chunker *ch)
-{
- (void)data;
- return ch->state == CHUNK_DONE;
-}
-
-static CURLcode httpchunk_readwrite(struct Curl_easy *data,
- struct Curl_chunker *ch,
- struct Curl_cwriter *cw_next,
- const char *buf, size_t blen,
- size_t *pconsumed)
+/*
+ * chunk_read() returns a OK for normal operations, or a positive return code
+ * for errors. STOP means this sequence of chunks is complete. The 'wrote'
+ * argument is set to tell the caller how many bytes we actually passed to the
+ * client (for byte-counting and whatever).
+ *
+ * The states and the state-machine is further explained in the header file.
+ *
+ * This function always uses ASCII hex values to accommodate non-ASCII hosts.
+ * For example, 0x0d and 0x0a are used instead of '\r' and '\n'.
+ */
+CHUNKcode Curl_httpchunk_read(struct Curl_easy *data,
+ char *buf,
+ size_t blen,
+ size_t *pconsumed,
+ CURLcode *extrap)
{
CURLcode result = CURLE_OK;
+ struct connectdata *conn = data->conn;
+ struct Curl_chunker *ch = &conn->chunk;
+ struct SingleRequest *k = &data->req;
size_t piece;
*pconsumed = 0; /* nothing's written yet */
- /* first check terminal states that will not progress anywhere */
- if(ch->state == CHUNK_DONE)
- return CURLE_OK;
- if(ch->state == CHUNK_FAILED)
- return CURLE_RECV_ERROR;
/* the original data is written to the client, but we go on with the
chunk read process, to properly calculate the content length */
- if(data->set.http_te_skip && !ch->ignore_body) {
- if(cw_next)
- result = Curl_cwriter_write(data, cw_next, CLIENTWRITE_BODY, buf, blen);
- else
- result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)buf, blen);
+ if(data->set.http_te_skip && !k->ignorebody) {
+ result = Curl_client_write(data, CLIENTWRITE_BODY, buf, blen);
if(result) {
- ch->state = CHUNK_FAILED;
- ch->last_code = CHUNKE_PASSTHRU_ERROR;
- return result;
+ *extrap = result;
+ return CHUNKE_PASSTHRU_ERROR;
}
}
@@ -146,35 +123,28 @@ static CURLcode httpchunk_readwrite(struct Curl_easy *data,
switch(ch->state) {
case CHUNK_HEX:
if(ISXDIGIT(*buf)) {
- if(ch->hexindex >= CHUNK_MAXNUM_LEN) {
- failf(data, "chunk hex-length longer than %d", CHUNK_MAXNUM_LEN);
- ch->state = CHUNK_FAILED;
- ch->last_code = CHUNKE_TOO_LONG_HEX; /* longer than we support */
- return CURLE_RECV_ERROR;
+ if(ch->hexindex < CHUNK_MAXNUM_LEN) {
+ ch->hexbuffer[ch->hexindex] = *buf;
+ buf++;
+ blen--;
+ ch->hexindex++;
+ }
+ else {
+ return CHUNKE_TOO_LONG_HEX; /* longer hex than we support */
}
- ch->hexbuffer[ch->hexindex++] = *buf;
- buf++;
- blen--;
- (*pconsumed)++;
}
else {
- if(0 == ch->hexindex) {
+ char *endptr;
+ if(0 == ch->hexindex)
/* This is illegal data, we received junk where we expected
a hexadecimal digit. */
- failf(data, "chunk hex-length char not a hex digit: 0x%x", *buf);
- ch->state = CHUNK_FAILED;
- ch->last_code = CHUNKE_ILLEGAL_HEX;
- return CURLE_RECV_ERROR;
- }
+ return CHUNKE_ILLEGAL_HEX;
/* blen and buf are unmodified */
ch->hexbuffer[ch->hexindex] = 0;
- if(curlx_strtoofft(ch->hexbuffer, NULL, 16, &ch->datasize)) {
- failf(data, "chunk hex-length not valid: '%s'", ch->hexbuffer);
- ch->state = CHUNK_FAILED;
- ch->last_code = CHUNKE_ILLEGAL_HEX;
- return CURLE_RECV_ERROR;
- }
+
+ if(curlx_strtoofft(ch->hexbuffer, &endptr, 16, &ch->datasize))
+ return CHUNKE_ILLEGAL_HEX;
ch->state = CHUNK_LF; /* now wait for the CRLF */
}
break;
@@ -182,20 +152,16 @@ static CURLcode httpchunk_readwrite(struct Curl_easy *data,
case CHUNK_LF:
/* waiting for the LF after a chunk size */
if(*buf == 0x0a) {
- /* we are now expecting data to come, unless size was zero! */
+ /* we're now expecting data to come, unless size was zero! */
if(0 == ch->datasize) {
ch->state = CHUNK_TRAILER; /* now check for trailers */
}
- else {
+ else
ch->state = CHUNK_DATA;
- CURL_TRC_WRITE(data, "http_chunked, chunk start of %"
- FMT_OFF_T " bytes", ch->datasize);
- }
}
buf++;
blen--;
- (*pconsumed)++;
break;
case CHUNK_DATA:
@@ -207,17 +173,12 @@ static CURLcode httpchunk_readwrite(struct Curl_easy *data,
piece = curlx_sotouz(ch->datasize);
/* Write the data portion available */
- if(!data->set.http_te_skip && !ch->ignore_body) {
- if(cw_next)
- result = Curl_cwriter_write(data, cw_next, CLIENTWRITE_BODY,
- buf, piece);
- else
- result = Curl_client_write(data, CLIENTWRITE_BODY,
- (char *)buf, piece);
+ if(!data->set.http_te_skip && !k->ignorebody) {
+ result = Curl_client_write(data, CLIENTWRITE_BODY, buf, piece);
+
if(result) {
- ch->state = CHUNK_FAILED;
- ch->last_code = CHUNKE_PASSTHRU_ERROR;
- return result;
+ *extrap = result;
+ return CHUNKE_PASSTHRU_ERROR;
}
}
@@ -225,9 +186,6 @@ static CURLcode httpchunk_readwrite(struct Curl_easy *data,
ch->datasize -= piece; /* decrease amount left to expect */
buf += piece; /* move read pointer forward */
blen -= piece; /* decrease space left in this round */
- CURL_TRC_WRITE(data, "http_chunked, write %zu body bytes, %"
- FMT_OFF_T " bytes in chunk remain",
- piece, ch->datasize);
if(0 == ch->datasize)
/* end of data this round, we now expect a trailing CRLF */
@@ -237,74 +195,56 @@ static CURLcode httpchunk_readwrite(struct Curl_easy *data,
case CHUNK_POSTLF:
if(*buf == 0x0a) {
/* The last one before we go back to hex state and start all over. */
- Curl_httpchunk_reset(data, ch, ch->ignore_body);
- }
- else if(*buf != 0x0d) {
- ch->state = CHUNK_FAILED;
- ch->last_code = CHUNKE_BAD_CHUNK;
- return CURLE_RECV_ERROR;
+ Curl_httpchunk_init(data); /* sets state back to CHUNK_HEX */
}
+ else if(*buf != 0x0d)
+ return CHUNKE_BAD_CHUNK;
buf++;
blen--;
- (*pconsumed)++;
break;
case CHUNK_TRAILER:
if((*buf == 0x0d) || (*buf == 0x0a)) {
- char *tr = Curl_dyn_ptr(&ch->trailer);
+ char *tr = Curl_dyn_ptr(&conn->trailer);
/* this is the end of a trailer, but if the trailer was zero bytes
there was no trailer and we move on */
if(tr) {
size_t trlen;
- result = Curl_dyn_addn(&ch->trailer, (char *)STRCONST("\x0d\x0a"));
- if(result) {
- ch->state = CHUNK_FAILED;
- ch->last_code = CHUNKE_OUT_OF_MEMORY;
- return result;
- }
- tr = Curl_dyn_ptr(&ch->trailer);
- trlen = Curl_dyn_len(&ch->trailer);
+ result = Curl_dyn_addn(&conn->trailer, (char *)STRCONST("\x0d\x0a"));
+ if(result)
+ return CHUNKE_OUT_OF_MEMORY;
+
+ tr = Curl_dyn_ptr(&conn->trailer);
+ trlen = Curl_dyn_len(&conn->trailer);
if(!data->set.http_te_skip) {
- if(cw_next)
- result = Curl_cwriter_write(data, cw_next,
- CLIENTWRITE_HEADER|
- CLIENTWRITE_TRAILER,
- tr, trlen);
- else
- result = Curl_client_write(data,
- CLIENTWRITE_HEADER|
- CLIENTWRITE_TRAILER,
- tr, trlen);
+ result = Curl_client_write(data,
+ CLIENTWRITE_HEADER|CLIENTWRITE_TRAILER,
+ tr, trlen);
if(result) {
- ch->state = CHUNK_FAILED;
- ch->last_code = CHUNKE_PASSTHRU_ERROR;
- return result;
+ *extrap = result;
+ return CHUNKE_PASSTHRU_ERROR;
}
}
- Curl_dyn_reset(&ch->trailer);
+ Curl_dyn_reset(&conn->trailer);
ch->state = CHUNK_TRAILER_CR;
if(*buf == 0x0a)
/* already on the LF */
break;
}
else {
- /* no trailer, we are on the final CRLF pair */
+ /* no trailer, we're on the final CRLF pair */
ch->state = CHUNK_TRAILER_POSTCR;
- break; /* do not advance the pointer */
+ break; /* don't advance the pointer */
}
}
else {
- result = Curl_dyn_addn(&ch->trailer, buf, 1);
- if(result) {
- ch->state = CHUNK_FAILED;
- ch->last_code = CHUNKE_OUT_OF_MEMORY;
- return result;
- }
+ result = Curl_dyn_addn(&conn->trailer, buf, 1);
+ if(result)
+ return CHUNKE_OUT_OF_MEMORY;
}
buf++;
blen--;
- (*pconsumed)++;
break;
case CHUNK_TRAILER_CR:
@@ -312,13 +252,9 @@ static CURLcode httpchunk_readwrite(struct Curl_easy *data,
ch->state = CHUNK_TRAILER_POSTCR;
buf++;
blen--;
- (*pconsumed)++;
- }
- else {
- ch->state = CHUNK_FAILED;
- ch->last_code = CHUNKE_BAD_CHUNK;
- return CURLE_RECV_ERROR;
}
+ else
+ return CHUNKE_BAD_CHUNK;
break;
case CHUNK_TRAILER_POSTCR:
@@ -333,7 +269,6 @@ static CURLcode httpchunk_readwrite(struct Curl_easy *data,
/* skip if CR */
buf++;
blen--;
- (*pconsumed)++;
}
/* now wait for the final LF */
ch->state = CHUNK_STOP;
@@ -342,33 +277,21 @@ static CURLcode httpchunk_readwrite(struct Curl_easy *data,
case CHUNK_STOP:
if(*buf == 0x0a) {
blen--;
- (*pconsumed)++;
+
/* Record the length of any data left in the end of the buffer
- even if there is no more chunks to read */
+ even if there's no more chunks to read */
ch->datasize = blen;
- ch->state = CHUNK_DONE;
- CURL_TRC_WRITE(data, "http_chunk, response complete");
- return CURLE_OK;
- }
- else {
- ch->state = CHUNK_FAILED;
- ch->last_code = CHUNKE_BAD_CHUNK;
- CURL_TRC_WRITE(data, "http_chunk error, expected 0x0a, seeing 0x%ux",
- (unsigned int)*buf);
- return CURLE_RECV_ERROR;
- }
- case CHUNK_DONE:
- return CURLE_OK;
- case CHUNK_FAILED:
- return CURLE_RECV_ERROR;
+ return CHUNKE_STOP; /* return stop */
+ }
+ else
+ return CHUNKE_BAD_CHUNK;
}
-
}
- return CURLE_OK;
+ return CHUNKE_OK;
}
-static const char *Curl_chunked_strerror(CHUNKcode code)
+const char *Curl_chunked_strerror(CHUNKcode code)
{
switch(code) {
default:
@@ -380,7 +303,8 @@ static const char *Curl_chunked_strerror(CHUNKcode code)
case CHUNKE_BAD_CHUNK:
return "Malformed encoding found";
case CHUNKE_PASSTHRU_ERROR:
- return "Error writing data to client";
+ DEBUGASSERT(0); /* never used */
+ return "";
case CHUNKE_BAD_ENCODING:
return "Bad content-encoding found";
case CHUNKE_OUT_OF_MEMORY:
@@ -388,295 +312,4 @@ static const char *Curl_chunked_strerror(CHUNKcode code)
}
}
-CURLcode Curl_httpchunk_read(struct Curl_easy *data,
- struct Curl_chunker *ch,
- char *buf, size_t blen,
- size_t *pconsumed)
-{
- return httpchunk_readwrite(data, ch, NULL, buf, blen, pconsumed);
-}
-
-struct chunked_writer {
- struct Curl_cwriter super;
- struct Curl_chunker ch;
-};
-
-static CURLcode cw_chunked_init(struct Curl_easy *data,
- struct Curl_cwriter *writer)
-{
- struct chunked_writer *ctx = writer->ctx;
-
- data->req.chunk = TRUE; /* chunks coming our way. */
- Curl_httpchunk_init(data, &ctx->ch, FALSE);
- return CURLE_OK;
-}
-
-static void cw_chunked_close(struct Curl_easy *data,
- struct Curl_cwriter *writer)
-{
- struct chunked_writer *ctx = writer->ctx;
- Curl_httpchunk_free(data, &ctx->ch);
-}
-
-static CURLcode cw_chunked_write(struct Curl_easy *data,
- struct Curl_cwriter *writer, int type,
- const char *buf, size_t blen)
-{
- struct chunked_writer *ctx = writer->ctx;
- CURLcode result;
- size_t consumed;
-
- if(!(type & CLIENTWRITE_BODY))
- return Curl_cwriter_write(data, writer->next, type, buf, blen);
-
- consumed = 0;
- result = httpchunk_readwrite(data, &ctx->ch, writer->next, buf, blen,
- &consumed);
-
- if(result) {
- if(CHUNKE_PASSTHRU_ERROR == ctx->ch.last_code) {
- failf(data, "Failed reading the chunked-encoded stream");
- }
- else {
- failf(data, "%s in chunked-encoding",
- Curl_chunked_strerror(ctx->ch.last_code));
- }
- return result;
- }
-
- blen -= consumed;
- if(CHUNK_DONE == ctx->ch.state) {
- /* chunks read successfully, download is complete */
- data->req.download_done = TRUE;
- if(blen) {
- infof(data, "Leftovers after chunking: %zu bytes", blen);
- }
- }
- else if((type & CLIENTWRITE_EOS) && !data->req.no_body) {
- failf(data, "transfer closed with outstanding read data remaining");
- return CURLE_PARTIAL_FILE;
- }
-
- return CURLE_OK;
-}
-
-/* HTTP chunked Transfer-Encoding decoder */
-const struct Curl_cwtype Curl_httpchunk_unencoder = {
- "chunked",
- NULL,
- cw_chunked_init,
- cw_chunked_write,
- cw_chunked_close,
- sizeof(struct chunked_writer)
-};
-
-/* max length of an HTTP chunk that we want to generate */
-#define CURL_CHUNKED_MINLEN (1024)
-#define CURL_CHUNKED_MAXLEN (64 * 1024)
-
-struct chunked_reader {
- struct Curl_creader super;
- struct bufq chunkbuf;
- BIT(read_eos); /* we read an EOS from the next reader */
- BIT(eos); /* we have returned an EOS */
-};
-
-static CURLcode cr_chunked_init(struct Curl_easy *data,
- struct Curl_creader *reader)
-{
- struct chunked_reader *ctx = reader->ctx;
- (void)data;
- Curl_bufq_init2(&ctx->chunkbuf, CURL_CHUNKED_MAXLEN, 2, BUFQ_OPT_SOFT_LIMIT);
- return CURLE_OK;
-}
-
-static void cr_chunked_close(struct Curl_easy *data,
- struct Curl_creader *reader)
-{
- struct chunked_reader *ctx = reader->ctx;
- (void)data;
- Curl_bufq_free(&ctx->chunkbuf);
-}
-
-static CURLcode add_last_chunk(struct Curl_easy *data,
- struct Curl_creader *reader)
-{
- struct chunked_reader *ctx = reader->ctx;
- struct curl_slist *trailers = NULL, *tr;
- CURLcode result;
- size_t n;
- int rc;
-
- if(!data->set.trailer_callback) {
- CURL_TRC_READ(data, "http_chunk, added last, empty chunk");
- return Curl_bufq_cwrite(&ctx->chunkbuf, STRCONST("0\r\n\r\n"), &n);
- }
-
- result = Curl_bufq_cwrite(&ctx->chunkbuf, STRCONST("0\r\n"), &n);
- if(result)
- goto out;
-
- Curl_set_in_callback(data, true);
- rc = data->set.trailer_callback(&trailers, data->set.trailer_data);
- Curl_set_in_callback(data, false);
-
- if(rc != CURL_TRAILERFUNC_OK) {
- failf(data, "operation aborted by trailing headers callback");
- result = CURLE_ABORTED_BY_CALLBACK;
- goto out;
- }
-
- for(tr = trailers; tr; tr = tr->next) {
- /* only add correctly formatted trailers */
- char *ptr = strchr(tr->data, ':');
- if(!ptr || *(ptr + 1) != ' ') {
- infof(data, "Malformatted trailing header, skipping trailer");
- continue;
- }
-
- result = Curl_bufq_cwrite(&ctx->chunkbuf, tr->data,
- strlen(tr->data), &n);
- if(!result)
- result = Curl_bufq_cwrite(&ctx->chunkbuf, STRCONST("\r\n"), &n);
- if(result)
- goto out;
- }
-
- result = Curl_bufq_cwrite(&ctx->chunkbuf, STRCONST("\r\n"), &n);
-
-out:
- curl_slist_free_all(trailers);
- CURL_TRC_READ(data, "http_chunk, added last chunk with trailers "
- "from client -> %d", result);
- return result;
-}
-
-static CURLcode add_chunk(struct Curl_easy *data,
- struct Curl_creader *reader,
- char *buf, size_t blen)
-{
- struct chunked_reader *ctx = reader->ctx;
- CURLcode result;
- char tmp[CURL_CHUNKED_MINLEN];
- size_t nread;
- bool eos;
-
- DEBUGASSERT(!ctx->read_eos);
- blen = CURLMIN(blen, CURL_CHUNKED_MAXLEN); /* respect our buffer pref */
- if(blen < sizeof(tmp)) {
- /* small read, make a chunk of decent size */
- buf = tmp;
- blen = sizeof(tmp);
- }
- else {
- /* larger read, make a chunk that will fit when read back */
- blen -= (8 + 2 + 2); /* deduct max overhead, 8 hex + 2*crlf */
- }
-
- result = Curl_creader_read(data, reader->next, buf, blen, &nread, &eos);
- if(result)
- return result;
- if(eos)
- ctx->read_eos = TRUE;
-
- if(nread) {
- /* actually got bytes, wrap them into the chunkbuf */
- char hd[11] = "";
- int hdlen;
- size_t n;
-
- hdlen = msnprintf(hd, sizeof(hd), "%zx\r\n", nread);
- if(hdlen <= 0)
- return CURLE_READ_ERROR;
- /* On a soft-limited bufq, we do not need to check that all was written */
- result = Curl_bufq_cwrite(&ctx->chunkbuf, hd, hdlen, &n);
- if(!result)
- result = Curl_bufq_cwrite(&ctx->chunkbuf, buf, nread, &n);
- if(!result)
- result = Curl_bufq_cwrite(&ctx->chunkbuf, "\r\n", 2, &n);
- CURL_TRC_READ(data, "http_chunk, made chunk of %zu bytes -> %d",
- nread, result);
- if(result)
- return result;
- }
-
- if(ctx->read_eos)
- return add_last_chunk(data, reader);
- return CURLE_OK;
-}
-
-static CURLcode cr_chunked_read(struct Curl_easy *data,
- struct Curl_creader *reader,
- char *buf, size_t blen,
- size_t *pnread, bool *peos)
-{
- struct chunked_reader *ctx = reader->ctx;
- CURLcode result = CURLE_READ_ERROR;
-
- *pnread = 0;
- *peos = ctx->eos;
-
- if(!ctx->eos) {
- if(!ctx->read_eos && Curl_bufq_is_empty(&ctx->chunkbuf)) {
- /* Still getting data form the next reader, buffer is empty */
- result = add_chunk(data, reader, buf, blen);
- if(result)
- return result;
- }
-
- if(!Curl_bufq_is_empty(&ctx->chunkbuf)) {
- result = Curl_bufq_cread(&ctx->chunkbuf, buf, blen, pnread);
- if(!result && ctx->read_eos && Curl_bufq_is_empty(&ctx->chunkbuf)) {
- /* no more data, read all, done. */
- ctx->eos = TRUE;
- *peos = TRUE;
- }
- return result;
- }
- }
- /* We may get here, because we are done or because callbacks paused */
- DEBUGASSERT(ctx->eos || !ctx->read_eos);
- return CURLE_OK;
-}
-
-static curl_off_t cr_chunked_total_length(struct Curl_easy *data,
- struct Curl_creader *reader)
-{
- /* this reader changes length depending on input */
- (void)data;
- (void)reader;
- return -1;
-}
-
-/* HTTP chunked Transfer-Encoding encoder */
-const struct Curl_crtype Curl_httpchunk_encoder = {
- "chunked",
- cr_chunked_init,
- cr_chunked_read,
- cr_chunked_close,
- Curl_creader_def_needs_rewind,
- cr_chunked_total_length,
- Curl_creader_def_resume_from,
- Curl_creader_def_rewind,
- Curl_creader_def_unpause,
- Curl_creader_def_is_paused,
- Curl_creader_def_done,
- sizeof(struct chunked_reader)
-};
-
-CURLcode Curl_httpchunk_add_reader(struct Curl_easy *data)
-{
- struct Curl_creader *reader = NULL;
- CURLcode result;
-
- result = Curl_creader_create(&reader, data, &Curl_httpchunk_encoder,
- CURL_CR_TRANSFER_ENCODE);
- if(!result)
- result = Curl_creader_add(data, reader);
-
- if(result && reader)
- Curl_creader_free(data, reader);
- return result;
-}
-
#endif /* CURL_DISABLE_HTTP */
diff --git a/contrib/libs/curl/lib/http_chunks.h b/contrib/libs/curl/lib/http_chunks.h
index 34951ea0f4..0a36f379b1 100644
--- a/contrib/libs/curl/lib/http_chunks.h
+++ b/contrib/libs/curl/lib/http_chunks.h
@@ -24,21 +24,17 @@
*
***************************************************************************/
-#ifndef CURL_DISABLE_HTTP
-
-#include "dynbuf.h"
-
struct connectdata;
/*
* The longest possible hexadecimal number we support in a chunked transfer.
* Neither RFC2616 nor the later HTTP specs define a maximum chunk size.
- * For 64-bit curl_off_t we support 16 digits. For 32-bit, 8 digits.
+ * For 64 bit curl_off_t we support 16 digits. For 32 bit, 8 digits.
*/
#define CHUNK_MAXNUM_LEN (SIZEOF_CURL_OFF_T * 2)
typedef enum {
- /* await and buffer all hexadecimal digits until we get one that is not a
+ /* await and buffer all hexadecimal digits until we get one that isn't a
hexadecimal digit. When done, we go CHUNK_LF */
CHUNK_HEX,
@@ -54,9 +50,9 @@ typedef enum {
big deal. */
CHUNK_POSTLF,
- /* Used to mark that we are out of the game. NOTE: that there is a
- 'datasize' field in the struct that will tell how many bytes that were
- not passed to the client in the end of the last buffer! */
+ /* Used to mark that we're out of the game. NOTE: that there's a 'datasize'
+ field in the struct that will tell how many bytes that were not passed to
+ the client in the end of the last buffer! */
CHUNK_STOP,
/* At this point optional trailer headers can be found, unless the next line
@@ -71,75 +67,34 @@ typedef enum {
signalled If this is an empty trailer CHUNKE_STOP will be signalled.
Otherwise the trailer will be broadcasted via Curl_client_write() and the
next state will be CHUNK_TRAILER */
- CHUNK_TRAILER_POSTCR,
-
- /* Successfully de-chunked everything */
- CHUNK_DONE,
-
- /* Failed on seeing a bad or not correctly terminated chunk */
- CHUNK_FAILED
+ CHUNK_TRAILER_POSTCR
} ChunkyState;
typedef enum {
+ CHUNKE_STOP = -1,
CHUNKE_OK = 0,
CHUNKE_TOO_LONG_HEX = 1,
CHUNKE_ILLEGAL_HEX,
CHUNKE_BAD_CHUNK,
CHUNKE_BAD_ENCODING,
CHUNKE_OUT_OF_MEMORY,
- CHUNKE_PASSTHRU_ERROR /* Curl_httpchunk_read() returns a CURLcode to use */
+ CHUNKE_PASSTHRU_ERROR, /* Curl_httpchunk_read() returns a CURLcode to use */
+ CHUNKE_LAST
} CHUNKcode;
+const char *Curl_chunked_strerror(CHUNKcode code);
+
struct Curl_chunker {
curl_off_t datasize;
ChunkyState state;
- CHUNKcode last_code;
- struct dynbuf trailer; /* for chunked-encoded trailer */
unsigned char hexindex;
- char hexbuffer[CHUNK_MAXNUM_LEN + 1]; /* +1 for null-terminator */
- BIT(ignore_body); /* never write response body data */
+ char hexbuffer[ CHUNK_MAXNUM_LEN + 1]; /* +1 for null-terminator */
};
/* The following functions are defined in http_chunks.c */
-void Curl_httpchunk_init(struct Curl_easy *data, struct Curl_chunker *ch,
- bool ignore_body);
-void Curl_httpchunk_free(struct Curl_easy *data, struct Curl_chunker *ch);
-void Curl_httpchunk_reset(struct Curl_easy *data, struct Curl_chunker *ch,
- bool ignore_body);
-
-/*
- * Read BODY bytes in HTTP/1.1 chunked encoding from `buf` and return
- * the amount of bytes consumed. The actual response bytes and trailer
- * headers are written out to the client.
- * On success, this will consume all bytes up to the end of the response,
- * e.g. the last chunk, has been processed.
- * @param data the transfer involved
- * @param ch the chunker instance keeping state across calls
- * @param buf the response data
- * @param blen amount of bytes in `buf`
- * @param pconsumed on successful return, the number of bytes in `buf`
- * consumed
- *
- * This function always uses ASCII hex values to accommodate non-ASCII hosts.
- * For example, 0x0d and 0x0a are used instead of '\r' and '\n'.
- */
-CURLcode Curl_httpchunk_read(struct Curl_easy *data, struct Curl_chunker *ch,
- char *buf, size_t blen, size_t *pconsumed);
-
-/**
- * @return TRUE iff chunked decoded has finished successfully.
- */
-bool Curl_httpchunk_is_done(struct Curl_easy *data, struct Curl_chunker *ch);
-
-extern const struct Curl_cwtype Curl_httpchunk_unencoder;
-
-extern const struct Curl_crtype Curl_httpchunk_encoder;
-
-/**
- * Add a transfer-encoding "chunked" reader to the transfers reader stack
- */
-CURLcode Curl_httpchunk_add_reader(struct Curl_easy *data);
-
-#endif /* !CURL_DISABLE_HTTP */
+void Curl_httpchunk_init(struct Curl_easy *data);
+CHUNKcode Curl_httpchunk_read(struct Curl_easy *data, char *buf,
+ size_t blen, size_t *pconsumed,
+ CURLcode *passthru);
#endif /* HEADER_CURL_HTTP_CHUNKS_H */
diff --git a/contrib/libs/curl/lib/http_negotiate.c b/contrib/libs/curl/lib/http_negotiate.c
index 26e475c273..153e3d4ab8 100644
--- a/contrib/libs/curl/lib/http_negotiate.c
+++ b/contrib/libs/curl/lib/http_negotiate.c
@@ -30,7 +30,6 @@
#include "sendf.h"
#include "http_negotiate.h"
#include "vauth/vauth.h"
-#include "vtls/vtls.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@@ -96,7 +95,7 @@ CURLcode Curl_input_negotiate(struct Curl_easy *data, struct connectdata *conn,
Curl_http_auth_cleanup_negotiate(conn);
}
else if(state != GSS_AUTHNONE) {
- /* The server rejected our authentication and has not supplied any more
+ /* The server rejected our authentication and hasn't supplied any more
negotiation mechanisms */
Curl_http_auth_cleanup_negotiate(conn);
return CURLE_LOGIN_DENIED;
@@ -107,27 +106,11 @@ CURLcode Curl_input_negotiate(struct Curl_easy *data, struct connectdata *conn,
#if defined(USE_WINDOWS_SSPI) && defined(SECPKG_ATTR_ENDPOINT_BINDINGS)
neg_ctx->sslContext = conn->sslContext;
#endif
- /* Check if the connection is using SSL and get the channel binding data */
-#ifdef HAVE_GSSAPI
- if(conn->handler->flags & PROTOPT_SSL) {
- Curl_dyn_init(&neg_ctx->channel_binding_data, SSL_CB_MAX_SIZE);
- result = Curl_ssl_get_channel_binding(
- data, FIRSTSOCKET, &neg_ctx->channel_binding_data);
- if(result) {
- Curl_http_auth_cleanup_negotiate(conn);
- return result;
- }
- }
-#endif
/* Initialize the security context and decode our challenge */
result = Curl_auth_decode_spnego_message(data, userp, passwdp, service,
host, header, neg_ctx);
-#ifdef HAVE_GSSAPI
- Curl_dyn_free(&neg_ctx->channel_binding_data);
-#endif
-
if(result)
Curl_http_auth_cleanup_negotiate(conn);
@@ -137,29 +120,16 @@ CURLcode Curl_input_negotiate(struct Curl_easy *data, struct connectdata *conn,
CURLcode Curl_output_negotiate(struct Curl_easy *data,
struct connectdata *conn, bool proxy)
{
- struct negotiatedata *neg_ctx;
- struct auth *authp;
- curlnegotiate *state;
+ struct negotiatedata *neg_ctx = proxy ? &conn->proxyneg :
+ &conn->negotiate;
+ struct auth *authp = proxy ? &data->state.authproxy : &data->state.authhost;
+ curlnegotiate *state = proxy ? &conn->proxy_negotiate_state :
+ &conn->http_negotiate_state;
char *base64 = NULL;
size_t len = 0;
char *userp;
CURLcode result;
- if(proxy) {
-#ifndef CURL_DISABLE_PROXY
- neg_ctx = &conn->proxyneg;
- authp = &data->state.authproxy;
- state = &conn->proxy_negotiate_state;
-#else
- return CURLE_NOT_BUILT_IN;
-#endif
- }
- else {
- neg_ctx = &conn->negotiate;
- authp = &data->state.authhost;
- state = &conn->http_negotiate_state;
- }
-
authp->done = FALSE;
if(*state == GSS_AUTHRECV) {
@@ -201,10 +171,8 @@ CURLcode Curl_output_negotiate(struct Curl_easy *data,
base64);
if(proxy) {
-#ifndef CURL_DISABLE_PROXY
Curl_safefree(data->state.aptr.proxyuserpwd);
data->state.aptr.proxyuserpwd = userp;
-#endif
}
else {
Curl_safefree(data->state.aptr.userpwd);
@@ -235,7 +203,7 @@ CURLcode Curl_output_negotiate(struct Curl_easy *data,
if(*state == GSS_AUTHDONE || *state == GSS_AUTHSUCC) {
/* connection is already authenticated,
- * do not send a header in future requests */
+ * don't send a header in future requests */
authp->done = TRUE;
}
diff --git a/contrib/libs/curl/lib/http_ntlm.c b/contrib/libs/curl/lib/http_ntlm.c
index 49230bc1bd..b845ddf37f 100644
--- a/contrib/libs/curl/lib/http_ntlm.c
+++ b/contrib/libs/curl/lib/http_ntlm.c
@@ -40,6 +40,7 @@
#include "strcase.h"
#include "http_ntlm.h"
#include "curl_ntlm_core.h"
+#include "curl_ntlm_wb.h"
#include "curl_base64.h"
#include "vauth/vauth.h"
#include "url.h"
@@ -123,7 +124,7 @@ CURLcode Curl_input_ntlm(struct Curl_easy *data,
}
/*
- * This is for creating NTLM header output
+ * This is for creating ntlm header output
*/
CURLcode Curl_output_ntlm(struct Curl_easy *data, bool proxy)
{
@@ -187,10 +188,10 @@ CURLcode Curl_output_ntlm(struct Curl_easy *data, bool proxy)
passwdp = "";
#ifdef USE_WINDOWS_SSPI
- if(!Curl_hSecDll) {
+ if(!s_hSecDll) {
/* not thread safe and leaks - use curl_global_init() to avoid */
CURLcode err = Curl_sspi_global_init();
- if(!Curl_hSecDll)
+ if(!s_hSecDll)
return err;
}
#ifdef SECPKG_ATTR_ENDPOINT_BINDINGS
@@ -200,7 +201,7 @@ CURLcode Curl_output_ntlm(struct Curl_easy *data, bool proxy)
Curl_bufref_init(&ntlmmsg);
- /* connection is already authenticated, do not send a header in future
+ /* connection is already authenticated, don't send a header in future
* requests so go directly to NTLMSTATE_LAST */
if(*state == NTLMSTATE_TYPE3)
*state = NTLMSTATE_LAST;
@@ -265,6 +266,10 @@ void Curl_http_auth_cleanup_ntlm(struct connectdata *conn)
{
Curl_auth_cleanup_ntlm(&conn->ntlm);
Curl_auth_cleanup_ntlm(&conn->proxyntlm);
+
+#if defined(NTLM_WB_ENABLED)
+ Curl_http_auth_cleanup_ntlm_wb(conn);
+#endif
}
#endif /* !CURL_DISABLE_HTTP && USE_NTLM */
diff --git a/contrib/libs/curl/lib/http_ntlm.h b/contrib/libs/curl/lib/http_ntlm.h
index c1cf05701f..f37572baec 100644
--- a/contrib/libs/curl/lib/http_ntlm.h
+++ b/contrib/libs/curl/lib/http_ntlm.h
@@ -28,11 +28,11 @@
#if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM)
-/* this is for NTLM header input */
+/* this is for ntlm header input */
CURLcode Curl_input_ntlm(struct Curl_easy *data, bool proxy,
const char *header);
-/* this is for creating NTLM header output */
+/* this is for creating ntlm header output */
CURLcode Curl_output_ntlm(struct Curl_easy *data, bool proxy);
void Curl_http_auth_cleanup_ntlm(struct connectdata *conn);
diff --git a/contrib/libs/curl/lib/http_proxy.c b/contrib/libs/curl/lib/http_proxy.c
index 4cbe59fc3f..2235ce786a 100644
--- a/contrib/libs/curl/lib/http_proxy.c
+++ b/contrib/libs/curl/lib/http_proxy.c
@@ -131,8 +131,8 @@ CURLcode Curl_http_proxy_create_CONNECT(struct httpreq **preq,
goto out;
}
- if(!Curl_checkProxyheaders(data, cf->conn, STRCONST("User-Agent")) &&
- data->set.str[STRING_USERAGENT] && *data->set.str[STRING_USERAGENT]) {
+ if(!Curl_checkProxyheaders(data, cf->conn, STRCONST("User-Agent"))
+ && data->set.str[STRING_USERAGENT]) {
result = Curl_dynhds_cadd(&req->headers, "User-Agent",
data->set.str[STRING_USERAGENT]);
if(result)
@@ -293,12 +293,11 @@ static void http_proxy_cf_close(struct Curl_cfilter *cf,
struct Curl_cftype Curl_cft_http_proxy = {
"HTTP-PROXY",
- CF_TYPE_IP_CONNECT|CF_TYPE_PROXY,
+ CF_TYPE_IP_CONNECT,
0,
http_proxy_cf_destroy,
http_proxy_cf_connect,
http_proxy_cf_close,
- Curl_cf_def_shutdown,
Curl_cf_http_proxy_get_host,
Curl_cf_def_adjust_pollset,
Curl_cf_def_data_pending,
diff --git a/contrib/libs/curl/lib/idn.c b/contrib/libs/curl/lib/idn.c
index 102da52cff..76b44564b3 100644
--- a/contrib/libs/curl/lib/idn.c
+++ b/contrib/libs/curl/lib/idn.c
@@ -50,108 +50,10 @@
#include "curl_memory.h"
#include "memdebug.h"
-/* for macOS and iOS targets */
-#if defined(USE_APPLE_IDN)
-#error #include <unicode/uidna.h>
-#include <iconv.h>
-#include <langinfo.h>
-
-#define MAX_HOST_LENGTH 512
-
-static CURLcode iconv_to_utf8(const char *in, size_t inlen,
- char **out, size_t *outlen)
-{
- iconv_t cd = iconv_open("UTF-8", nl_langinfo(CODESET));
- if(cd != (iconv_t)-1) {
- size_t iconv_outlen = *outlen;
- char *iconv_in = (char *)in;
- size_t iconv_inlen = inlen;
- size_t iconv_result = iconv(cd, &iconv_in, &iconv_inlen,
- out, &iconv_outlen);
- *outlen -= iconv_outlen;
- iconv_close(cd);
- if(iconv_result == (size_t)-1) {
- if(errno == ENOMEM)
- return CURLE_OUT_OF_MEMORY;
- else
- return CURLE_URL_MALFORMAT;
- }
-
- return CURLE_OK;
- }
- else {
- if(errno == ENOMEM)
- return CURLE_OUT_OF_MEMORY;
- else
- return CURLE_FAILED_INIT;
- }
-}
-
-static CURLcode mac_idn_to_ascii(const char *in, char **out)
-{
- size_t inlen = strlen(in);
- if(inlen < MAX_HOST_LENGTH) {
- char iconv_buffer[MAX_HOST_LENGTH] = {0};
- char *iconv_outptr = iconv_buffer;
- size_t iconv_outlen = sizeof(iconv_buffer);
- CURLcode iconv_result = iconv_to_utf8(in, inlen,
- &iconv_outptr, &iconv_outlen);
- if(!iconv_result) {
- UErrorCode err = U_ZERO_ERROR;
- UIDNA* idna = uidna_openUTS46(
- UIDNA_CHECK_BIDI|UIDNA_NONTRANSITIONAL_TO_ASCII, &err);
- if(!U_FAILURE(err)) {
- UIDNAInfo info = UIDNA_INFO_INITIALIZER;
- char buffer[MAX_HOST_LENGTH] = {0};
- (void)uidna_nameToASCII_UTF8(idna, iconv_buffer, (int)iconv_outlen,
- buffer, sizeof(buffer) - 1, &info, &err);
- uidna_close(idna);
- if(!U_FAILURE(err) && !info.errors) {
- *out = strdup(buffer);
- if(*out)
- return CURLE_OK;
- else
- return CURLE_OUT_OF_MEMORY;
- }
- }
- }
- else
- return iconv_result;
- }
- return CURLE_URL_MALFORMAT;
-}
-
-static CURLcode mac_ascii_to_idn(const char *in, char **out)
-{
- size_t inlen = strlen(in);
- if(inlen < MAX_HOST_LENGTH) {
- UErrorCode err = U_ZERO_ERROR;
- UIDNA* idna = uidna_openUTS46(
- UIDNA_CHECK_BIDI|UIDNA_NONTRANSITIONAL_TO_UNICODE, &err);
- if(!U_FAILURE(err)) {
- UIDNAInfo info = UIDNA_INFO_INITIALIZER;
- char buffer[MAX_HOST_LENGTH] = {0};
- (void)uidna_nameToUnicodeUTF8(idna, in, -1, buffer,
- sizeof(buffer) - 1, &info, &err);
- uidna_close(idna);
- if(!U_FAILURE(err)) {
- *out = strdup(buffer);
- if(*out)
- return CURLE_OK;
- else
- return CURLE_OUT_OF_MEMORY;
- }
- }
- }
- return CURLE_URL_MALFORMAT;
-}
-#endif
-
#ifdef USE_WIN32_IDN
/* using Windows kernel32 and normaliz libraries. */
-#if (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x600) && \
- (!defined(WINVER) || WINVER < 0x600)
+#if !defined(_WIN32_WINNT) || _WIN32_WINNT < 0x600
WINBASEAPI int WINAPI IdnToAscii(DWORD dwFlags,
const WCHAR *lpUnicodeCharStr,
int cchUnicodeChar,
@@ -248,7 +150,7 @@ bool Curl_is_ASCII_name(const char *hostname)
* Curl_idn_decode() returns an allocated IDN decoded string if it was
* possible. NULL on error.
*
- * CURLE_URL_MALFORMAT - the hostname could not be converted
+ * CURLE_URL_MALFORMAT - the host name could not be converted
* CURLE_OUT_OF_MEMORY - memory problem
*
*/
@@ -279,8 +181,6 @@ static CURLcode idn_decode(const char *input, char **output)
result = CURLE_NOT_BUILT_IN;
#elif defined(USE_WIN32_IDN)
result = win32_idn_to_ascii(input, &decoded);
-#elif defined(USE_APPLE_IDN)
- result = mac_idn_to_ascii(input, &decoded);
#endif
if(!result)
*output = decoded;
@@ -298,10 +198,6 @@ static CURLcode idn_encode(const char *puny, char **output)
CURLcode result = win32_ascii_to_idn(puny, &enc);
if(result)
return result;
-#elif defined(USE_APPLE_IDN)
- CURLcode result = mac_ascii_to_idn(puny, &enc);
- if(result)
- return result;
#endif
*output = enc;
return CURLE_OK;
@@ -350,7 +246,11 @@ CURLcode Curl_idn_encode(const char *puny, char **output)
*/
void Curl_free_idnconverted_hostname(struct hostname *host)
{
- Curl_safefree(host->encalloc);
+ if(host->encalloc) {
+ /* must be freed with idn2_free() if allocated by libidn */
+ Curl_idn_free(host->encalloc);
+ host->encalloc = NULL;
+ }
}
#endif /* USE_IDN */
@@ -360,18 +260,27 @@ void Curl_free_idnconverted_hostname(struct hostname *host)
*/
CURLcode Curl_idnconvert_hostname(struct hostname *host)
{
- /* set the name we use to display the hostname */
+ /* set the name we use to display the host name */
host->dispname = host->name;
#ifdef USE_IDN
/* Check name for non-ASCII and convert hostname if we can */
if(!Curl_is_ASCII_name(host->name)) {
char *decoded;
- CURLcode result = Curl_idn_decode(host->name, &decoded);
- if(result)
+ CURLcode result = idn_decode(host->name, &decoded);
+ if(!result) {
+ if(!*decoded) {
+ /* zero length is a bad host name */
+ Curl_idn_free(decoded);
+ return CURLE_URL_MALFORMAT;
+ }
+ /* successful */
+ host->encalloc = decoded;
+ /* change the name pointer to point to the encoded hostname */
+ host->name = host->encalloc;
+ }
+ else
return result;
- /* successful */
- host->name = host->encalloc = decoded;
}
#endif
return CURLE_OK;
diff --git a/contrib/libs/curl/lib/idn.h b/contrib/libs/curl/lib/idn.h
index 2bdce8927f..74bbcaf498 100644
--- a/contrib/libs/curl/lib/idn.h
+++ b/contrib/libs/curl/lib/idn.h
@@ -26,11 +26,16 @@
bool Curl_is_ASCII_name(const char *hostname);
CURLcode Curl_idnconvert_hostname(struct hostname *host);
-#if defined(USE_LIBIDN2) || defined(USE_WIN32_IDN) || defined(USE_APPLE_IDN)
+#if defined(USE_LIBIDN2) || defined(USE_WIN32_IDN)
#define USE_IDN
void Curl_free_idnconverted_hostname(struct hostname *host);
CURLcode Curl_idn_decode(const char *input, char **output);
CURLcode Curl_idn_encode(const char *input, char **output);
+#ifdef USE_LIBIDN2
+#define Curl_idn_free(x) idn2_free(x)
+#else
+#define Curl_idn_free(x) free(x)
+#endif
#else
#define Curl_free_idnconverted_hostname(x)
diff --git a/contrib/libs/curl/lib/if2ip.c b/contrib/libs/curl/lib/if2ip.c
index 55afd553d6..5249f6cc7e 100644
--- a/contrib/libs/curl/lib/if2ip.c
+++ b/contrib/libs/curl/lib/if2ip.c
@@ -62,7 +62,7 @@
/* ------------------------------------------------------------------ */
-#ifdef USE_IPV6
+#ifdef ENABLE_IPV6
/* Return the scope of the given address. */
unsigned int Curl_ipv6_scope(const struct sockaddr *sa)
{
@@ -97,17 +97,17 @@ unsigned int Curl_ipv6_scope(const struct sockaddr *sa)
#if defined(HAVE_GETIFADDRS)
if2ip_result_t Curl_if2ip(int af,
-#ifdef USE_IPV6
+#ifdef ENABLE_IPV6
unsigned int remote_scope,
unsigned int local_scope_id,
#endif
const char *interf,
- char *buf, size_t buf_size)
+ char *buf, int buf_size)
{
struct ifaddrs *iface, *head;
if2ip_result_t res = IF2IP_NOT_FOUND;
-#if defined(USE_IPV6) && \
+#if defined(ENABLE_IPV6) && \
!defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID)
(void) local_scope_id;
#endif
@@ -121,7 +121,7 @@ if2ip_result_t Curl_if2ip(int af,
const char *ip;
char scope[12] = "";
char ipstr[64];
-#ifdef USE_IPV6
+#ifdef ENABLE_IPV6
if(af == AF_INET6) {
#ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
unsigned int scopeid = 0;
@@ -182,12 +182,12 @@ if2ip_result_t Curl_if2ip(int af,
#elif defined(HAVE_IOCTL_SIOCGIFADDR)
if2ip_result_t Curl_if2ip(int af,
-#ifdef USE_IPV6
+#ifdef ENABLE_IPV6
unsigned int remote_scope,
unsigned int local_scope_id,
#endif
const char *interf,
- char *buf, size_t buf_size)
+ char *buf, int buf_size)
{
struct ifreq req;
struct in_addr in;
@@ -196,7 +196,7 @@ if2ip_result_t Curl_if2ip(int af,
size_t len;
const char *r;
-#ifdef USE_IPV6
+#ifdef ENABLE_IPV6
(void)remote_scope;
(void)local_scope_id;
#endif
@@ -216,15 +216,7 @@ if2ip_result_t Curl_if2ip(int af,
memcpy(req.ifr_name, interf, len + 1);
req.ifr_addr.sa_family = AF_INET;
-#if defined(__GNUC__) && defined(_AIX)
-/* Suppress warning inside system headers */
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wshift-sign-overflow"
-#endif
if(ioctl(dummy, SIOCGIFADDR, &req) < 0) {
-#if defined(__GNUC__) && defined(_AIX)
-#pragma GCC diagnostic pop
-#endif
sclose(dummy);
/* With SIOCGIFADDR, we cannot tell the difference between an interface
that does not exist and an interface that has no address of the
@@ -245,15 +237,15 @@ if2ip_result_t Curl_if2ip(int af,
#else
if2ip_result_t Curl_if2ip(int af,
-#ifdef USE_IPV6
+#ifdef ENABLE_IPV6
unsigned int remote_scope,
unsigned int local_scope_id,
#endif
const char *interf,
- char *buf, size_t buf_size)
+ char *buf, int buf_size)
{
(void) af;
-#ifdef USE_IPV6
+#ifdef ENABLE_IPV6
(void) remote_scope;
(void) local_scope_id;
#endif
diff --git a/contrib/libs/curl/lib/if2ip.h b/contrib/libs/curl/lib/if2ip.h
index f4b2f4c15d..1f973505c0 100644
--- a/contrib/libs/curl/lib/if2ip.h
+++ b/contrib/libs/curl/lib/if2ip.h
@@ -32,7 +32,7 @@
#define IPV6_SCOPE_UNIQUELOCAL 3 /* Unique local */
#define IPV6_SCOPE_NODELOCAL 4 /* Loopback. */
-#ifdef USE_IPV6
+#ifdef ENABLE_IPV6
unsigned int Curl_ipv6_scope(const struct sockaddr *sa);
#else
#define Curl_ipv6_scope(x) 0
@@ -45,12 +45,12 @@ typedef enum {
} if2ip_result_t;
if2ip_result_t Curl_if2ip(int af,
-#ifdef USE_IPV6
+#ifdef ENABLE_IPV6
unsigned int remote_scope,
unsigned int local_scope_id,
#endif
const char *interf,
- char *buf, size_t buf_size);
+ char *buf, int buf_size);
#ifdef __INTERIX
diff --git a/contrib/libs/curl/lib/imap.c b/contrib/libs/curl/lib/imap.c
index 4979a18edc..47cff4897c 100644
--- a/contrib/libs/curl/lib/imap.c
+++ b/contrib/libs/curl/lib/imap.c
@@ -97,8 +97,7 @@ static CURLcode imap_doing(struct Curl_easy *data, bool *dophase_done);
static CURLcode imap_setup_connection(struct Curl_easy *data,
struct connectdata *conn);
static char *imap_atom(const char *str, bool escape_only);
-static CURLcode imap_sendf(struct Curl_easy *data, const char *fmt, ...)
- CURL_PRINTF(2, 3);
+static CURLcode imap_sendf(struct Curl_easy *data, const char *fmt, ...);
static CURLcode imap_parse_url_options(struct connectdata *conn);
static CURLcode imap_parse_url_path(struct Curl_easy *data);
static CURLcode imap_parse_custom_request(struct Curl_easy *data);
@@ -117,7 +116,7 @@ static CURLcode imap_get_message(struct Curl_easy *data, struct bufref *out);
*/
const struct Curl_handler Curl_handler_imap = {
- "imap", /* scheme */
+ "IMAP", /* scheme */
imap_setup_connection, /* setup_connection */
imap_do, /* do_it */
imap_done, /* done */
@@ -130,8 +129,7 @@ const struct Curl_handler Curl_handler_imap = {
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
imap_disconnect, /* disconnect */
- ZERO_NULL, /* write_resp */
- ZERO_NULL, /* write_resp_hd */
+ ZERO_NULL, /* readwrite */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_IMAP, /* defport */
@@ -147,7 +145,7 @@ const struct Curl_handler Curl_handler_imap = {
*/
const struct Curl_handler Curl_handler_imaps = {
- "imaps", /* scheme */
+ "IMAPS", /* scheme */
imap_setup_connection, /* setup_connection */
imap_do, /* do_it */
imap_done, /* done */
@@ -160,8 +158,7 @@ const struct Curl_handler Curl_handler_imaps = {
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
imap_disconnect, /* disconnect */
- ZERO_NULL, /* write_resp */
- ZERO_NULL, /* write_resp_hd */
+ ZERO_NULL, /* readwrite */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_IMAPS, /* defport */
@@ -357,8 +354,8 @@ static bool imap_endofresp(struct Curl_easy *data, struct connectdata *conn,
*/
static CURLcode imap_get_message(struct Curl_easy *data, struct bufref *out)
{
- char *message = Curl_dyn_ptr(&data->conn->proto.imapc.pp.recvbuf);
- size_t len = data->conn->proto.imapc.pp.nfinal;
+ char *message = data->state.buffer;
+ size_t len = strlen(message);
if(len > 2) {
/* Find the start of the message */
@@ -512,7 +509,7 @@ static CURLcode imap_perform_login(struct Curl_easy *data,
char *passwd;
/* Check we have a username and password to authenticate with and end the
- connect phase if we do not */
+ connect phase if we don't */
if(!data->state.aptr.user) {
imap_state(data, IMAP_STOP);
@@ -612,7 +609,7 @@ static CURLcode imap_perform_authentication(struct Curl_easy *data,
saslprogress progress;
/* Check if already authenticated OR if there is enough data to authenticate
- with and end the connect phase if we do not */
+ with and end the connect phase if we don't */
if(imapc->preauth ||
!Curl_sasl_can_authenticate(&imapc->sasl, data)) {
imap_state(data, IMAP_STOP);
@@ -772,11 +769,10 @@ static CURLcode imap_perform_append(struct Curl_easy *data)
return CURLE_URL_MALFORMAT;
}
-#ifndef CURL_DISABLE_MIME
/* Prepare the mime data if some. */
if(data->set.mimepost.kind != MIMEKIND_NONE) {
/* Use the whole structure as data. */
- data->set.mimepost.flags &= ~(unsigned int)MIME_BODY_ONLY;
+ data->set.mimepost.flags &= ~MIME_BODY_ONLY;
/* Add external headers and mime version. */
curl_mime_headers(&data->set.mimepost, data->set.headers, 0);
@@ -788,18 +784,18 @@ static CURLcode imap_perform_append(struct Curl_easy *data)
result = Curl_mime_add_header(&data->set.mimepost.curlheaders,
"Mime-Version: 1.0");
+ /* Make sure we will read the entire mime structure. */
if(!result)
- result = Curl_creader_set_mime(data, &data->set.mimepost);
- if(result)
- return result;
- data->state.infilesize = Curl_creader_client_length(data);
- }
- else
-#endif
- {
- result = Curl_creader_set_fread(data, data->state.infilesize);
+ result = Curl_mime_rewind(&data->set.mimepost);
+
if(result)
return result;
+
+ data->state.infilesize = Curl_mime_size(&data->set.mimepost);
+
+ /* Read from mime structure. */
+ data->state.fread_func = (curl_read_callback) Curl_mime_read;
+ data->state.in = (void *) &data->set.mimepost;
}
/* Check we know the size of the upload */
@@ -814,7 +810,8 @@ static CURLcode imap_perform_append(struct Curl_easy *data)
return CURLE_OUT_OF_MEMORY;
/* Send the APPEND command */
- result = imap_sendf(data, "APPEND %s (\\Seen) {%" FMT_OFF_T "}",
+ result = imap_sendf(data,
+ "APPEND %s (\\Seen) {%" CURL_FORMAT_CURL_OFF_T "}",
mailbox, data->state.infilesize);
free(mailbox);
@@ -898,7 +895,7 @@ static CURLcode imap_state_capability_resp(struct Curl_easy *data,
CURLcode result = CURLE_OK;
struct connectdata *conn = data->conn;
struct imap_conn *imapc = &conn->proto.imapc;
- const char *line = Curl_dyn_ptr(&imapc->pp.recvbuf);
+ const char *line = data->state.buffer;
(void)instate; /* no use for this yet */
@@ -984,7 +981,7 @@ static CURLcode imap_state_starttls_resp(struct Curl_easy *data,
(void)instate; /* no use for this yet */
/* Pipelining in response is forbidden. */
- if(data->conn->proto.imapc.pp.overflow)
+ if(data->conn->proto.imapc.pp.cache_size)
return CURLE_WEIRD_SERVER_REPLY;
if(imapcode != IMAP_RESP_OK) {
@@ -1060,13 +1057,17 @@ static CURLcode imap_state_listsearch_resp(struct Curl_easy *data,
imapstate instate)
{
CURLcode result = CURLE_OK;
- char *line = Curl_dyn_ptr(&data->conn->proto.imapc.pp.recvbuf);
- size_t len = data->conn->proto.imapc.pp.nfinal;
+ char *line = data->state.buffer;
+ size_t len = strlen(line);
(void)instate; /* No use for this yet */
- if(imapcode == '*')
- result = Curl_client_write(data, CLIENTWRITE_BODY, line, len);
+ if(imapcode == '*') {
+ /* Temporarily add the LF character back and send as body to the client */
+ line[len] = '\n';
+ result = Curl_client_write(data, CLIENTWRITE_BODY, line, len + 1);
+ line[len] = '\0';
+ }
else if(imapcode != IMAP_RESP_OK)
result = CURLE_QUOTE_ERROR;
else
@@ -1084,7 +1085,7 @@ static CURLcode imap_state_select_resp(struct Curl_easy *data, int imapcode,
struct connectdata *conn = data->conn;
struct IMAP *imap = data->req.p.imap;
struct imap_conn *imapc = &conn->proto.imapc;
- const char *line = Curl_dyn_ptr(&data->conn->proto.imapc.pp.recvbuf);
+ const char *line = data->state.buffer;
(void)instate; /* no use for this yet */
@@ -1143,8 +1144,7 @@ static CURLcode imap_state_fetch_resp(struct Curl_easy *data,
CURLcode result = CURLE_OK;
struct imap_conn *imapc = &conn->proto.imapc;
struct pingpong *pp = &imapc->pp;
- const char *ptr = Curl_dyn_ptr(&data->conn->proto.imapc.pp.recvbuf);
- size_t len = data->conn->proto.imapc.pp.nfinal;
+ const char *ptr = data->state.buffer;
bool parsed = FALSE;
curl_off_t size = 0;
@@ -1158,72 +1158,74 @@ static CURLcode imap_state_fetch_resp(struct Curl_easy *data,
/* Something like this is received "* 1 FETCH (BODY[TEXT] {2021}\r" so parse
the continuation data contained within the curly brackets */
- ptr = memchr(ptr, '{', len);
- if(ptr) {
+ while(*ptr && (*ptr != '{'))
+ ptr++;
+
+ if(*ptr == '{') {
char *endptr;
- if(!curlx_strtoofft(ptr + 1, &endptr, 10, &size) &&
- (endptr - ptr > 1 && *endptr == '}'))
- parsed = TRUE;
+ if(!curlx_strtoofft(ptr + 1, &endptr, 10, &size)) {
+ if(endptr - ptr > 1 && endptr[0] == '}' &&
+ endptr[1] == '\r' && endptr[2] == '\0')
+ parsed = TRUE;
+ }
}
if(parsed) {
- infof(data, "Found %" FMT_OFF_T " bytes to download", size);
+ infof(data, "Found %" CURL_FORMAT_CURL_OFF_T " bytes to download",
+ size);
Curl_pgrsSetDownloadSize(data, size);
- if(pp->overflow) {
- /* At this point there is a data in the receive buffer that is body
- content, send it as body and then skip it. Do note that there may
- even be additional "headers" after the body. */
- size_t chunk = pp->overflow;
-
- /* keep only the overflow */
- Curl_dyn_tail(&pp->recvbuf, chunk);
- pp->nfinal = 0; /* done */
+ if(pp->cache) {
+ /* At this point there is a bunch of data in the header "cache" that is
+ actually body content, send it as body and then skip it. Do note
+ that there may even be additional "headers" after the body. */
+ size_t chunk = pp->cache_size;
if(chunk > (size_t)size)
/* The conversion from curl_off_t to size_t is always fine here */
chunk = (size_t)size;
if(!chunk) {
- /* no size, we are done with the data */
+ /* no size, we're done with the data */
imap_state(data, IMAP_STOP);
return CURLE_OK;
}
- result = Curl_client_write(data, CLIENTWRITE_BODY,
- Curl_dyn_ptr(&pp->recvbuf), chunk);
+ result = Curl_client_write(data, CLIENTWRITE_BODY, pp->cache, chunk);
if(result)
return result;
- infof(data, "Written %zu bytes, %" FMT_OFF_TU
+ infof(data, "Written %zu bytes, %" CURL_FORMAT_CURL_OFF_TU
" bytes are left for transfer", chunk, size - chunk);
- /* Have we used the entire overflow or just part of it?*/
- if(pp->overflow > chunk) {
- /* remember the remaining trailing overflow data */
- pp->overflow -= chunk;
- Curl_dyn_tail(&pp->recvbuf, pp->overflow);
+ /* Have we used the entire cache or just part of it?*/
+ if(pp->cache_size > chunk) {
+ /* Only part of it so shrink the cache to fit the trailing data */
+ memmove(pp->cache, pp->cache + chunk, pp->cache_size - chunk);
+ pp->cache_size -= chunk;
}
else {
- pp->overflow = 0; /* handled */
/* Free the cache */
- Curl_dyn_reset(&pp->recvbuf);
+ Curl_safefree(pp->cache);
+
+ /* Reset the cache size */
+ pp->cache_size = 0;
}
}
if(data->req.bytecount == size)
/* The entire data is already transferred! */
- Curl_xfer_setup_nop(data);
+ Curl_setup_transfer(data, -1, -1, FALSE, -1);
else {
/* IMAP download */
data->req.maxdownload = size;
/* force a recv/send check of this connection, as the data might've been
read off the socket already */
- data->state.select_bits = CURL_CSELECT_IN;
- Curl_xfer_setup1(data, CURL_XFER_RECV, size, FALSE);
+ data->conn->cselect_bits = CURL_CSELECT_IN;
+ Curl_setup_transfer(data, FIRSTSOCKET, size, FALSE, -1);
}
}
else {
- /* We do not know how to parse this line */
+ /* We don't know how to parse this line */
failf(data, "Failed to parse FETCH response.");
result = CURLE_WEIRD_SERVER_REPLY;
}
@@ -1267,7 +1269,7 @@ static CURLcode imap_state_append_resp(struct Curl_easy *data, int imapcode,
Curl_pgrsSetUploadSize(data, data->state.infilesize);
/* IMAP upload */
- Curl_xfer_setup1(data, CURL_XFER_SEND, -1, FALSE);
+ Curl_setup_transfer(data, -1, -1, FALSE, FIRSTSOCKET);
/* End of DO phase */
imap_state(data, IMAP_STOP);
@@ -1298,6 +1300,7 @@ static CURLcode imap_statemachine(struct Curl_easy *data,
struct connectdata *conn)
{
CURLcode result = CURLE_OK;
+ curl_socket_t sock = conn->sock[FIRSTSOCKET];
int imapcode;
struct imap_conn *imapc = &conn->proto.imapc;
struct pingpong *pp = &imapc->pp;
@@ -1314,7 +1317,7 @@ static CURLcode imap_statemachine(struct Curl_easy *data,
do {
/* Read the response from the server */
- result = Curl_pp_readresp(data, FIRSTSOCKET, pp, &imapcode, &nread);
+ result = Curl_pp_readresp(data, sock, pp, &imapcode, &nread);
if(result)
return result;
@@ -1373,6 +1376,7 @@ static CURLcode imap_statemachine(struct Curl_easy *data,
break;
case IMAP_LOGOUT:
+ /* fallthrough, just stop! */
default:
/* internal error */
imap_state(data, IMAP_STOP);
@@ -1468,7 +1472,9 @@ static CURLcode imap_connect(struct Curl_easy *data, bool *done)
Curl_sasl_init(&imapc->sasl, data, &saslimap);
Curl_dyn_init(&imapc->dyn, DYN_IMAP_CMD);
- Curl_pp_init(pp);
+ /* Initialise the pingpong layer */
+ Curl_pp_setup(pp);
+ Curl_pp_init(data, pp);
/* Parse the URL options */
result = imap_parse_url_options(conn);
@@ -1513,10 +1519,10 @@ static CURLcode imap_done(struct Curl_easy *data, CURLcode status,
}
else if(!data->set.connect_only && !imap->custom &&
(imap->uid || imap->mindex || data->state.upload ||
- IS_MIME_POST(data))) {
+ data->set.mimepost.kind != MIMEKIND_NONE)) {
/* Handle responses after FETCH or APPEND transfer has finished */
- if(!data->state.upload && !IS_MIME_POST(data))
+ if(!data->state.upload && data->set.mimepost.kind == MIMEKIND_NONE)
imap_state(data, IMAP_FETCH_FINAL);
else {
/* End the APPEND command first by sending an empty line */
@@ -1582,7 +1588,7 @@ static CURLcode imap_perform(struct Curl_easy *data, bool *connected,
selected = TRUE;
/* Start the first command in the DO phase */
- if(data->state.upload || IS_MIME_POST(data))
+ if(data->state.upload || data->set.mimepost.kind != MIMEKIND_NONE)
/* APPEND can be executed directly */
result = imap_perform_append(data);
else if(imap->custom && (selected || !imap->mailbox))
@@ -1692,7 +1698,7 @@ static CURLcode imap_dophase_done(struct Curl_easy *data, bool connected)
if(imap->transfer != PPTRANSFER_BODY)
/* no data to transfer */
- Curl_xfer_setup_nop(data);
+ Curl_setup_transfer(data, -1, -1, FALSE, -1);
return CURLE_OK;
}
@@ -1789,14 +1795,7 @@ static CURLcode imap_sendf(struct Curl_easy *data, const char *fmt, ...)
if(!result) {
va_list ap;
va_start(ap, fmt);
-#ifdef __clang__
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wformat-nonliteral"
-#endif
result = Curl_pp_vsendf(data, &imapc->pp, Curl_dyn_ptr(&imapc->dyn), ap);
-#ifdef __clang__
-#pragma clang diagnostic pop
-#endif
va_end(ap);
}
return result;
diff --git a/contrib/libs/curl/lib/inet_ntop.c b/contrib/libs/curl/lib/inet_ntop.c
index a2812cf8e2..c9cee0c578 100644
--- a/contrib/libs/curl/lib/inet_ntop.c
+++ b/contrib/libs/curl/lib/inet_ntop.c
@@ -42,11 +42,11 @@
#define INT16SZ 2
/*
- * If USE_IPV6 is disabled, we still want to parse IPv6 addresses, so make
+ * If ENABLE_IPV6 is disabled, we still want to parse IPv6 addresses, so make
* sure we have _some_ value for AF_INET6 without polluting our fake value
* everywhere.
*/
-#if !defined(USE_IPV6) && !defined(AF_INET6)
+#if !defined(ENABLE_IPV6) && !defined(AF_INET6)
#define AF_INET6 (AF_INET + 1)
#endif
@@ -58,7 +58,7 @@
* - uses no statics
* - takes a unsigned char* not an in_addr as input
*/
-static char *inet_ntop4(const unsigned char *src, char *dst, size_t size)
+static char *inet_ntop4 (const unsigned char *src, char *dst, size_t size)
{
char tmp[sizeof("255.255.255.255")];
size_t len;
@@ -84,14 +84,14 @@ static char *inet_ntop4(const unsigned char *src, char *dst, size_t size)
/*
* Convert IPv6 binary address into presentation (printable) format.
*/
-static char *inet_ntop6(const unsigned char *src, char *dst, size_t size)
+static char *inet_ntop6 (const unsigned char *src, char *dst, size_t size)
{
/*
* Note that int32_t and int16_t need only be "at least" large enough
- * to contain a value of the specified size. On some systems, like
+ * to contain a value of the specified size. On some systems, like
* Crays, there is no such thing as an integer variable with 16 bits.
* Keep this in mind if you think this function should have been coded
- * to use pointer overlays. All the world's not a VAX.
+ * to use pointer overlays. All the world's not a VAX.
*/
char tmp[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
char *tp;
@@ -168,7 +168,7 @@ static char *inet_ntop6(const unsigned char *src, char *dst, size_t size)
*tp++ = ':';
*tp++ = '\0';
- /* Check for overflow, copy, and we are done.
+ /* Check for overflow, copy, and we're done.
*/
if((size_t)(tp - tmp) > size) {
errno = ENOSPC;
@@ -185,9 +185,10 @@ static char *inet_ntop6(const unsigned char *src, char *dst, size_t size)
* Returns NULL on error and errno set with the specific
* error, EAFNOSUPPORT or ENOSPC.
*
- * On Windows we store the error in the thread errno, not in the Winsock error
- * code. This is to avoid losing the actual last Winsock error. When this
- * function returns NULL, check errno not SOCKERRNO.
+ * On Windows we store the error in the thread errno, not
+ * in the winsock error code. This is to avoid losing the
+ * actual last winsock error. So when this function returns
+ * NULL, check errno not SOCKERRNO.
*/
char *Curl_inet_ntop(int af, const void *src, char *buf, size_t size)
{
diff --git a/contrib/libs/curl/lib/inet_ntop.h b/contrib/libs/curl/lib/inet_ntop.h
index f592f25251..7c3ead4341 100644
--- a/contrib/libs/curl/lib/inet_ntop.h
+++ b/contrib/libs/curl/lib/inet_ntop.h
@@ -32,13 +32,8 @@ char *Curl_inet_ntop(int af, const void *addr, char *buf, size_t size);
#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
-#ifdef _WIN32
#define Curl_inet_ntop(af,addr,buf,size) \
- inet_ntop(af, addr, buf, size)
-#else
-#define Curl_inet_ntop(af,addr,buf,size) \
- inet_ntop(af, addr, buf, (curl_socklen_t)(size))
-#endif
+ inet_ntop(af, addr, buf, (curl_socklen_t)size)
#endif
#endif /* HEADER_CURL_INET_NTOP_H */
diff --git a/contrib/libs/curl/lib/inet_pton.c b/contrib/libs/curl/lib/inet_pton.c
index 97e6f80d79..7d3c698795 100644
--- a/contrib/libs/curl/lib/inet_pton.c
+++ b/contrib/libs/curl/lib/inet_pton.c
@@ -39,17 +39,17 @@
#define INT16SZ 2
/*
- * If USE_IPV6 is disabled, we still want to parse IPv6 addresses, so make
+ * If ENABLE_IPV6 is disabled, we still want to parse IPv6 addresses, so make
* sure we have _some_ value for AF_INET6 without polluting our fake value
* everywhere.
*/
-#if !defined(USE_IPV6) && !defined(AF_INET6)
+#if !defined(ENABLE_IPV6) && !defined(AF_INET6)
#define AF_INET6 (AF_INET + 1)
#endif
/*
- * WARNING: Do not even consider trying to compile this on a system where
- * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
+ * WARNING: Don't even consider trying to compile this on a system where
+ * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
*/
static int inet_pton4(const char *src, unsigned char *dst);
@@ -61,12 +61,12 @@ static int inet_pton6(const char *src, unsigned char *dst);
* to network format (which is usually some kind of binary format).
* return:
* 1 if the address was valid for the specified address family
- * 0 if the address was not valid (`dst' is untouched in this case)
+ * 0 if the address wasn't valid (`dst' is untouched in this case)
* -1 if some other error occurred (`dst' is untouched in this case, too)
* notice:
* On Windows we store the error in the thread errno, not
- * in the Winsock error code. This is to avoid losing the
- * actual last Winsock error. When this function returns
+ * in the winsock error code. This is to avoid losing the
+ * actual last winsock error. So when this function returns
* -1, check errno not SOCKERRNO.
* author:
* Paul Vixie, 1996.
@@ -92,7 +92,7 @@ Curl_inet_pton(int af, const char *src, void *dst)
* return:
* 1 if `src' is a valid dotted quad, else 0.
* notice:
- * does not touch `dst' unless it is returning 1.
+ * does not touch `dst' unless it's returning 1.
* author:
* Paul Vixie, 1996.
*/
@@ -112,8 +112,7 @@ inet_pton4(const char *src, unsigned char *dst)
pch = strchr(digits, ch);
if(pch) {
- unsigned int val = (unsigned int)(*tp * 10) +
- (unsigned int)(pch - digits);
+ unsigned int val = *tp * 10 + (unsigned int)(pch - digits);
if(saw_digit && *tp == 0)
return (0);
@@ -147,7 +146,7 @@ inet_pton4(const char *src, unsigned char *dst)
* return:
* 1 if `src' is a valid [RFC1884 2.2] address, else 0.
* notice:
- * (1) does not touch `dst' unless it is returning 1.
+ * (1) does not touch `dst' unless it's returning 1.
* (2) :: in a full address is silently ignored.
* credit:
* inspired by Mark Andrews.
@@ -221,7 +220,7 @@ inet_pton6(const char *src, unsigned char *dst)
if(colonp) {
/*
* Since some memmove()'s erroneously fail to handle
- * overlapping regions, we will do the shift by hand.
+ * overlapping regions, we'll do the shift by hand.
*/
const ssize_t n = tp - colonp;
ssize_t i;
diff --git a/contrib/libs/curl/lib/inet_pton.h b/contrib/libs/curl/lib/inet_pton.h
index f8562fa8a7..82fde7e2eb 100644
--- a/contrib/libs/curl/lib/inet_pton.h
+++ b/contrib/libs/curl/lib/inet_pton.h
@@ -31,6 +31,9 @@ int Curl_inet_pton(int, const char *, void *);
#ifdef HAVE_INET_PTON
#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h>
+#elif defined(HAVE_WS2TCPIP_H)
+/* inet_pton() exists in Vista or later */
+#include <ws2tcpip.h>
#endif
#define Curl_inet_pton(x,y,z) inet_pton(x,y,z)
#endif
diff --git a/contrib/libs/curl/lib/krb5.c b/contrib/libs/curl/lib/krb5.c
index c97adeadd9..d74ea61559 100644
--- a/contrib/libs/curl/lib/krb5.c
+++ b/contrib/libs/curl/lib/krb5.c
@@ -25,7 +25,7 @@
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
@@ -52,7 +52,6 @@
#include "ftp.h"
#error #include "curl_gssapi.h"
#include "sendf.h"
-#include "transfer.h"
#include "curl_krb5.h"
#include "warnless.h"
#include "strcase.h"
@@ -66,7 +65,7 @@
static CURLcode ftpsend(struct Curl_easy *data, struct connectdata *conn,
const char *cmd)
{
- size_t bytes_written;
+ ssize_t bytes_written;
#define SBUF_SIZE 1024
char s[SBUF_SIZE];
size_t write_len;
@@ -76,7 +75,8 @@ static CURLcode ftpsend(struct Curl_easy *data, struct connectdata *conn,
unsigned char data_sec = conn->data_prot;
#endif
- DEBUGASSERT(cmd);
+ if(!cmd)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
write_len = strlen(cmd);
if(!write_len || write_len > (sizeof(s) -3))
@@ -91,7 +91,8 @@ static CURLcode ftpsend(struct Curl_easy *data, struct connectdata *conn,
#ifdef HAVE_GSSAPI
conn->data_prot = PROT_CMD;
#endif
- result = Curl_xfer_send(data, sptr, write_len, FALSE, &bytes_written);
+ result = Curl_nwrite(data, FIRSTSOCKET, sptr, write_len,
+ &bytes_written);
#ifdef HAVE_GSSAPI
DEBUGASSERT(data_sec > PROT_NONE && data_sec < PROT_LAST);
conn->data_prot = data_sec;
@@ -100,9 +101,9 @@ static CURLcode ftpsend(struct Curl_easy *data, struct connectdata *conn,
if(result)
break;
- Curl_debug(data, CURLINFO_HEADER_OUT, sptr, bytes_written);
+ Curl_debug(data, CURLINFO_HEADER_OUT, sptr, (size_t)bytes_written);
- if(bytes_written != write_len) {
+ if(bytes_written != (ssize_t)write_len) {
write_len -= bytes_written;
sptr += bytes_written;
}
@@ -169,7 +170,7 @@ krb5_encode(void *app_data, const void *from, int length, int level, void **to)
* libraries modify the input buffer in gss_wrap()
*/
dec.value = (void *)from;
- dec.length = (size_t)length;
+ dec.length = length;
maj = gss_wrap(&min, *context,
level == PROT_PRIVATE,
GSS_C_QOP_DEFAULT,
@@ -178,7 +179,7 @@ krb5_encode(void *app_data, const void *from, int length, int level, void **to)
if(maj != GSS_S_COMPLETE)
return -1;
- /* malloc a new buffer, in case gss_release_buffer does not work as
+ /* malloc a new buffer, in case gss_release_buffer doesn't work as
expected */
*to = malloc(enc.length);
if(!*to)
@@ -227,7 +228,7 @@ krb5_auth(void *app_data, struct Curl_easy *data, struct connectdata *conn)
/* this loop will execute twice (once for service, once for host) */
for(;;) {
- /* this really should not be repeated here, but cannot help it */
+ /* this really shouldn't be repeated here, but can't help it */
if(service == srv_host) {
result = ftpsend(data, conn, "AUTH GSSAPI");
if(result)
@@ -235,12 +236,9 @@ krb5_auth(void *app_data, struct Curl_easy *data, struct connectdata *conn)
if(Curl_GetFTPResponse(data, &nread, NULL))
return -1;
- else {
- struct pingpong *pp = &conn->proto.ftpc.pp;
- char *line = Curl_dyn_ptr(&pp->recvbuf);
- if(line[0] != '3')
- return -1;
- }
+
+ if(data->state.buffer[0] != '3')
+ return -1;
}
stringp = aprintf("%s@%s", service, host);
@@ -324,32 +322,25 @@ krb5_auth(void *app_data, struct Curl_easy *data, struct connectdata *conn)
ret = -1;
break;
}
- else {
- struct pingpong *pp = &conn->proto.ftpc.pp;
- size_t len = Curl_dyn_len(&pp->recvbuf);
- p = Curl_dyn_ptr(&pp->recvbuf);
- if((len < 4) || (p[0] != '2' && p[0] != '3')) {
- infof(data, "Server did not accept auth data");
- ret = AUTH_ERROR;
- break;
- }
+
+ if(data->state.buffer[0] != '2' && data->state.buffer[0] != '3') {
+ infof(data, "Server didn't accept auth data");
+ ret = AUTH_ERROR;
+ break;
}
_gssresp.value = NULL; /* make sure it is initialized */
- _gssresp.length = 0;
- p += 4; /* over '789 ' */
+ p = data->state.buffer + 4;
p = strstr(p, "ADAT=");
if(p) {
- unsigned char *outptr;
- size_t outlen;
- result = Curl_base64_decode(p + 5, &outptr, &outlen);
+ result = Curl_base64_decode(p + 5,
+ (unsigned char **)&_gssresp.value,
+ &_gssresp.length);
if(result) {
failf(data, "base64-decoding: %s", curl_easy_strerror(result));
ret = AUTH_CONTINUE;
break;
}
- _gssresp.value = outptr;
- _gssresp.length = outlen;
}
gssresp = &_gssresp;
@@ -426,6 +417,7 @@ static char level_to_char(int level)
case PROT_PRIVATE:
return 'P';
case PROT_CMD:
+ /* Fall through */
default:
/* Those 2 cases should not be reached! */
break;
@@ -438,9 +430,6 @@ static char level_to_char(int level)
/* Send an FTP command defined by |message| and the optional arguments. The
function returns the ftp_code. If an error occurs, -1 is returned. */
static int ftp_send_command(struct Curl_easy *data, const char *message, ...)
- CURL_PRINTF(2, 3);
-
-static int ftp_send_command(struct Curl_easy *data, const char *message, ...)
{
int ftp_code;
ssize_t nread = 0;
@@ -473,7 +462,7 @@ socket_read(struct Curl_easy *data, int sockindex, void *to, size_t len)
ssize_t nread = 0;
while(len > 0) {
- result = Curl_conn_recv(data, sockindex, to_p, len, &nread);
+ nread = Curl_conn_recv(data, sockindex, to_p, len, &result);
if(nread > 0) {
len -= nread;
to_p += nread;
@@ -497,11 +486,11 @@ socket_write(struct Curl_easy *data, int sockindex, const void *to,
{
const char *to_p = to;
CURLcode result;
- size_t written;
+ ssize_t written;
while(len > 0) {
- result = Curl_conn_send(data, sockindex, to_p, len, FALSE, &written);
- if(!result && written > 0) {
+ written = Curl_conn_send(data, sockindex, to_p, len, &result);
+ if(written > 0) {
len -= written;
to_p += written;
}
@@ -527,33 +516,24 @@ static CURLcode read_data(struct Curl_easy *data, int sockindex,
return result;
if(len) {
- len = (int)ntohl((uint32_t)len);
+ /* only realloc if there was a length */
+ len = ntohl(len);
if(len > CURL_MAX_INPUT_LENGTH)
- return CURLE_TOO_LARGE;
-
- Curl_dyn_reset(&buf->buf);
+ len = 0;
+ else
+ buf->data = Curl_saferealloc(buf->data, len);
}
- else
- return CURLE_RECV_ERROR;
+ if(!len || !buf->data)
+ return CURLE_OUT_OF_MEMORY;
- do {
- char buffer[1024];
- nread = CURLMIN(len, (int)sizeof(buffer));
- result = socket_read(data, sockindex, buffer, (size_t)nread);
- if(result)
- return result;
- result = Curl_dyn_addn(&buf->buf, buffer, nread);
- if(result)
- return result;
- len -= nread;
- } while(len);
- /* this decodes the dynbuf *in place* */
- nread = conn->mech->decode(conn->app_data,
- Curl_dyn_ptr(&buf->buf),
- len, conn->data_prot, conn);
+ result = socket_read(data, sockindex, buf->data, len);
+ if(result)
+ return result;
+ nread = conn->mech->decode(conn->app_data, buf->data, len,
+ conn->data_prot, conn);
if(nread < 0)
return CURLE_RECV_ERROR;
- Curl_dyn_setlen(&buf->buf, nread);
+ buf->size = (size_t)nread;
buf->index = 0;
return CURLE_OK;
}
@@ -561,10 +541,9 @@ static CURLcode read_data(struct Curl_easy *data, int sockindex,
static size_t
buffer_read(struct krb5buffer *buf, void *data, size_t len)
{
- size_t size = Curl_dyn_len(&buf->buf);
- if(size - buf->index < len)
- len = size - buf->index;
- memcpy(data, Curl_dyn_ptr(&buf->buf) + buf->index, len);
+ if(buf->size - buf->index < len)
+ len = buf->size - buf->index;
+ memcpy(data, (char *)buf->data + buf->index, len);
buf->index += len;
return len;
}
@@ -580,11 +559,8 @@ static ssize_t sec_recv(struct Curl_easy *data, int sockindex,
*err = CURLE_OK;
/* Handle clear text response. */
- if(conn->sec_complete == 0 || conn->data_prot == PROT_CLEAR) {
- ssize_t nread;
- *err = Curl_conn_recv(data, sockindex, buffer, len, &nread);
- return nread;
- }
+ if(conn->sec_complete == 0 || conn->data_prot == PROT_CLEAR)
+ return Curl_conn_recv(data, sockindex, buffer, len, err);
if(conn->in_buffer.eof_flag) {
conn->in_buffer.eof_flag = 0;
@@ -599,7 +575,7 @@ static ssize_t sec_recv(struct Curl_easy *data, int sockindex,
while(len > 0) {
if(read_data(data, sockindex, &conn->in_buffer))
return -1;
- if(Curl_dyn_len(&conn->in_buffer.buf) == 0) {
+ if(conn->in_buffer.size == 0) {
if(bytes_read > 0)
conn->in_buffer.eof_flag = 1;
return bytes_read;
@@ -633,7 +609,7 @@ static void do_sec_send(struct Curl_easy *data, struct connectdata *conn,
else
prot_level = conn->command_prot;
}
- bytes = conn->mech->encode(conn->app_data, from, length, (int)prot_level,
+ bytes = conn->mech->encode(conn->app_data, from, length, prot_level,
(void **)&buffer);
if(!buffer || bytes <= 0)
return; /* error */
@@ -661,7 +637,7 @@ static void do_sec_send(struct Curl_easy *data, struct connectdata *conn,
}
}
else {
- htonl_bytes = (int)htonl((OM_uint32)bytes);
+ htonl_bytes = htonl(bytes);
socket_write(data, fd, &htonl_bytes, sizeof(htonl_bytes));
socket_write(data, fd, buffer, curlx_sitouz(bytes));
}
@@ -689,12 +665,10 @@ static ssize_t sec_write(struct Curl_easy *data, struct connectdata *conn,
/* Matches Curl_send signature */
static ssize_t sec_send(struct Curl_easy *data, int sockindex,
- const void *buffer, size_t len, bool eos,
- CURLcode *err)
+ const void *buffer, size_t len, CURLcode *err)
{
struct connectdata *conn = data->conn;
curl_socket_t fd = conn->sock[sockindex];
- (void)eos; /* unused */
*err = CURLE_OK;
return sec_write(data, conn, fd, buffer, len);
}
@@ -729,7 +703,7 @@ int Curl_sec_read_msg(struct Curl_easy *data, struct connectdata *conn,
decoded_len = curlx_uztosi(decoded_sz);
decoded_len = conn->mech->decode(conn->app_data, buf, decoded_len,
- (int)level, conn);
+ level, conn);
if(decoded_len <= 0) {
free(buf);
return -1;
@@ -776,8 +750,6 @@ static int sec_set_protection_level(struct Curl_easy *data)
if(level) {
char *pbsz;
unsigned int buffer_size = 1 << 20; /* 1048576 */
- struct pingpong *pp = &conn->proto.ftpc.pp;
- char *line;
code = ftp_send_command(data, "PBSZ %u", buffer_size);
if(code < 0)
@@ -789,12 +761,11 @@ static int sec_set_protection_level(struct Curl_easy *data)
}
conn->buffer_size = buffer_size;
- line = Curl_dyn_ptr(&pp->recvbuf);
- pbsz = strstr(line, "PBSZ=");
+ pbsz = strstr(data->state.buffer, "PBSZ=");
if(pbsz) {
/* stick to default value if the check fails */
- if(ISDIGIT(pbsz[5]))
- buffer_size = (unsigned int)atoi(&pbsz[5]);
+ if(!strncmp(pbsz, "PBSZ=", 5) && ISDIGIT(pbsz[5]))
+ buffer_size = atoi(&pbsz[5]);
if(buffer_size < conn->buffer_size)
conn->buffer_size = buffer_size;
}
@@ -850,7 +821,6 @@ static CURLcode choose_mech(struct Curl_easy *data, struct connectdata *conn)
mech->name);
return CURLE_FAILED_INIT;
}
- Curl_dyn_init(&conn->in_buffer.buf, CURL_MAX_INPUT_LENGTH);
}
infof(data, "Trying mechanism %s...", mech->name);
@@ -883,7 +853,7 @@ static CURLcode choose_mech(struct Curl_easy *data, struct connectdata *conn)
if(ret != AUTH_CONTINUE) {
if(ret != AUTH_OK) {
- /* Mechanism has dumped the error to stderr, do not error here. */
+ /* Mechanism has dumped the error to stderr, don't error here. */
return CURLE_USE_SSL_FAILED;
}
DEBUGASSERT(ret == AUTH_OK);
@@ -915,10 +885,15 @@ Curl_sec_end(struct connectdata *conn)
{
if(conn->mech && conn->mech->end)
conn->mech->end(conn->app_data);
- Curl_safefree(conn->app_data);
- Curl_dyn_free(&conn->in_buffer.buf);
- conn->in_buffer.index = 0;
- conn->in_buffer.eof_flag = 0;
+ free(conn->app_data);
+ conn->app_data = NULL;
+ if(conn->in_buffer.data) {
+ free(conn->in_buffer.data);
+ conn->in_buffer.data = NULL;
+ conn->in_buffer.size = 0;
+ conn->in_buffer.index = 0;
+ conn->in_buffer.eof_flag = 0;
+ }
conn->sec_complete = 0;
conn->data_prot = PROT_CLEAR;
conn->mech = NULL;
diff --git a/contrib/libs/curl/lib/ldap.c b/contrib/libs/curl/lib/ldap.c
index 6ce3ffba9f..6eb25b8a0e 100644
--- a/contrib/libs/curl/lib/ldap.c
+++ b/contrib/libs/curl/lib/ldap.c
@@ -137,13 +137,13 @@ static void _ldap_free_urldesc(LDAPURLDesc *ludp);
_ldap_trace x; \
} while(0)
- static void _ldap_trace(const char *fmt, ...) CURL_PRINTF(1, 2);
+ static void _ldap_trace(const char *fmt, ...);
#else
#define LDAP_TRACE(x) Curl_nop_stmt
#endif
#if defined(USE_WIN32_LDAP) && defined(ldap_err2string)
-/* Use ANSI error strings in Unicode builds */
+/* Use ansi error strings in UNICODE builds */
#undef ldap_err2string
#define ldap_err2string ldap_err2stringA
#endif
@@ -164,7 +164,7 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done);
*/
const struct Curl_handler Curl_handler_ldap = {
- "ldap", /* scheme */
+ "LDAP", /* scheme */
ZERO_NULL, /* setup_connection */
ldap_do, /* do_it */
ZERO_NULL, /* done */
@@ -177,8 +177,7 @@ const struct Curl_handler Curl_handler_ldap = {
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
ZERO_NULL, /* disconnect */
- ZERO_NULL, /* write_resp */
- ZERO_NULL, /* write_resp_hd */
+ ZERO_NULL, /* readwrite */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_LDAP, /* defport */
@@ -193,7 +192,7 @@ const struct Curl_handler Curl_handler_ldap = {
*/
const struct Curl_handler Curl_handler_ldaps = {
- "ldaps", /* scheme */
+ "LDAPS", /* scheme */
ZERO_NULL, /* setup_connection */
ldap_do, /* do_it */
ZERO_NULL, /* done */
@@ -206,8 +205,7 @@ const struct Curl_handler Curl_handler_ldaps = {
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
ZERO_NULL, /* disconnect */
- ZERO_NULL, /* write_resp */
- ZERO_NULL, /* write_resp_hd */
+ ZERO_NULL, /* readwrite */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_LDAPS, /* defport */
@@ -252,17 +250,16 @@ static int ldap_win_bind_auth(LDAP *server, const char *user,
}
if(method && user && passwd) {
- CURLcode res = Curl_create_sspi_identity(user, passwd, &cred);
- rc = (int)res;
+ rc = Curl_create_sspi_identity(user, passwd, &cred);
if(!rc) {
- rc = (int)ldap_bind_s(server, NULL, (TCHAR *)&cred, method);
+ rc = ldap_bind_s(server, NULL, (TCHAR *)&cred, method);
Curl_sspi_free_identity(&cred);
}
}
else {
/* proceed with current user credentials */
method = LDAP_AUTH_NEGOTIATE;
- rc = (int)ldap_bind_s(server, NULL, NULL, method);
+ rc = ldap_bind_s(server, NULL, NULL, method);
}
return rc;
}
@@ -280,14 +277,14 @@ static int ldap_win_bind(struct Curl_easy *data, LDAP *server,
inuser = curlx_convert_UTF8_to_tchar((char *) user);
inpass = curlx_convert_UTF8_to_tchar((char *) passwd);
- rc = (int)ldap_simple_bind_s(server, inuser, inpass);
+ rc = ldap_simple_bind_s(server, inuser, inpass);
curlx_unicodefree(inuser);
curlx_unicodefree(inpass);
}
#if defined(USE_WINDOWS_SSPI)
else {
- rc = (int)ldap_win_bind_auth(server, user, passwd, data->set.httpauth);
+ rc = ldap_win_bind_auth(server, user, passwd, data->set.httpauth);
}
#endif
@@ -297,10 +294,8 @@ static int ldap_win_bind(struct Curl_easy *data, LDAP *server,
#if defined(USE_WIN32_LDAP)
#define FREE_ON_WINLDAP(x) curlx_unicodefree(x)
-#define curl_ldap_num_t ULONG
#else
#define FREE_ON_WINLDAP(x)
-#define curl_ldap_num_t int
#endif
@@ -340,7 +335,7 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
rc = _ldap_url_parse(data, conn, &ludp);
#endif
if(rc) {
- failf(data, "Bad LDAP URL: %s", ldap_err2string((curl_ldap_num_t)rc));
+ failf(data, "Bad LDAP URL: %s", ldap_err2string(rc));
result = CURLE_URL_MALFORMAT;
goto quit;
}
@@ -375,8 +370,8 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
if(ldap_ssl) {
#ifdef HAVE_LDAP_SSL
#ifdef USE_WIN32_LDAP
- /* Win32 LDAP SDK does not support insecure mode without CA! */
- server = ldap_sslinit(host, (curl_ldap_num_t)conn->primary.remote_port, 1);
+ /* Win32 LDAP SDK doesn't support insecure mode without CA! */
+ server = ldap_sslinit(host, conn->port, 1);
ldap_set_option(server, LDAP_OPT_SSL, LDAP_OPT_ON);
#else
int ldap_option;
@@ -422,10 +417,10 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
result = CURLE_SSL_CERTPROBLEM;
goto quit;
}
- server = ldapssl_init(host, conn->primary.remote_port, 1);
+ server = ldapssl_init(host, conn->port, 1);
if(!server) {
failf(data, "LDAP local: Cannot connect to %s:%u",
- conn->host.dispname, conn->primary.remote_port);
+ conn->host.dispname, conn->port);
result = CURLE_COULDNT_CONNECT;
goto quit;
}
@@ -463,10 +458,10 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
result = CURLE_SSL_CERTPROBLEM;
goto quit;
}
- server = ldap_init(host, conn->primary.remote_port);
+ server = ldap_init(host, conn->port);
if(!server) {
failf(data, "LDAP local: Cannot connect to %s:%u",
- conn->host.dispname, conn->primary.remote_port);
+ conn->host.dispname, conn->port);
result = CURLE_COULDNT_CONNECT;
goto quit;
}
@@ -488,8 +483,6 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
}
*/
#else
- (void)ldap_option;
- (void)ldap_ca;
/* we should probably never come up to here since configure
should check in first place if we can support LDAP SSL/TLS */
failf(data, "LDAP local: SSL/TLS not supported with this version "
@@ -506,10 +499,10 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
goto quit;
}
else {
- server = ldap_init(host, (curl_ldap_num_t)conn->primary.remote_port);
+ server = ldap_init(host, conn->port);
if(!server) {
failf(data, "LDAP local: Cannot connect to %s:%u",
- conn->host.dispname, conn->primary.remote_port);
+ conn->host.dispname, conn->port);
result = CURLE_COULDNT_CONNECT;
goto quit;
}
@@ -532,7 +525,7 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
if(rc) {
#ifdef USE_WIN32_LDAP
failf(data, "LDAP local: bind via ldap_win_bind %s",
- ldap_err2string((ULONG)rc));
+ ldap_err2string(rc));
#else
failf(data, "LDAP local: bind via ldap_simple_bind_s %s",
ldap_err2string(rc));
@@ -542,18 +535,16 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
}
Curl_pgrsSetDownloadCounter(data, 0);
- rc = (int)ldap_search_s(server, ludp->lud_dn,
- (curl_ldap_num_t)ludp->lud_scope,
- ludp->lud_filter, ludp->lud_attrs, 0, &ldapmsg);
+ rc = ldap_search_s(server, ludp->lud_dn, ludp->lud_scope,
+ ludp->lud_filter, ludp->lud_attrs, 0, &ldapmsg);
if(rc && rc != LDAP_SIZELIMIT_EXCEEDED) {
- failf(data, "LDAP remote: %s", ldap_err2string((curl_ldap_num_t)rc));
+ failf(data, "LDAP remote: %s", ldap_err2string(rc));
result = CURLE_LDAP_SEARCH_FAILED;
goto quit;
}
- num = 0;
- for(entryIterator = ldap_first_entry(server, ldapmsg);
+ for(num = 0, entryIterator = ldap_first_entry(server, ldapmsg);
entryIterator;
entryIterator = ldap_next_entry(server, entryIterator), num++) {
BerElement *ber = NULL;
@@ -758,7 +749,7 @@ quit:
FREE_ON_WINLDAP(host);
/* no data to transfer */
- Curl_xfer_setup_nop(data);
+ Curl_setup_transfer(data, -1, -1, FALSE, -1);
connclose(conn, "LDAP connection always disable reuse");
return result;
diff --git a/contrib/libs/curl/lib/llist.c b/contrib/libs/curl/lib/llist.c
index 7e19cd5095..5b6b0336da 100644
--- a/contrib/libs/curl/lib/llist.c
+++ b/contrib/libs/curl/lib/llist.c
@@ -32,34 +32,16 @@
/* this must be the last include file */
#include "memdebug.h"
-#define LLISTINIT 0x100cc001 /* random pattern */
-#define NODEINIT 0x12344321 /* random pattern */
-#define NODEREM 0x54321012 /* random pattern */
-
-
-#ifdef DEBUGBUILD
-#define VERIFYNODE(x) verifynode(x)
-static struct Curl_llist_node *verifynode(struct Curl_llist_node *n)
-{
- DEBUGASSERT(!n || (n->_init == NODEINIT));
- return n;
-}
-#else
-#define VERIFYNODE(x) x
-#endif
/*
* @unittest: 1300
*/
void
Curl_llist_init(struct Curl_llist *l, Curl_llist_dtor dtor)
{
- l->_size = 0;
- l->_dtor = dtor;
- l->_head = NULL;
- l->_tail = NULL;
-#ifdef DEBUGBUILD
- l->_init = LLISTINIT;
-#endif
+ l->size = 0;
+ l->dtor = dtor;
+ l->head = NULL;
+ l->tail = NULL;
}
/*
@@ -74,193 +56,91 @@ Curl_llist_init(struct Curl_llist *l, Curl_llist_dtor dtor)
* @unittest: 1300
*/
void
-Curl_llist_insert_next(struct Curl_llist *list,
- struct Curl_llist_node *e, /* may be NULL */
+Curl_llist_insert_next(struct Curl_llist *list, struct Curl_llist_element *e,
const void *p,
- struct Curl_llist_node *ne)
+ struct Curl_llist_element *ne)
{
- DEBUGASSERT(list);
- DEBUGASSERT(list->_init == LLISTINIT);
- DEBUGASSERT(ne);
-
-#ifdef DEBUGBUILD
- ne->_init = NODEINIT;
-#endif
- ne->_ptr = (void *) p;
- ne->_list = list;
- if(list->_size == 0) {
- list->_head = ne;
- list->_head->_prev = NULL;
- list->_head->_next = NULL;
- list->_tail = ne;
+ ne->ptr = (void *) p;
+ if(list->size == 0) {
+ list->head = ne;
+ list->head->prev = NULL;
+ list->head->next = NULL;
+ list->tail = ne;
}
else {
/* if 'e' is NULL here, we insert the new element first in the list */
- ne->_next = e?e->_next:list->_head;
- ne->_prev = e;
+ ne->next = e?e->next:list->head;
+ ne->prev = e;
if(!e) {
- list->_head->_prev = ne;
- list->_head = ne;
+ list->head->prev = ne;
+ list->head = ne;
}
- else if(e->_next) {
- e->_next->_prev = ne;
+ else if(e->next) {
+ e->next->prev = ne;
}
else {
- list->_tail = ne;
+ list->tail = ne;
}
if(e)
- e->_next = ne;
+ e->next = ne;
}
- ++list->_size;
-}
-
-/*
- * Curl_llist_append()
- *
- * Adds a new list element to the end of the list.
- *
- * The 'ne' argument should be a pointer into the object to store.
- *
- * @unittest: 1300
- */
-void
-Curl_llist_append(struct Curl_llist *list, const void *p,
- struct Curl_llist_node *ne)
-{
- DEBUGASSERT(list);
- DEBUGASSERT(list->_init == LLISTINIT);
- DEBUGASSERT(ne);
- Curl_llist_insert_next(list, list->_tail, p, ne);
+ ++list->size;
}
/*
* @unittest: 1300
*/
void
-Curl_node_uremove(struct Curl_llist_node *e, void *user)
+Curl_llist_remove(struct Curl_llist *list, struct Curl_llist_element *e,
+ void *user)
{
void *ptr;
- struct Curl_llist *list;
- if(!e)
+ if(!e || list->size == 0)
return;
- list = e->_list;
- DEBUGASSERT(list);
- DEBUGASSERT(list->_init == LLISTINIT);
- DEBUGASSERT(list->_size);
- DEBUGASSERT(e->_init == NODEINIT);
- if(e == list->_head) {
- list->_head = e->_next;
+ if(e == list->head) {
+ list->head = e->next;
- if(!list->_head)
- list->_tail = NULL;
+ if(!list->head)
+ list->tail = NULL;
else
- e->_next->_prev = NULL;
+ e->next->prev = NULL;
}
else {
- if(e->_prev)
- e->_prev->_next = e->_next;
+ if(e->prev)
+ e->prev->next = e->next;
- if(!e->_next)
- list->_tail = e->_prev;
+ if(!e->next)
+ list->tail = e->prev;
else
- e->_next->_prev = e->_prev;
+ e->next->prev = e->prev;
}
- ptr = e->_ptr;
+ ptr = e->ptr;
- e->_list = NULL;
- e->_ptr = NULL;
- e->_prev = NULL;
- e->_next = NULL;
-#ifdef DEBUGBUILD
- e->_init = NODEREM; /* specific pattern on remove - not zero */
-#endif
+ e->ptr = NULL;
+ e->prev = NULL;
+ e->next = NULL;
- --list->_size;
+ --list->size;
/* call the dtor() last for when it actually frees the 'e' memory itself */
- if(list->_dtor)
- list->_dtor(user, ptr);
-}
-
-void Curl_node_remove(struct Curl_llist_node *e)
-{
- Curl_node_uremove(e, NULL);
+ if(list->dtor)
+ list->dtor(user, ptr);
}
void
Curl_llist_destroy(struct Curl_llist *list, void *user)
{
if(list) {
- DEBUGASSERT(list->_init == LLISTINIT);
- while(list->_size > 0)
- Curl_node_uremove(list->_tail, user);
+ while(list->size > 0)
+ Curl_llist_remove(list, list->tail, user);
}
}
-/* Curl_llist_head() returns the first 'struct Curl_llist_node *', which
- might be NULL */
-struct Curl_llist_node *Curl_llist_head(struct Curl_llist *list)
-{
- DEBUGASSERT(list);
- DEBUGASSERT(list->_init == LLISTINIT);
- return VERIFYNODE(list->_head);
-}
-
-#ifdef UNITTESTS
-/* Curl_llist_tail() returns the last 'struct Curl_llist_node *', which
- might be NULL */
-struct Curl_llist_node *Curl_llist_tail(struct Curl_llist *list)
-{
- DEBUGASSERT(list);
- DEBUGASSERT(list->_init == LLISTINIT);
- return VERIFYNODE(list->_tail);
-}
-#endif
-
-/* Curl_llist_count() returns a size_t the number of nodes in the list */
-size_t Curl_llist_count(struct Curl_llist *list)
-{
- DEBUGASSERT(list);
- DEBUGASSERT(list->_init == LLISTINIT);
- return list->_size;
-}
-
-/* Curl_node_elem() returns the custom data from a Curl_llist_node */
-void *Curl_node_elem(struct Curl_llist_node *n)
-{
- DEBUGASSERT(n);
- DEBUGASSERT(n->_init == NODEINIT);
- return n->_ptr;
-}
-
-/* Curl_node_next() returns the next element in a list from a given
- Curl_llist_node */
-struct Curl_llist_node *Curl_node_next(struct Curl_llist_node *n)
-{
- DEBUGASSERT(n);
- DEBUGASSERT(n->_init == NODEINIT);
- return VERIFYNODE(n->_next);
-}
-
-#ifdef UNITTESTS
-
-/* Curl_node_prev() returns the previous element in a list from a given
- Curl_llist_node */
-struct Curl_llist_node *Curl_node_prev(struct Curl_llist_node *n)
-{
- DEBUGASSERT(n);
- DEBUGASSERT(n->_init == NODEINIT);
- return VERIFYNODE(n->_prev);
-}
-
-#endif
-
-struct Curl_llist *Curl_node_llist(struct Curl_llist_node *n)
+size_t
+Curl_llist_count(struct Curl_llist *list)
{
- DEBUGASSERT(n);
- DEBUGASSERT(!n->_list || n->_init == NODEINIT);
- return n->_list;
+ return list->size;
}
diff --git a/contrib/libs/curl/lib/llist.h b/contrib/libs/curl/lib/llist.h
index 26581869a3..320580e33c 100644
--- a/contrib/libs/curl/lib/llist.h
+++ b/contrib/libs/curl/lib/llist.h
@@ -27,63 +27,26 @@
#include "curl_setup.h"
#include <stddef.h>
-typedef void (*Curl_llist_dtor)(void *user, void *elem);
+typedef void (*Curl_llist_dtor)(void *, void *);
-/* none of these struct members should be referenced directly, use the
- dedicated functions */
-
-struct Curl_llist {
- struct Curl_llist_node *_head;
- struct Curl_llist_node *_tail;
- Curl_llist_dtor _dtor;
- size_t _size;
-#ifdef DEBUGBUILD
- int _init; /* detect API usage mistakes */
-#endif
+struct Curl_llist_element {
+ void *ptr;
+ struct Curl_llist_element *prev;
+ struct Curl_llist_element *next;
};
-struct Curl_llist_node {
- struct Curl_llist *_list; /* the list where this belongs */
- void *_ptr;
- struct Curl_llist_node *_prev;
- struct Curl_llist_node *_next;
-#ifdef DEBUGBUILD
- int _init; /* detect API usage mistakes */
-#endif
+struct Curl_llist {
+ struct Curl_llist_element *head;
+ struct Curl_llist_element *tail;
+ Curl_llist_dtor dtor;
+ size_t size;
};
void Curl_llist_init(struct Curl_llist *, Curl_llist_dtor);
-void Curl_llist_insert_next(struct Curl_llist *, struct Curl_llist_node *,
- const void *, struct Curl_llist_node *node);
-void Curl_llist_append(struct Curl_llist *,
- const void *, struct Curl_llist_node *node);
-void Curl_node_uremove(struct Curl_llist_node *, void *);
-void Curl_node_remove(struct Curl_llist_node *);
+void Curl_llist_insert_next(struct Curl_llist *, struct Curl_llist_element *,
+ const void *, struct Curl_llist_element *node);
+void Curl_llist_remove(struct Curl_llist *, struct Curl_llist_element *,
+ void *);
+size_t Curl_llist_count(struct Curl_llist *);
void Curl_llist_destroy(struct Curl_llist *, void *);
-
-/* Curl_llist_head() returns the first 'struct Curl_llist_node *', which
- might be NULL */
-struct Curl_llist_node *Curl_llist_head(struct Curl_llist *list);
-
-/* Curl_llist_tail() returns the last 'struct Curl_llist_node *', which
- might be NULL */
-struct Curl_llist_node *Curl_llist_tail(struct Curl_llist *list);
-
-/* Curl_llist_count() returns a size_t the number of nodes in the list */
-size_t Curl_llist_count(struct Curl_llist *list);
-
-/* Curl_node_elem() returns the custom data from a Curl_llist_node */
-void *Curl_node_elem(struct Curl_llist_node *n);
-
-/* Curl_node_next() returns the next element in a list from a given
- Curl_llist_node */
-struct Curl_llist_node *Curl_node_next(struct Curl_llist_node *n);
-
-/* Curl_node_prev() returns the previous element in a list from a given
- Curl_llist_node */
-struct Curl_llist_node *Curl_node_prev(struct Curl_llist_node *n);
-
-/* Curl_node_llist() return the list the node is in or NULL. */
-struct Curl_llist *Curl_node_llist(struct Curl_llist_node *n);
-
#endif /* HEADER_CURL_LLIST_H */
diff --git a/contrib/libs/curl/lib/macos.c b/contrib/libs/curl/lib/macos.c
index e4662be1d3..9e8e76e867 100644
--- a/contrib/libs/curl/lib/macos.c
+++ b/contrib/libs/curl/lib/macos.c
@@ -34,19 +34,21 @@
CURLcode Curl_macos_init(void)
{
- /*
- * The automagic conversion from IPv4 literals to IPv6 literals only
- * works if the SCDynamicStoreCopyProxies system function gets called
- * first. As Curl currently does not support system-wide HTTP proxies, we
- * therefore do not use any value this function might return.
- *
- * This function is only available on macOS and is not needed for
- * IPv4-only builds, hence the conditions for defining
- * CURL_MACOS_CALL_COPYPROXIES in curl_setup.h.
- */
- CFDictionaryRef dict = SCDynamicStoreCopyProxies(NULL);
- if(dict)
- CFRelease(dict);
+ {
+ /*
+ * The automagic conversion from IPv4 literals to IPv6 literals only
+ * works if the SCDynamicStoreCopyProxies system function gets called
+ * first. As Curl currently doesn't support system-wide HTTP proxies, we
+ * therefore don't use any value this function might return.
+ *
+ * This function is only available on macOS and is not needed for
+ * IPv4-only builds, hence the conditions for defining
+ * CURL_MACOS_CALL_COPYPROXIES in curl_setup.h.
+ */
+ CFDictionaryRef dict = SCDynamicStoreCopyProxies(NULL);
+ if(dict)
+ CFRelease(dict);
+ }
return CURLE_OK;
}
diff --git a/contrib/libs/curl/lib/md4.c b/contrib/libs/curl/lib/md4.c
index 1057721915..d0015387b0 100644
--- a/contrib/libs/curl/lib/md4.c
+++ b/contrib/libs/curl/lib/md4.c
@@ -28,7 +28,6 @@
#include <string.h>
-#include "strdup.h"
#include "curl_md4.h"
#include "warnless.h"
@@ -37,9 +36,6 @@
#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) && !defined(USE_AMISSL)
/* OpenSSL 3.0.0 marks the MD4 functions as deprecated */
#define OPENSSL_NO_MD4
-#else
-/* Cover also OPENSSL_NO_MD4 configured in openssl */
-#include <openssl/opensslconf.h>
#endif
#endif /* USE_OPENSSL */
@@ -58,8 +54,7 @@
#else
#error #include <mbedtls/config.h>
#endif
-#if(MBEDTLS_VERSION_NUMBER >= 0x02070000) && \
- (MBEDTLS_VERSION_NUMBER < 0x03000000)
+#if(MBEDTLS_VERSION_NUMBER >= 0x02070000)
#define HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS
#endif
#endif /* USE_MBEDTLS */
@@ -199,9 +194,11 @@ static int MD4_Init(MD4_CTX *ctx)
static void MD4_Update(MD4_CTX *ctx, const void *data, unsigned long size)
{
if(!ctx->data) {
- ctx->data = Curl_memdup(data, size);
- if(ctx->data)
+ ctx->data = malloc(size);
+ if(ctx->data) {
+ memcpy(ctx->data, data, size);
ctx->size = size;
+ }
}
}
@@ -220,7 +217,7 @@ static void MD4_Final(unsigned char *result, MD4_CTX *ctx)
}
#else
-/* When no other crypto library is available, or the crypto library does not
+/* When no other crypto library is available, or the crypto library doesn't
* support MD4, we use this code segment this implementation of it
*
* This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.
@@ -232,8 +229,8 @@ static void MD4_Final(unsigned char *result, MD4_CTX *ctx)
* Author:
* Alexander Peslyak, better known as Solar Designer <solar at openwall.com>
*
- * This software was written by Alexander Peslyak in 2001. No copyright is
- * claimed, and the software is hereby placed in the public domain. In case
+ * This software was written by Alexander Peslyak in 2001. No copyright is
+ * claimed, and the software is hereby placed in the public domain. In case
* this attempt to disclaim copyright and place the software in the public
* domain is deemed null and void, then the software is Copyright (c) 2001
* Alexander Peslyak and it is hereby released to the general public under the
@@ -242,19 +239,19 @@ static void MD4_Final(unsigned char *result, MD4_CTX *ctx)
* Redistribution and use in source and binary forms, with or without
* modification, are permitted.
*
- * There is ABSOLUTELY NO WARRANTY, express or implied.
+ * There's ABSOLUTELY NO WARRANTY, express or implied.
*
* (This is a heavily cut-down "BSD license".)
*
* This differs from Colin Plumb's older public domain implementation in that
* no exactly 32-bit integer data type is required (any 32-bit or wider
- * unsigned integer data type will do), there is no compile-time endianness
- * configuration, and the function prototypes match OpenSSL's. No code from
+ * unsigned integer data type will do), there's no compile-time endianness
+ * configuration, and the function prototypes match OpenSSL's. No code from
* Colin Plumb's implementation has been reused; this comment merely compares
* the properties of the two independent implementations.
*
* The primary goals of this implementation are portability and ease of use.
- * It is meant to be fast, but not as fast as possible. Some known
+ * It is meant to be fast, but not as fast as possible. Some known
* optimizations are not included to reduce source code size and avoid
* compile-time configuration.
*/
@@ -280,14 +277,14 @@ static void MD4_Final(unsigned char *result, MD4_CTX *ctx);
* F and G are optimized compared to their RFC 1320 definitions, with the
* optimization for F borrowed from Colin Plumb's MD5 implementation.
*/
-#define MD4_F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
-#define MD4_G(x, y, z) (((x) & ((y) | (z))) | ((y) & (z)))
-#define MD4_H(x, y, z) ((x) ^ (y) ^ (z))
+#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
+#define G(x, y, z) (((x) & ((y) | (z))) | ((y) & (z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
/*
* The MD4 transformation for all three rounds.
*/
-#define MD4_STEP(f, a, b, c, d, x, s) \
+#define STEP(f, a, b, c, d, x, s) \
(a) += f((b), (c), (d)) + (x); \
(a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s))));
@@ -296,31 +293,30 @@ static void MD4_Final(unsigned char *result, MD4_CTX *ctx);
* in a properly aligned word in host byte order.
*
* The check for little-endian architectures that tolerate unaligned
- * memory accesses is just an optimization. Nothing will break if it
- * does not work.
+ * memory accesses is just an optimization. Nothing will break if it
+ * doesn't work.
*/
#if defined(__i386__) || defined(__x86_64__) || defined(__vax__)
-#define MD4_SET(n) \
+#define SET(n) \
(*(MD4_u32plus *)(void *)&ptr[(n) * 4])
-#define MD4_GET(n) \
- MD4_SET(n)
+#define GET(n) \
+ SET(n)
#else
-#define MD4_SET(n) \
+#define SET(n) \
(ctx->block[(n)] = \
(MD4_u32plus)ptr[(n) * 4] | \
((MD4_u32plus)ptr[(n) * 4 + 1] << 8) | \
((MD4_u32plus)ptr[(n) * 4 + 2] << 16) | \
((MD4_u32plus)ptr[(n) * 4 + 3] << 24))
-#define MD4_GET(n) \
+#define GET(n) \
(ctx->block[(n)])
#endif
/*
* This processes one or more 64-byte data blocks, but does NOT update
- * the bit counters. There are no alignment requirements.
+ * the bit counters. There are no alignment requirements.
*/
-static const void *my_md4_body(MD4_CTX *ctx,
- const void *data, unsigned long size)
+static const void *body(MD4_CTX *ctx, const void *data, unsigned long size)
{
const unsigned char *ptr;
MD4_u32plus a, b, c, d;
@@ -341,58 +337,58 @@ static const void *my_md4_body(MD4_CTX *ctx,
saved_d = d;
/* Round 1 */
- MD4_STEP(MD4_F, a, b, c, d, MD4_SET(0), 3)
- MD4_STEP(MD4_F, d, a, b, c, MD4_SET(1), 7)
- MD4_STEP(MD4_F, c, d, a, b, MD4_SET(2), 11)
- MD4_STEP(MD4_F, b, c, d, a, MD4_SET(3), 19)
- MD4_STEP(MD4_F, a, b, c, d, MD4_SET(4), 3)
- MD4_STEP(MD4_F, d, a, b, c, MD4_SET(5), 7)
- MD4_STEP(MD4_F, c, d, a, b, MD4_SET(6), 11)
- MD4_STEP(MD4_F, b, c, d, a, MD4_SET(7), 19)
- MD4_STEP(MD4_F, a, b, c, d, MD4_SET(8), 3)
- MD4_STEP(MD4_F, d, a, b, c, MD4_SET(9), 7)
- MD4_STEP(MD4_F, c, d, a, b, MD4_SET(10), 11)
- MD4_STEP(MD4_F, b, c, d, a, MD4_SET(11), 19)
- MD4_STEP(MD4_F, a, b, c, d, MD4_SET(12), 3)
- MD4_STEP(MD4_F, d, a, b, c, MD4_SET(13), 7)
- MD4_STEP(MD4_F, c, d, a, b, MD4_SET(14), 11)
- MD4_STEP(MD4_F, b, c, d, a, MD4_SET(15), 19)
+ STEP(F, a, b, c, d, SET(0), 3)
+ STEP(F, d, a, b, c, SET(1), 7)
+ STEP(F, c, d, a, b, SET(2), 11)
+ STEP(F, b, c, d, a, SET(3), 19)
+ STEP(F, a, b, c, d, SET(4), 3)
+ STEP(F, d, a, b, c, SET(5), 7)
+ STEP(F, c, d, a, b, SET(6), 11)
+ STEP(F, b, c, d, a, SET(7), 19)
+ STEP(F, a, b, c, d, SET(8), 3)
+ STEP(F, d, a, b, c, SET(9), 7)
+ STEP(F, c, d, a, b, SET(10), 11)
+ STEP(F, b, c, d, a, SET(11), 19)
+ STEP(F, a, b, c, d, SET(12), 3)
+ STEP(F, d, a, b, c, SET(13), 7)
+ STEP(F, c, d, a, b, SET(14), 11)
+ STEP(F, b, c, d, a, SET(15), 19)
/* Round 2 */
- MD4_STEP(MD4_G, a, b, c, d, MD4_GET(0) + 0x5a827999, 3)
- MD4_STEP(MD4_G, d, a, b, c, MD4_GET(4) + 0x5a827999, 5)
- MD4_STEP(MD4_G, c, d, a, b, MD4_GET(8) + 0x5a827999, 9)
- MD4_STEP(MD4_G, b, c, d, a, MD4_GET(12) + 0x5a827999, 13)
- MD4_STEP(MD4_G, a, b, c, d, MD4_GET(1) + 0x5a827999, 3)
- MD4_STEP(MD4_G, d, a, b, c, MD4_GET(5) + 0x5a827999, 5)
- MD4_STEP(MD4_G, c, d, a, b, MD4_GET(9) + 0x5a827999, 9)
- MD4_STEP(MD4_G, b, c, d, a, MD4_GET(13) + 0x5a827999, 13)
- MD4_STEP(MD4_G, a, b, c, d, MD4_GET(2) + 0x5a827999, 3)
- MD4_STEP(MD4_G, d, a, b, c, MD4_GET(6) + 0x5a827999, 5)
- MD4_STEP(MD4_G, c, d, a, b, MD4_GET(10) + 0x5a827999, 9)
- MD4_STEP(MD4_G, b, c, d, a, MD4_GET(14) + 0x5a827999, 13)
- MD4_STEP(MD4_G, a, b, c, d, MD4_GET(3) + 0x5a827999, 3)
- MD4_STEP(MD4_G, d, a, b, c, MD4_GET(7) + 0x5a827999, 5)
- MD4_STEP(MD4_G, c, d, a, b, MD4_GET(11) + 0x5a827999, 9)
- MD4_STEP(MD4_G, b, c, d, a, MD4_GET(15) + 0x5a827999, 13)
+ STEP(G, a, b, c, d, GET(0) + 0x5a827999, 3)
+ STEP(G, d, a, b, c, GET(4) + 0x5a827999, 5)
+ STEP(G, c, d, a, b, GET(8) + 0x5a827999, 9)
+ STEP(G, b, c, d, a, GET(12) + 0x5a827999, 13)
+ STEP(G, a, b, c, d, GET(1) + 0x5a827999, 3)
+ STEP(G, d, a, b, c, GET(5) + 0x5a827999, 5)
+ STEP(G, c, d, a, b, GET(9) + 0x5a827999, 9)
+ STEP(G, b, c, d, a, GET(13) + 0x5a827999, 13)
+ STEP(G, a, b, c, d, GET(2) + 0x5a827999, 3)
+ STEP(G, d, a, b, c, GET(6) + 0x5a827999, 5)
+ STEP(G, c, d, a, b, GET(10) + 0x5a827999, 9)
+ STEP(G, b, c, d, a, GET(14) + 0x5a827999, 13)
+ STEP(G, a, b, c, d, GET(3) + 0x5a827999, 3)
+ STEP(G, d, a, b, c, GET(7) + 0x5a827999, 5)
+ STEP(G, c, d, a, b, GET(11) + 0x5a827999, 9)
+ STEP(G, b, c, d, a, GET(15) + 0x5a827999, 13)
/* Round 3 */
- MD4_STEP(MD4_H, a, b, c, d, MD4_GET(0) + 0x6ed9eba1, 3)
- MD4_STEP(MD4_H, d, a, b, c, MD4_GET(8) + 0x6ed9eba1, 9)
- MD4_STEP(MD4_H, c, d, a, b, MD4_GET(4) + 0x6ed9eba1, 11)
- MD4_STEP(MD4_H, b, c, d, a, MD4_GET(12) + 0x6ed9eba1, 15)
- MD4_STEP(MD4_H, a, b, c, d, MD4_GET(2) + 0x6ed9eba1, 3)
- MD4_STEP(MD4_H, d, a, b, c, MD4_GET(10) + 0x6ed9eba1, 9)
- MD4_STEP(MD4_H, c, d, a, b, MD4_GET(6) + 0x6ed9eba1, 11)
- MD4_STEP(MD4_H, b, c, d, a, MD4_GET(14) + 0x6ed9eba1, 15)
- MD4_STEP(MD4_H, a, b, c, d, MD4_GET(1) + 0x6ed9eba1, 3)
- MD4_STEP(MD4_H, d, a, b, c, MD4_GET(9) + 0x6ed9eba1, 9)
- MD4_STEP(MD4_H, c, d, a, b, MD4_GET(5) + 0x6ed9eba1, 11)
- MD4_STEP(MD4_H, b, c, d, a, MD4_GET(13) + 0x6ed9eba1, 15)
- MD4_STEP(MD4_H, a, b, c, d, MD4_GET(3) + 0x6ed9eba1, 3)
- MD4_STEP(MD4_H, d, a, b, c, MD4_GET(11) + 0x6ed9eba1, 9)
- MD4_STEP(MD4_H, c, d, a, b, MD4_GET(7) + 0x6ed9eba1, 11)
- MD4_STEP(MD4_H, b, c, d, a, MD4_GET(15) + 0x6ed9eba1, 15)
+ STEP(H, a, b, c, d, GET(0) + 0x6ed9eba1, 3)
+ STEP(H, d, a, b, c, GET(8) + 0x6ed9eba1, 9)
+ STEP(H, c, d, a, b, GET(4) + 0x6ed9eba1, 11)
+ STEP(H, b, c, d, a, GET(12) + 0x6ed9eba1, 15)
+ STEP(H, a, b, c, d, GET(2) + 0x6ed9eba1, 3)
+ STEP(H, d, a, b, c, GET(10) + 0x6ed9eba1, 9)
+ STEP(H, c, d, a, b, GET(6) + 0x6ed9eba1, 11)
+ STEP(H, b, c, d, a, GET(14) + 0x6ed9eba1, 15)
+ STEP(H, a, b, c, d, GET(1) + 0x6ed9eba1, 3)
+ STEP(H, d, a, b, c, GET(9) + 0x6ed9eba1, 9)
+ STEP(H, c, d, a, b, GET(5) + 0x6ed9eba1, 11)
+ STEP(H, b, c, d, a, GET(13) + 0x6ed9eba1, 15)
+ STEP(H, a, b, c, d, GET(3) + 0x6ed9eba1, 3)
+ STEP(H, d, a, b, c, GET(11) + 0x6ed9eba1, 9)
+ STEP(H, c, d, a, b, GET(7) + 0x6ed9eba1, 11)
+ STEP(H, b, c, d, a, GET(15) + 0x6ed9eba1, 15)
a += saved_a;
b += saved_b;
@@ -446,11 +442,11 @@ static void MD4_Update(MD4_CTX *ctx, const void *data, unsigned long size)
memcpy(&ctx->buffer[used], data, available);
data = (const unsigned char *)data + available;
size -= available;
- my_md4_body(ctx, ctx->buffer, 64);
+ body(ctx, ctx->buffer, 64);
}
if(size >= 64) {
- data = my_md4_body(ctx, data, size & ~(unsigned long)0x3f);
+ data = body(ctx, data, size & ~(unsigned long)0x3f);
size &= 0x3f;
}
@@ -469,7 +465,7 @@ static void MD4_Final(unsigned char *result, MD4_CTX *ctx)
if(available < 8) {
memset(&ctx->buffer[used], 0, available);
- my_md4_body(ctx, ctx->buffer, 64);
+ body(ctx, ctx->buffer, 64);
used = 0;
available = 64;
}
@@ -486,7 +482,7 @@ static void MD4_Final(unsigned char *result, MD4_CTX *ctx)
ctx->buffer[62] = curlx_ultouc((ctx->hi >> 16)&0xff);
ctx->buffer[63] = curlx_ultouc(ctx->hi >> 24);
- my_md4_body(ctx, ctx->buffer, 64);
+ body(ctx, ctx->buffer, 64);
result[0] = curlx_ultouc((ctx->a)&0xff);
result[1] = curlx_ultouc((ctx->a >> 8)&0xff);
diff --git a/contrib/libs/curl/lib/md5.c b/contrib/libs/curl/lib/md5.c
index 56f10e930d..36191e64db 100644
--- a/contrib/libs/curl/lib/md5.c
+++ b/contrib/libs/curl/lib/md5.c
@@ -172,7 +172,7 @@ static void my_md5_final(unsigned char *digest, my_md5_ctx *ctx)
/* For Apple operating systems: CommonCrypto has the functions we need.
These functions are available on Tiger and later, as well as iOS 2.0
- and later. If you are building for an older cat, well, sorry.
+ and later. If you're building for an older cat, well, sorry.
Declaring the functions as static like this seems to be a bit more
reliable than defining COMMON_DIGEST_FOR_OPENSSL on older cats. */
@@ -254,7 +254,7 @@ static void my_md5_final(unsigned char *digest, my_md5_ctx *ctx)
* Author:
* Alexander Peslyak, better known as Solar Designer <solar at openwall.com>
*
- * This software was written by Alexander Peslyak in 2001. No copyright is
+ * This software was written by Alexander Peslyak in 2001. No copyright is
* claimed, and the software is hereby placed in the public domain.
* In case this attempt to disclaim copyright and place the software in the
* public domain is deemed null and void, then the software is
@@ -264,19 +264,19 @@ static void my_md5_final(unsigned char *digest, my_md5_ctx *ctx)
* Redistribution and use in source and binary forms, with or without
* modification, are permitted.
*
- * There is ABSOLUTELY NO WARRANTY, express or implied.
+ * There's ABSOLUTELY NO WARRANTY, express or implied.
*
* (This is a heavily cut-down "BSD license".)
*
* This differs from Colin Plumb's older public domain implementation in that
* no exactly 32-bit integer data type is required (any 32-bit or wider
- * unsigned integer data type will do), there is no compile-time endianness
- * configuration, and the function prototypes match OpenSSL's. No code from
+ * unsigned integer data type will do), there's no compile-time endianness
+ * configuration, and the function prototypes match OpenSSL's. No code from
* Colin Plumb's implementation has been reused; this comment merely compares
* the properties of the two independent implementations.
*
* The primary goals of this implementation are portability and ease of use.
- * It is meant to be fast, but not as fast as possible. Some known
+ * It is meant to be fast, but not as fast as possible. Some known
* optimizations are not included to reduce source code size and avoid
* compile-time configuration.
*/
@@ -304,16 +304,16 @@ static void my_md5_final(unsigned char *result, my_md5_ctx *ctx);
* architectures that lack an AND-NOT instruction, just like in Colin Plumb's
* implementation.
*/
-#define MD5_F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
-#define MD5_G(x, y, z) ((y) ^ ((z) & ((x) ^ (y))))
-#define MD5_H(x, y, z) (((x) ^ (y)) ^ (z))
-#define MD5_H2(x, y, z) ((x) ^ ((y) ^ (z)))
-#define MD5_I(x, y, z) ((y) ^ ((x) | ~(z)))
+#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
+#define G(x, y, z) ((y) ^ ((z) & ((x) ^ (y))))
+#define H(x, y, z) (((x) ^ (y)) ^ (z))
+#define H2(x, y, z) ((x) ^ ((y) ^ (z)))
+#define I(x, y, z) ((y) ^ ((x) | ~(z)))
/*
* The MD5 transformation for all four rounds.
*/
-#define MD5_STEP(f, a, b, c, d, x, t, s) \
+#define STEP(f, a, b, c, d, x, t, s) \
(a) += f((b), (c), (d)) + (x) + (t); \
(a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \
(a) += (b);
@@ -323,31 +323,30 @@ static void my_md5_final(unsigned char *result, my_md5_ctx *ctx);
* in a properly aligned word in host byte order.
*
* The check for little-endian architectures that tolerate unaligned
- * memory accesses is just an optimization. Nothing will break if it
- * does not work.
+ * memory accesses is just an optimization. Nothing will break if it
+ * doesn't work.
*/
#if defined(__i386__) || defined(__x86_64__) || defined(__vax__)
-#define MD5_SET(n) \
+#define SET(n) \
(*(MD5_u32plus *)(void *)&ptr[(n) * 4])
-#define MD5_GET(n) \
- MD5_SET(n)
+#define GET(n) \
+ SET(n)
#else
-#define MD5_SET(n) \
+#define SET(n) \
(ctx->block[(n)] = \
(MD5_u32plus)ptr[(n) * 4] | \
((MD5_u32plus)ptr[(n) * 4 + 1] << 8) | \
((MD5_u32plus)ptr[(n) * 4 + 2] << 16) | \
((MD5_u32plus)ptr[(n) * 4 + 3] << 24))
-#define MD5_GET(n) \
+#define GET(n) \
(ctx->block[(n)])
#endif
/*
* This processes one or more 64-byte data blocks, but does NOT update
- * the bit counters. There are no alignment requirements.
+ * the bit counters. There are no alignment requirements.
*/
-static const void *my_md5_body(my_md5_ctx *ctx,
- const void *data, unsigned long size)
+static const void *body(my_md5_ctx *ctx, const void *data, unsigned long size)
{
const unsigned char *ptr;
MD5_u32plus a, b, c, d;
@@ -368,76 +367,76 @@ static const void *my_md5_body(my_md5_ctx *ctx,
saved_d = d;
/* Round 1 */
- MD5_STEP(MD5_F, a, b, c, d, MD5_SET(0), 0xd76aa478, 7)
- MD5_STEP(MD5_F, d, a, b, c, MD5_SET(1), 0xe8c7b756, 12)
- MD5_STEP(MD5_F, c, d, a, b, MD5_SET(2), 0x242070db, 17)
- MD5_STEP(MD5_F, b, c, d, a, MD5_SET(3), 0xc1bdceee, 22)
- MD5_STEP(MD5_F, a, b, c, d, MD5_SET(4), 0xf57c0faf, 7)
- MD5_STEP(MD5_F, d, a, b, c, MD5_SET(5), 0x4787c62a, 12)
- MD5_STEP(MD5_F, c, d, a, b, MD5_SET(6), 0xa8304613, 17)
- MD5_STEP(MD5_F, b, c, d, a, MD5_SET(7), 0xfd469501, 22)
- MD5_STEP(MD5_F, a, b, c, d, MD5_SET(8), 0x698098d8, 7)
- MD5_STEP(MD5_F, d, a, b, c, MD5_SET(9), 0x8b44f7af, 12)
- MD5_STEP(MD5_F, c, d, a, b, MD5_SET(10), 0xffff5bb1, 17)
- MD5_STEP(MD5_F, b, c, d, a, MD5_SET(11), 0x895cd7be, 22)
- MD5_STEP(MD5_F, a, b, c, d, MD5_SET(12), 0x6b901122, 7)
- MD5_STEP(MD5_F, d, a, b, c, MD5_SET(13), 0xfd987193, 12)
- MD5_STEP(MD5_F, c, d, a, b, MD5_SET(14), 0xa679438e, 17)
- MD5_STEP(MD5_F, b, c, d, a, MD5_SET(15), 0x49b40821, 22)
+ STEP(F, a, b, c, d, SET(0), 0xd76aa478, 7)
+ STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12)
+ STEP(F, c, d, a, b, SET(2), 0x242070db, 17)
+ STEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22)
+ STEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7)
+ STEP(F, d, a, b, c, SET(5), 0x4787c62a, 12)
+ STEP(F, c, d, a, b, SET(6), 0xa8304613, 17)
+ STEP(F, b, c, d, a, SET(7), 0xfd469501, 22)
+ STEP(F, a, b, c, d, SET(8), 0x698098d8, 7)
+ STEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12)
+ STEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17)
+ STEP(F, b, c, d, a, SET(11), 0x895cd7be, 22)
+ STEP(F, a, b, c, d, SET(12), 0x6b901122, 7)
+ STEP(F, d, a, b, c, SET(13), 0xfd987193, 12)
+ STEP(F, c, d, a, b, SET(14), 0xa679438e, 17)
+ STEP(F, b, c, d, a, SET(15), 0x49b40821, 22)
/* Round 2 */
- MD5_STEP(MD5_G, a, b, c, d, MD5_GET(1), 0xf61e2562, 5)
- MD5_STEP(MD5_G, d, a, b, c, MD5_GET(6), 0xc040b340, 9)
- MD5_STEP(MD5_G, c, d, a, b, MD5_GET(11), 0x265e5a51, 14)
- MD5_STEP(MD5_G, b, c, d, a, MD5_GET(0), 0xe9b6c7aa, 20)
- MD5_STEP(MD5_G, a, b, c, d, MD5_GET(5), 0xd62f105d, 5)
- MD5_STEP(MD5_G, d, a, b, c, MD5_GET(10), 0x02441453, 9)
- MD5_STEP(MD5_G, c, d, a, b, MD5_GET(15), 0xd8a1e681, 14)
- MD5_STEP(MD5_G, b, c, d, a, MD5_GET(4), 0xe7d3fbc8, 20)
- MD5_STEP(MD5_G, a, b, c, d, MD5_GET(9), 0x21e1cde6, 5)
- MD5_STEP(MD5_G, d, a, b, c, MD5_GET(14), 0xc33707d6, 9)
- MD5_STEP(MD5_G, c, d, a, b, MD5_GET(3), 0xf4d50d87, 14)
- MD5_STEP(MD5_G, b, c, d, a, MD5_GET(8), 0x455a14ed, 20)
- MD5_STEP(MD5_G, a, b, c, d, MD5_GET(13), 0xa9e3e905, 5)
- MD5_STEP(MD5_G, d, a, b, c, MD5_GET(2), 0xfcefa3f8, 9)
- MD5_STEP(MD5_G, c, d, a, b, MD5_GET(7), 0x676f02d9, 14)
- MD5_STEP(MD5_G, b, c, d, a, MD5_GET(12), 0x8d2a4c8a, 20)
+ STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5)
+ STEP(G, d, a, b, c, GET(6), 0xc040b340, 9)
+ STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14)
+ STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20)
+ STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5)
+ STEP(G, d, a, b, c, GET(10), 0x02441453, 9)
+ STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14)
+ STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20)
+ STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5)
+ STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9)
+ STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14)
+ STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20)
+ STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5)
+ STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9)
+ STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14)
+ STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20)
/* Round 3 */
- MD5_STEP(MD5_H, a, b, c, d, MD5_GET(5), 0xfffa3942, 4)
- MD5_STEP(MD5_H2, d, a, b, c, MD5_GET(8), 0x8771f681, 11)
- MD5_STEP(MD5_H, c, d, a, b, MD5_GET(11), 0x6d9d6122, 16)
- MD5_STEP(MD5_H2, b, c, d, a, MD5_GET(14), 0xfde5380c, 23)
- MD5_STEP(MD5_H, a, b, c, d, MD5_GET(1), 0xa4beea44, 4)
- MD5_STEP(MD5_H2, d, a, b, c, MD5_GET(4), 0x4bdecfa9, 11)
- MD5_STEP(MD5_H, c, d, a, b, MD5_GET(7), 0xf6bb4b60, 16)
- MD5_STEP(MD5_H2, b, c, d, a, MD5_GET(10), 0xbebfbc70, 23)
- MD5_STEP(MD5_H, a, b, c, d, MD5_GET(13), 0x289b7ec6, 4)
- MD5_STEP(MD5_H2, d, a, b, c, MD5_GET(0), 0xeaa127fa, 11)
- MD5_STEP(MD5_H, c, d, a, b, MD5_GET(3), 0xd4ef3085, 16)
- MD5_STEP(MD5_H2, b, c, d, a, MD5_GET(6), 0x04881d05, 23)
- MD5_STEP(MD5_H, a, b, c, d, MD5_GET(9), 0xd9d4d039, 4)
- MD5_STEP(MD5_H2, d, a, b, c, MD5_GET(12), 0xe6db99e5, 11)
- MD5_STEP(MD5_H, c, d, a, b, MD5_GET(15), 0x1fa27cf8, 16)
- MD5_STEP(MD5_H2, b, c, d, a, MD5_GET(2), 0xc4ac5665, 23)
+ STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4)
+ STEP(H2, d, a, b, c, GET(8), 0x8771f681, 11)
+ STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16)
+ STEP(H2, b, c, d, a, GET(14), 0xfde5380c, 23)
+ STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4)
+ STEP(H2, d, a, b, c, GET(4), 0x4bdecfa9, 11)
+ STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16)
+ STEP(H2, b, c, d, a, GET(10), 0xbebfbc70, 23)
+ STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4)
+ STEP(H2, d, a, b, c, GET(0), 0xeaa127fa, 11)
+ STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16)
+ STEP(H2, b, c, d, a, GET(6), 0x04881d05, 23)
+ STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4)
+ STEP(H2, d, a, b, c, GET(12), 0xe6db99e5, 11)
+ STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16)
+ STEP(H2, b, c, d, a, GET(2), 0xc4ac5665, 23)
/* Round 4 */
- MD5_STEP(MD5_I, a, b, c, d, MD5_GET(0), 0xf4292244, 6)
- MD5_STEP(MD5_I, d, a, b, c, MD5_GET(7), 0x432aff97, 10)
- MD5_STEP(MD5_I, c, d, a, b, MD5_GET(14), 0xab9423a7, 15)
- MD5_STEP(MD5_I, b, c, d, a, MD5_GET(5), 0xfc93a039, 21)
- MD5_STEP(MD5_I, a, b, c, d, MD5_GET(12), 0x655b59c3, 6)
- MD5_STEP(MD5_I, d, a, b, c, MD5_GET(3), 0x8f0ccc92, 10)
- MD5_STEP(MD5_I, c, d, a, b, MD5_GET(10), 0xffeff47d, 15)
- MD5_STEP(MD5_I, b, c, d, a, MD5_GET(1), 0x85845dd1, 21)
- MD5_STEP(MD5_I, a, b, c, d, MD5_GET(8), 0x6fa87e4f, 6)
- MD5_STEP(MD5_I, d, a, b, c, MD5_GET(15), 0xfe2ce6e0, 10)
- MD5_STEP(MD5_I, c, d, a, b, MD5_GET(6), 0xa3014314, 15)
- MD5_STEP(MD5_I, b, c, d, a, MD5_GET(13), 0x4e0811a1, 21)
- MD5_STEP(MD5_I, a, b, c, d, MD5_GET(4), 0xf7537e82, 6)
- MD5_STEP(MD5_I, d, a, b, c, MD5_GET(11), 0xbd3af235, 10)
- MD5_STEP(MD5_I, c, d, a, b, MD5_GET(2), 0x2ad7d2bb, 15)
- MD5_STEP(MD5_I, b, c, d, a, MD5_GET(9), 0xeb86d391, 21)
+ STEP(I, a, b, c, d, GET(0), 0xf4292244, 6)
+ STEP(I, d, a, b, c, GET(7), 0x432aff97, 10)
+ STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15)
+ STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21)
+ STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6)
+ STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10)
+ STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15)
+ STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21)
+ STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6)
+ STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10)
+ STEP(I, c, d, a, b, GET(6), 0xa3014314, 15)
+ STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21)
+ STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6)
+ STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10)
+ STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15)
+ STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21)
a += saved_a;
b += saved_b;
@@ -493,11 +492,11 @@ static void my_md5_update(my_md5_ctx *ctx, const void *data,
memcpy(&ctx->buffer[used], data, available);
data = (const unsigned char *)data + available;
size -= available;
- my_md5_body(ctx, ctx->buffer, 64);
+ body(ctx, ctx->buffer, 64);
}
if(size >= 64) {
- data = my_md5_body(ctx, data, size & ~(unsigned long)0x3f);
+ data = body(ctx, data, size & ~(unsigned long)0x3f);
size &= 0x3f;
}
@@ -516,7 +515,7 @@ static void my_md5_final(unsigned char *result, my_md5_ctx *ctx)
if(available < 8) {
memset(&ctx->buffer[used], 0, available);
- my_md5_body(ctx, ctx->buffer, 64);
+ body(ctx, ctx->buffer, 64);
used = 0;
available = 64;
}
@@ -533,7 +532,7 @@ static void my_md5_final(unsigned char *result, my_md5_ctx *ctx)
ctx->buffer[62] = curlx_ultouc((ctx->hi >> 16)&0xff);
ctx->buffer[63] = curlx_ultouc(ctx->hi >> 24);
- my_md5_body(ctx, ctx->buffer, 64);
+ body(ctx, ctx->buffer, 64);
result[0] = curlx_ultouc((ctx->a)&0xff);
result[1] = curlx_ultouc((ctx->a >> 8)&0xff);
diff --git a/contrib/libs/curl/lib/memdebug.c b/contrib/libs/curl/lib/memdebug.c
index bc83d3eea3..f6ced85cd9 100644
--- a/contrib/libs/curl/lib/memdebug.c
+++ b/contrib/libs/curl/lib/memdebug.c
@@ -30,7 +30,7 @@
#include "urldata.h"
-#define MEMDEBUG_NODEFINES /* do not redefine the standard functions */
+#define MEMDEBUG_NODEFINES /* don't redefine the standard functions */
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@@ -44,8 +44,8 @@ struct memdebug {
double d;
void *p;
} mem[1];
- /* I am hoping this is the thing with the strictest alignment
- * requirements. That also means we waste some space :-( */
+ /* I'm hoping this is the thing with the strictest alignment
+ * requirements. That also means we waste some space :-( */
};
/*
@@ -53,7 +53,7 @@ struct memdebug {
* remain so. For advanced analysis, record a log file and write perl scripts
* to analyze them!
*
- * Do not use these with multithreaded test programs!
+ * Don't use these with multithreaded test programs!
*/
FILE *curl_dbg_logfile = NULL;
@@ -75,7 +75,7 @@ static void curl_dbg_cleanup(void)
curl_dbg_logfile = NULL;
}
-/* this sets the log filename */
+/* this sets the log file name */
void curl_dbg_memdebug(const char *logname)
{
if(!curl_dbg_logfile) {
@@ -84,7 +84,7 @@ void curl_dbg_memdebug(const char *logname)
else
curl_dbg_logfile = stderr;
#ifdef MEMDEBUG_LOG_SYNC
- /* Flush the log file after every line so the log is not lost in a crash */
+ /* Flush the log file after every line so the log isn't lost in a crash */
if(curl_dbg_logfile)
setbuf(curl_dbg_logfile, (char *)NULL);
#endif
@@ -103,7 +103,7 @@ void curl_dbg_memlimit(long limit)
}
}
-/* returns TRUE if this is not allowed! */
+/* returns TRUE if this isn't allowed! */
static bool countcheck(const char *func, int line, const char *source)
{
/* if source is NULL, then the call is made internally and this check
@@ -304,6 +304,12 @@ void curl_dbg_free(void *ptr, int line, const char *source)
curl_socket_t curl_dbg_socket(int domain, int type, int protocol,
int line, const char *source)
{
+ const char *fmt = (sizeof(curl_socket_t) == sizeof(int)) ?
+ "FD %s:%d socket() = %d\n" :
+ (sizeof(curl_socket_t) == sizeof(long)) ?
+ "FD %s:%d socket() = %ld\n" :
+ "FD %s:%d socket() = %zd\n";
+
curl_socket_t sockfd;
if(countcheck("socket", line, source))
@@ -312,8 +318,7 @@ curl_socket_t curl_dbg_socket(int domain, int type, int protocol,
sockfd = socket(domain, type, protocol);
if(source && (sockfd != CURL_SOCKET_BAD))
- curl_dbg_log("FD %s:%d socket() = %" FMT_SOCKET_T "\n",
- source, line, sockfd);
+ curl_dbg_log(fmt, source, line, sockfd);
return sockfd;
}
@@ -352,12 +357,16 @@ int curl_dbg_socketpair(int domain, int type, int protocol,
curl_socket_t socket_vector[2],
int line, const char *source)
{
+ const char *fmt = (sizeof(curl_socket_t) == sizeof(int)) ?
+ "FD %s:%d socketpair() = %d %d\n" :
+ (sizeof(curl_socket_t) == sizeof(long)) ?
+ "FD %s:%d socketpair() = %ld %ld\n" :
+ "FD %s:%d socketpair() = %zd %zd\n";
+
int res = socketpair(domain, type, protocol, socket_vector);
if(source && (0 == res))
- curl_dbg_log("FD %s:%d socketpair() = "
- "%" FMT_SOCKET_T " %" FMT_SOCKET_T "\n",
- source, line, socket_vector[0], socket_vector[1]);
+ curl_dbg_log(fmt, source, line, socket_vector[0], socket_vector[1]);
return res;
}
@@ -366,14 +375,19 @@ int curl_dbg_socketpair(int domain, int type, int protocol,
curl_socket_t curl_dbg_accept(curl_socket_t s, void *saddr, void *saddrlen,
int line, const char *source)
{
+ const char *fmt = (sizeof(curl_socket_t) == sizeof(int)) ?
+ "FD %s:%d accept() = %d\n" :
+ (sizeof(curl_socket_t) == sizeof(long)) ?
+ "FD %s:%d accept() = %ld\n" :
+ "FD %s:%d accept() = %zd\n";
+
struct sockaddr *addr = (struct sockaddr *)saddr;
curl_socklen_t *addrlen = (curl_socklen_t *)saddrlen;
curl_socket_t sockfd = accept(s, addr, addrlen);
if(source && (sockfd != CURL_SOCKET_BAD))
- curl_dbg_log("FD %s:%d accept() = %" FMT_SOCKET_T "\n",
- source, line, sockfd);
+ curl_dbg_log(fmt, source, line, sockfd);
return sockfd;
}
@@ -381,9 +395,14 @@ curl_socket_t curl_dbg_accept(curl_socket_t s, void *saddr, void *saddrlen,
/* separate function to allow libcurl to mark a "faked" close */
void curl_dbg_mark_sclose(curl_socket_t sockfd, int line, const char *source)
{
+ const char *fmt = (sizeof(curl_socket_t) == sizeof(int)) ?
+ "FD %s:%d sclose(%d)\n":
+ (sizeof(curl_socket_t) == sizeof(long)) ?
+ "FD %s:%d sclose(%ld)\n":
+ "FD %s:%d sclose(%zd)\n";
+
if(source)
- curl_dbg_log("FD %s:%d sclose(%" FMT_SOCKET_T ")\n",
- source, line, sockfd);
+ curl_dbg_log(fmt, source, line, sockfd);
}
/* this is our own defined way to close sockets on *ALL* platforms */
diff --git a/contrib/libs/curl/lib/memdebug.h b/contrib/libs/curl/lib/memdebug.h
index cabadbcc89..78a012580c 100644
--- a/contrib/libs/curl/lib/memdebug.h
+++ b/contrib/libs/curl/lib/memdebug.h
@@ -34,9 +34,9 @@
#include "functypes.h"
#if defined(__GNUC__) && __GNUC__ >= 3
-# define ALLOC_FUNC __attribute__((__malloc__))
-# define ALLOC_SIZE(s) __attribute__((__alloc_size__(s)))
-# define ALLOC_SIZE2(n, s) __attribute__((__alloc_size__(n, s)))
+# define ALLOC_FUNC __attribute__((malloc))
+# define ALLOC_SIZE(s) __attribute__((alloc_size(s)))
+# define ALLOC_SIZE2(n, s) __attribute__((alloc_size(n, s)))
#elif defined(_MSC_VER)
# define ALLOC_FUNC __declspec(restrict)
# define ALLOC_SIZE(s)
@@ -72,7 +72,7 @@ CURL_EXTERN ALLOC_FUNC wchar_t *curl_dbg_wcsdup(const wchar_t *str,
CURL_EXTERN void curl_dbg_memdebug(const char *logname);
CURL_EXTERN void curl_dbg_memlimit(long limit);
-CURL_EXTERN void curl_dbg_log(const char *format, ...) CURL_PRINTF(1, 2);
+CURL_EXTERN void curl_dbg_log(const char *format, ...);
/* file descriptor manipulators */
CURL_EXTERN curl_socket_t curl_dbg_socket(int domain, int type, int protocol,
@@ -114,17 +114,11 @@ CURL_EXTERN int curl_dbg_fclose(FILE *file, int line, const char *source);
/* Set this symbol on the command-line, recompile all lib-sources */
#undef strdup
#define strdup(ptr) curl_dbg_strdup(ptr, __LINE__, __FILE__)
-#undef malloc
#define malloc(size) curl_dbg_malloc(size, __LINE__, __FILE__)
-#undef calloc
#define calloc(nbelem,size) curl_dbg_calloc(nbelem, size, __LINE__, __FILE__)
-#undef realloc
#define realloc(ptr,size) curl_dbg_realloc(ptr, size, __LINE__, __FILE__)
-#undef free
#define free(ptr) curl_dbg_free(ptr, __LINE__, __FILE__)
-#undef send
#define send(a,b,c,d) curl_dbg_send(a,b,c,d, __LINE__, __FILE__)
-#undef recv
#define recv(a,b,c,d) curl_dbg_recv(a,b,c,d, __LINE__, __FILE__)
#ifdef _WIN32
@@ -143,14 +137,13 @@ CURL_EXTERN int curl_dbg_fclose(FILE *file, int line, const char *source);
#undef socket
#define socket(domain,type,protocol)\
- curl_dbg_socket((int)domain, type, protocol, __LINE__, __FILE__)
+ curl_dbg_socket(domain, type, protocol, __LINE__, __FILE__)
#undef accept /* for those with accept as a macro */
#define accept(sock,addr,len)\
curl_dbg_accept(sock, addr, len, __LINE__, __FILE__)
#ifdef HAVE_SOCKETPAIR
#define socketpair(domain,type,protocol,socket_vector)\
- curl_dbg_socketpair((int)domain, type, protocol, socket_vector, \
- __LINE__, __FILE__)
+ curl_dbg_socketpair(domain, type, protocol, socket_vector, __LINE__, __FILE__)
#endif
#ifdef HAVE_GETADDRINFO
diff --git a/contrib/libs/curl/lib/mime.c b/contrib/libs/curl/lib/mime.c
index 5df2d68918..b9335e6d37 100644
--- a/contrib/libs/curl/lib/mime.c
+++ b/contrib/libs/curl/lib/mime.c
@@ -30,7 +30,6 @@
#include "warnless.h"
#include "urldata.h"
#include "sendf.h"
-#include "strdup.h"
#if !defined(CURL_DISABLE_MIME) && (!defined(CURL_DISABLE_HTTP) || \
!defined(CURL_DISABLE_SMTP) || \
@@ -74,7 +73,6 @@ static curl_off_t encoder_base64_size(curl_mimepart *part);
static size_t encoder_qp_read(char *buffer, size_t size, bool ateof,
curl_mimepart *part);
static curl_off_t encoder_qp_size(curl_mimepart *part);
-static curl_off_t mime_size(curl_mimepart *part);
static const struct mime_encoder encoders[] = {
{"binary", encoder_nop_read, encoder_nop_size},
@@ -92,7 +90,7 @@ static const char base64enc[] =
/* Quoted-printable character class table.
*
* We cannot rely on ctype functions since quoted-printable input data
- * is assumed to be ASCII-compatible, even on non-ASCII platforms. */
+ * is assumed to be ascii-compatible, even on non-ascii platforms. */
#define QP_OK 1 /* Can be represented by itself. */
#define QP_SP 2 /* Space or tab. */
#define QP_CR 3 /* Carriage return. */
@@ -557,7 +555,7 @@ static size_t encoder_qp_read(char *buffer, size_t size, bool ateof,
/* On all platforms, input is supposed to be ASCII compatible: for this
reason, we use hexadecimal ASCII codes in this function rather than
- character constants that can be interpreted as non-ASCII on some
+ character constants that can be interpreted as non-ascii on some
platforms. Preserve ASCII encoding on output too. */
while(st->bufbeg < st->bufend) {
size_t len = 1;
@@ -819,7 +817,7 @@ static size_t read_part_content(curl_mimepart *part,
case MIMEKIND_FILE:
if(part->fp && feof(part->fp))
break; /* At EOF. */
- FALLTHROUGH();
+ /* FALLTHROUGH */
default:
if(part->readfunc) {
if(!(part->flags & MIME_FAST_READ)) {
@@ -938,7 +936,7 @@ static size_t readback_part(curl_mimepart *part,
mimesetstate(&part->state, MIMESTATE_USERHEADERS, hdr->next);
break;
}
- FALLTHROUGH();
+ /* FALLTHROUGH */
case MIMESTATE_CURLHEADERS:
if(!hdr)
mimesetstate(&part->state, MIMESTATE_USERHEADERS, part->userheaders);
@@ -972,7 +970,7 @@ static size_t readback_part(curl_mimepart *part,
fclose(part->fp);
part->fp = NULL;
}
- FALLTHROUGH();
+ /* FALLTHROUGH */
case CURL_READFUNC_ABORT:
case CURL_READFUNC_PAUSE:
case READ_ERROR:
@@ -1137,7 +1135,7 @@ static void cleanup_part_content(curl_mimepart *part)
part->datasize = (curl_off_t) 0; /* No size yet. */
cleanup_encoder_state(&part->encstate);
part->kind = MIMEKIND_NONE;
- part->flags &= ~(unsigned int)MIME_FAST_READ;
+ part->flags &= ~MIME_FAST_READ;
part->lastreadstatus = 1; /* Successful read status. */
part->state.state = MIMESTATE_BEGIN;
}
@@ -1147,7 +1145,7 @@ static void mime_subparts_free(void *ptr)
curl_mime *mime = (curl_mime *) ptr;
if(mime && mime->parent) {
- mime->parent->freefunc = NULL; /* Be sure we will not be called again. */
+ mime->parent->freefunc = NULL; /* Be sure we won't be called again. */
cleanup_part_content(mime->parent); /* Avoid dangling pointer in part. */
}
curl_mime_free(mime);
@@ -1159,7 +1157,7 @@ static void mime_subparts_unbind(void *ptr)
curl_mime *mime = (curl_mime *) ptr;
if(mime && mime->parent) {
- mime->parent->freefunc = NULL; /* Be sure we will not be called again. */
+ mime->parent->freefunc = NULL; /* Be sure we won't be called again. */
cleanup_part_content(mime->parent); /* Avoid dangling pointer in part. */
mime->parent = NULL;
}
@@ -1186,7 +1184,7 @@ void curl_mime_free(curl_mime *mime)
curl_mimepart *part;
if(mime) {
- mime_subparts_unbind(mime); /* Be sure it is not referenced anymore. */
+ mime_subparts_unbind(mime); /* Be sure it's not referenced anymore. */
while(mime->firstpart) {
part = mime->firstpart;
mime->firstpart = part->nextpart;
@@ -1237,7 +1235,6 @@ CURLcode Curl_mime_duppart(struct Curl_easy *data,
}
break;
default: /* Invalid kind: should not occur. */
- DEBUGF(infof(data, "invalid MIMEKIND* attempt"));
res = CURLE_BAD_FUNCTION_ARGUMENT; /* Internal error? */
break;
}
@@ -1354,7 +1351,7 @@ CURLcode curl_mime_name(curl_mimepart *part, const char *name)
return CURLE_OK;
}
-/* Set mime part remote filename. */
+/* Set mime part remote file name. */
CURLcode curl_mime_filename(curl_mimepart *part, const char *filename)
{
if(!part)
@@ -1373,22 +1370,27 @@ CURLcode curl_mime_filename(curl_mimepart *part, const char *filename)
/* Set mime part content from memory data. */
CURLcode curl_mime_data(curl_mimepart *part,
- const char *ptr, size_t datasize)
+ const char *data, size_t datasize)
{
if(!part)
return CURLE_BAD_FUNCTION_ARGUMENT;
cleanup_part_content(part);
- if(ptr) {
+ if(data) {
if(datasize == CURL_ZERO_TERMINATED)
- datasize = strlen(ptr);
+ datasize = strlen(data);
- part->data = Curl_memdup0(ptr, datasize);
+ part->data = malloc(datasize + 1);
if(!part->data)
return CURLE_OUT_OF_MEMORY;
part->datasize = datasize;
+
+ if(datasize)
+ memcpy(part->data, data, datasize);
+ part->data[datasize] = '\0'; /* Set a null terminator as sentinel. */
+
part->readfunc = mime_mem_read;
part->seekfunc = mime_mem_seek;
part->freefunc = mime_mem_free;
@@ -1413,35 +1415,36 @@ CURLcode curl_mime_filedata(curl_mimepart *part, const char *filename)
char *base;
struct_stat sbuf;
- if(stat(filename, &sbuf))
+ if(stat(filename, &sbuf) || access(filename, R_OK))
result = CURLE_READ_ERROR;
+
+ part->data = strdup(filename);
+ if(!part->data)
+ result = CURLE_OUT_OF_MEMORY;
+
+ part->datasize = -1;
+ if(!result && S_ISREG(sbuf.st_mode)) {
+ part->datasize = filesize(filename, sbuf);
+ part->seekfunc = mime_file_seek;
+ }
+
+ part->readfunc = mime_file_read;
+ part->freefunc = mime_file_free;
+ part->kind = MIMEKIND_FILE;
+
+ /* As a side effect, set the filename to the current file's base name.
+ It is possible to withdraw this by explicitly calling
+ curl_mime_filename() with a NULL filename argument after the current
+ call. */
+ base = strippath(filename);
+ if(!base)
+ result = CURLE_OUT_OF_MEMORY;
else {
- part->data = strdup(filename);
- if(!part->data)
- result = CURLE_OUT_OF_MEMORY;
- else {
- part->datasize = -1;
- if(S_ISREG(sbuf.st_mode)) {
- part->datasize = filesize(filename, sbuf);
- part->seekfunc = mime_file_seek;
- }
+ CURLcode res = curl_mime_filename(part, base);
- part->readfunc = mime_file_read;
- part->freefunc = mime_file_free;
- part->kind = MIMEKIND_FILE;
-
- /* As a side effect, set the filename to the current file's base name.
- It is possible to withdraw this by explicitly calling
- curl_mime_filename() with a NULL filename argument after the current
- call. */
- base = strippath(filename);
- if(!base)
- result = CURLE_OUT_OF_MEMORY;
- else {
- result = curl_mime_filename(part, base);
- free(base);
- }
- }
+ if(res)
+ result = res;
+ free(base);
}
}
return result;
@@ -1497,7 +1500,7 @@ CURLcode curl_mime_headers(curl_mimepart *part,
if(part->flags & MIME_USERHEADERS_OWNER) {
if(part->userheaders != headers) /* Allow setting twice the same list. */
curl_slist_free_all(part->userheaders);
- part->flags &= ~(unsigned int)MIME_USERHEADERS_OWNER;
+ part->flags &= ~MIME_USERHEADERS_OWNER;
}
part->userheaders = headers;
if(headers && take_ownership)
@@ -1554,7 +1557,7 @@ CURLcode Curl_mime_set_subparts(curl_mimepart *part,
while(root->parent && root->parent->parent)
root = root->parent->parent;
if(subparts == root) {
- /* cannot add as a subpart of itself. */
+ /* Can't add as a subpart of itself. */
return CURLE_BAD_FUNCTION_ARGUMENT;
}
}
@@ -1587,8 +1590,6 @@ size_t Curl_mime_read(char *buffer, size_t size, size_t nitems, void *instream)
(void) size; /* Always 1. */
- /* TODO: this loop is broken. If `nitems` is <= 4, some encoders will
- * return STOP_FILLING without adding any data and this loops infinitely. */
do {
hasread = FALSE;
ret = readback_part(part, buffer, nitems, &hasread);
@@ -1604,7 +1605,7 @@ size_t Curl_mime_read(char *buffer, size_t size, size_t nitems, void *instream)
}
/* Rewind mime stream. */
-static CURLcode mime_rewind(curl_mimepart *part)
+CURLcode Curl_mime_rewind(curl_mimepart *part)
{
return mime_part_rewind(part) == CURL_SEEKFUNC_OK?
CURLE_OK: CURLE_SEND_FAIL_REWIND;
@@ -1636,7 +1637,7 @@ static curl_off_t multipart_size(curl_mime *mime)
size = boundarysize; /* Final boundary - CRLF after headers. */
for(part = mime->firstpart; part; part = part->nextpart) {
- curl_off_t sz = mime_size(part);
+ curl_off_t sz = Curl_mime_size(part);
if(sz < 0)
size = sz;
@@ -1649,7 +1650,7 @@ static curl_off_t multipart_size(curl_mime *mime)
}
/* Get/compute mime size. */
-static curl_off_t mime_size(curl_mimepart *part)
+curl_off_t Curl_mime_size(curl_mimepart *part)
{
curl_off_t size;
@@ -1664,8 +1665,7 @@ static curl_off_t mime_size(curl_mimepart *part)
if(size >= 0 && !(part->flags & MIME_BODY_ONLY)) {
/* Compute total part size. */
size += slist_size(part->curlheaders, 2, NULL, 0);
- size += slist_size(part->userheaders, 2,
- STRCONST("Content-Type"));
+ size += slist_size(part->userheaders, 2, STRCONST("Content-Type"));
size += 2; /* CRLF after headers. */
}
return size;
@@ -1680,7 +1680,7 @@ CURLcode Curl_mime_add_header(struct curl_slist **slp, const char *fmt, ...)
va_list ap;
va_start(ap, fmt);
- s = vaprintf(fmt, ap);
+ s = curl_mvaprintf(fmt, ap);
va_end(ap);
if(s) {
@@ -1773,7 +1773,7 @@ CURLcode Curl_mime_prepare_headers(struct Curl_easy *data,
curl_slist_free_all(part->curlheaders);
part->curlheaders = NULL;
- /* Be sure we will not access old headers later. */
+ /* Be sure we won't access old headers later. */
if(part->state.state == MIMESTATE_CURLHEADERS)
mimesetstate(&part->state, MIMESTATE_CURLHEADERS, NULL);
@@ -1899,7 +1899,7 @@ CURLcode Curl_mime_prepare_headers(struct Curl_easy *data,
}
/* Recursively reset paused status in the given part. */
-static void mime_unpause(curl_mimepart *part)
+void Curl_mime_unpause(curl_mimepart *part)
{
if(part) {
if(part->lastreadstatus == CURL_READFUNC_PAUSE)
@@ -1911,264 +1911,12 @@ static void mime_unpause(curl_mimepart *part)
curl_mimepart *subpart;
for(subpart = mime->firstpart; subpart; subpart = subpart->nextpart)
- mime_unpause(subpart);
+ Curl_mime_unpause(subpart);
}
}
}
}
-struct cr_mime_ctx {
- struct Curl_creader super;
- curl_mimepart *part;
- curl_off_t total_len;
- curl_off_t read_len;
- CURLcode error_result;
- BIT(seen_eos);
- BIT(errored);
-};
-
-static CURLcode cr_mime_init(struct Curl_easy *data,
- struct Curl_creader *reader)
-{
- struct cr_mime_ctx *ctx = reader->ctx;
- (void)data;
- ctx->total_len = -1;
- ctx->read_len = 0;
- return CURLE_OK;
-}
-
-/* Real client reader to installed client callbacks. */
-static CURLcode cr_mime_read(struct Curl_easy *data,
- struct Curl_creader *reader,
- char *buf, size_t blen,
- size_t *pnread, bool *peos)
-{
- struct cr_mime_ctx *ctx = reader->ctx;
- size_t nread;
-
-
- /* Once we have errored, we will return the same error forever */
- if(ctx->errored) {
- CURL_TRC_READ(data, "cr_mime_read(len=%zu) is errored -> %d, eos=0",
- blen, ctx->error_result);
- *pnread = 0;
- *peos = FALSE;
- return ctx->error_result;
- }
- if(ctx->seen_eos) {
- CURL_TRC_READ(data, "cr_mime_read(len=%zu) seen eos -> 0, eos=1", blen);
- *pnread = 0;
- *peos = TRUE;
- return CURLE_OK;
- }
- /* respect length limitations */
- if(ctx->total_len >= 0) {
- curl_off_t remain = ctx->total_len - ctx->read_len;
- if(remain <= 0)
- blen = 0;
- else if(remain < (curl_off_t)blen)
- blen = (size_t)remain;
- }
-
- if(blen <= 4) {
- /* TODO: Curl_mime_read() may go into an infinite loop when reading
- * such small lengths. Returning 0 bytes read is a fix that only works
- * as request upload buffers will get flushed eventually and larger
- * reads will happen again. */
- CURL_TRC_READ(data, "cr_mime_read(len=%zu), too small, return", blen);
- *pnread = 0;
- *peos = FALSE;
- goto out;
- }
-
- nread = Curl_mime_read(buf, 1, blen, ctx->part);
- CURL_TRC_READ(data, "cr_mime_read(len=%zu), mime_read() -> %zd",
- blen, nread);
-
- switch(nread) {
- case 0:
- if((ctx->total_len >= 0) && (ctx->read_len < ctx->total_len)) {
- failf(data, "client mime read EOF fail, "
- "only %"FMT_OFF_T"/%"FMT_OFF_T
- " of needed bytes read", ctx->read_len, ctx->total_len);
- return CURLE_READ_ERROR;
- }
- *pnread = 0;
- *peos = TRUE;
- ctx->seen_eos = TRUE;
- break;
-
- case CURL_READFUNC_ABORT:
- failf(data, "operation aborted by callback");
- *pnread = 0;
- *peos = FALSE;
- ctx->errored = TRUE;
- ctx->error_result = CURLE_ABORTED_BY_CALLBACK;
- return CURLE_ABORTED_BY_CALLBACK;
-
- case CURL_READFUNC_PAUSE:
- /* CURL_READFUNC_PAUSE pauses read callbacks that feed socket writes */
- CURL_TRC_READ(data, "cr_mime_read(len=%zu), paused by callback", blen);
- data->req.keepon |= KEEP_SEND_PAUSE; /* mark socket send as paused */
- *pnread = 0;
- *peos = FALSE;
- break; /* nothing was read */
-
- case STOP_FILLING:
- case READ_ERROR:
- failf(data, "read error getting mime data");
- *pnread = 0;
- *peos = FALSE;
- ctx->errored = TRUE;
- ctx->error_result = CURLE_READ_ERROR;
- return CURLE_READ_ERROR;
-
- default:
- if(nread > blen) {
- /* the read function returned a too large value */
- failf(data, "read function returned funny value");
- *pnread = 0;
- *peos = FALSE;
- ctx->errored = TRUE;
- ctx->error_result = CURLE_READ_ERROR;
- return CURLE_READ_ERROR;
- }
- ctx->read_len += nread;
- if(ctx->total_len >= 0)
- ctx->seen_eos = (ctx->read_len >= ctx->total_len);
- *pnread = nread;
- *peos = ctx->seen_eos;
- break;
- }
-
-out:
- CURL_TRC_READ(data, "cr_mime_read(len=%zu, total=%" FMT_OFF_T
- ", read=%"FMT_OFF_T") -> %d, %zu, %d",
- blen, ctx->total_len, ctx->read_len, CURLE_OK, *pnread, *peos);
- return CURLE_OK;
-}
-
-static bool cr_mime_needs_rewind(struct Curl_easy *data,
- struct Curl_creader *reader)
-{
- struct cr_mime_ctx *ctx = reader->ctx;
- (void)data;
- return ctx->read_len > 0;
-}
-
-static curl_off_t cr_mime_total_length(struct Curl_easy *data,
- struct Curl_creader *reader)
-{
- struct cr_mime_ctx *ctx = reader->ctx;
- (void)data;
- return ctx->total_len;
-}
-
-static CURLcode cr_mime_resume_from(struct Curl_easy *data,
- struct Curl_creader *reader,
- curl_off_t offset)
-{
- struct cr_mime_ctx *ctx = reader->ctx;
-
- if(offset > 0) {
- curl_off_t passed = 0;
-
- do {
- char scratch[4*1024];
- size_t readthisamountnow =
- (offset - passed > (curl_off_t)sizeof(scratch)) ?
- sizeof(scratch) :
- curlx_sotouz(offset - passed);
- size_t nread;
-
- nread = Curl_mime_read(scratch, 1, readthisamountnow, ctx->part);
- passed += (curl_off_t)nread;
- if((nread == 0) || (nread > readthisamountnow)) {
- /* this checks for greater-than only to make sure that the
- CURL_READFUNC_ABORT return code still aborts */
- failf(data, "Could only read %" FMT_OFF_T
- " bytes from the mime post", passed);
- return CURLE_READ_ERROR;
- }
- } while(passed < offset);
-
- /* now, decrease the size of the read */
- if(ctx->total_len > 0) {
- ctx->total_len -= offset;
-
- if(ctx->total_len <= 0) {
- failf(data, "Mime post already completely uploaded");
- return CURLE_PARTIAL_FILE;
- }
- }
- /* we have passed, proceed as normal */
- }
- return CURLE_OK;
-}
-
-static CURLcode cr_mime_rewind(struct Curl_easy *data,
- struct Curl_creader *reader)
-{
- struct cr_mime_ctx *ctx = reader->ctx;
- CURLcode result = mime_rewind(ctx->part);
- if(result)
- failf(data, "Cannot rewind mime/post data");
- return result;
-}
-
-static CURLcode cr_mime_unpause(struct Curl_easy *data,
- struct Curl_creader *reader)
-{
- struct cr_mime_ctx *ctx = reader->ctx;
- (void)data;
- mime_unpause(ctx->part);
- return CURLE_OK;
-}
-
-static bool cr_mime_is_paused(struct Curl_easy *data,
- struct Curl_creader *reader)
-{
- struct cr_mime_ctx *ctx = reader->ctx;
- (void)data;
- return (ctx->part && ctx->part->lastreadstatus == CURL_READFUNC_PAUSE);
-}
-
-static const struct Curl_crtype cr_mime = {
- "cr-mime",
- cr_mime_init,
- cr_mime_read,
- Curl_creader_def_close,
- cr_mime_needs_rewind,
- cr_mime_total_length,
- cr_mime_resume_from,
- cr_mime_rewind,
- cr_mime_unpause,
- cr_mime_is_paused,
- Curl_creader_def_done,
- sizeof(struct cr_mime_ctx)
-};
-
-CURLcode Curl_creader_set_mime(struct Curl_easy *data, curl_mimepart *part)
-{
- struct Curl_creader *r;
- struct cr_mime_ctx *ctx;
- CURLcode result;
-
- result = Curl_creader_create(&r, data, &cr_mime, CURL_CR_CLIENT);
- if(result)
- return result;
- ctx = r->ctx;
- ctx->part = part;
- /* Make sure we will read the entire mime structure. */
- result = mime_rewind(ctx->part);
- if(result) {
- Curl_creader_free(data, r);
- return result;
- }
- ctx->total_len = mime_size(ctx->part);
-
- return Curl_creader_set(data, r);
-}
#else /* !CURL_DISABLE_MIME && (!CURL_DISABLE_HTTP ||
!CURL_DISABLE_SMTP || !CURL_DISABLE_IMAP) */
diff --git a/contrib/libs/curl/lib/mime.h b/contrib/libs/curl/lib/mime.h
index 5073a38f70..0a05c2a5aa 100644
--- a/contrib/libs/curl/lib/mime.h
+++ b/contrib/libs/curl/lib/mime.h
@@ -112,7 +112,7 @@ struct curl_mimepart {
curl_mimepart *nextpart; /* Forward linked list. */
enum mimekind kind; /* The part kind. */
unsigned int flags; /* Flags. */
- char *data; /* Memory data or filename. */
+ char *data; /* Memory data or file name. */
curl_read_callback readfunc; /* Read function. */
curl_seek_callback seekfunc; /* Seek function. */
curl_free_callback freefunc; /* Argument free function. */
@@ -121,7 +121,7 @@ struct curl_mimepart {
struct curl_slist *curlheaders; /* Part headers. */
struct curl_slist *userheaders; /* Part headers. */
char *mimetype; /* Part mime type. */
- char *filename; /* Remote filename. */
+ char *filename; /* Remote file name. */
char *name; /* Data name. */
curl_off_t datasize; /* Expected data size. */
struct mime_state state; /* Current readback state. */
@@ -130,8 +130,7 @@ struct curl_mimepart {
size_t lastreadstatus; /* Last read callback returned status. */
};
-CURLcode Curl_mime_add_header(struct curl_slist **slp, const char *fmt, ...)
- CURL_PRINTF(2, 3);
+CURLcode Curl_mime_add_header(struct curl_slist **slp, const char *fmt, ...);
#if !defined(CURL_DISABLE_MIME) && (!defined(CURL_DISABLE_HTTP) || \
!defined(CURL_DISABLE_SMTP) || \
@@ -151,15 +150,12 @@ CURLcode Curl_mime_prepare_headers(struct Curl_easy *data,
const char *contenttype,
const char *disposition,
enum mimestrategy strategy);
+curl_off_t Curl_mime_size(struct curl_mimepart *part);
size_t Curl_mime_read(char *buffer, size_t size, size_t nitems,
void *instream);
+CURLcode Curl_mime_rewind(struct curl_mimepart *part);
const char *Curl_mime_contenttype(const char *filename);
-
-/**
- * Install a client reader as upload source that reads the given
- * mime part.
- */
-CURLcode Curl_creader_set_mime(struct Curl_easy *data, curl_mimepart *part);
+void Curl_mime_unpause(struct curl_mimepart *part);
#else
/* if disabled */
@@ -168,8 +164,10 @@ CURLcode Curl_creader_set_mime(struct Curl_easy *data, curl_mimepart *part);
#define Curl_mime_duppart(x,y,z) CURLE_OK /* Nothing to duplicate. Succeed */
#define Curl_mime_set_subparts(a,b,c) CURLE_NOT_BUILT_IN
#define Curl_mime_prepare_headers(a,b,c,d,e) CURLE_NOT_BUILT_IN
+#define Curl_mime_size(x) (curl_off_t) -1
#define Curl_mime_read NULL
-#define Curl_creader_set_mime(x,y) ((void)x, CURLE_NOT_BUILT_IN)
+#define Curl_mime_rewind(x) ((void)x, CURLE_NOT_BUILT_IN)
+#define Curl_mime_unpause(x)
#endif
diff --git a/contrib/libs/curl/lib/mprintf.c b/contrib/libs/curl/lib/mprintf.c
index 42993c7177..6b5df5bdde 100644
--- a/contrib/libs/curl/lib/mprintf.c
+++ b/contrib/libs/curl/lib/mprintf.c
@@ -20,11 +20,26 @@
*
* SPDX-License-Identifier: curl
*
+ *
+ * Purpose:
+ * A merge of Bjorn Reese's format() function and Daniel's dsprintf()
+ * 1.0. A full blooded printf() clone with full support for <num>$
+ * everywhere (parameters, widths and precisions) including variabled
+ * sized parameters (like doubles, long longs, long doubles and even
+ * void * in 64-bit architectures).
+ *
+ * Current restrictions:
+ * - Max 128 parameters
+ * - No 'long double' support.
+ *
+ * If you ever want truly portable and good *printf() clones, the project that
+ * took on from here is named 'Trio' and you find more details on the trio web
+ * page at https://daniel.haxx.se/projects/trio/
*/
#include "curl_setup.h"
#include "dynbuf.h"
-#include "curl_printf.h"
+#include <curl/mprintf.h>
#include "curl_memory.h"
/* The last #include file should be: */
@@ -48,6 +63,16 @@
#endif
/*
+ * Non-ANSI integer extensions
+ */
+
+#if (defined(_WIN32_WCE)) || \
+ (defined(__MINGW32__)) || \
+ (defined(_MSC_VER) && (_MSC_VER >= 900) && (_INTEGRAL_MAX_BITS >= 64))
+# define MP_HAVE_INT_EXTENSIONS
+#endif
+
+/*
* Max integer data types that mprintf.c is capable
*/
@@ -61,8 +86,7 @@
#define BUFFSIZE 326 /* buffer for long-to-str and float-to-str calcs, should
fit negative DBL_MAX (317 letters) */
-#define MAX_PARAMETERS 128 /* number of input arguments */
-#define MAX_SEGMENTS 128 /* number of output segments */
+#define MAX_PARAMETERS 128 /* lame static limit */
#ifdef __AMIGA__
# undef FORMAT_INT
@@ -74,33 +98,31 @@ static const char lower_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
/* Upper-case digits. */
static const char upper_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
-#define OUTCHAR(x) \
- do { \
- if(!stream((unsigned char)x, userp)) \
- done++; \
- else \
- return done; /* return on failure */ \
+#define OUTCHAR(x) \
+ do { \
+ if(stream((unsigned char)(x), (FILE *)data) != -1) \
+ done++; \
+ else \
+ return done; /* return immediately on failure */ \
} while(0)
/* Data type to read from the arglist */
typedef enum {
+ FORMAT_UNKNOWN = 0,
FORMAT_STRING,
FORMAT_PTR,
- FORMAT_INTPTR,
FORMAT_INT,
+ FORMAT_INTPTR,
FORMAT_LONG,
FORMAT_LONGLONG,
- FORMAT_INTU,
- FORMAT_LONGU,
- FORMAT_LONGLONGU,
FORMAT_DOUBLE,
FORMAT_LONGDOUBLE,
- FORMAT_WIDTH,
- FORMAT_PRECISION
+ FORMAT_WIDTH /* For internal use */
} FormatType;
/* conversion and display flags */
enum {
+ FLAGS_NEW = 0,
FLAGS_SPACE = 1<<0,
FLAGS_SHOWSIGN = 1<<1,
FLAGS_LEFT = 1<<2,
@@ -120,40 +142,23 @@ enum {
FLAGS_PRECPARAM = 1<<16, /* precision PARAMETER was specified */
FLAGS_CHAR = 1<<17, /* %c story */
FLAGS_FLOATE = 1<<18, /* %e or %E */
- FLAGS_FLOATG = 1<<19, /* %g or %G */
- FLAGS_SUBSTR = 1<<20 /* no input, only substring */
-};
-
-enum {
- DOLLAR_UNKNOWN,
- DOLLAR_NOPE,
- DOLLAR_USE
+ FLAGS_FLOATG = 1<<19 /* %g or %G */
};
-/*
- * Describes an input va_arg type and hold its value.
- */
-struct va_input {
- FormatType type; /* FormatType */
+struct va_stack {
+ FormatType type;
+ int flags;
+ long width; /* width OR width parameter number */
+ long precision; /* precision OR precision parameter number */
union {
char *str;
void *ptr;
- mp_intmax_t nums; /* signed */
- mp_uintmax_t numu; /* unsigned */
+ union {
+ mp_intmax_t as_signed;
+ mp_uintmax_t as_unsigned;
+ } num;
double dnum;
- } val;
-};
-
-/*
- * Describes an output segment.
- */
-struct outsegment {
- int width; /* width OR width parameter number */
- int precision; /* precision OR precision parameter number */
- unsigned int flags;
- unsigned int input; /* input argument array index */
- char *start; /* format string start to output */
- size_t outlen; /* number of bytes from the format string to output */
+ } data;
};
struct nsprintf {
@@ -164,124 +169,118 @@ struct nsprintf {
struct asprintf {
struct dynbuf *b;
- char merr;
+ bool fail; /* if an alloc has failed and thus the output is not the complete
+ data */
};
-/* the provided input number is 1-based but this returns the number 0-based.
+static long dprintf_DollarString(char *input, char **end)
+{
+ int number = 0;
+ while(ISDIGIT(*input)) {
+ if(number < MAX_PARAMETERS) {
+ number *= 10;
+ number += *input - '0';
+ }
+ input++;
+ }
+ if(number <= MAX_PARAMETERS && ('$' == *input)) {
+ *end = ++input;
+ return number;
+ }
+ return 0;
+}
- returns -1 if no valid number was provided.
-*/
-static int dollarstring(char *input, char **end)
+static bool dprintf_IsQualifierNoDollar(const char *fmt)
{
- if(ISDIGIT(*input)) {
- int number = 0;
- do {
- if(number < MAX_PARAMETERS) {
- number *= 10;
- number += *input - '0';
- }
- input++;
- } while(ISDIGIT(*input));
+#if defined(MP_HAVE_INT_EXTENSIONS)
+ if(!strncmp(fmt, "I32", 3) || !strncmp(fmt, "I64", 3)) {
+ return TRUE;
+ }
+#endif
- if(number && (number <= MAX_PARAMETERS) && ('$' == *input)) {
- *end = ++input;
- return number - 1;
- }
+ switch(*fmt) {
+ case '-': case '+': case ' ': case '#': case '.':
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ case 'h': case 'l': case 'L': case 'z': case 'q':
+ case '*': case 'O':
+#if defined(MP_HAVE_INT_EXTENSIONS)
+ case 'I':
+#endif
+ return TRUE;
+
+ default:
+ return FALSE;
}
- return -1;
}
-/*
- * Parse the format string.
+/******************************************************************
*
- * Create two arrays. One describes the inputs, one describes the outputs.
+ * Pass 1:
+ * Create an index with the type of each parameter entry and its
+ * value (may vary in size)
*
* Returns zero on success.
- */
+ *
+ ******************************************************************/
-#define PFMT_OK 0
-#define PFMT_DOLLAR 1 /* bad dollar for main param */
-#define PFMT_DOLLARWIDTH 2 /* bad dollar use for width */
-#define PFMT_DOLLARPREC 3 /* bad dollar use for precision */
-#define PFMT_MANYARGS 4 /* too many input arguments used */
-#define PFMT_PREC 5 /* precision overflow */
-#define PFMT_PRECMIX 6 /* bad mix of precision specifiers */
-#define PFMT_WIDTH 7 /* width overflow */
-#define PFMT_INPUTGAP 8 /* gap in arguments */
-#define PFMT_WIDTHARG 9 /* attempted to use same arg twice, for width */
-#define PFMT_PRECARG 10 /* attempted to use same arg twice, for prec */
-#define PFMT_MANYSEGS 11 /* maxed out output segments */
-
-static int parsefmt(const char *format,
- struct outsegment *out,
- struct va_input *in,
- int *opieces,
- int *ipieces, va_list arglist)
+static int dprintf_Pass1(const char *format, struct va_stack *vto,
+ char **endpos, va_list arglist)
{
char *fmt = (char *)format;
int param_num = 0;
- int param;
- int width;
- int precision;
- unsigned int flags;
- FormatType type;
- int max_param = -1;
- int i;
- int ocount = 0;
- unsigned char usedinput[MAX_PARAMETERS/8];
- size_t outlen = 0;
- struct outsegment *optr;
- int use_dollar = DOLLAR_UNKNOWN;
- char *start = fmt;
-
- /* clear, set a bit for each used input */
- memset(usedinput, 0, sizeof(usedinput));
+ long this_param;
+ long width;
+ long precision;
+ int flags;
+ long max_param = 0;
+ long i;
while(*fmt) {
- if(*fmt == '%') {
- struct va_input *iptr;
- bool loopit = TRUE;
- fmt++;
- outlen = (size_t)(fmt - start - 1);
+ if(*fmt++ == '%') {
if(*fmt == '%') {
- /* this means a %% that should be output only as %. Create an output
- segment. */
- if(outlen) {
- optr = &out[ocount++];
- if(ocount > MAX_SEGMENTS)
- return PFMT_MANYSEGS;
- optr->input = 0;
- optr->flags = FLAGS_SUBSTR;
- optr->start = start;
- optr->outlen = outlen;
- }
- start = fmt;
fmt++;
continue; /* while */
}
- flags = 0;
- width = precision = 0;
+ flags = FLAGS_NEW;
+
+ /* Handle the positional case (N$) */
- if(use_dollar != DOLLAR_NOPE) {
- param = dollarstring(fmt, &fmt);
- if(param < 0) {
- if(use_dollar == DOLLAR_USE)
- /* illegal combo */
- return PFMT_DOLLAR;
+ param_num++;
- /* we got no positional, just get the next arg */
- param = -1;
- use_dollar = DOLLAR_NOPE;
+ this_param = dprintf_DollarString(fmt, &fmt);
+ if(0 == this_param)
+ /* we got no positional, get the next counter */
+ this_param = param_num;
+
+ if(this_param > max_param)
+ max_param = this_param;
+
+ /*
+ * The parameter with number 'i' should be used. Next, we need
+ * to get SIZE and TYPE of the parameter. Add the information
+ * to our array.
+ */
+
+ width = 0;
+ precision = 0;
+
+ /* Handle the flags */
+
+ while(dprintf_IsQualifierNoDollar(fmt)) {
+#if defined(MP_HAVE_INT_EXTENSIONS)
+ if(!strncmp(fmt, "I32", 3)) {
+ flags |= FLAGS_LONG;
+ fmt += 3;
+ }
+ else if(!strncmp(fmt, "I64", 3)) {
+ flags |= FLAGS_LONGLONG;
+ fmt += 3;
}
else
- use_dollar = DOLLAR_USE;
- }
- else
- param = -1;
+#endif
- /* Handle the flags */
- while(loopit) {
switch(*fmt++) {
case ' ':
flags |= FLAGS_SPACE;
@@ -291,7 +290,7 @@ static int parsefmt(const char *format,
break;
case '-':
flags |= FLAGS_LEFT;
- flags &= ~(unsigned int)FLAGS_PAD_NIL;
+ flags &= ~FLAGS_PAD_NIL;
break;
case '#':
flags |= FLAGS_ALT;
@@ -299,66 +298,42 @@ static int parsefmt(const char *format,
case '.':
if('*' == *fmt) {
/* The precision is picked from a specified parameter */
+
flags |= FLAGS_PRECPARAM;
fmt++;
+ param_num++;
- if(use_dollar == DOLLAR_USE) {
- precision = dollarstring(fmt, &fmt);
- if(precision < 0)
- /* illegal combo */
- return PFMT_DOLLARPREC;
- }
+ i = dprintf_DollarString(fmt, &fmt);
+ if(i)
+ precision = i;
else
- /* get it from the next argument */
- precision = -1;
+ precision = param_num;
+
+ if(precision > max_param)
+ max_param = precision;
}
else {
- bool is_neg = FALSE;
flags |= FLAGS_PREC;
- precision = 0;
- if('-' == *fmt) {
- is_neg = TRUE;
- fmt++;
- }
- while(ISDIGIT(*fmt)) {
- if(precision > INT_MAX/10)
- return PFMT_PREC;
- precision *= 10;
- precision += *fmt - '0';
- fmt++;
- }
- if(is_neg)
- precision = -precision;
+ precision = strtol(fmt, &fmt, 10);
}
if((flags & (FLAGS_PREC | FLAGS_PRECPARAM)) ==
(FLAGS_PREC | FLAGS_PRECPARAM))
/* it is not permitted to use both kinds of precision for the same
argument */
- return PFMT_PRECMIX;
+ return 1;
break;
case 'h':
flags |= FLAGS_SHORT;
break;
-#if defined(_WIN32) || defined(_WIN32_WCE)
+#if defined(MP_HAVE_INT_EXTENSIONS)
case 'I':
- /* Non-ANSI integer extensions I32 I64 */
- if((fmt[0] == '3') && (fmt[1] == '2')) {
- flags |= FLAGS_LONG;
- fmt += 2;
- }
- else if((fmt[0] == '6') && (fmt[1] == '4')) {
- flags |= FLAGS_LONGLONG;
- fmt += 2;
- }
- else {
#if (SIZEOF_CURL_OFF_T > SIZEOF_LONG)
- flags |= FLAGS_LONGLONG;
+ flags |= FLAGS_LONGLONG;
#else
- flags |= FLAGS_LONG;
+ flags |= FLAGS_LONG;
#endif
- }
break;
-#endif /* _WIN32 || _WIN32_WCE */
+#endif
case 'l':
if(flags & FLAGS_LONG)
flags |= FLAGS_LONGLONG;
@@ -390,421 +365,401 @@ static int parsefmt(const char *format,
case '0':
if(!(flags & FLAGS_LEFT))
flags |= FLAGS_PAD_NIL;
- FALLTHROUGH();
+ /* FALLTHROUGH */
case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
flags |= FLAGS_WIDTH;
- width = 0;
- fmt--;
- do {
- if(width > INT_MAX/10)
- return PFMT_WIDTH;
- width *= 10;
- width += *fmt - '0';
- fmt++;
- } while(ISDIGIT(*fmt));
+ width = strtol(fmt-1, &fmt, 10);
break;
- case '*': /* read width from argument list */
+ case '*': /* Special case */
flags |= FLAGS_WIDTHPARAM;
- if(use_dollar == DOLLAR_USE) {
- width = dollarstring(fmt, &fmt);
- if(width < 0)
- /* illegal combo */
- return PFMT_DOLLARWIDTH;
- }
+ param_num++;
+
+ i = dprintf_DollarString(fmt, &fmt);
+ if(i)
+ width = i;
else
- /* pick from the next argument */
- width = -1;
+ width = param_num;
+ if(width > max_param)
+ max_param = width;
break;
- default:
- loopit = FALSE;
+ case '\0':
fmt--;
+ default:
break;
- } /* switch */
- } /* while */
+ }
+ } /* switch */
+
+ /* Handle the specifier */
+
+ i = this_param - 1;
+
+ if((i < 0) || (i >= MAX_PARAMETERS))
+ /* out of allowed range */
+ return 1;
switch(*fmt) {
case 'S':
flags |= FLAGS_ALT;
- FALLTHROUGH();
+ /* FALLTHROUGH */
case 's':
- type = FORMAT_STRING;
+ vto[i].type = FORMAT_STRING;
break;
case 'n':
- type = FORMAT_INTPTR;
+ vto[i].type = FORMAT_INTPTR;
break;
case 'p':
- type = FORMAT_PTR;
+ vto[i].type = FORMAT_PTR;
break;
- case 'd':
- case 'i':
- if(flags & FLAGS_LONGLONG)
- type = FORMAT_LONGLONG;
- else if(flags & FLAGS_LONG)
- type = FORMAT_LONG;
- else
- type = FORMAT_INT;
+ case 'd': case 'i':
+ vto[i].type = FORMAT_INT;
break;
case 'u':
- if(flags & FLAGS_LONGLONG)
- type = FORMAT_LONGLONGU;
- else if(flags & FLAGS_LONG)
- type = FORMAT_LONGU;
- else
- type = FORMAT_INTU;
+ vto[i].type = FORMAT_INT;
flags |= FLAGS_UNSIGNED;
break;
case 'o':
- type = FORMAT_INT;
+ vto[i].type = FORMAT_INT;
flags |= FLAGS_OCTAL;
break;
case 'x':
- type = FORMAT_INTU;
+ vto[i].type = FORMAT_INT;
flags |= FLAGS_HEX|FLAGS_UNSIGNED;
break;
case 'X':
- type = FORMAT_INTU;
+ vto[i].type = FORMAT_INT;
flags |= FLAGS_HEX|FLAGS_UPPER|FLAGS_UNSIGNED;
break;
case 'c':
- type = FORMAT_INT;
+ vto[i].type = FORMAT_INT;
flags |= FLAGS_CHAR;
break;
case 'f':
- type = FORMAT_DOUBLE;
+ vto[i].type = FORMAT_DOUBLE;
break;
case 'e':
- type = FORMAT_DOUBLE;
+ vto[i].type = FORMAT_DOUBLE;
flags |= FLAGS_FLOATE;
break;
case 'E':
- type = FORMAT_DOUBLE;
+ vto[i].type = FORMAT_DOUBLE;
flags |= FLAGS_FLOATE|FLAGS_UPPER;
break;
case 'g':
- type = FORMAT_DOUBLE;
+ vto[i].type = FORMAT_DOUBLE;
flags |= FLAGS_FLOATG;
break;
case 'G':
- type = FORMAT_DOUBLE;
+ vto[i].type = FORMAT_DOUBLE;
flags |= FLAGS_FLOATG|FLAGS_UPPER;
break;
default:
- /* invalid instruction, disregard and continue */
- continue;
+ vto[i].type = FORMAT_UNKNOWN;
+ break;
} /* switch */
+ vto[i].flags = flags;
+ vto[i].width = width;
+ vto[i].precision = precision;
+
if(flags & FLAGS_WIDTHPARAM) {
- if(width < 0)
- width = param_num++;
- else {
- /* if this identifies a parameter already used, this
- is illegal */
- if(usedinput[width/8] & (1 << (width&7)))
- return PFMT_WIDTHARG;
- }
- if(width >= MAX_PARAMETERS)
- return PFMT_MANYARGS;
- if(width >= max_param)
- max_param = width;
-
- in[width].type = FORMAT_WIDTH;
- /* mark as used */
- usedinput[width/8] |= (unsigned char)(1 << (width&7));
+ /* we have the width specified from a parameter, so we make that
+ parameter's info setup properly */
+ long k = width - 1;
+ if((k < 0) || (k >= MAX_PARAMETERS))
+ /* out of allowed range */
+ return 1;
+ vto[i].width = k;
+ vto[k].type = FORMAT_WIDTH;
+ vto[k].flags = FLAGS_NEW;
+ /* can't use width or precision of width! */
+ vto[k].width = 0;
+ vto[k].precision = 0;
}
-
if(flags & FLAGS_PRECPARAM) {
- if(precision < 0)
- precision = param_num++;
- else {
- /* if this identifies a parameter already used, this
- is illegal */
- if(usedinput[precision/8] & (1 << (precision&7)))
- return PFMT_PRECARG;
- }
- if(precision >= MAX_PARAMETERS)
- return PFMT_MANYARGS;
- if(precision >= max_param)
- max_param = precision;
-
- in[precision].type = FORMAT_PRECISION;
- usedinput[precision/8] |= (unsigned char)(1 << (precision&7));
+ /* we have the precision specified from a parameter, so we make that
+ parameter's info setup properly */
+ long k = precision - 1;
+ if((k < 0) || (k >= MAX_PARAMETERS))
+ /* out of allowed range */
+ return 1;
+ vto[i].precision = k;
+ vto[k].type = FORMAT_WIDTH;
+ vto[k].flags = FLAGS_NEW;
+ /* can't use width or precision of width! */
+ vto[k].width = 0;
+ vto[k].precision = 0;
}
-
- /* Handle the specifier */
- if(param < 0)
- param = param_num++;
- if(param >= MAX_PARAMETERS)
- return PFMT_MANYARGS;
- if(param >= max_param)
- max_param = param;
-
- iptr = &in[param];
- iptr->type = type;
-
- /* mark this input as used */
- usedinput[param/8] |= (unsigned char)(1 << (param&7));
-
- fmt++;
- optr = &out[ocount++];
- if(ocount > MAX_SEGMENTS)
- return PFMT_MANYSEGS;
- optr->input = (unsigned int)param;
- optr->flags = flags;
- optr->width = width;
- optr->precision = precision;
- optr->start = start;
- optr->outlen = outlen;
- start = fmt;
+ *endpos++ = fmt + ((*fmt == '\0') ? 0 : 1); /* end of this sequence */
}
- else
- fmt++;
- }
-
- /* is there a trailing piece */
- outlen = (size_t)(fmt - start);
- if(outlen) {
- optr = &out[ocount++];
- if(ocount > MAX_SEGMENTS)
- return PFMT_MANYSEGS;
- optr->input = 0;
- optr->flags = FLAGS_SUBSTR;
- optr->start = start;
- optr->outlen = outlen;
}
/* Read the arg list parameters into our data list */
- for(i = 0; i < max_param + 1; i++) {
- struct va_input *iptr = &in[i];
- if(!(usedinput[i/8] & (1 << (i&7))))
- /* bad input */
- return PFMT_INPUTGAP;
-
- /* based on the type, read the correct argument */
- switch(iptr->type) {
+ for(i = 0; i<max_param; i++) {
+ /* Width/precision arguments must be read before the main argument
+ they are attached to */
+ if(vto[i].flags & FLAGS_WIDTHPARAM) {
+ vto[vto[i].width].data.num.as_signed =
+ (mp_intmax_t)va_arg(arglist, int);
+ }
+ if(vto[i].flags & FLAGS_PRECPARAM) {
+ vto[vto[i].precision].data.num.as_signed =
+ (mp_intmax_t)va_arg(arglist, int);
+ }
+
+ switch(vto[i].type) {
case FORMAT_STRING:
- iptr->val.str = va_arg(arglist, char *);
+ vto[i].data.str = va_arg(arglist, char *);
break;
case FORMAT_INTPTR:
+ case FORMAT_UNKNOWN:
case FORMAT_PTR:
- iptr->val.ptr = va_arg(arglist, void *);
- break;
-
- case FORMAT_LONGLONGU:
- iptr->val.numu = (mp_uintmax_t)va_arg(arglist, mp_uintmax_t);
+ vto[i].data.ptr = va_arg(arglist, void *);
break;
- case FORMAT_LONGLONG:
- iptr->val.nums = (mp_intmax_t)va_arg(arglist, mp_intmax_t);
- break;
-
- case FORMAT_LONGU:
- iptr->val.numu = (mp_uintmax_t)va_arg(arglist, unsigned long);
- break;
-
- case FORMAT_LONG:
- iptr->val.nums = (mp_intmax_t)va_arg(arglist, long);
+ case FORMAT_INT:
+#ifdef HAVE_LONG_LONG_TYPE
+ if((vto[i].flags & FLAGS_LONGLONG) && (vto[i].flags & FLAGS_UNSIGNED))
+ vto[i].data.num.as_unsigned =
+ (mp_uintmax_t)va_arg(arglist, mp_uintmax_t);
+ else if(vto[i].flags & FLAGS_LONGLONG)
+ vto[i].data.num.as_signed =
+ (mp_intmax_t)va_arg(arglist, mp_intmax_t);
+ else
+#endif
+ {
+ if((vto[i].flags & FLAGS_LONG) && (vto[i].flags & FLAGS_UNSIGNED))
+ vto[i].data.num.as_unsigned =
+ (mp_uintmax_t)va_arg(arglist, unsigned long);
+ else if(vto[i].flags & FLAGS_LONG)
+ vto[i].data.num.as_signed =
+ (mp_intmax_t)va_arg(arglist, long);
+ else if(vto[i].flags & FLAGS_UNSIGNED)
+ vto[i].data.num.as_unsigned =
+ (mp_uintmax_t)va_arg(arglist, unsigned int);
+ else
+ vto[i].data.num.as_signed =
+ (mp_intmax_t)va_arg(arglist, int);
+ }
break;
- case FORMAT_INTU:
- iptr->val.numu = (mp_uintmax_t)va_arg(arglist, unsigned int);
+ case FORMAT_DOUBLE:
+ vto[i].data.dnum = va_arg(arglist, double);
break;
- case FORMAT_INT:
case FORMAT_WIDTH:
- case FORMAT_PRECISION:
- iptr->val.nums = (mp_intmax_t)va_arg(arglist, int);
- break;
-
- case FORMAT_DOUBLE:
- iptr->val.dnum = va_arg(arglist, double);
+ /* Argument has been read. Silently convert it into an integer
+ * for later use
+ */
+ vto[i].type = FORMAT_INT;
break;
default:
- DEBUGASSERT(NULL); /* unexpected */
break;
}
}
- *ipieces = max_param + 1;
- *opieces = ocount;
- return PFMT_OK;
-}
+ return 0;
-/*
- * formatf() - the general printf function.
- *
- * It calls parsefmt() to parse the format string. It populates two arrays;
- * one that describes the input arguments and one that describes a number of
- * output segments.
- *
- * On success, the input array describes the type of all arguments and their
- * values.
- *
- * The function then iterates over the output segments and outputs them one
- * by one until done. Using the appropriate input arguments (if any).
- *
- * All output is sent to the 'stream()' callback, one byte at a time.
- */
+}
-static int formatf(
- void *userp, /* untouched by format(), just sent to the stream() function in
- the second argument */
+static int dprintf_formatf(
+ void *data, /* untouched by format(), just sent to the stream() function in
+ the second argument */
/* function pointer called for each output character */
- int (*stream)(unsigned char, void *),
+ int (*stream)(int, FILE *),
const char *format, /* %-formatted string */
va_list ap_save) /* list of parameters */
{
- static const char nilstr[] = "(nil)";
- const char *digits = lower_digits; /* Base-36 digits for numbers. */
- int done = 0; /* number of characters written */
- int i;
- int ocount = 0; /* number of output segments */
- int icount = 0; /* number of input arguments */
-
- struct outsegment output[MAX_SEGMENTS];
- struct va_input input[MAX_PARAMETERS];
+ /* Base-36 digits for numbers. */
+ const char *digits = lower_digits;
+
+ /* Pointer into the format string. */
+ char *f;
+
+ /* Number of characters written. */
+ int done = 0;
+
+ long param; /* current parameter to read */
+ long param_num = 0; /* parameter counter */
+
+ struct va_stack vto[MAX_PARAMETERS];
+ char *endpos[MAX_PARAMETERS];
+ char **end;
char work[BUFFSIZE];
+ struct va_stack *p;
/* 'workend' points to the final buffer byte position, but with an extra
byte as margin to avoid the (false?) warning Coverity gives us
otherwise */
char *workend = &work[sizeof(work) - 2];
- /* Parse the format string */
- if(parsefmt(format, output, input, &ocount, &icount, ap_save))
+ /* Do the actual %-code parsing */
+ if(dprintf_Pass1(format, vto, endpos, ap_save))
return 0;
- for(i = 0; i < ocount; i++) {
- struct outsegment *optr = &output[i];
- struct va_input *iptr;
- bool is_alt; /* Format spec modifiers. */
- int width; /* Width of a field. */
- int prec; /* Precision of a field. */
- bool is_neg; /* Decimal integer is negative. */
- unsigned long base; /* Base of a number to be written. */
- mp_uintmax_t num; /* Integral values to be written. */
- mp_intmax_t signed_num; /* Used to convert negative in positive. */
+ end = &endpos[0]; /* the initial end-position from the list dprintf_Pass1()
+ created for us */
+
+ f = (char *)format;
+ while(*f != '\0') {
+ /* Format spec modifiers. */
+ int is_alt;
+
+ /* Width of a field. */
+ long width;
+
+ /* Precision of a field. */
+ long prec;
+
+ /* Decimal integer is negative. */
+ int is_neg;
+
+ /* Base of a number to be written. */
+ unsigned long base;
+
+ /* Integral values to be written. */
+ mp_uintmax_t num;
+
+ /* Used to convert negative in positive. */
+ mp_intmax_t signed_num;
+
char *w;
- size_t outlen = optr->outlen;
- unsigned int flags = optr->flags;
-
- if(outlen) {
- char *str = optr->start;
- for(; outlen && *str; outlen--)
- OUTCHAR(*str++);
- if(optr->flags & FLAGS_SUBSTR)
- /* this is just a substring */
- continue;
+
+ if(*f != '%') {
+ /* This isn't a format spec, so write everything out until the next one
+ OR end of string is reached. */
+ do {
+ OUTCHAR(*f);
+ } while(*++f && ('%' != *f));
+ continue;
}
+ ++f;
+
+ /* Check for "%%". Note that although the ANSI standard lists
+ '%' as a conversion specifier, it says "The complete format
+ specification shall be `%%'," so we can avoid all the width
+ and precision processing. */
+ if(*f == '%') {
+ ++f;
+ OUTCHAR('%');
+ continue;
+ }
+
+ /* If this is a positional parameter, the position must follow immediately
+ after the %, thus create a %<num>$ sequence */
+ param = dprintf_DollarString(f, &f);
+
+ if(!param)
+ param = param_num;
+ else
+ --param;
+
+ param_num++; /* increase this always to allow "%2$s %1$s %s" and then the
+ third %s will pick the 3rd argument */
+
+ p = &vto[param];
+
/* pick up the specified width */
- if(flags & FLAGS_WIDTHPARAM) {
- width = (int)input[optr->width].val.nums;
+ if(p->flags & FLAGS_WIDTHPARAM) {
+ width = (long)vto[p->width].data.num.as_signed;
+ param_num++; /* since the width is extracted from a parameter, we
+ must skip that to get to the next one properly */
if(width < 0) {
/* "A negative field width is taken as a '-' flag followed by a
positive field width." */
- if(width == INT_MIN)
- width = INT_MAX;
- else
- width = -width;
- flags |= FLAGS_LEFT;
- flags &= ~(unsigned int)FLAGS_PAD_NIL;
+ width = -width;
+ p->flags |= FLAGS_LEFT;
+ p->flags &= ~FLAGS_PAD_NIL;
}
}
else
- width = optr->width;
+ width = p->width;
/* pick up the specified precision */
- if(flags & FLAGS_PRECPARAM) {
- prec = (int)input[optr->precision].val.nums;
+ if(p->flags & FLAGS_PRECPARAM) {
+ prec = (long)vto[p->precision].data.num.as_signed;
+ param_num++; /* since the precision is extracted from a parameter, we
+ must skip that to get to the next one properly */
if(prec < 0)
/* "A negative precision is taken as if the precision were
omitted." */
prec = -1;
}
- else if(flags & FLAGS_PREC)
- prec = optr->precision;
+ else if(p->flags & FLAGS_PREC)
+ prec = p->precision;
else
prec = -1;
- is_alt = (flags & FLAGS_ALT) ? 1 : 0;
- iptr = &input[optr->input];
+ is_alt = (p->flags & FLAGS_ALT) ? 1 : 0;
- switch(iptr->type) {
- case FORMAT_INTU:
- case FORMAT_LONGU:
- case FORMAT_LONGLONGU:
- flags |= FLAGS_UNSIGNED;
- FALLTHROUGH();
+ switch(p->type) {
case FORMAT_INT:
- case FORMAT_LONG:
- case FORMAT_LONGLONG:
- num = iptr->val.numu;
- if(flags & FLAGS_CHAR) {
+ num = p->data.num.as_unsigned;
+ if(p->flags & FLAGS_CHAR) {
/* Character. */
- if(!(flags & FLAGS_LEFT))
+ if(!(p->flags & FLAGS_LEFT))
while(--width > 0)
OUTCHAR(' ');
OUTCHAR((char) num);
- if(flags & FLAGS_LEFT)
+ if(p->flags & FLAGS_LEFT)
while(--width > 0)
OUTCHAR(' ');
break;
}
- if(flags & FLAGS_OCTAL) {
- /* Octal unsigned integer */
+ if(p->flags & FLAGS_OCTAL) {
+ /* Octal unsigned integer. */
base = 8;
- is_neg = FALSE;
+ goto unsigned_number;
}
- else if(flags & FLAGS_HEX) {
- /* Hexadecimal unsigned integer */
- digits = (flags & FLAGS_UPPER)? upper_digits : lower_digits;
+ else if(p->flags & FLAGS_HEX) {
+ /* Hexadecimal unsigned integer. */
+
+ digits = (p->flags & FLAGS_UPPER)? upper_digits : lower_digits;
base = 16;
- is_neg = FALSE;
+ goto unsigned_number;
}
- else if(flags & FLAGS_UNSIGNED) {
- /* Decimal unsigned integer */
+ else if(p->flags & FLAGS_UNSIGNED) {
+ /* Decimal unsigned integer. */
base = 10;
- is_neg = FALSE;
+ goto unsigned_number;
}
- else {
- /* Decimal integer. */
- base = 10;
- is_neg = (iptr->val.nums < (mp_intmax_t)0);
- if(is_neg) {
- /* signed_num might fail to hold absolute negative minimum by 1 */
- signed_num = iptr->val.nums + (mp_intmax_t)1;
- signed_num = -signed_num;
- num = (mp_uintmax_t)signed_num;
- num += (mp_uintmax_t)1;
- }
+ /* Decimal integer. */
+ base = 10;
+
+ is_neg = (p->data.num.as_signed < (mp_intmax_t)0) ? 1 : 0;
+ if(is_neg) {
+ /* signed_num might fail to hold absolute negative minimum by 1 */
+ signed_num = p->data.num.as_signed + (mp_intmax_t)1;
+ signed_num = -signed_num;
+ num = (mp_uintmax_t)signed_num;
+ num += (mp_uintmax_t)1;
}
+
+ goto number;
+
+unsigned_number:
+ /* Unsigned number of base BASE. */
+ is_neg = 0;
+
number:
+ /* Number of base BASE. */
+
/* Supply a default precision if none was given. */
if(prec == -1)
prec = 1;
/* Put the number in WORK. */
w = workend;
- switch(base) {
- case 10:
- while(num > 0) {
- *w-- = (char)('0' + (num % 10));
- num /= 10;
- }
- break;
- default:
- while(num > 0) {
- *w-- = digits[num % base];
- num /= base;
- }
- break;
+ while(num > 0) {
+ *w-- = digits[num % base];
+ num /= base;
}
- width -= (int)(workend - w);
- prec -= (int)(workend - w);
+ width -= (long)(workend - w);
+ prec -= (long)(workend - w);
if(is_alt && base == 8 && prec <= 0) {
*w-- = '0';
@@ -820,29 +775,29 @@ number:
if(is_alt && base == 16)
width -= 2;
- if(is_neg || (flags & FLAGS_SHOWSIGN) || (flags & FLAGS_SPACE))
+ if(is_neg || (p->flags & FLAGS_SHOWSIGN) || (p->flags & FLAGS_SPACE))
--width;
- if(!(flags & FLAGS_LEFT) && !(flags & FLAGS_PAD_NIL))
+ if(!(p->flags & FLAGS_LEFT) && !(p->flags & FLAGS_PAD_NIL))
while(width-- > 0)
OUTCHAR(' ');
if(is_neg)
OUTCHAR('-');
- else if(flags & FLAGS_SHOWSIGN)
+ else if(p->flags & FLAGS_SHOWSIGN)
OUTCHAR('+');
- else if(flags & FLAGS_SPACE)
+ else if(p->flags & FLAGS_SPACE)
OUTCHAR(' ');
if(is_alt && base == 16) {
OUTCHAR('0');
- if(flags & FLAGS_UPPER)
+ if(p->flags & FLAGS_UPPER)
OUTCHAR('X');
else
OUTCHAR('x');
}
- if(!(flags & FLAGS_LEFT) && (flags & FLAGS_PAD_NIL))
+ if(!(p->flags & FLAGS_LEFT) && (p->flags & FLAGS_PAD_NIL))
while(width-- > 0)
OUTCHAR('0');
@@ -851,200 +806,219 @@ number:
OUTCHAR(*w);
}
- if(flags & FLAGS_LEFT)
+ if(p->flags & FLAGS_LEFT)
while(width-- > 0)
OUTCHAR(' ');
break;
- case FORMAT_STRING: {
- const char *str;
- size_t len;
-
- str = (char *)iptr->val.str;
- if(!str) {
- /* Write null string if there is space. */
- if(prec == -1 || prec >= (int) sizeof(nilstr) - 1) {
- str = nilstr;
- len = sizeof(nilstr) - 1;
- /* Disable quotes around (nil) */
- flags &= ~(unsigned int)FLAGS_ALT;
+ case FORMAT_STRING:
+ /* String. */
+ {
+ static const char null[] = "(nil)";
+ const char *str;
+ size_t len;
+
+ str = (char *) p->data.str;
+ if(!str) {
+ /* Write null[] if there's space. */
+ if(prec == -1 || prec >= (long) sizeof(null) - 1) {
+ str = null;
+ len = sizeof(null) - 1;
+ /* Disable quotes around (nil) */
+ p->flags &= (~FLAGS_ALT);
+ }
+ else {
+ str = "";
+ len = 0;
+ }
}
- else {
- str = "";
+ else if(prec != -1)
+ len = (size_t)prec;
+ else if(*str == '\0')
len = 0;
- }
- }
- else if(prec != -1)
- len = (size_t)prec;
- else if(*str == '\0')
- len = 0;
- else
- len = strlen(str);
+ else
+ len = strlen(str);
- width -= (len > INT_MAX) ? INT_MAX : (int)len;
+ width -= (len > LONG_MAX) ? LONG_MAX : (long)len;
- if(flags & FLAGS_ALT)
- OUTCHAR('"');
+ if(p->flags & FLAGS_ALT)
+ OUTCHAR('"');
- if(!(flags & FLAGS_LEFT))
- while(width-- > 0)
- OUTCHAR(' ');
+ if(!(p->flags&FLAGS_LEFT))
+ while(width-- > 0)
+ OUTCHAR(' ');
- for(; len && *str; len--)
- OUTCHAR(*str++);
- if(flags & FLAGS_LEFT)
- while(width-- > 0)
- OUTCHAR(' ');
+ for(; len && *str; len--)
+ OUTCHAR(*str++);
+ if(p->flags&FLAGS_LEFT)
+ while(width-- > 0)
+ OUTCHAR(' ');
- if(flags & FLAGS_ALT)
- OUTCHAR('"');
+ if(p->flags & FLAGS_ALT)
+ OUTCHAR('"');
+ }
break;
- }
case FORMAT_PTR:
/* Generic pointer. */
- if(iptr->val.ptr) {
- /* If the pointer is not NULL, write it as a %#x spec. */
- base = 16;
- digits = (flags & FLAGS_UPPER)? upper_digits : lower_digits;
- is_alt = TRUE;
- num = (size_t) iptr->val.ptr;
- is_neg = FALSE;
- goto number;
- }
- else {
- /* Write "(nil)" for a nil pointer. */
- const char *point;
-
- width -= (int)(sizeof(nilstr) - 1);
- if(flags & FLAGS_LEFT)
- while(width-- > 0)
- OUTCHAR(' ');
- for(point = nilstr; *point != '\0'; ++point)
- OUTCHAR(*point);
- if(!(flags & FLAGS_LEFT))
- while(width-- > 0)
- OUTCHAR(' ');
+ {
+ void *ptr;
+ ptr = (void *) p->data.ptr;
+ if(ptr) {
+ /* If the pointer is not NULL, write it as a %#x spec. */
+ base = 16;
+ digits = (p->flags & FLAGS_UPPER)? upper_digits : lower_digits;
+ is_alt = 1;
+ num = (size_t) ptr;
+ is_neg = 0;
+ goto number;
+ }
+ else {
+ /* Write "(nil)" for a nil pointer. */
+ static const char strnil[] = "(nil)";
+ const char *point;
+
+ width -= (long)(sizeof(strnil) - 1);
+ if(p->flags & FLAGS_LEFT)
+ while(width-- > 0)
+ OUTCHAR(' ');
+ for(point = strnil; *point != '\0'; ++point)
+ OUTCHAR(*point);
+ if(!(p->flags & FLAGS_LEFT))
+ while(width-- > 0)
+ OUTCHAR(' ');
+ }
}
break;
- case FORMAT_DOUBLE: {
- char formatbuf[32]="%";
- char *fptr = &formatbuf[1];
- size_t left = sizeof(formatbuf)-strlen(formatbuf);
- int len;
-
- if(flags & FLAGS_WIDTH)
- width = optr->width;
-
- if(flags & FLAGS_PREC)
- prec = optr->precision;
-
- if(flags & FLAGS_LEFT)
- *fptr++ = '-';
- if(flags & FLAGS_SHOWSIGN)
- *fptr++ = '+';
- if(flags & FLAGS_SPACE)
- *fptr++ = ' ';
- if(flags & FLAGS_ALT)
- *fptr++ = '#';
-
- *fptr = 0;
-
- if(width >= 0) {
- size_t dlen;
- if(width >= (int)sizeof(work))
- width = sizeof(work)-1;
- /* RECURSIVE USAGE */
- dlen = (size_t)curl_msnprintf(fptr, left, "%d", width);
- fptr += dlen;
- left -= dlen;
- }
- if(prec >= 0) {
- /* for each digit in the integer part, we can have one less
- precision */
- size_t maxprec = sizeof(work) - 2;
- double val = iptr->val.dnum;
- if(width > 0 && prec <= width)
- maxprec -= (size_t)width;
- while(val >= 10.0) {
- val /= 10;
- maxprec--;
+ case FORMAT_DOUBLE:
+ {
+ char formatbuf[32]="%";
+ char *fptr = &formatbuf[1];
+ size_t left = sizeof(formatbuf)-strlen(formatbuf);
+ int len;
+
+ width = -1;
+ if(p->flags & FLAGS_WIDTH)
+ width = p->width;
+ else if(p->flags & FLAGS_WIDTHPARAM)
+ width = (long)vto[p->width].data.num.as_signed;
+
+ prec = -1;
+ if(p->flags & FLAGS_PREC)
+ prec = p->precision;
+ else if(p->flags & FLAGS_PRECPARAM)
+ prec = (long)vto[p->precision].data.num.as_signed;
+
+ if(p->flags & FLAGS_LEFT)
+ *fptr++ = '-';
+ if(p->flags & FLAGS_SHOWSIGN)
+ *fptr++ = '+';
+ if(p->flags & FLAGS_SPACE)
+ *fptr++ = ' ';
+ if(p->flags & FLAGS_ALT)
+ *fptr++ = '#';
+
+ *fptr = 0;
+
+ if(width >= 0) {
+ if(width >= (long)sizeof(work))
+ width = sizeof(work)-1;
+ /* RECURSIVE USAGE */
+ len = curl_msnprintf(fptr, left, "%ld", width);
+ fptr += len;
+ left -= len;
}
+ if(prec >= 0) {
+ /* for each digit in the integer part, we can have one less
+ precision */
+ size_t maxprec = sizeof(work) - 2;
+ double val = p->data.dnum;
+ if(width > 0 && prec <= width)
+ maxprec -= width;
+ while(val >= 10.0) {
+ val /= 10;
+ maxprec--;
+ }
- if(prec > (int)maxprec)
- prec = (int)maxprec-1;
- if(prec < 0)
- prec = 0;
- /* RECURSIVE USAGE */
- len = curl_msnprintf(fptr, left, ".%d", prec);
- fptr += len;
- }
- if(flags & FLAGS_LONG)
- *fptr++ = 'l';
+ if(prec > (long)maxprec)
+ prec = (long)maxprec-1;
+ if(prec < 0)
+ prec = 0;
+ /* RECURSIVE USAGE */
+ len = curl_msnprintf(fptr, left, ".%ld", prec);
+ fptr += len;
+ }
+ if(p->flags & FLAGS_LONG)
+ *fptr++ = 'l';
- if(flags & FLAGS_FLOATE)
- *fptr++ = (char)((flags & FLAGS_UPPER) ? 'E':'e');
- else if(flags & FLAGS_FLOATG)
- *fptr++ = (char)((flags & FLAGS_UPPER) ? 'G' : 'g');
- else
- *fptr++ = 'f';
+ if(p->flags & FLAGS_FLOATE)
+ *fptr++ = (char)((p->flags & FLAGS_UPPER) ? 'E':'e');
+ else if(p->flags & FLAGS_FLOATG)
+ *fptr++ = (char)((p->flags & FLAGS_UPPER) ? 'G' : 'g');
+ else
+ *fptr++ = 'f';
- *fptr = 0; /* and a final null-termination */
+ *fptr = 0; /* and a final null-termination */
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wformat-nonliteral"
#endif
- /* NOTE NOTE NOTE!! Not all sprintf implementations return number of
- output characters */
+ /* NOTE NOTE NOTE!! Not all sprintf implementations return number of
+ output characters */
#ifdef HAVE_SNPRINTF
- (snprintf)(work, sizeof(work), formatbuf, iptr->val.dnum);
+ (snprintf)(work, sizeof(work), formatbuf, p->data.dnum);
#else
- (sprintf)(work, formatbuf, iptr->val.dnum);
+ (sprintf)(work, formatbuf, p->data.dnum);
#endif
#ifdef __clang__
#pragma clang diagnostic pop
#endif
- DEBUGASSERT(strlen(work) <= sizeof(work));
- for(fptr = work; *fptr; fptr++)
- OUTCHAR(*fptr);
+ DEBUGASSERT(strlen(work) <= sizeof(work));
+ for(fptr = work; *fptr; fptr++)
+ OUTCHAR(*fptr);
+ }
break;
- }
case FORMAT_INTPTR:
/* Answer the count of characters written. */
#ifdef HAVE_LONG_LONG_TYPE
- if(flags & FLAGS_LONGLONG)
- *(LONG_LONG_TYPE *) iptr->val.ptr = (LONG_LONG_TYPE)done;
+ if(p->flags & FLAGS_LONGLONG)
+ *(LONG_LONG_TYPE *) p->data.ptr = (LONG_LONG_TYPE)done;
else
#endif
- if(flags & FLAGS_LONG)
- *(long *) iptr->val.ptr = (long)done;
- else if(!(flags & FLAGS_SHORT))
- *(int *) iptr->val.ptr = (int)done;
+ if(p->flags & FLAGS_LONG)
+ *(long *) p->data.ptr = (long)done;
+ else if(!(p->flags & FLAGS_SHORT))
+ *(int *) p->data.ptr = (int)done;
else
- *(short *) iptr->val.ptr = (short)done;
+ *(short *) p->data.ptr = (short)done;
break;
default:
break;
}
+ f = *end++; /* goto end of %-code */
+
}
return done;
}
/* fputc() look-alike */
-static int addbyter(unsigned char outc, void *f)
+static int addbyter(int output, FILE *data)
{
- struct nsprintf *infop = f;
+ struct nsprintf *infop = (struct nsprintf *)data;
+ unsigned char outc = (unsigned char)output;
+
if(infop->length < infop->max) {
- /* only do this if we have not reached max length yet */
- *infop->buffer++ = (char)outc; /* store */
+ /* only do this if we haven't reached max length yet */
+ infop->buffer[0] = outc; /* store */
+ infop->buffer++; /* increase pointer */
infop->length++; /* we are now one byte larger */
- return 0; /* fputc() returns like this on success */
+ return outc; /* fputc() returns like this on success */
}
- return 1;
+ return -1;
}
int curl_mvsnprintf(char *buffer, size_t maxlength, const char *format,
@@ -1057,14 +1031,14 @@ int curl_mvsnprintf(char *buffer, size_t maxlength, const char *format,
info.length = 0;
info.max = maxlength;
- retcode = formatf(&info, addbyter, format, ap_save);
+ retcode = dprintf_formatf(&info, addbyter, format, ap_save);
if(info.max) {
/* we terminate this with a zero byte */
if(info.max == info.length) {
- /* we are at maximum, scrap the last letter */
+ /* we're at maximum, scrap the last letter */
info.buffer[-1] = 0;
DEBUGASSERT(retcode);
- retcode--; /* do not count the nul byte */
+ retcode--; /* don't count the nul byte */
}
else
info.buffer[0] = 0;
@@ -1083,28 +1057,29 @@ int curl_msnprintf(char *buffer, size_t maxlength, const char *format, ...)
}
/* fputc() look-alike */
-static int alloc_addbyter(unsigned char outc, void *f)
+static int alloc_addbyter(int output, FILE *data)
{
- struct asprintf *infop = f;
- CURLcode result = Curl_dyn_addn(infop->b, &outc, 1);
- if(result) {
- infop->merr = result == CURLE_TOO_LARGE ? MERR_TOO_LARGE : MERR_MEM;
- return 1 ; /* fail */
+ struct asprintf *infop = (struct asprintf *)data;
+ unsigned char outc = (unsigned char)output;
+
+ if(Curl_dyn_addn(infop->b, &outc, 1)) {
+ infop->fail = 1;
+ return -1; /* fail */
}
- return 0;
+ return outc; /* fputc() returns like this on success */
}
-/* appends the formatted string, returns MERR error code */
+/* appends the formatted string, returns 0 on success, 1 on error */
int Curl_dyn_vprintf(struct dynbuf *dyn, const char *format, va_list ap_save)
{
struct asprintf info;
info.b = dyn;
- info.merr = MERR_OK;
+ info.fail = 0;
- (void)formatf(&info, alloc_addbyter, format, ap_save);
- if(info.merr) {
+ (void)dprintf_formatf(&info, alloc_addbyter, format, ap_save);
+ if(info.fail) {
Curl_dyn_free(info.b);
- return info.merr;
+ return 1;
}
return 0;
}
@@ -1115,10 +1090,10 @@ char *curl_mvaprintf(const char *format, va_list ap_save)
struct dynbuf dyn;
info.b = &dyn;
Curl_dyn_init(info.b, DYN_APRINTF);
- info.merr = MERR_OK;
+ info.fail = 0;
- (void)formatf(&info, alloc_addbyter, format, ap_save);
- if(info.merr) {
+ (void)dprintf_formatf(&info, alloc_addbyter, format, ap_save);
+ if(info.fail) {
Curl_dyn_free(info.b);
return NULL;
}
@@ -1137,12 +1112,13 @@ char *curl_maprintf(const char *format, ...)
return s;
}
-static int storebuffer(unsigned char outc, void *f)
+static int storebuffer(int output, FILE *data)
{
- char **buffer = f;
- **buffer = (char)outc;
+ char **buffer = (char **)data;
+ unsigned char outc = (unsigned char)output;
+ **buffer = outc;
(*buffer)++;
- return 0;
+ return outc; /* act like fputc() ! */
}
int curl_msprintf(char *buffer, const char *format, ...)
@@ -1150,27 +1126,19 @@ int curl_msprintf(char *buffer, const char *format, ...)
va_list ap_save; /* argument pointer */
int retcode;
va_start(ap_save, format);
- retcode = formatf(&buffer, storebuffer, format, ap_save);
+ retcode = dprintf_formatf(&buffer, storebuffer, format, ap_save);
va_end(ap_save);
*buffer = 0; /* we terminate this with a zero byte */
return retcode;
}
-static int fputc_wrapper(unsigned char outc, void *f)
-{
- int out = outc;
- FILE *s = f;
- int rc = fputc(out, s);
- return rc == EOF;
-}
-
int curl_mprintf(const char *format, ...)
{
int retcode;
va_list ap_save; /* argument pointer */
va_start(ap_save, format);
- retcode = formatf(stdout, fputc_wrapper, format, ap_save);
+ retcode = dprintf_formatf(stdout, fputc, format, ap_save);
va_end(ap_save);
return retcode;
}
@@ -1180,24 +1148,25 @@ int curl_mfprintf(FILE *whereto, const char *format, ...)
int retcode;
va_list ap_save; /* argument pointer */
va_start(ap_save, format);
- retcode = formatf(whereto, fputc_wrapper, format, ap_save);
+ retcode = dprintf_formatf(whereto, fputc, format, ap_save);
va_end(ap_save);
return retcode;
}
int curl_mvsprintf(char *buffer, const char *format, va_list ap_save)
{
- int retcode = formatf(&buffer, storebuffer, format, ap_save);
+ int retcode;
+ retcode = dprintf_formatf(&buffer, storebuffer, format, ap_save);
*buffer = 0; /* we terminate this with a zero byte */
return retcode;
}
int curl_mvprintf(const char *format, va_list ap_save)
{
- return formatf(stdout, fputc_wrapper, format, ap_save);
+ return dprintf_formatf(stdout, fputc, format, ap_save);
}
int curl_mvfprintf(FILE *whereto, const char *format, va_list ap_save)
{
- return formatf(whereto, fputc_wrapper, format, ap_save);
+ return dprintf_formatf(whereto, fputc, format, ap_save);
}
diff --git a/contrib/libs/curl/lib/mqtt.c b/contrib/libs/curl/lib/mqtt.c
index 22d354a5c2..366235c559 100644
--- a/contrib/libs/curl/lib/mqtt.c
+++ b/contrib/libs/curl/lib/mqtt.c
@@ -75,7 +75,7 @@ static CURLcode mqtt_setup_conn(struct Curl_easy *data,
*/
const struct Curl_handler Curl_handler_mqtt = {
- "mqtt", /* scheme */
+ "MQTT", /* scheme */
mqtt_setup_conn, /* setup_connection */
mqtt_do, /* do_it */
mqtt_done, /* done */
@@ -88,8 +88,7 @@ const struct Curl_handler Curl_handler_mqtt = {
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
ZERO_NULL, /* disconnect */
- ZERO_NULL, /* write_resp */
- ZERO_NULL, /* write_resp_hd */
+ ZERO_NULL, /* readwrite */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_MQTT, /* defport */
@@ -120,12 +119,12 @@ static CURLcode mqtt_send(struct Curl_easy *data,
{
CURLcode result = CURLE_OK;
struct MQTT *mq = data->req.p.mqtt;
- size_t n;
- result = Curl_xfer_send(data, buf, len, FALSE, &n);
+ ssize_t n;
+ result = Curl_nwrite(data, FIRSTSOCKET, buf, len, &n);
if(result)
return result;
Curl_debug(data, CURLINFO_HEADER_OUT, buf, (size_t)n);
- if(len != n) {
+ if(len != (size_t)n) {
size_t nsend = len - n;
char *sendleftovers = Curl_memdup(&buf[n], nsend);
if(!sendleftovers)
@@ -154,15 +153,15 @@ static int mqtt_getsock(struct Curl_easy *data,
static int mqtt_encode_len(char *buf, size_t len)
{
+ unsigned char encoded;
int i;
for(i = 0; (len > 0) && (i<4); i++) {
- unsigned char encoded;
encoded = len % 0x80;
len /= 0x80;
if(len)
encoded |= 0x80;
- buf[i] = (char)encoded;
+ buf[i] = encoded;
}
return i;
@@ -312,7 +311,7 @@ static CURLcode mqtt_connect(struct Curl_easy *data)
start_user = pos + 3 + MQTT_CLIENTID_LEN;
/* position where starts the password payload */
start_pwd = start_user + ulen;
- /* if username was provided, add it to the packet */
+ /* if user name was provided, add it to the packet */
if(ulen) {
start_pwd += 2;
@@ -367,7 +366,8 @@ static CURLcode mqtt_recv_atleast(struct Curl_easy *data, size_t nbytes)
ssize_t nread;
DEBUGASSERT(nbytes - rlen < sizeof(readbuf));
- result = Curl_xfer_recv(data, (char *)readbuf, nbytes - rlen, &nread);
+ result = Curl_read(data, data->conn->sock[FIRSTSOCKET],
+ (char *)readbuf, nbytes - rlen, &nread);
if(result)
return result;
DEBUGASSERT(nread >= 0);
@@ -524,10 +524,8 @@ static CURLcode mqtt_publish(struct Curl_easy *data)
char encodedbytes[4];
curl_off_t postfieldsize = data->set.postfieldsize;
- if(!payload) {
- DEBUGF(infof(data, "mqtt_publish without payload, return bad arg"));
+ if(!payload)
return CURLE_BAD_FUNCTION_ARGUMENT;
- }
if(postfieldsize < 0)
payloadlen = strlen(payload);
else
@@ -585,7 +583,7 @@ static size_t mqtt_decode_len(unsigned char *buf,
return len;
}
-#ifdef DEBUGBUILD
+#ifdef CURLDEBUG
static const char *statenames[]={
"MQTT_FIRST",
"MQTT_REMAINING_LENGTH",
@@ -606,7 +604,7 @@ static void mqstate(struct Curl_easy *data,
{
struct connectdata *conn = data->conn;
struct mqtt_conn *mqtt = &conn->proto.mqtt;
-#ifdef DEBUGBUILD
+#ifdef CURLDEBUG
infof(data, "%s (from %s) (next is %s)",
statenames[state],
statenames[mqtt->state],
@@ -622,7 +620,9 @@ static CURLcode mqtt_read_publish(struct Curl_easy *data, bool *done)
{
CURLcode result = CURLE_OK;
struct connectdata *conn = data->conn;
+ curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
ssize_t nread;
+ unsigned char *pkt = (unsigned char *)data->state.buffer;
size_t remlen;
struct mqtt_conn *mqtt = &conn->proto.mqtt;
struct MQTT *mq = data->req.p.mqtt;
@@ -671,14 +671,13 @@ MQTT_SUBACK_COMING:
data->req.bytecount = 0;
data->req.size = remlen;
mq->npacket = remlen; /* get this many bytes */
- FALLTHROUGH();
+ /* FALLTHROUGH */
case MQTT_PUB_REMAIN: {
/* read rest of packet, but no more. Cap to buffer size */
- char buffer[4*1024];
size_t rest = mq->npacket;
- if(rest > sizeof(buffer))
- rest = sizeof(buffer);
- result = Curl_xfer_recv(data, buffer, rest, &nread);
+ if(rest > (size_t)data->set.buffer_size)
+ rest = (size_t)data->set.buffer_size;
+ result = Curl_read(data, sockfd, (char *)pkt, rest, &nread);
if(result) {
if(CURLE_AGAIN == result) {
infof(data, "EEEE AAAAGAIN");
@@ -691,12 +690,14 @@ MQTT_SUBACK_COMING:
goto end;
}
+ mq->npacket -= nread;
+
/* if QoS is set, message contains packet id */
- result = Curl_client_write(data, CLIENTWRITE_BODY, buffer, nread);
+
+ result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)pkt, nread);
if(result)
goto end;
- mq->npacket -= nread;
if(!mq->npacket)
/* no more PUBLISH payload, back to subscribe wait state */
mqstate(data, MQTT_FIRST, MQTT_PUBWAIT);
@@ -743,7 +744,9 @@ static CURLcode mqtt_doing(struct Curl_easy *data, bool *done)
struct mqtt_conn *mqtt = &conn->proto.mqtt;
struct MQTT *mq = data->req.p.mqtt;
ssize_t nread;
- unsigned char recvbyte;
+ curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
+ unsigned char *pkt = (unsigned char *)data->state.buffer;
+ unsigned char byte;
*done = FALSE;
@@ -760,7 +763,7 @@ static CURLcode mqtt_doing(struct Curl_easy *data, bool *done)
switch(mqtt->state) {
case MQTT_FIRST:
/* Read the initial byte only */
- result = Curl_xfer_recv(data, (char *)&mq->firstbyte, 1, &nread);
+ result = Curl_read(data, sockfd, (char *)&mq->firstbyte, 1, &nread);
if(result)
break;
else if(!nread) {
@@ -773,22 +776,22 @@ static CURLcode mqtt_doing(struct Curl_easy *data, bool *done)
/* remember the first byte */
mq->npacket = 0;
mqstate(data, MQTT_REMAINING_LENGTH, MQTT_NOSTATE);
- FALLTHROUGH();
+ /* FALLTHROUGH */
case MQTT_REMAINING_LENGTH:
do {
- result = Curl_xfer_recv(data, (char *)&recvbyte, 1, &nread);
- if(result || !nread)
+ result = Curl_read(data, sockfd, (char *)&byte, 1, &nread);
+ if(!nread)
break;
- Curl_debug(data, CURLINFO_HEADER_IN, (char *)&recvbyte, 1);
- mq->pkt_hd[mq->npacket++] = recvbyte;
- } while((recvbyte & 0x80) && (mq->npacket < 4));
- if(!result && nread && (recvbyte & 0x80))
+ Curl_debug(data, CURLINFO_HEADER_IN, (char *)&byte, 1);
+ pkt[mq->npacket++] = byte;
+ } while((byte & 0x80) && (mq->npacket < 4));
+ if(nread && (byte & 0x80))
/* MQTT supports up to 127 * 128^0 + 127 * 128^1 + 127 * 128^2 +
127 * 128^3 bytes. server tried to send more */
result = CURLE_WEIRD_SERVER_REPLY;
if(result)
break;
- mq->remaining_length = mqtt_decode_len(mq->pkt_hd, mq->npacket, NULL);
+ mq->remaining_length = mqtt_decode_len(&pkt[0], mq->npacket, NULL);
mq->npacket = 0;
if(mq->remaining_length) {
mqstate(data, mqtt->nextstate, MQTT_NOSTATE);
diff --git a/contrib/libs/curl/lib/mqtt.h b/contrib/libs/curl/lib/mqtt.h
index 99ab12a98a..84f177022e 100644
--- a/contrib/libs/curl/lib/mqtt.h
+++ b/contrib/libs/curl/lib/mqtt.h
@@ -57,7 +57,6 @@ struct MQTT {
unsigned char firstbyte;
size_t remaining_length;
struct dynbuf recvbuf;
- unsigned char pkt_hd[4]; /* for decoding the arriving packet length */
};
#endif /* HEADER_CURL_MQTT_H */
diff --git a/contrib/libs/curl/lib/multi.c b/contrib/libs/curl/lib/multi.c
index 78e5c0a1e5..5456113be7 100644
--- a/contrib/libs/curl/lib/multi.c
+++ b/contrib/libs/curl/lib/multi.c
@@ -57,7 +57,7 @@
/*
CURL_SOCKET_HASH_TABLE_SIZE should be a prime number. Increasing it from 97
- to 911 takes on a 32-bit machine 4 x 804 = 3211 more bytes. Still, every
+ to 911 takes on a 32-bit machine 4 x 804 = 3211 more bytes. Still, every
CURL handle takes 45-50 K memory, therefore this 3K are not significant.
*/
#ifndef CURL_SOCKET_HASH_TABLE_SIZE
@@ -86,26 +86,19 @@
((x) && (x)->magic == CURL_MULTI_HANDLE)
#endif
-static void move_pending_to_connect(struct Curl_multi *multi,
- struct Curl_easy *data);
static CURLMcode singlesocket(struct Curl_multi *multi,
struct Curl_easy *data);
static CURLMcode add_next_timeout(struct curltime now,
struct Curl_multi *multi,
struct Curl_easy *d);
static CURLMcode multi_timeout(struct Curl_multi *multi,
- struct curltime *expire_time,
long *timeout_ms);
static void process_pending_handles(struct Curl_multi *multi);
-static void multi_xfer_bufs_free(struct Curl_multi *multi);
-static void Curl_expire_ex(struct Curl_easy *data, const struct curltime *nowp,
- timediff_t milli, expire_id id);
#ifdef DEBUGBUILD
static const char * const multi_statename[]={
"INIT",
"PENDING",
- "SETUP",
"CONNECT",
"RESOLVING",
"CONNECTING",
@@ -138,7 +131,7 @@ static void init_completed(struct Curl_easy *data)
{
/* this is a completed transfer */
- /* Important: reset the conn pointer so that we do not point to memory
+ /* Important: reset the conn pointer so that we don't point to memory
that could be freed anytime */
Curl_detach_connection(data);
Curl_expire_clear(data); /* stop all timers */
@@ -155,7 +148,6 @@ static void mstate(struct Curl_easy *data, CURLMstate state
static const init_multistate_func finit[MSTATE_LAST] = {
NULL, /* INIT */
NULL, /* PENDING */
- NULL, /* SETUP */
Curl_init_CONNECT, /* CONNECT */
NULL, /* RESOLVING */
NULL, /* CONNECTING */
@@ -178,7 +170,7 @@ static void mstate(struct Curl_easy *data, CURLMstate state
#endif
if(oldstate == state)
- /* do not bother when the new state is the same as the old state */
+ /* don't bother when the new state is the same as the old state */
return;
data->mstate = state;
@@ -194,13 +186,9 @@ static void mstate(struct Curl_easy *data, CURLMstate state
#endif
if(state == MSTATE_COMPLETED) {
- /* changing to COMPLETED means there is one less easy handle 'alive' */
+ /* changing to COMPLETED means there's one less easy handle 'alive' */
DEBUGASSERT(data->multi->num_alive > 0);
data->multi->num_alive--;
- if(!data->multi->num_alive) {
- /* free the transfer buffer when we have no more active transfers */
- multi_xfer_bufs_free(data->multi);
- }
}
/* if this state has an init-function, run it */
@@ -250,8 +238,10 @@ static size_t trhash(void *key, size_t key_length, size_t slots_num)
static size_t trhash_compare(void *k1, size_t k1_len, void *k2, size_t k2_len)
{
+ (void)k1_len;
(void)k2_len;
- return !memcmp(k1, k2, k1_len);
+
+ return *(struct Curl_easy **)k1 == *(struct Curl_easy **)k2;
}
static void trhash_dtor(void *nada)
@@ -344,7 +334,7 @@ static size_t hash_fd(void *key, size_t key_length, size_t slots_num)
curl_socket_t fd = *((curl_socket_t *) key);
(void) key_length;
- return (fd % (curl_socket_t)slots_num);
+ return (fd % slots_num);
}
/*
@@ -355,33 +345,22 @@ static size_t hash_fd(void *key, size_t key_length, size_t slots_num)
* "Some tests at 7000 and 9000 connections showed that the socket hash lookup
* is somewhat of a bottle neck. Its current implementation may be a bit too
* limiting. It simply has a fixed-size array, and on each entry in the array
- * it has a linked list with entries. The hash only checks which list to scan
- * through. The code I had used so for used a list with merely 7 slots (as
- * that is what the DNS hash uses) but with 7000 connections that would make
- * an average of 1000 nodes in each list to run through. I upped that to 97
- * slots (I believe a prime is suitable) and noticed a significant speed
- * increase. I need to reconsider the hash implementation or use a rather
+ * it has a linked list with entries. So the hash only checks which list to
+ * scan through. The code I had used so for used a list with merely 7 slots
+ * (as that is what the DNS hash uses) but with 7000 connections that would
+ * make an average of 1000 nodes in each list to run through. I upped that to
+ * 97 slots (I believe a prime is suitable) and noticed a significant speed
+ * increase. I need to reconsider the hash implementation or use a rather
* large default value like this. At 9000 connections I was still below 10us
* per call."
*
*/
-static void sh_init(struct Curl_hash *hash, size_t hashsize)
+static void sh_init(struct Curl_hash *hash, int hashsize)
{
Curl_hash_init(hash, hashsize, hash_fd, fd_key_compare,
sh_freeentry);
}
-/* multi->proto_hash destructor. Should never be called as elements
- * MUST be added with their own destructor */
-static void ph_freeentry(void *p)
-{
- (void)p;
- /* Will always be FALSE. Cannot use a 0 assert here since compilers
- * are not in agreement if they then want a NORETURN attribute or
- * not. *sigh* */
- DEBUGASSERT(p == NULL);
-}
-
/*
* multi_addmsg()
*
@@ -390,12 +369,13 @@ static void ph_freeentry(void *p)
*/
static void multi_addmsg(struct Curl_multi *multi, struct Curl_message *msg)
{
- Curl_llist_append(&multi->msglist, msg, &msg->list);
+ Curl_llist_insert_next(&multi->msglist, multi->msglist.tail, msg,
+ &msg->list);
}
-struct Curl_multi *Curl_multi_handle(size_t hashsize, /* socket hash */
- size_t chashsize, /* connection hash */
- size_t dnssize) /* dns hash */
+struct Curl_multi *Curl_multi_handle(int hashsize, /* socket hash */
+ int chashsize, /* connection hash */
+ int dnssize) /* dns hash */
{
struct Curl_multi *multi = calloc(1, sizeof(struct Curl_multi));
@@ -408,21 +388,15 @@ struct Curl_multi *Curl_multi_handle(size_t hashsize, /* socket hash */
sh_init(&multi->sockhash, hashsize);
- Curl_hash_init(&multi->proto_hash, 23,
- Curl_hash_str, Curl_str_key_compare, ph_freeentry);
-
- if(Curl_cpool_init(&multi->cpool, Curl_on_disconnect,
- multi, NULL, chashsize))
+ if(Curl_conncache_init(&multi->conn_cache, chashsize))
goto error;
Curl_llist_init(&multi->msglist, NULL);
- Curl_llist_init(&multi->process, NULL);
Curl_llist_init(&multi->pending, NULL);
Curl_llist_init(&multi->msgsent, NULL);
multi->multiplexing = TRUE;
multi->max_concurrent_streams = 100;
- multi->last_timeout_ms = -1;
#ifdef USE_WINSOCK
multi->wsa_event = WSACreateEvent();
@@ -430,7 +404,14 @@ struct Curl_multi *Curl_multi_handle(size_t hashsize, /* socket hash */
goto error;
#else
#ifdef ENABLE_WAKEUP
- if(wakeup_create(multi->wakeup_pair, TRUE) < 0) {
+ if(wakeup_create(multi->wakeup_pair) < 0) {
+ multi->wakeup_pair[0] = CURL_SOCKET_BAD;
+ multi->wakeup_pair[1] = CURL_SOCKET_BAD;
+ }
+ else if(curlx_nonblock(multi->wakeup_pair[0], TRUE) < 0 ||
+ curlx_nonblock(multi->wakeup_pair[1], TRUE) < 0) {
+ wakeup_close(multi->wakeup_pair[0]);
+ wakeup_close(multi->wakeup_pair[1]);
multi->wakeup_pair[0] = CURL_SOCKET_BAD;
multi->wakeup_pair[1] = CURL_SOCKET_BAD;
}
@@ -442,9 +423,8 @@ struct Curl_multi *Curl_multi_handle(size_t hashsize, /* socket hash */
error:
sockhash_destroy(&multi->sockhash);
- Curl_hash_destroy(&multi->proto_hash);
Curl_hash_destroy(&multi->hostcache);
- Curl_cpool_destroy(&multi->cpool);
+ Curl_conncache_destroy(&multi->conn_cache);
free(multi);
return NULL;
}
@@ -470,6 +450,52 @@ static void multi_warn_debug(struct Curl_multi *multi, struct Curl_easy *data)
#define multi_warn_debug(x,y) Curl_nop_stmt
#endif
+/* returns TRUE if the easy handle is supposed to be present in the main link
+ list */
+static bool in_main_list(struct Curl_easy *data)
+{
+ return ((data->mstate != MSTATE_PENDING) &&
+ (data->mstate != MSTATE_MSGSENT));
+}
+
+static void link_easy(struct Curl_multi *multi,
+ struct Curl_easy *data)
+{
+ /* We add the new easy entry last in the list. */
+ data->next = NULL; /* end of the line */
+ if(multi->easyp) {
+ struct Curl_easy *last = multi->easylp;
+ last->next = data;
+ data->prev = last;
+ multi->easylp = data; /* the new last node */
+ }
+ else {
+ /* first node, make prev NULL! */
+ data->prev = NULL;
+ multi->easylp = multi->easyp = data; /* both first and last */
+ }
+}
+
+/* unlink the given easy handle from the linked list of easy handles */
+static void unlink_easy(struct Curl_multi *multi,
+ struct Curl_easy *data)
+{
+ /* make the previous node point to our next */
+ if(data->prev)
+ data->prev->next = data->next;
+ else
+ multi->easyp = data->next; /* point to first node */
+
+ /* make our next point to our previous node */
+ if(data->next)
+ data->next->prev = data->prev;
+ else
+ multi->easylp = data->prev; /* point to last node */
+
+ data->prev = data->next = NULL;
+}
+
+
CURLMcode curl_multi_add_handle(struct Curl_multi *multi,
struct Curl_easy *data)
{
@@ -499,27 +525,18 @@ CURLMcode curl_multi_add_handle(struct Curl_multi *multi,
multi->dead = FALSE;
}
- if(data->multi_easy) {
- /* if this easy handle was previously used for curl_easy_perform(), there
- is a private multi handle here that we can kill */
- curl_multi_cleanup(data->multi_easy);
- data->multi_easy = NULL;
- }
-
/* Initialize timeout list for this handle */
Curl_llist_init(&data->state.timeoutlist, NULL);
/*
- * No failure allowed in this function beyond this point. No modification of
- * easy nor multi handle allowed before this except for potential multi's
- * connection pool growing which will not be undone in this function no
- * matter what.
+ * No failure allowed in this function beyond this point. And no
+ * modification of easy nor multi handle allowed before this except for
+ * potential multi's connection cache growing which won't be undone in this
+ * function no matter what.
*/
if(data->set.errorbuffer)
data->set.errorbuffer[0] = 0;
- data->state.os_errno = 0;
-
/* make the Curl_easy refer back to this multi handle - before Curl_expire()
is called. */
data->multi = multi;
@@ -532,11 +549,21 @@ CURLMcode curl_multi_add_handle(struct Curl_multi *multi,
happen. */
Curl_expire(data, 0, EXPIRE_RUN_NOW);
+ /* A somewhat crude work-around for a little glitch in Curl_update_timer()
+ that happens if the lastcall time is set to the same time when the handle
+ is removed as when the next handle is added, as then the check in
+ Curl_update_timer() that prevents calling the application multiple times
+ with the same timer info will not trigger and then the new handle's
+ timeout will not be notified to the app.
+
+ The work-around is thus simply to clear the 'lastcall' variable to force
+ Curl_update_timer() to always trigger a callback to the app when a new
+ easy handle is added */
+ memset(&multi->timer_lastcall, 0, sizeof(multi->timer_lastcall));
+
rc = Curl_update_timer(multi);
- if(rc) {
- data->multi = NULL; /* not anymore */
+ if(rc)
return rc;
- }
/* set the easy handle */
multistate(data, MSTATE_INIT);
@@ -549,6 +576,13 @@ CURLMcode curl_multi_add_handle(struct Curl_multi *multi,
data->dns.hostcachetype = HCACHE_MULTI;
}
+ /* Point to the shared or multi handle connection cache */
+ if(data->share && (data->share->specifier & (1<< CURL_LOCK_DATA_CONNECT)))
+ data->state.conn_cache = &data->share->conn_cache;
+ else
+ data->state.conn_cache = &multi->conn_cache;
+ data->state.lastconnect_id = -1;
+
#ifdef USE_LIBPSL
/* Do the same for PSL. */
if(data->share && (data->share->specifier & (1 << CURL_LOCK_DATA_PSL)))
@@ -557,8 +591,7 @@ CURLMcode curl_multi_add_handle(struct Curl_multi *multi,
data->psl = &multi->psl;
#endif
- /* add the easy handle to the process list */
- Curl_llist_append(&multi->process, data, &data->multi_queue);
+ link_easy(multi, data);
/* increase the node-counter */
multi->num_easy++;
@@ -566,12 +599,21 @@ CURLMcode curl_multi_add_handle(struct Curl_multi *multi,
/* increase the alive-counter */
multi->num_alive++;
- /* the identifier inside the multi instance */
- data->mid = multi->next_easy_mid++;
- if(multi->next_easy_mid <= 0)
- multi->next_easy_mid = 0;
+ CONNCACHE_LOCK(data);
+ /* The closure handle only ever has default timeouts set. To improve the
+ state somewhat we clone the timeouts from each added handle so that the
+ closure handle always has the same timeouts as the most recently added
+ easy handle. */
+ data->state.conn_cache->closure_handle->set.timeout = data->set.timeout;
+ data->state.conn_cache->closure_handle->set.server_response_timeout =
+ data->set.server_response_timeout;
+ data->state.conn_cache->closure_handle->set.no_signal =
+ data->set.no_signal;
+ data->id = data->state.conn_cache->next_easy_id++;
+ if(data->state.conn_cache->next_easy_id <= 0)
+ data->state.conn_cache->next_easy_id = 0;
+ CONNCACHE_UNLOCK(data);
- Curl_cpool_xfer_init(data);
multi_warn_debug(multi, data);
return CURLM_OK;
@@ -593,101 +635,13 @@ static void debug_print_sock_hash(void *p)
}
#endif
-struct multi_done_ctx {
- BIT(premature);
-};
-
-static void multi_done_locked(struct connectdata *conn,
- struct Curl_easy *data,
- void *userdata)
-{
- struct multi_done_ctx *mdctx = userdata;
-
- Curl_detach_connection(data);
-
- if(CONN_INUSE(conn)) {
- /* Stop if still used. */
- DEBUGF(infof(data, "Connection still in use %zu, "
- "no more multi_done now!",
- Curl_llist_count(&conn->easyq)));
- return;
- }
-
- data->state.done = TRUE; /* called just now! */
- data->state.recent_conn_id = conn->connection_id;
-
- if(conn->dns_entry)
- Curl_resolv_unlink(data, &conn->dns_entry); /* done with this */
- Curl_hostcache_prune(data);
-
- /* if data->set.reuse_forbid is TRUE, it means the libcurl client has
- forced us to close this connection. This is ignored for requests taking
- place in a NTLM/NEGOTIATE authentication handshake
-
- if conn->bits.close is TRUE, it means that the connection should be
- closed in spite of all our efforts to be nice, due to protocol
- restrictions in our or the server's end
-
- if premature is TRUE, it means this connection was said to be DONE before
- the entire request operation is complete and thus we cannot know in what
- state it is for reusing, so we are forced to close it. In a perfect world
- we can add code that keep track of if we really must close it here or not,
- but currently we have no such detail knowledge.
- */
-
- if((data->set.reuse_forbid
-#if defined(USE_NTLM)
- && !(conn->http_ntlm_state == NTLMSTATE_TYPE2 ||
- conn->proxy_ntlm_state == NTLMSTATE_TYPE2)
-#endif
-#if defined(USE_SPNEGO)
- && !(conn->http_negotiate_state == GSS_AUTHRECV ||
- conn->proxy_negotiate_state == GSS_AUTHRECV)
-#endif
- ) || conn->bits.close
- || (mdctx->premature && !Curl_conn_is_multiplex(conn, FIRSTSOCKET))) {
- DEBUGF(infof(data, "multi_done, not reusing connection=%"
- FMT_OFF_T ", forbid=%d"
- ", close=%d, premature=%d, conn_multiplex=%d",
- conn->connection_id, data->set.reuse_forbid,
- conn->bits.close, mdctx->premature,
- Curl_conn_is_multiplex(conn, FIRSTSOCKET)));
- connclose(conn, "disconnecting");
- Curl_cpool_disconnect(data, conn, mdctx->premature);
- }
- else {
- /* the connection is no longer in use by any transfer */
- if(Curl_cpool_conn_now_idle(data, conn)) {
- /* connection kept in the cpool */
- const char *host =
-#ifndef CURL_DISABLE_PROXY
- conn->bits.socksproxy ?
- conn->socks_proxy.host.dispname :
- conn->bits.httpproxy ? conn->http_proxy.host.dispname :
-#endif
- conn->bits.conn_to_host ? conn->conn_to_host.dispname :
- conn->host.dispname;
- data->state.lastconnect_id = conn->connection_id;
- infof(data, "Connection #%" FMT_OFF_T " to host %s left intact",
- conn->connection_id, host);
- }
- else {
- /* connection was removed from the cpool and destroyed. */
- data->state.lastconnect_id = -1;
- }
- }
-}
-
static CURLcode multi_done(struct Curl_easy *data,
CURLcode status, /* an error if this is called
after an error was detected */
bool premature)
{
- CURLcode result, r2;
+ CURLcode result;
struct connectdata *conn = data->conn;
- struct multi_done_ctx mdctx;
-
- memset(&mdctx, 0, sizeof(mdctx));
#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
DEBUGF(infof(data, "multi_done[%s]: status: %d prem: %d done: %d",
@@ -713,12 +667,11 @@ static CURLcode multi_done(struct Curl_easy *data,
case CURLE_ABORTED_BY_CALLBACK:
case CURLE_READ_ERROR:
case CURLE_WRITE_ERROR:
- /* When we are aborted due to a callback return code it basically have to
- be counted as premature as there is trouble ahead if we do not. We have
+ /* When we're aborted due to a callback return code it basically have to
+ be counted as premature as there is trouble ahead if we don't. We have
many callbacks and protocols work differently, we could potentially do
this more fine-grained in the future. */
premature = TRUE;
- FALLTHROUGH();
default:
break;
}
@@ -737,35 +690,116 @@ static CURLcode multi_done(struct Curl_easy *data,
result = CURLE_ABORTED_BY_CALLBACK;
}
- /* Make sure that transfer client writes are really done now. */
- r2 = Curl_xfer_write_done(data, premature);
- if(r2 && !result)
- result = r2;
-
/* Inform connection filters that this transfer is done */
Curl_conn_ev_data_done(data, premature);
process_pending_handles(data->multi); /* connection / multiplex */
- if(!result)
- result = Curl_req_done(&data->req, data, premature);
+ Curl_safefree(data->state.ulbuf);
+
+ Curl_client_cleanup(data);
+
+ CONNCACHE_LOCK(data);
+ Curl_detach_connection(data);
+ if(CONN_INUSE(conn)) {
+ /* Stop if still used. */
+ CONNCACHE_UNLOCK(data);
+ DEBUGF(infof(data, "Connection still in use %zu, "
+ "no more multi_done now!",
+ conn->easyq.size));
+ return CURLE_OK;
+ }
+
+ data->state.done = TRUE; /* called just now! */
+
+ if(conn->dns_entry) {
+ Curl_resolv_unlock(data, conn->dns_entry); /* done with this */
+ conn->dns_entry = NULL;
+ }
+ Curl_hostcache_prune(data);
+
+ /* if data->set.reuse_forbid is TRUE, it means the libcurl client has
+ forced us to close this connection. This is ignored for requests taking
+ place in a NTLM/NEGOTIATE authentication handshake
+
+ if conn->bits.close is TRUE, it means that the connection should be
+ closed in spite of all our efforts to be nice, due to protocol
+ restrictions in our or the server's end
- /* Under the potential connection pool's share lock, decide what to
- * do with the transfer's connection. */
- mdctx.premature = premature;
- Curl_cpool_do_locked(data, data->conn, multi_done_locked, &mdctx);
+ if premature is TRUE, it means this connection was said to be DONE before
+ the entire request operation is complete and thus we can't know in what
+ state it is for reusing, so we're forced to close it. In a perfect world
+ we can add code that keep track of if we really must close it here or not,
+ but currently we have no such detail knowledge.
+ */
+ data->state.recent_conn_id = conn->connection_id;
+ if((data->set.reuse_forbid
+#if defined(USE_NTLM)
+ && !(conn->http_ntlm_state == NTLMSTATE_TYPE2 ||
+ conn->proxy_ntlm_state == NTLMSTATE_TYPE2)
+#endif
+#if defined(USE_SPNEGO)
+ && !(conn->http_negotiate_state == GSS_AUTHRECV ||
+ conn->proxy_negotiate_state == GSS_AUTHRECV)
+#endif
+ ) || conn->bits.close
+ || (premature && !Curl_conn_is_multiplex(conn, FIRSTSOCKET))) {
+ DEBUGF(infof(data, "multi_done, not reusing connection=%"
+ CURL_FORMAT_CURL_OFF_T ", forbid=%d"
+ ", close=%d, premature=%d, conn_multiplex=%d",
+ conn->connection_id,
+ data->set.reuse_forbid, conn->bits.close, premature,
+ Curl_conn_is_multiplex(conn, FIRSTSOCKET)));
+ connclose(conn, "disconnecting");
+ Curl_conncache_remove_conn(data, conn, FALSE);
+ CONNCACHE_UNLOCK(data);
+ Curl_disconnect(data, conn, premature);
+ }
+ else {
+ char buffer[256];
+ const char *host =
+#ifndef CURL_DISABLE_PROXY
+ conn->bits.socksproxy ?
+ conn->socks_proxy.host.dispname :
+ conn->bits.httpproxy ? conn->http_proxy.host.dispname :
+#endif
+ conn->bits.conn_to_host ? conn->conn_to_host.dispname :
+ conn->host.dispname;
+ /* create string before returning the connection */
+ curl_off_t connection_id = conn->connection_id;
+ msnprintf(buffer, sizeof(buffer),
+ "Connection #%" CURL_FORMAT_CURL_OFF_T " to host %s left intact",
+ connection_id, host);
+ /* the connection is no longer in use by this transfer */
+ CONNCACHE_UNLOCK(data);
+ if(Curl_conncache_return_conn(data, conn)) {
+ /* remember the most recently used connection */
+ data->state.lastconnect_id = connection_id;
+ data->state.recent_conn_id = connection_id;
+ infof(data, "%s", buffer);
+ }
+ else
+ data->state.lastconnect_id = -1;
+ }
+
+ Curl_safefree(data->state.buffer);
return result;
}
-static void close_connect_only(struct connectdata *conn,
- struct Curl_easy *data,
- void *userdata)
+static int close_connect_only(struct Curl_easy *data,
+ struct connectdata *conn, void *param)
{
- (void)userdata;
- (void)data;
- if(conn->connect_only)
- connclose(conn, "Removing connect-only easy handle");
+ (void)param;
+ if(data->state.lastconnect_id != conn->connection_id)
+ return 0;
+
+ if(!conn->connect_only)
+ return 1;
+
+ connclose(conn, "Removing connect-only easy handle");
+
+ return 1;
}
CURLMcode curl_multi_remove_handle(struct Curl_multi *multi,
@@ -773,16 +807,15 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi,
{
struct Curl_easy *easy = data;
bool premature;
- struct Curl_llist_node *e;
+ struct Curl_llist_element *e;
CURLMcode rc;
- bool removed_timer = FALSE;
/* First, make some basic checks that the CURLM handle is a good handle */
if(!GOOD_MULTI_HANDLE(multi))
return CURLM_BAD_HANDLE;
/* Verify that we got a somewhat good easy handle too */
- if(!GOOD_EASY_HANDLE(data) || !multi->num_easy)
+ if(!GOOD_EASY_HANDLE(data))
return CURLM_BAD_EASY_HANDLE;
/* Prevent users from trying to remove same easy handle more than once */
@@ -809,7 +842,7 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi,
if(data->conn &&
data->mstate > MSTATE_DO &&
data->mstate < MSTATE_COMPLETED) {
- /* Set connection owner so that the DONE function closes it. We can
+ /* Set connection owner so that the DONE function closes it. We can
safely do this here since connection is killed. */
streamclose(data->conn, "Removed with partial response");
}
@@ -818,7 +851,7 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi,
/* multi_done() clears the association between the easy handle and the
connection.
- Note that this ignores the return code simply because there is
+ Note that this ignores the return code simply because there's
nothing really useful to do with it anyway! */
(void)multi_done(data, data->result, premature);
}
@@ -826,10 +859,18 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi,
/* The timer must be shut down before data->multi is set to NULL, else the
timenode will remain in the splay tree after curl_easy_cleanup is
called. Do it after multi_done() in case that sets another time! */
- removed_timer = Curl_expire_clear(data);
+ Curl_expire_clear(data);
- /* the handle is in a list, remove it from whichever it is */
- Curl_node_remove(&data->multi_queue);
+ if(data->connect_queue.ptr) {
+ /* the handle is in the pending or msgsent lists, so go ahead and remove
+ it */
+ if(data->mstate == MSTATE_PENDING)
+ Curl_llist_remove(&multi->pending, &data->connect_queue, NULL);
+ else
+ Curl_llist_remove(&multi->msgsent, &data->connect_queue, NULL);
+ }
+ if(in_main_list(data))
+ unlink_easy(multi, data);
if(data->dns.hostcachetype == HCACHE_MULTI) {
/* stop using the multi handle's DNS cache, *after* the possible
@@ -844,7 +885,7 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi,
what we want */
data->mstate = MSTATE_COMPLETED;
- /* This ignores the return code even in case of problems because there is
+ /* This ignores the return code even in case of problems because there's
nothing more to do about that, here */
(void)singlesocket(multi, easy); /* to let the application know what sockets
that vanish with this handle */
@@ -856,7 +897,7 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi,
/* This removes a handle that was part the multi interface that used
CONNECT_ONLY, that connection is now left alive but since this handle
has bits.close set nothing can use that transfer anymore and it is
- forbidden from reuse. This easy handle cannot find the connection
+ forbidden from reuse. And this easy handle cannot find the connection
anymore once removed from the multi handle
Better close the connection here, at once.
@@ -865,14 +906,15 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi,
curl_socket_t s;
s = Curl_getconnectinfo(data, &c);
if((s != CURL_SOCKET_BAD) && c) {
- Curl_cpool_disconnect(data, c, TRUE);
+ Curl_conncache_remove_conn(data, c, TRUE);
+ Curl_disconnect(data, c, TRUE);
}
}
if(data->state.lastconnect_id != -1) {
/* Mark any connect-only connection for closure */
- Curl_cpool_do_by_id(data, data->state.lastconnect_id,
- close_connect_only, NULL);
+ Curl_conncache_foreach(data, data->state.conn_cache,
+ NULL, close_connect_only);
}
#ifdef USE_LIBPSL
@@ -881,31 +923,33 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi,
data->psl = NULL;
#endif
- /* make sure there is no pending message in the queue sent from this easy
+ /* as this was using a shared connection cache we clear the pointer to that
+ since we're not part of that multi handle anymore */
+ data->state.conn_cache = NULL;
+
+ data->multi = NULL; /* clear the association to this multi handle */
+
+ /* make sure there's no pending message in the queue sent from this easy
handle */
- for(e = Curl_llist_head(&multi->msglist); e; e = Curl_node_next(e)) {
- struct Curl_message *msg = Curl_node_elem(e);
+ for(e = multi->msglist.head; e; e = e->next) {
+ struct Curl_message *msg = e->ptr;
if(msg->extmsg.easy_handle == easy) {
- Curl_node_remove(e);
+ Curl_llist_remove(&multi->msglist, e, NULL);
/* there can only be one from this specific handle */
break;
}
}
- data->multi = NULL; /* clear the association to this multi handle */
- data->mid = -1;
-
/* NOTE NOTE NOTE
We do not touch the easy handle here! */
multi->num_easy--; /* one less to care about now */
+
process_pending_handles(multi);
- if(removed_timer) {
- rc = Curl_update_timer(multi);
- if(rc)
- return rc;
- }
+ rc = Curl_update_timer(multi);
+ if(rc)
+ return rc;
return CURLM_OK;
}
@@ -926,7 +970,7 @@ void Curl_detach_connection(struct Curl_easy *data)
struct connectdata *conn = data->conn;
if(conn) {
Curl_conn_ev_data_detach(conn, data);
- Curl_node_remove(&data->conn_queue);
+ Curl_llist_remove(&conn->easyq, &data->conn_queue, NULL);
}
data->conn = NULL;
}
@@ -937,114 +981,43 @@ void Curl_detach_connection(struct Curl_easy *data)
* This is the only function that should assign data->conn
*/
void Curl_attach_connection(struct Curl_easy *data,
- struct connectdata *conn)
+ struct connectdata *conn)
{
- DEBUGASSERT(data);
DEBUGASSERT(!data->conn);
DEBUGASSERT(conn);
data->conn = conn;
- Curl_llist_append(&conn->easyq, data, &data->conn_queue);
+ Curl_llist_insert_next(&conn->easyq, conn->easyq.tail, data,
+ &data->conn_queue);
if(conn->handler && conn->handler->attach)
conn->handler->attach(data, conn);
Curl_conn_ev_data_attach(conn, data);
}
-static int connecting_getsock(struct Curl_easy *data, curl_socket_t *socks)
+static int domore_getsock(struct Curl_easy *data,
+ struct connectdata *conn,
+ curl_socket_t *socks)
{
- struct connectdata *conn = data->conn;
- curl_socket_t sockfd;
-
- if(!conn)
- return GETSOCK_BLANK;
- sockfd = Curl_conn_get_socket(data, FIRSTSOCKET);
- if(sockfd != CURL_SOCKET_BAD) {
- /* Default is to wait to something from the server */
- socks[0] = sockfd;
- return GETSOCK_READSOCK(0);
- }
- return GETSOCK_BLANK;
-}
-
-static int protocol_getsock(struct Curl_easy *data, curl_socket_t *socks)
-{
- struct connectdata *conn = data->conn;
- curl_socket_t sockfd;
-
- if(!conn)
- return GETSOCK_BLANK;
- if(conn->handler->proto_getsock)
- return conn->handler->proto_getsock(data, conn, socks);
- sockfd = Curl_conn_get_socket(data, FIRSTSOCKET);
- if(sockfd != CURL_SOCKET_BAD) {
- /* Default is to wait to something from the server */
- socks[0] = sockfd;
- return GETSOCK_READSOCK(0);
- }
- return GETSOCK_BLANK;
-}
-
-static int domore_getsock(struct Curl_easy *data, curl_socket_t *socks)
-{
- struct connectdata *conn = data->conn;
- if(!conn)
- return GETSOCK_BLANK;
- if(conn->handler->domore_getsock)
+ if(conn && conn->handler->domore_getsock)
return conn->handler->domore_getsock(data, conn, socks);
- else if(conn->sockfd != CURL_SOCKET_BAD) {
- /* Default is that we want to send something to the server */
- socks[0] = conn->sockfd;
- return GETSOCK_WRITESOCK(0);
- }
return GETSOCK_BLANK;
}
-static int doing_getsock(struct Curl_easy *data, curl_socket_t *socks)
+static int doing_getsock(struct Curl_easy *data,
+ struct connectdata *conn,
+ curl_socket_t *socks)
{
- struct connectdata *conn = data->conn;
- if(!conn)
- return GETSOCK_BLANK;
- if(conn->handler->doing_getsock)
+ if(conn && conn->handler->doing_getsock)
return conn->handler->doing_getsock(data, conn, socks);
- else if(conn->sockfd != CURL_SOCKET_BAD) {
- /* Default is that we want to send something to the server */
- socks[0] = conn->sockfd;
- return GETSOCK_WRITESOCK(0);
- }
return GETSOCK_BLANK;
}
-static int perform_getsock(struct Curl_easy *data, curl_socket_t *sock)
+static int protocol_getsock(struct Curl_easy *data,
+ struct connectdata *conn,
+ curl_socket_t *socks)
{
- struct connectdata *conn = data->conn;
- if(!conn)
- return GETSOCK_BLANK;
- else if(conn->handler->perform_getsock)
- return conn->handler->perform_getsock(data, conn, sock);
- else {
- /* Default is to obey the data->req.keepon flags for send/recv */
- int bitmap = GETSOCK_BLANK;
- unsigned sockindex = 0;
- if(CURL_WANT_RECV(data)) {
- DEBUGASSERT(conn->sockfd != CURL_SOCKET_BAD);
- bitmap |= GETSOCK_READSOCK(sockindex);
- sock[sockindex] = conn->sockfd;
- }
-
- if(Curl_req_want_send(data)) {
- if((conn->sockfd != conn->writesockfd) ||
- bitmap == GETSOCK_BLANK) {
- /* only if they are not the same socket and we have a readable
- one, we increase index */
- if(bitmap != GETSOCK_BLANK)
- sockindex++; /* increase index if we need two entries */
-
- DEBUGASSERT(conn->writesockfd != CURL_SOCKET_BAD);
- sock[sockindex] = conn->writesockfd;
- }
- bitmap |= GETSOCK_WRITESOCK(sockindex);
- }
- return bitmap;
- }
+ if(conn->handler->proto_getsock)
+ return conn->handler->proto_getsock(data, conn, socks);
+ return GETSOCK_BLANK;
}
/* Initializes `poll_set` with the current socket poll actions needed
@@ -1052,7 +1025,6 @@ static int perform_getsock(struct Curl_easy *data, curl_socket_t *sock)
static void multi_getsock(struct Curl_easy *data,
struct easy_pollset *ps)
{
- bool expect_sockets = TRUE;
/* The no connection case can happen when this is called from
curl_multi_remove_handle() => singlesocket() => multi_getsock().
*/
@@ -1061,75 +1033,45 @@ static void multi_getsock(struct Curl_easy *data,
return;
switch(data->mstate) {
- case MSTATE_INIT:
- case MSTATE_PENDING:
- case MSTATE_SETUP:
- case MSTATE_CONNECT:
- /* nothing to poll for yet */
- expect_sockets = FALSE;
+ default:
break;
case MSTATE_RESOLVING:
- Curl_pollset_add_socks(data, ps, Curl_resolv_getsock);
- /* connection filters are not involved in this phase. It's ok if we get no
- * sockets to wait for. Resolving can wake up from other sources. */
- expect_sockets = FALSE;
- break;
-
- case MSTATE_CONNECTING:
- case MSTATE_TUNNELING:
- Curl_pollset_add_socks(data, ps, connecting_getsock);
- Curl_conn_adjust_pollset(data, ps);
- break;
+ Curl_pollset_add_socks2(data, ps, Curl_resolv_getsock);
+ /* connection filters are not involved in this phase */
+ return;
- case MSTATE_PROTOCONNECT:
case MSTATE_PROTOCONNECTING:
+ case MSTATE_PROTOCONNECT:
Curl_pollset_add_socks(data, ps, protocol_getsock);
- Curl_conn_adjust_pollset(data, ps);
break;
case MSTATE_DO:
case MSTATE_DOING:
Curl_pollset_add_socks(data, ps, doing_getsock);
- Curl_conn_adjust_pollset(data, ps);
+ break;
+
+ case MSTATE_TUNNELING:
+ case MSTATE_CONNECTING:
break;
case MSTATE_DOING_MORE:
Curl_pollset_add_socks(data, ps, domore_getsock);
- Curl_conn_adjust_pollset(data, ps);
break;
- case MSTATE_DID: /* same as PERFORMING in regard to polling */
+ case MSTATE_DID: /* since is set after DO is completed, we switch to
+ waiting for the same as the PERFORMING state */
case MSTATE_PERFORMING:
- Curl_pollset_add_socks(data, ps, perform_getsock);
- Curl_conn_adjust_pollset(data, ps);
+ Curl_pollset_add_socks(data, ps, Curl_single_getsock);
break;
case MSTATE_RATELIMITING:
- /* we need to let time pass, ignore socket(s) */
- expect_sockets = FALSE;
- break;
-
- case MSTATE_DONE:
- case MSTATE_COMPLETED:
- case MSTATE_MSGSENT:
- /* nothing more to poll for */
- expect_sockets = FALSE;
- break;
-
- default:
- failf(data, "multi_getsock: unexpected multi state %d", data->mstate);
- DEBUGASSERT(0);
- expect_sockets = FALSE;
- break;
+ /* nothing to wait for */
+ return;
}
- if(expect_sockets && !ps->num &&
- !(data->req.keepon & (KEEP_RECV_PAUSE|KEEP_SEND_PAUSE)) &&
- Curl_conn_is_ip_connected(data, FIRSTSOCKET)) {
- infof(data, "WARNING: no socket in pollset, transfer may stall!");
- DEBUGASSERT(0);
- }
+ /* Let connection filters add/remove as needed */
+ Curl_conn_adjust_pollset(data, ps);
}
CURLMcode curl_multi_fdset(struct Curl_multi *multi,
@@ -1139,8 +1081,10 @@ CURLMcode curl_multi_fdset(struct Curl_multi *multi,
/* Scan through all the easy handles to get the file descriptors set.
Some easy handles may not have connected to the remote host yet,
and then we must make sure that is done. */
+ struct Curl_easy *data;
int this_max_fd = -1;
- struct Curl_llist_node *e;
+ struct easy_pollset ps;
+ unsigned int i;
(void)exc_fd_set; /* not used */
if(!GOOD_MULTI_HANDLE(multi))
@@ -1149,22 +1093,20 @@ CURLMcode curl_multi_fdset(struct Curl_multi *multi,
if(multi->in_callback)
return CURLM_RECURSIVE_API_CALL;
- for(e = Curl_llist_head(&multi->process); e; e = Curl_node_next(e)) {
- struct Curl_easy *data = Curl_node_elem(e);
- unsigned int i;
+ memset(&ps, 0, sizeof(ps));
+ for(data = multi->easyp; data; data = data->next) {
+ multi_getsock(data, &ps);
- multi_getsock(data, &data->last_poll);
-
- for(i = 0; i < data->last_poll.num; i++) {
- if(!FDSET_SOCK(data->last_poll.sockets[i]))
- /* pretend it does not exist */
+ for(i = 0; i < ps.num; i++) {
+ if(!FDSET_SOCK(ps.sockets[i]))
+ /* pretend it doesn't exist */
continue;
- if(data->last_poll.actions[i] & CURL_POLL_IN)
- FD_SET(data->last_poll.sockets[i], read_fd_set);
- if(data->last_poll.actions[i] & CURL_POLL_OUT)
- FD_SET(data->last_poll.sockets[i], write_fd_set);
- if((int)data->last_poll.sockets[i] > this_max_fd)
- this_max_fd = (int)data->last_poll.sockets[i];
+ if(ps.actions[i] & CURL_POLL_IN)
+ FD_SET(ps.sockets[i], read_fd_set);
+ if(ps.actions[i] & CURL_POLL_OUT)
+ FD_SET(ps.sockets[i], write_fd_set);
+ if((int)ps.sockets[i] > this_max_fd)
+ this_max_fd = (int)ps.sockets[i];
}
}
@@ -1173,47 +1115,8 @@ CURLMcode curl_multi_fdset(struct Curl_multi *multi,
return CURLM_OK;
}
-CURLMcode curl_multi_waitfds(struct Curl_multi *multi,
- struct curl_waitfd *ufds,
- unsigned int size,
- unsigned int *fd_count)
-{
- struct curl_waitfds cwfds;
- CURLMcode result = CURLM_OK;
- struct Curl_llist_node *e;
-
- if(!ufds)
- return CURLM_BAD_FUNCTION_ARGUMENT;
-
- if(!GOOD_MULTI_HANDLE(multi))
- return CURLM_BAD_HANDLE;
-
- if(multi->in_callback)
- return CURLM_RECURSIVE_API_CALL;
-
- Curl_waitfds_init(&cwfds, ufds, size);
- for(e = Curl_llist_head(&multi->process); e; e = Curl_node_next(e)) {
- struct Curl_easy *data = Curl_node_elem(e);
- multi_getsock(data, &data->last_poll);
- if(Curl_waitfds_add_ps(&cwfds, &data->last_poll)) {
- result = CURLM_OUT_OF_MEMORY;
- goto out;
- }
- }
-
- if(Curl_cpool_add_waitfds(&multi->cpool, &cwfds)) {
- result = CURLM_OUT_OF_MEMORY;
- goto out;
- }
-
-out:
- if(fd_count)
- *fd_count = cwfds.n;
- return result;
-}
-
#ifdef USE_WINSOCK
-/* Reset FD_WRITE for TCP sockets. Nothing is actually sent. UDP sockets cannot
+/* Reset FD_WRITE for TCP sockets. Nothing is actually sent. UDP sockets can't
* be reset this way because an empty datagram would be sent. #9203
*
* "On Windows the internal state of FD_WRITE as returned from
@@ -1238,16 +1141,16 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
bool extrawait, /* when no socket, wait */
bool use_wakeup)
{
+ struct Curl_easy *data;
+ struct easy_pollset ps;
size_t i;
- struct curltime expire_time;
+ unsigned int nfds = 0;
+ unsigned int curlfds;
long timeout_internal;
int retcode = 0;
struct pollfd a_few_on_stack[NUM_POLLS_ON_STACK];
- struct curl_pollfds cpfds;
- unsigned int curl_nfds = 0; /* how many pfds are for curl transfers */
- CURLMcode result = CURLM_OK;
- struct Curl_llist_node *e;
-
+ struct pollfd *ufds = &a_few_on_stack[0];
+ bool ufds_malloc = FALSE;
#ifdef USE_WINSOCK
WSANETWORKEVENTS wsa_events;
DEBUGASSERT(multi->wsa_event != WSA_INVALID_EVENT);
@@ -1265,108 +1168,148 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
if(timeout_ms < 0)
return CURLM_BAD_FUNCTION_ARGUMENT;
- Curl_pollfds_init(&cpfds, a_few_on_stack, NUM_POLLS_ON_STACK);
+ /* Count up how many fds we have from the multi handle */
+ memset(&ps, 0, sizeof(ps));
+ for(data = multi->easyp; data; data = data->next) {
+ multi_getsock(data, &ps);
+ nfds += ps.num;
+ }
- /* Add the curl handles to our pollfds first */
- for(e = Curl_llist_head(&multi->process); e; e = Curl_node_next(e)) {
- struct Curl_easy *data = Curl_node_elem(e);
+ /* If the internally desired timeout is actually shorter than requested from
+ the outside, then use the shorter time! But only if the internal timer
+ is actually larger than -1! */
+ (void)multi_timeout(multi, &timeout_internal);
+ if((timeout_internal >= 0) && (timeout_internal < (long)timeout_ms))
+ timeout_ms = (int)timeout_internal;
- multi_getsock(data, &data->last_poll);
- if(Curl_pollfds_add_ps(&cpfds, &data->last_poll)) {
- result = CURLM_OUT_OF_MEMORY;
- goto out;
- }
+ curlfds = nfds; /* number of internal file descriptors */
+ nfds += extra_nfds; /* add the externally provided ones */
+
+#ifdef ENABLE_WAKEUP
+#ifdef USE_WINSOCK
+ if(use_wakeup) {
+#else
+ if(use_wakeup && multi->wakeup_pair[0] != CURL_SOCKET_BAD) {
+#endif
+ ++nfds;
}
+#endif
- if(Curl_cpool_add_pollfds(&multi->cpool, &cpfds)) {
- result = CURLM_OUT_OF_MEMORY;
- goto out;
+ if(nfds > NUM_POLLS_ON_STACK) {
+ /* 'nfds' is a 32 bit value and 'struct pollfd' is typically 8 bytes
+ big, so at 2^29 sockets this value might wrap. When a process gets
+ the capability to actually handle over 500 million sockets this
+ calculation needs a integer overflow check. */
+ ufds = malloc(nfds * sizeof(struct pollfd));
+ if(!ufds)
+ return CURLM_OUT_OF_MEMORY;
+ ufds_malloc = TRUE;
}
+ nfds = 0;
- curl_nfds = cpfds.n; /* what curl internally uses in cpfds */
- /* Add external file descriptions from poll-like struct curl_waitfd */
- for(i = 0; i < extra_nfds; i++) {
- unsigned short events = 0;
- if(extra_fds[i].events & CURL_WAIT_POLLIN)
- events |= POLLIN;
- if(extra_fds[i].events & CURL_WAIT_POLLPRI)
- events |= POLLPRI;
- if(extra_fds[i].events & CURL_WAIT_POLLOUT)
- events |= POLLOUT;
- if(Curl_pollfds_add_sock(&cpfds, extra_fds[i].fd, events)) {
- result = CURLM_OUT_OF_MEMORY;
- goto out;
+ /* only do the second loop if we found descriptors in the first stage run
+ above */
+
+ if(curlfds) {
+ /* Add the curl handles to our pollfds first */
+ for(data = multi->easyp; data; data = data->next) {
+ multi_getsock(data, &ps);
+
+ for(i = 0; i < ps.num; i++) {
+ struct pollfd *ufd = &ufds[nfds++];
+#ifdef USE_WINSOCK
+ long mask = 0;
+#endif
+ ufd->fd = ps.sockets[i];
+ ufd->events = 0;
+ if(ps.actions[i] & CURL_POLL_IN) {
+#ifdef USE_WINSOCK
+ mask |= FD_READ|FD_ACCEPT|FD_CLOSE;
+#endif
+ ufd->events |= POLLIN;
+ }
+ if(ps.actions[i] & CURL_POLL_OUT) {
+#ifdef USE_WINSOCK
+ mask |= FD_WRITE|FD_CONNECT|FD_CLOSE;
+ reset_socket_fdwrite(ps.sockets[i]);
+#endif
+ ufd->events |= POLLOUT;
+ }
+#ifdef USE_WINSOCK
+ if(WSAEventSelect(ps.sockets[i], multi->wsa_event, mask) != 0) {
+ if(ufds_malloc)
+ free(ufds);
+ return CURLM_INTERNAL_ERROR;
+ }
+#endif
+ }
}
}
+ /* Add external file descriptions from poll-like struct curl_waitfd */
+ for(i = 0; i < extra_nfds; i++) {
#ifdef USE_WINSOCK
- /* Set the WSA events based on the collected pollds */
- for(i = 0; i < cpfds.n; i++) {
long mask = 0;
- if(cpfds.pfds[i].events & POLLIN)
+ if(extra_fds[i].events & CURL_WAIT_POLLIN)
mask |= FD_READ|FD_ACCEPT|FD_CLOSE;
- if(cpfds.pfds[i].events & POLLPRI)
+ if(extra_fds[i].events & CURL_WAIT_POLLPRI)
mask |= FD_OOB;
- if(cpfds.pfds[i].events & POLLOUT) {
+ if(extra_fds[i].events & CURL_WAIT_POLLOUT) {
mask |= FD_WRITE|FD_CONNECT|FD_CLOSE;
- reset_socket_fdwrite(cpfds.pfds[i].fd);
+ reset_socket_fdwrite(extra_fds[i].fd);
}
- if(mask) {
- if(WSAEventSelect(cpfds.pfds[i].fd, multi->wsa_event, mask) != 0) {
- result = CURLM_OUT_OF_MEMORY;
- goto out;
- }
+ if(WSAEventSelect(extra_fds[i].fd, multi->wsa_event, mask) != 0) {
+ if(ufds_malloc)
+ free(ufds);
+ return CURLM_INTERNAL_ERROR;
}
- }
#endif
+ ufds[nfds].fd = extra_fds[i].fd;
+ ufds[nfds].events = 0;
+ if(extra_fds[i].events & CURL_WAIT_POLLIN)
+ ufds[nfds].events |= POLLIN;
+ if(extra_fds[i].events & CURL_WAIT_POLLPRI)
+ ufds[nfds].events |= POLLPRI;
+ if(extra_fds[i].events & CURL_WAIT_POLLOUT)
+ ufds[nfds].events |= POLLOUT;
+ ++nfds;
+ }
#ifdef ENABLE_WAKEUP
#ifndef USE_WINSOCK
if(use_wakeup && multi->wakeup_pair[0] != CURL_SOCKET_BAD) {
- if(Curl_pollfds_add_sock(&cpfds, multi->wakeup_pair[0], POLLIN)) {
- result = CURLM_OUT_OF_MEMORY;
- goto out;
- }
+ ufds[nfds].fd = multi->wakeup_pair[0];
+ ufds[nfds].events = POLLIN;
+ ++nfds;
}
#endif
#endif
- /* We check the internal timeout *AFTER* we collected all sockets to
- * poll. Collecting the sockets may install new timers by protocols
- * and connection filters.
- * Use the shorter one of the internal and the caller requested timeout. */
- (void)multi_timeout(multi, &expire_time, &timeout_internal);
- if((timeout_internal >= 0) && (timeout_internal < (long)timeout_ms))
- timeout_ms = (int)timeout_internal;
-
#if defined(ENABLE_WAKEUP) && defined(USE_WINSOCK)
- if(cpfds.n || use_wakeup) {
+ if(nfds || use_wakeup) {
#else
- if(cpfds.n) {
+ if(nfds) {
#endif
int pollrc;
#ifdef USE_WINSOCK
- if(cpfds.n) /* just pre-check with Winsock */
- pollrc = Curl_poll(cpfds.pfds, cpfds.n, 0);
+ if(nfds)
+ pollrc = Curl_poll(ufds, nfds, 0); /* just pre-check with WinSock */
else
pollrc = 0;
#else
- pollrc = Curl_poll(cpfds.pfds, cpfds.n, timeout_ms); /* wait... */
+ pollrc = Curl_poll(ufds, nfds, timeout_ms); /* wait... */
#endif
- if(pollrc < 0) {
- result = CURLM_UNRECOVERABLE_POLL;
- goto out;
- }
+ if(pollrc < 0)
+ return CURLM_UNRECOVERABLE_POLL;
if(pollrc > 0) {
retcode = pollrc;
#ifdef USE_WINSOCK
}
else { /* now wait... if not ready during the pre-check (pollrc == 0) */
- WSAWaitForMultipleEvents(1, &multi->wsa_event, FALSE, (DWORD)timeout_ms,
- FALSE);
+ WSAWaitForMultipleEvents(1, &multi->wsa_event, FALSE, timeout_ms, FALSE);
}
- /* With Winsock, we have to run the following section unconditionally
+ /* With WinSock, we have to run the following section unconditionally
to call WSAEventSelect(fd, event, 0) on all the sockets */
{
#endif
@@ -1374,7 +1317,7 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
struct, the bit values of the actual underlying poll() implementation
may not be the same as the ones in the public libcurl API! */
for(i = 0; i < extra_nfds; i++) {
- unsigned r = (unsigned)cpfds.pfds[curl_nfds + i].revents;
+ unsigned r = ufds[curlfds + i].revents;
unsigned short mask = 0;
#ifdef USE_WINSOCK
curl_socket_t s = extra_fds[i].fd;
@@ -1391,7 +1334,7 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
}
WSAEventSelect(s, multi->wsa_event, 0);
if(!pollrc) {
- extra_fds[i].revents = (short)mask;
+ extra_fds[i].revents = mask;
continue;
}
#endif
@@ -1401,25 +1344,25 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
mask |= CURL_WAIT_POLLOUT;
if(r & POLLPRI)
mask |= CURL_WAIT_POLLPRI;
- extra_fds[i].revents = (short)mask;
+ extra_fds[i].revents = mask;
}
#ifdef USE_WINSOCK
/* Count up all our own sockets that had activity,
and remove them from the event. */
- if(curl_nfds) {
- for(e = Curl_llist_head(&multi->process); e && !result;
- e = Curl_node_next(e)) {
- struct Curl_easy *data = Curl_node_elem(e);
+ if(curlfds) {
+
+ for(data = multi->easyp; data; data = data->next) {
+ multi_getsock(data, &ps);
- for(i = 0; i < data->last_poll.num; i++) {
+ for(i = 0; i < ps.num; i++) {
wsa_events.lNetworkEvents = 0;
- if(WSAEnumNetworkEvents(data->last_poll.sockets[i], NULL,
+ if(WSAEnumNetworkEvents(ps.sockets[i], NULL,
&wsa_events) == 0) {
if(ret && !pollrc && wsa_events.lNetworkEvents)
retcode++;
}
- WSAEventSelect(data->last_poll.sockets[i], multi->wsa_event, 0);
+ WSAEventSelect(ps.sockets[i], multi->wsa_event, 0);
}
}
}
@@ -1428,7 +1371,7 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
#else
#ifdef ENABLE_WAKEUP
if(use_wakeup && multi->wakeup_pair[0] != CURL_SOCKET_BAD) {
- if(cpfds.pfds[curl_nfds + extra_nfds].revents & POLLIN) {
+ if(ufds[curlfds + extra_nfds].revents & POLLIN) {
char buf[64];
ssize_t nread;
while(1) {
@@ -1452,16 +1395,18 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
}
}
+ if(ufds_malloc)
+ free(ufds);
if(ret)
*ret = retcode;
#if defined(ENABLE_WAKEUP) && defined(USE_WINSOCK)
- if(extrawait && !cpfds.n && !use_wakeup) {
+ if(extrawait && !nfds && !use_wakeup) {
#else
- if(extrawait && !cpfds.n) {
+ if(extrawait && !nfds) {
#endif
long sleep_ms = 0;
- /* Avoid busy-looping when there is nothing particular to wait for */
+ /* Avoid busy-looping when there's nothing particular to wait for */
if(!curl_multi_timeout(multi, &sleep_ms) && sleep_ms) {
if(sleep_ms > timeout_ms)
sleep_ms = timeout_ms;
@@ -1473,9 +1418,7 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
}
}
-out:
- Curl_pollfds_cleanup(&cpfds);
- return result;
+ return CURLM_OK;
}
CURLMcode curl_multi_wait(struct Curl_multi *multi,
@@ -1504,15 +1447,6 @@ CURLMcode curl_multi_wakeup(struct Curl_multi *multi)
it has to be careful only to access parts of the
Curl_multi struct that are constant */
-#if defined(ENABLE_WAKEUP) && !defined(USE_WINSOCK)
-#ifdef USE_EVENTFD
- const void *buf;
- const uint64_t val = 1;
-#else
- char buf[1];
-#endif
-#endif
-
/* GOOD_MULTI_HANDLE can be safely called */
if(!GOOD_MULTI_HANDLE(multi))
return CURLM_BAD_HANDLE;
@@ -1526,11 +1460,8 @@ CURLMcode curl_multi_wakeup(struct Curl_multi *multi)
making it safe to access from another thread after the init part
and before cleanup */
if(multi->wakeup_pair[1] != CURL_SOCKET_BAD) {
-#ifdef USE_EVENTFD
- buf = &val;
-#else
+ char buf[1];
buf[0] = 1;
-#endif
while(1) {
/* swrite() is not thread-safe in general, because concurrent calls
can have their messages interleaved, but in this case the content
@@ -1539,7 +1470,7 @@ CURLMcode curl_multi_wakeup(struct Curl_multi *multi)
The write socket is set to non-blocking, this way this function
cannot block, making it safe to call even from the same thread
that will call curl_multi_wait(). If swrite() returns that it
- would block, it is considered successful because it means that
+ would block, it's considered successful because it means that
previous calls to this function will wake up the poll(). */
if(wakeup_write(multi->wakeup_pair[1], buf, sizeof(buf)) < 0) {
int err = SOCKERRNO;
@@ -1603,7 +1534,7 @@ CURLMcode Curl_multi_add_perform(struct Curl_multi *multi,
if(!rc) {
struct SingleRequest *k = &data->req;
- /* pass in NULL for 'conn' here since we do not want to init the
+ /* pass in NULL for 'conn' here since we don't want to init the
connection, only this transfer */
Curl_init_do(data, NULL);
@@ -1635,7 +1566,7 @@ static CURLcode multi_do(struct Curl_easy *data, bool *done)
* second connection.
*
* 'complete' can return 0 for incomplete, 1 for done and -1 for go back to
- * DOING state there is more work to do!
+ * DOING state there's more work to do!
*/
static CURLcode multi_do_more(struct Curl_easy *data, int *complete)
@@ -1660,47 +1591,47 @@ static bool multi_handle_timeout(struct Curl_easy *data,
CURLcode *result,
bool connect_timeout)
{
- timediff_t timeout_ms = Curl_timeleft(data, now, connect_timeout);
+ timediff_t timeout_ms;
+ timeout_ms = Curl_timeleft(data, now, connect_timeout);
+
if(timeout_ms < 0) {
/* Handle timed out */
- struct curltime since;
- if(connect_timeout)
- since = data->progress.t_startsingle;
- else
- since = data->progress.t_startop;
if(data->mstate == MSTATE_RESOLVING)
- failf(data, "Resolving timed out after %" FMT_TIMEDIFF_T
- " milliseconds", Curl_timediff(*now, since));
+ failf(data, "Resolving timed out after %" CURL_FORMAT_TIMEDIFF_T
+ " milliseconds",
+ Curl_timediff(*now, data->progress.t_startsingle));
else if(data->mstate == MSTATE_CONNECTING)
- failf(data, "Connection timed out after %" FMT_TIMEDIFF_T
- " milliseconds", Curl_timediff(*now, since));
+ failf(data, "Connection timed out after %" CURL_FORMAT_TIMEDIFF_T
+ " milliseconds",
+ Curl_timediff(*now, data->progress.t_startsingle));
else {
struct SingleRequest *k = &data->req;
if(k->size != -1) {
- failf(data, "Operation timed out after %" FMT_TIMEDIFF_T
- " milliseconds with %" FMT_OFF_T " out of %"
- FMT_OFF_T " bytes received",
- Curl_timediff(*now, since), k->bytecount, k->size);
+ failf(data, "Operation timed out after %" CURL_FORMAT_TIMEDIFF_T
+ " milliseconds with %" CURL_FORMAT_CURL_OFF_T " out of %"
+ CURL_FORMAT_CURL_OFF_T " bytes received",
+ Curl_timediff(*now, data->progress.t_startsingle),
+ k->bytecount, k->size);
}
else {
- failf(data, "Operation timed out after %" FMT_TIMEDIFF_T
- " milliseconds with %" FMT_OFF_T " bytes received",
- Curl_timediff(*now, since), k->bytecount);
+ failf(data, "Operation timed out after %" CURL_FORMAT_TIMEDIFF_T
+ " milliseconds with %" CURL_FORMAT_CURL_OFF_T
+ " bytes received",
+ Curl_timediff(*now, data->progress.t_startsingle),
+ k->bytecount);
}
}
- *result = CURLE_OPERATION_TIMEDOUT;
- if(data->conn) {
- /* Force connection closed if the connection has indeed been used */
- if(data->mstate > MSTATE_DO) {
- streamclose(data->conn, "Disconnect due to timeout");
- *stream_error = TRUE;
- }
- (void)multi_done(data, *result, TRUE);
+
+ /* Force connection closed if the connection has indeed been used */
+ if(data->mstate > MSTATE_DO) {
+ streamclose(data->conn, "Disconnected with pending data");
+ *stream_error = TRUE;
}
- return TRUE;
+ *result = CURLE_OPERATION_TIMEDOUT;
+ (void)multi_done(data, *result, TRUE);
}
- return FALSE;
+ return (timeout_ms < 0);
}
/*
@@ -1763,10 +1694,10 @@ static CURLcode protocol_connect(struct Curl_easy *data,
&& conn->bits.protoconnstart) {
/* We already are connected, get back. This may happen when the connect
worked fine in the first call, like when we connect to a local server
- or proxy. Note that we do not know if the protocol is actually done.
+ or proxy. Note that we don't know if the protocol is actually done.
- Unless this protocol does not have any protocol-connect callback, as
- then we know we are done. */
+ Unless this protocol doesn't have any protocol-connect callback, as
+ then we know we're done. */
if(!conn->handler->connecting)
*protocol_done = TRUE;
@@ -1783,7 +1714,7 @@ static CURLcode protocol_connect(struct Curl_easy *data,
else
*protocol_done = TRUE;
- /* it has started, possibly even completed but that knowledge is not stored
+ /* it has started, possibly even completed but that knowledge isn't stored
in this bit! */
if(!result)
conn->bits.protoconnstart = TRUE;
@@ -1792,23 +1723,108 @@ static CURLcode protocol_connect(struct Curl_easy *data,
return result; /* pass back status */
}
-static void set_in_callback(struct Curl_multi *multi, bool value)
+/*
+ * readrewind() rewinds the read stream. This is typically used for HTTP
+ * POST/PUT with multi-pass authentication when a sending was denied and a
+ * resend is necessary.
+ */
+static CURLcode readrewind(struct Curl_easy *data)
{
- multi->in_callback = value;
+ curl_mimepart *mimepart = &data->set.mimepost;
+ DEBUGASSERT(data->conn);
+
+ data->state.rewindbeforesend = FALSE; /* we rewind now */
+
+ /* explicitly switch off sending data on this connection now since we are
+ about to restart a new transfer and thus we want to avoid inadvertently
+ sending more data on the existing connection until the next transfer
+ starts */
+ data->req.keepon &= ~KEEP_SEND;
+
+ /* We have sent away data. If not using CURLOPT_POSTFIELDS or
+ CURLOPT_HTTPPOST, call app to rewind
+ */
+#ifndef CURL_DISABLE_HTTP
+ if(data->conn->handler->protocol & PROTO_FAMILY_HTTP) {
+ if(data->state.mimepost)
+ mimepart = data->state.mimepost;
+ }
+#endif
+ if(data->set.postfields ||
+ (data->state.httpreq == HTTPREQ_GET) ||
+ (data->state.httpreq == HTTPREQ_HEAD))
+ ; /* no need to rewind */
+ else if(data->state.httpreq == HTTPREQ_POST_MIME ||
+ data->state.httpreq == HTTPREQ_POST_FORM) {
+ CURLcode result = Curl_mime_rewind(mimepart);
+ if(result) {
+ failf(data, "Cannot rewind mime/post data");
+ return result;
+ }
+ }
+ else {
+ if(data->set.seek_func) {
+ int err;
+
+ Curl_set_in_callback(data, true);
+ err = (data->set.seek_func)(data->set.seek_client, 0, SEEK_SET);
+ Curl_set_in_callback(data, false);
+ if(err) {
+ failf(data, "seek callback returned error %d", (int)err);
+ return CURLE_SEND_FAIL_REWIND;
+ }
+ }
+ else if(data->set.ioctl_func) {
+ curlioerr err;
+
+ Curl_set_in_callback(data, true);
+ err = (data->set.ioctl_func)(data, CURLIOCMD_RESTARTREAD,
+ data->set.ioctl_client);
+ Curl_set_in_callback(data, false);
+ infof(data, "the ioctl callback returned %d", (int)err);
+
+ if(err) {
+ failf(data, "ioctl callback returned error %d", (int)err);
+ return CURLE_SEND_FAIL_REWIND;
+ }
+ }
+ else {
+ /* If no CURLOPT_READFUNCTION is used, we know that we operate on a
+ given FILE * stream and we can actually attempt to rewind that
+ ourselves with fseek() */
+ if(data->state.fread_func == (curl_read_callback)fread) {
+ if(-1 != fseek(data->state.in, 0, SEEK_SET))
+ /* successful rewind */
+ return CURLE_OK;
+ }
+
+ /* no callback set or failure above, makes us fail at once */
+ failf(data, "necessary data rewind wasn't possible");
+ return CURLE_SEND_FAIL_REWIND;
+ }
+ }
+ return CURLE_OK;
}
/*
- * posttransfer() is called immediately after a transfer ends
+ * Curl_preconnect() is called immediately before a connect starts. When a
+ * redirect is followed, this is then called multiple times during a single
+ * transfer.
*/
-static void multi_posttransfer(struct Curl_easy *data)
+CURLcode Curl_preconnect(struct Curl_easy *data)
{
-#if defined(HAVE_SIGNAL) && defined(SIGPIPE) && !defined(HAVE_MSG_NOSIGNAL)
- /* restore the signal handler for SIGPIPE before we get back */
- if(!data->set.no_signal)
- signal(SIGPIPE, data->state.prev_signal);
-#else
- (void)data; /* unused parameter */
-#endif
+ if(!data->state.buffer) {
+ data->state.buffer = malloc(data->set.buffer_size + 1);
+ if(!data->state.buffer)
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ return CURLE_OK;
+}
+
+static void set_in_callback(struct Curl_multi *multi, bool value)
+{
+ multi->in_callback = value;
}
static CURLMcode multi_runsingle(struct Curl_multi *multi,
@@ -1820,6 +1836,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
bool async;
bool protocol_connected = FALSE;
bool dophase_done = FALSE;
+ bool done = FALSE;
CURLMcode rc;
CURLcode result = CURLE_OK;
timediff_t recv_timeout_ms;
@@ -1833,7 +1850,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
/* a multi-level callback returned error before, meaning every individual
transfer now has failed */
result = CURLE_ABORTED_BY_CALLBACK;
- multi_posttransfer(data);
+ Curl_posttransfer(data);
multi_done(data, result, FALSE);
multistate(data, MSTATE_COMPLETED);
}
@@ -1859,63 +1876,74 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
return CURLM_INTERNAL_ERROR;
}
- /* Wait for the connect state as only then is the start time stored, but
- we must not check already completed handles */
- if((data->mstate >= MSTATE_CONNECT) && (data->mstate < MSTATE_COMPLETED) &&
- multi_handle_timeout(data, nowp, &stream_error, &result, FALSE))
- /* Skip the statemachine and go directly to error handling section. */
- goto statemachine_end;
+ if(data->conn &&
+ (data->mstate >= MSTATE_CONNECT) &&
+ (data->mstate < MSTATE_COMPLETED)) {
+ /* Check for overall operation timeout here but defer handling the
+ * connection timeout to later, to allow for a connection to be set up
+ * in the window since we last checked timeout. This prevents us
+ * tearing down a completed connection in the case where we were slow
+ * to check the timeout (e.g. process descheduled during this loop).
+ * We set connect_timeout=FALSE to do this. */
+
+ /* we need to wait for the connect state as only then is the start time
+ stored, but we must not check already completed handles */
+ if(multi_handle_timeout(data, nowp, &stream_error, &result, FALSE)) {
+ /* Skip the statemachine and go directly to error handling section. */
+ goto statemachine_end;
+ }
+ }
switch(data->mstate) {
case MSTATE_INIT:
- /* Transitional state. init this transfer. A handle never comes
- back to this state. */
+ /* init this transfer. */
result = Curl_pretransfer(data);
+
+ if(!result) {
+ /* after init, go CONNECT */
+ multistate(data, MSTATE_CONNECT);
+ *nowp = Curl_pgrsTime(data, TIMER_STARTOP);
+ rc = CURLM_CALL_MULTI_PERFORM;
+ }
+ break;
+
+ case MSTATE_CONNECT:
+ /* Connect. We want to get a connection identifier filled in. */
+ /* init this transfer. */
+ result = Curl_preconnect(data);
if(result)
break;
- /* after init, go SETUP */
- multistate(data, MSTATE_SETUP);
- (void)Curl_pgrsTime(data, TIMER_STARTOP);
- FALLTHROUGH();
-
- case MSTATE_SETUP:
- /* Transitional state. Setup things for a new transfer. The handle
- can come back to this state on a redirect. */
*nowp = Curl_pgrsTime(data, TIMER_STARTSINGLE);
if(data->set.timeout)
Curl_expire(data, data->set.timeout, EXPIRE_TIMEOUT);
+
if(data->set.connecttimeout)
- /* Since a connection might go to pending and back to CONNECT several
- times before it actually takes off, we need to set the timeout once
- in SETUP before we enter CONNECT the first time. */
Curl_expire(data, data->set.connecttimeout, EXPIRE_CONNECTTIMEOUT);
- multistate(data, MSTATE_CONNECT);
- FALLTHROUGH();
-
- case MSTATE_CONNECT:
- /* Connect. We want to get a connection identifier filled in. This state
- can be entered from SETUP and from PENDING. */
result = Curl_connect(data, &async, &connected);
if(CURLE_NO_CONNECTION_AVAILABLE == result) {
/* There was no connection available. We will go to the pending
state and wait for an available connection. */
multistate(data, MSTATE_PENDING);
- /* unlink from process list */
- Curl_node_remove(&data->multi_queue);
- /* add handle to pending list */
- Curl_llist_append(&multi->pending, data, &data->multi_queue);
+
+ /* add this handle to the list of connect-pending handles */
+ Curl_llist_insert_next(&multi->pending, multi->pending.tail, data,
+ &data->connect_queue);
+ /* unlink from the main list */
+ unlink_easy(multi, data);
result = CURLE_OK;
break;
}
- else
+ else if(data->state.previouslypending) {
+ /* this transfer comes from the pending queue so try move another */
+ infof(data, "Transfer was pending, now try another");
process_pending_handles(data->multi);
+ }
if(!result) {
- *nowp = Curl_pgrsTime(data, TIMER_POSTQUEUE);
if(async)
- /* We are now waiting for an asynchronous name lookup */
+ /* We're now waiting for an asynchronous name lookup */
multistate(data, MSTATE_RESOLVING);
else {
/* after the connect has been sent off, go WAITCONNECT unless the
@@ -1923,14 +1951,8 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
WAITDO or DO! */
rc = CURLM_CALL_MULTI_PERFORM;
- if(connected) {
- if(!data->conn->bits.reuse &&
- Curl_conn_is_multiplex(data->conn, FIRSTSOCKET)) {
- /* new connection, can multiplex, wake pending handles */
- process_pending_handles(data->multi);
- }
+ if(connected)
multistate(data, MSTATE_PROTOCONNECT);
- }
else {
multistate(data, MSTATE_CONNECTING);
}
@@ -1957,12 +1979,12 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
hostname = conn->host.name;
/* check if we have the name resolved by now */
- dns = Curl_fetch_addr(data, hostname, conn->primary.remote_port);
+ dns = Curl_fetch_addr(data, hostname, (int)conn->port);
if(dns) {
#ifdef CURLRES_ASYNCH
- data->state.async.dns = dns;
- data->state.async.done = TRUE;
+ conn->resolve_async.dns = dns;
+ conn->resolve_async.done = TRUE;
#endif
result = CURLE_OK;
infof(data, "Hostname '%s' was found in DNS cache", hostname);
@@ -1974,7 +1996,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
/* Update sockets here, because the socket(s) may have been
closed and the application thus needs to be told, even if it
is likely that the same socket(s) will again be used further
- down. If the name has not yet been resolved, it is likely
+ down. If the name has not yet been resolved, it is likely
that new sockets have been opened in an attempt to contact
another resolver. */
rc = singlesocket(multi, data);
@@ -2014,12 +2036,22 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
/* this is HTTP-specific, but sending CONNECT to a proxy is HTTP... */
DEBUGASSERT(data->conn);
result = Curl_http_connect(data, &protocol_connected);
- if(!result) {
+#ifndef CURL_DISABLE_PROXY
+ if(data->conn->bits.proxy_connect_closed) {
rc = CURLM_CALL_MULTI_PERFORM;
- /* initiate protocol connect phase */
- multistate(data, MSTATE_PROTOCONNECT);
+ /* connect back to proxy again */
+ result = CURLE_OK;
+ multi_done(data, CURLE_OK, FALSE);
+ multistate(data, MSTATE_CONNECT);
}
else
+#endif
+ if(!result) {
+ rc = CURLM_CALL_MULTI_PERFORM;
+ /* initiate protocol connect phase */
+ multistate(data, MSTATE_PROTOCONNECT);
+ }
+ else
stream_error = TRUE;
break;
#endif
@@ -2029,17 +2061,12 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
DEBUGASSERT(data->conn);
result = Curl_conn_connect(data, FIRSTSOCKET, FALSE, &connected);
if(connected && !result) {
- if(!data->conn->bits.reuse &&
- Curl_conn_is_multiplex(data->conn, FIRSTSOCKET)) {
- /* new connection, can multiplex, wake pending handles */
- process_pending_handles(data->multi);
- }
rc = CURLM_CALL_MULTI_PERFORM;
multistate(data, MSTATE_PROTOCONNECT);
}
else if(result) {
/* failure detected */
- multi_posttransfer(data);
+ Curl_posttransfer(data);
multi_done(data, result, TRUE);
stream_error = TRUE;
break;
@@ -2047,6 +2074,9 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
break;
case MSTATE_PROTOCONNECT:
+ if(data->state.rewindbeforesend)
+ result = readrewind(data);
+
if(!result && data->conn->bits.reuse) {
/* ftp seems to hang when protoconnect on reused connection
* since we handle PROTOCONNECT in general inside the filers, it
@@ -2069,7 +2099,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
}
else {
/* failure detected */
- multi_posttransfer(data);
+ Curl_posttransfer(data);
multi_done(data, result, TRUE);
stream_error = TRUE;
}
@@ -2085,7 +2115,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
}
else if(result) {
/* failure detected */
- multi_posttransfer(data);
+ Curl_posttransfer(data);
multi_done(data, result, TRUE);
stream_error = TRUE;
}
@@ -2098,17 +2128,16 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
/* call the prerequest callback function */
Curl_set_in_callback(data, true);
prereq_rc = data->set.fprereq(data->set.prereq_userp,
- data->info.primary.remote_ip,
- data->info.primary.local_ip,
- data->info.primary.remote_port,
- data->info.primary.local_port);
+ data->info.conn_primary_ip,
+ data->info.conn_local_ip,
+ data->info.conn_primary_port,
+ data->info.conn_local_port);
Curl_set_in_callback(data, false);
if(prereq_rc != CURL_PREREQFUNC_OK) {
failf(data, "operation aborted by pre-request callback");
- /* failure in pre-request callback - do not do any other
- processing */
+ /* failure in pre-request callback - don't do any other processing */
result = CURLE_ABORTED_BY_CALLBACK;
- multi_posttransfer(data);
+ Curl_posttransfer(data);
multi_done(data, result, FALSE);
stream_error = TRUE;
break;
@@ -2138,7 +2167,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
/* skip some states if it is important */
multi_done(data, CURLE_OK, FALSE);
- /* if there is no connection left, skip the DONE state */
+ /* if there's no connection left, skip the DONE state */
multistate(data, data->conn ?
MSTATE_DONE : MSTATE_COMPLETED);
rc = CURLM_CALL_MULTI_PERFORM;
@@ -2154,13 +2183,13 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
/* after DO, go DO_DONE... or DO_MORE */
else if(data->conn->bits.do_more) {
- /* we are supposed to do more, but we need to sit down, relax
+ /* we're supposed to do more, but we need to sit down, relax
and wait a little while first */
multistate(data, MSTATE_DOING_MORE);
rc = CURLM_CALL_MULTI_PERFORM;
}
else {
- /* we are done with the DO, now DID */
+ /* we're done with the DO, now DID */
multistate(data, MSTATE_DID);
rc = CURLM_CALL_MULTI_PERFORM;
}
@@ -2169,7 +2198,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
data->conn->bits.reuse) {
/*
* In this situation, a connection that we were trying to use
- * may have unexpectedly died. If possible, send the connection
+ * may have unexpectedly died. If possible, send the connection
* back to the CONNECT phase so we can try again.
*/
char *newurl = NULL;
@@ -2183,7 +2212,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
stream_error = TRUE;
}
- multi_posttransfer(data);
+ Curl_posttransfer(data);
drc = multi_done(data, result, FALSE);
/* When set to retry the connection, we must go back to the CONNECT
@@ -2193,7 +2222,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
follow = FOLLOW_RETRY;
drc = Curl_follow(data, newurl, follow);
if(!drc) {
- multistate(data, MSTATE_SETUP);
+ multistate(data, MSTATE_CONNECT);
rc = CURLM_CALL_MULTI_PERFORM;
result = CURLE_OK;
}
@@ -2203,19 +2232,19 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
}
}
else {
- /* done did not return OK or SEND_ERROR */
+ /* done didn't return OK or SEND_ERROR */
result = drc;
}
}
else {
- /* Have error handler disconnect conn if we cannot retry */
+ /* Have error handler disconnect conn if we can't retry */
stream_error = TRUE;
}
free(newurl);
}
else {
/* failure detected */
- multi_posttransfer(data);
+ Curl_posttransfer(data);
if(data->conn)
multi_done(data, result, FALSE);
stream_error = TRUE;
@@ -2237,7 +2266,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
}
else {
/* failure detected */
- multi_posttransfer(data);
+ Curl_posttransfer(data);
multi_done(data, result, FALSE);
stream_error = TRUE;
}
@@ -2263,7 +2292,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
}
else {
/* failure detected */
- multi_posttransfer(data);
+ Curl_posttransfer(data);
multi_done(data, result, FALSE);
stream_error = TRUE;
}
@@ -2275,7 +2304,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
/* Check if we can move pending requests to send pipe */
process_pending_handles(multi); /* multiplexed */
- /* Only perform the transfer if there is a good socket to work with.
+ /* Only perform the transfer if there's a good socket to work with.
Having both BAD is a signal to skip immediately to DONE */
if((data->conn->sockfd != CURL_SOCKET_BAD) ||
(data->conn->writesockfd != CURL_SOCKET_BAD))
@@ -2305,29 +2334,31 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
result != CURLE_HTTP2_STREAM)
streamclose(data->conn, "Transfer returned error");
- multi_posttransfer(data);
+ Curl_posttransfer(data);
multi_done(data, result, TRUE);
}
else {
send_timeout_ms = 0;
if(data->set.max_send_speed)
send_timeout_ms =
- Curl_pgrsLimitWaitTime(&data->progress.ul,
+ Curl_pgrsLimitWaitTime(data->progress.uploaded,
+ data->progress.ul_limit_size,
data->set.max_send_speed,
+ data->progress.ul_limit_start,
*nowp);
recv_timeout_ms = 0;
if(data->set.max_recv_speed)
recv_timeout_ms =
- Curl_pgrsLimitWaitTime(&data->progress.dl,
+ Curl_pgrsLimitWaitTime(data->progress.downloaded,
+ data->progress.dl_limit_size,
data->set.max_recv_speed,
+ data->progress.dl_limit_start,
*nowp);
if(!send_timeout_ms && !recv_timeout_ms) {
multistate(data, MSTATE_PERFORMING);
Curl_ratelimit(data, *nowp);
- /* start performing again right away */
- rc = CURLM_CALL_MULTI_PERFORM;
}
else if(send_timeout_ms >= recv_timeout_ms)
Curl_expire(data, send_timeout_ms, EXPIRE_TOOFAST);
@@ -2340,18 +2371,24 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
{
char *newurl = NULL;
bool retry = FALSE;
+ bool comeback = FALSE;
+ DEBUGASSERT(data->state.buffer);
/* check if over send speed */
send_timeout_ms = 0;
if(data->set.max_send_speed)
- send_timeout_ms = Curl_pgrsLimitWaitTime(&data->progress.ul,
+ send_timeout_ms = Curl_pgrsLimitWaitTime(data->progress.uploaded,
+ data->progress.ul_limit_size,
data->set.max_send_speed,
+ data->progress.ul_limit_start,
*nowp);
/* check if over recv speed */
recv_timeout_ms = 0;
if(data->set.max_recv_speed)
- recv_timeout_ms = Curl_pgrsLimitWaitTime(&data->progress.dl,
+ recv_timeout_ms = Curl_pgrsLimitWaitTime(data->progress.downloaded,
+ data->progress.dl_limit_size,
data->set.max_recv_speed,
+ data->progress.dl_limit_start,
*nowp);
if(send_timeout_ms || recv_timeout_ms) {
@@ -2365,9 +2402,9 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
}
/* read/write data if it is ready to do so */
- result = Curl_sendrecv(data, nowp);
+ result = Curl_readwrite(data->conn, data, &done, &comeback);
- if(data->req.done || (result == CURLE_RECV_ERROR)) {
+ if(done || (result == CURLE_RECV_ERROR)) {
/* If CURLE_RECV_ERROR happens early enough, we assume it was a race
* condition and the server closed the reused connection exactly when
* we wanted to use it, so figure out if that is indeed the case.
@@ -2382,7 +2419,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
/* if we are to retry, set the result to OK and consider the
request as done */
result = CURLE_OK;
- data->req.done = TRUE;
+ done = TRUE;
}
}
else if((CURLE_HTTP2_STREAM == result) &&
@@ -2402,7 +2439,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
as done */
retry = TRUE;
result = CURLE_OK;
- data->req.done = TRUE;
+ done = TRUE;
}
else
result = ret;
@@ -2411,8 +2448,8 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
if(result) {
/*
* The transfer phase returned error, we mark the connection to get
- * closed to prevent being reused. This is because we cannot possibly
- * know if the connection is in a good shape or not now. Unless it is
+ * closed to prevent being reused. This is because we can't possibly
+ * know if the connection is in a good shape or not now. Unless it is
* a protocol which uses two "channels" like FTP, as then the error
* happened in the data connection.
*/
@@ -2421,13 +2458,13 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
result != CURLE_HTTP2_STREAM)
streamclose(data->conn, "Transfer returned error");
- multi_posttransfer(data);
+ Curl_posttransfer(data);
multi_done(data, result, TRUE);
}
- else if(data->req.done && !Curl_cwriter_is_paused(data)) {
+ else if(done) {
/* call this even if the readwrite function returned error */
- multi_posttransfer(data);
+ Curl_posttransfer(data);
/* When we follow redirects or is set to retry the connection, we must
to go back to the CONNECT state */
@@ -2447,20 +2484,22 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
/* multi_done() might return CURLE_GOT_NOTHING */
result = Curl_follow(data, newurl, follow);
if(!result) {
- multistate(data, MSTATE_SETUP);
+ multistate(data, MSTATE_CONNECT);
rc = CURLM_CALL_MULTI_PERFORM;
}
+ free(newurl);
}
else {
/* after the transfer is done, go DONE */
- /* but first check to see if we got a location info even though we
- are not following redirects */
+ /* but first check to see if we got a location info even though we're
+ not following redirects */
if(data->req.location) {
free(newurl);
newurl = data->req.location;
data->req.location = NULL;
result = Curl_follow(data, newurl, FOLLOW_FAKE);
+ free(newurl);
if(result) {
stream_error = TRUE;
result = multi_done(data, result, TRUE);
@@ -2473,13 +2512,12 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
}
}
}
- else if(data->state.select_bits && !Curl_xfer_is_blocked(data)) {
+ else if(comeback) {
/* This avoids CURLM_CALL_MULTI_PERFORM so that a very fast transfer
- will not get stuck on this transfer at the expense of other
- concurrent transfers */
+ won't get stuck on this transfer at the expense of other concurrent
+ transfers */
Curl_expire(data, 0, EXPIRE_RUN_NOW);
}
- free(newurl);
break;
}
@@ -2490,6 +2528,10 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
if(data->conn) {
CURLcode res;
+ if(data->conn->bits.multiplex)
+ /* Check if we can move pending requests to connection */
+ process_pending_handles(multi); /* multiplexing */
+
/* post-transfer command */
res = multi_done(data, result, FALSE);
@@ -2508,8 +2550,8 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
}
}
#endif
- /* after we have DONE what we are supposed to do, go COMPLETED, and
- it does not matter what the multi_done() returned! */
+ /* after we have DONE what we're supposed to do, go COMPLETED, and
+ it doesn't matter what the multi_done() returned! */
multistate(data, MSTATE_COMPLETED);
break;
@@ -2526,7 +2568,8 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
return CURLM_INTERNAL_ERROR;
}
- if(data->mstate >= MSTATE_CONNECT &&
+ if(data->conn &&
+ data->mstate >= MSTATE_CONNECT &&
data->mstate < MSTATE_DO &&
rc != CURLM_CALL_MULTI_PERFORM &&
!multi_ischanged(multi, false)) {
@@ -2536,7 +2579,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
* (i.e. CURLM_CALL_MULTI_PERFORM == TRUE) then we should do that before
* declaring the connection timed out as we may almost have a completed
* connection. */
- multi_handle_timeout(data, nowp, &stream_error, &result, FALSE);
+ multi_handle_timeout(data, nowp, &stream_error, &result, TRUE);
}
statemachine_end:
@@ -2544,7 +2587,7 @@ statemachine_end:
if(data->mstate < MSTATE_COMPLETED) {
if(result) {
/*
- * If an error was returned, and we are not in completed state now,
+ * If an error was returned, and we aren't in completed state now,
* then we go to completed and consider this transfer aborted.
*/
@@ -2556,27 +2599,31 @@ statemachine_end:
if(data->conn) {
if(stream_error) {
- /* Do not attempt to send data over a connection that timed out */
+ /* Don't attempt to send data over a connection that timed out */
bool dead_connection = result == CURLE_OPERATION_TIMEDOUT;
struct connectdata *conn = data->conn;
/* This is where we make sure that the conn pointer is reset.
- We do not have to do this in every case block above where a
+ We don't have to do this in every case block above where a
failure is detected */
Curl_detach_connection(data);
- Curl_cpool_disconnect(data, conn, dead_connection);
+
+ /* remove connection from cache */
+ Curl_conncache_remove_conn(data, conn, TRUE);
+
+ /* disconnect properly */
+ Curl_disconnect(data, conn, dead_connection);
}
}
else if(data->mstate == MSTATE_CONNECT) {
/* Curl_connect() failed */
- multi_posttransfer(data);
- Curl_pgrsUpdate_nometer(data);
+ (void)Curl_posttransfer(data);
}
multistate(data, MSTATE_COMPLETED);
rc = CURLM_CALL_MULTI_PERFORM;
}
- /* if there is still a connection to use, call the progress function */
+ /* if there's still a connection to use, call the progress function */
else if(data->conn && Curl_pgrsUpdate(data)) {
/* aborted due to progress callback return code must close the
connection */
@@ -2608,10 +2655,11 @@ statemachine_end:
}
multistate(data, MSTATE_MSGSENT);
- /* unlink from the process list */
- Curl_node_remove(&data->multi_queue);
- /* add this handle msgsent list */
- Curl_llist_append(&multi->msgsent, data, &data->multi_queue);
+ /* add this handle to the list of msgsent handles */
+ Curl_llist_insert_next(&multi->msgsent, multi->msgsent.tail, data,
+ &data->connect_queue);
+ /* unlink from the main list */
+ unlink_easy(multi, data);
return CURLM_OK;
}
} while((rc == CURLM_CALL_MULTI_PERFORM) || multi_ischanged(multi, FALSE));
@@ -2623,12 +2671,10 @@ statemachine_end:
CURLMcode curl_multi_perform(struct Curl_multi *multi, int *running_handles)
{
+ struct Curl_easy *data;
CURLMcode returncode = CURLM_OK;
- struct Curl_tree *t = NULL;
+ struct Curl_tree *t;
struct curltime now = Curl_now();
- struct Curl_llist_node *e;
- struct Curl_llist_node *n = NULL;
- SIGPIPE_VARIABLE(pipe_st);
if(!GOOD_MULTI_HANDLE(multi))
return CURLM_BAD_HANDLE;
@@ -2636,31 +2682,31 @@ CURLMcode curl_multi_perform(struct Curl_multi *multi, int *running_handles)
if(multi->in_callback)
return CURLM_RECURSIVE_API_CALL;
- sigpipe_init(&pipe_st);
- for(e = Curl_llist_head(&multi->process); e; e = n) {
- struct Curl_easy *data = Curl_node_elem(e);
+ data = multi->easyp;
+ if(data) {
CURLMcode result;
+ bool nosig = data->set.no_signal;
+ SIGPIPE_VARIABLE(pipe_st);
+ sigpipe_ignore(data, &pipe_st);
/* Do the loop and only alter the signal ignore state if the next handle
has a different NO_SIGNAL state than the previous */
-
- /* the current node might be unlinked in multi_runsingle(), get the next
- pointer now */
- n = Curl_node_next(e);
-
- if(data != multi->cpool.idata) {
- /* connection pool handle is processed below */
- sigpipe_apply(data, &pipe_st);
+ do {
+ /* the current node might be unlinked in multi_runsingle(), get the next
+ pointer now */
+ struct Curl_easy *datanext = data->next;
+ if(data->set.no_signal != nosig) {
+ sigpipe_restore(&pipe_st);
+ sigpipe_ignore(data, &pipe_st);
+ nosig = data->set.no_signal;
+ }
result = multi_runsingle(multi, &now, data);
if(result)
returncode = result;
- }
+ data = datanext; /* operate on next handle */
+ } while(data);
+ sigpipe_restore(&pipe_st);
}
- sigpipe_apply(multi->cpool.idata, &pipe_st);
- Curl_cpool_multi_perform(multi);
-
- sigpipe_restore(&pipe_st);
-
/*
* Simply remove all expired timers from the splay since handles are dealt
* with unconditionally by this function and curl_multi_timeout() requires
@@ -2673,24 +2719,13 @@ CURLMcode curl_multi_perform(struct Curl_multi *multi, int *running_handles)
*/
do {
multi->timetree = Curl_splaygetbest(now, multi->timetree, &t);
- if(t) {
+ if(t)
/* the removed may have another timeout in queue */
- struct Curl_easy *data = Curl_splayget(t);
- if(data->mstate == MSTATE_PENDING) {
- bool stream_unused;
- CURLcode result_unused;
- if(multi_handle_timeout(data, &now, &stream_unused, &result_unused,
- FALSE)) {
- infof(data, "PENDING handle timeout");
- move_pending_to_connect(multi, data);
- }
- }
- (void)add_next_timeout(now, multi, Curl_splayget(t));
- }
+ (void)add_next_timeout(now, multi, t->payload);
+
} while(t);
- if(running_handles)
- *running_handles = (int)multi->num_alive;
+ *running_handles = multi->num_alive;
if(CURLM_OK >= returncode)
returncode = Curl_update_timer(multi);
@@ -2698,45 +2733,35 @@ CURLMcode curl_multi_perform(struct Curl_multi *multi, int *running_handles)
return returncode;
}
-/* unlink_all_msgsent_handles() moves all nodes back from the msgsent list to
- the process list */
+/* unlink_all_msgsent_handles() detaches all those easy handles from this
+ multi handle */
static void unlink_all_msgsent_handles(struct Curl_multi *multi)
{
- struct Curl_llist_node *e;
- for(e = Curl_llist_head(&multi->msgsent); e; e = Curl_node_next(e)) {
- struct Curl_easy *data = Curl_node_elem(e);
- if(data) {
- DEBUGASSERT(data->mstate == MSTATE_MSGSENT);
- Curl_node_remove(&data->multi_queue);
- /* put it into the process list */
- Curl_llist_append(&multi->process, data, &data->multi_queue);
- }
+ struct Curl_llist_element *e = multi->msgsent.head;
+ if(e) {
+ struct Curl_easy *data = e->ptr;
+ DEBUGASSERT(data->mstate == MSTATE_MSGSENT);
+ data->multi = NULL;
}
}
CURLMcode curl_multi_cleanup(struct Curl_multi *multi)
{
+ struct Curl_easy *data;
+ struct Curl_easy *nextdata;
+
if(GOOD_MULTI_HANDLE(multi)) {
- struct Curl_llist_node *e;
- struct Curl_llist_node *n;
if(multi->in_callback)
return CURLM_RECURSIVE_API_CALL;
multi->magic = 0; /* not good anymore */
- /* move the pending and msgsent entries back to process
- so that there is just one list to iterate over */
unlink_all_msgsent_handles(multi);
process_pending_handles(multi);
-
/* First remove all remaining easy handles */
- for(e = Curl_llist_head(&multi->process); e; e = n) {
- struct Curl_easy *data = Curl_node_elem(e);
-
- if(!GOOD_EASY_HANDLE(data))
- return CURLM_BAD_HANDLE;
-
- n = Curl_node_next(e);
+ data = multi->easyp;
+ while(data) {
+ nextdata = data->next;
if(!data->state.done && data->conn)
/* if DONE was never called for this handle */
(void)multi_done(data, CURLE_OK, TRUE);
@@ -2747,18 +2772,23 @@ CURLMcode curl_multi_cleanup(struct Curl_multi *multi)
data->dns.hostcachetype = HCACHE_NONE;
}
+ /* Clear the pointer to the connection cache */
+ data->state.conn_cache = NULL;
data->multi = NULL; /* clear the association */
#ifdef USE_LIBPSL
if(data->psl == &multi->psl)
data->psl = NULL;
#endif
+
+ data = nextdata;
}
- Curl_cpool_destroy(&multi->cpool);
+ /* Close all the connections in the connection cache */
+ Curl_conncache_close_all_connections(&multi->conn_cache);
sockhash_destroy(&multi->sockhash);
- Curl_hash_destroy(&multi->proto_hash);
+ Curl_conncache_destroy(&multi->conn_cache);
Curl_hash_destroy(&multi->hostcache);
Curl_psl_destroy(&multi->psl);
@@ -2767,13 +2797,14 @@ CURLMcode curl_multi_cleanup(struct Curl_multi *multi)
#else
#ifdef ENABLE_WAKEUP
wakeup_close(multi->wakeup_pair[0]);
-#ifndef USE_EVENTFD
wakeup_close(multi->wakeup_pair[1]);
#endif
#endif
+
+#ifdef USE_SSL
+ Curl_free_multi_ssl_backend_data(multi->ssl_backend_data);
#endif
- multi_xfer_bufs_free(multi);
free(multi);
return CURLM_OK;
@@ -2801,15 +2832,15 @@ CURLMsg *curl_multi_info_read(struct Curl_multi *multi, int *msgs_in_queue)
!multi->in_callback &&
Curl_llist_count(&multi->msglist)) {
/* there is one or more messages in the list */
- struct Curl_llist_node *e;
+ struct Curl_llist_element *e;
/* extract the head of the list to return */
- e = Curl_llist_head(&multi->msglist);
+ e = multi->msglist.head;
- msg = Curl_node_elem(e);
+ msg = e->ptr;
/* remove the extracted entry */
- Curl_node_remove(e);
+ Curl_llist_remove(&multi->msglist, e, NULL);
*msgs_in_queue = curlx_uztosi(Curl_llist_count(&multi->msglist));
@@ -2827,54 +2858,41 @@ static CURLMcode singlesocket(struct Curl_multi *multi,
struct Curl_easy *data)
{
struct easy_pollset cur_poll;
- CURLMcode mresult;
-
- /* Fill in the 'current' struct with the state as it is now: what sockets to
- supervise and for what actions */
- multi_getsock(data, &cur_poll);
- mresult = Curl_multi_pollset_ev(multi, data, &cur_poll, &data->last_poll);
-
- if(!mresult) /* Remember for next time */
- memcpy(&data->last_poll, &cur_poll, sizeof(cur_poll));
- return mresult;
-}
-
-CURLMcode Curl_multi_pollset_ev(struct Curl_multi *multi,
- struct Curl_easy *data,
- struct easy_pollset *ps,
- struct easy_pollset *last_ps)
-{
unsigned int i;
struct Curl_sh_entry *entry;
curl_socket_t s;
int rc;
+ /* Fill in the 'current' struct with the state as it is now: what sockets to
+ supervise and for what actions */
+ multi_getsock(data, &cur_poll);
+
/* We have 0 .. N sockets already and we get to know about the 0 .. M
sockets we should have from now on. Detect the differences, remove no
longer supervised ones and add new ones */
/* walk over the sockets we got right now */
- for(i = 0; i < ps->num; i++) {
- unsigned char cur_action = ps->actions[i];
+ for(i = 0; i < cur_poll.num; i++) {
+ unsigned char cur_action = cur_poll.actions[i];
unsigned char last_action = 0;
int comboaction;
- s = ps->sockets[i];
+ s = cur_poll.sockets[i];
/* get it from the hash */
entry = sh_getentry(&multi->sockhash, s);
if(entry) {
/* check if new for this transfer */
unsigned int j;
- for(j = 0; j< last_ps->num; j++) {
- if(s == last_ps->sockets[j]) {
- last_action = last_ps->actions[j];
+ for(j = 0; j< data->last_poll.num; j++) {
+ if(s == data->last_poll.sockets[j]) {
+ last_action = data->last_poll.actions[j];
break;
}
}
}
else {
- /* this is a socket we did not have before, add it to the hash! */
+ /* this is a socket we didn't have before, add it to the hash! */
entry = sh_addentry(&multi->sockhash, s);
if(!entry)
/* fatal */
@@ -2882,30 +2900,23 @@ CURLMcode Curl_multi_pollset_ev(struct Curl_multi *multi,
}
if(last_action && (last_action != cur_action)) {
/* Socket was used already, but different action now */
- if(last_action & CURL_POLL_IN) {
- DEBUGASSERT(entry->readers);
+ if(last_action & CURL_POLL_IN)
entry->readers--;
- }
- if(last_action & CURL_POLL_OUT) {
- DEBUGASSERT(entry->writers);
+ if(last_action & CURL_POLL_OUT)
entry->writers--;
- }
- if(cur_action & CURL_POLL_IN) {
+ if(cur_action & CURL_POLL_IN)
entry->readers++;
- }
if(cur_action & CURL_POLL_OUT)
entry->writers++;
}
- else if(!last_action &&
- !Curl_hash_pick(&entry->transfers, (char *)&data, /* hash key */
- sizeof(struct Curl_easy *))) {
- DEBUGASSERT(entry->users < 100000); /* detect weird values */
+ else if(!last_action) {
/* a new transfer using this socket */
entry->users++;
if(cur_action & CURL_POLL_IN)
entry->readers++;
if(cur_action & CURL_POLL_OUT)
entry->writers++;
+
/* add 'data' to the transfer hash on this socket! */
if(!Curl_hash_add(&entry->transfers, (char *)&data, /* hash key */
sizeof(struct Curl_easy *), data)) {
@@ -2934,19 +2945,18 @@ CURLMcode Curl_multi_pollset_ev(struct Curl_multi *multi,
}
}
- /* store the current action state */
- entry->action = (unsigned int)comboaction;
+ entry->action = comboaction; /* store the current action state */
}
- /* Check for last_poll.sockets that no longer appear in ps->sockets.
+ /* Check for last_poll.sockets that no longer appear in cur_poll.sockets.
* Need to remove the easy handle from the multi->sockhash->transfers and
* remove multi->sockhash entry when this was the last transfer */
- for(i = 0; i < last_ps->num; i++) {
+ for(i = 0; i< data->last_poll.num; i++) {
unsigned int j;
bool stillused = FALSE;
- s = last_ps->sockets[i];
- for(j = 0; j < ps->num; j++) {
- if(s == ps->sockets[j]) {
+ s = data->last_poll.sockets[i];
+ for(j = 0; j < cur_poll.num; j++) {
+ if(s == cur_poll.sockets[j]) {
/* this is still supervised */
stillused = TRUE;
break;
@@ -2959,29 +2969,25 @@ CURLMcode Curl_multi_pollset_ev(struct Curl_multi *multi,
/* if this is NULL here, the socket has been closed and notified so
already by Curl_multi_closed() */
if(entry) {
- unsigned char oldactions = last_ps->actions[i];
+ unsigned char oldactions = data->last_poll.actions[i];
/* this socket has been removed. Decrease user count */
- DEBUGASSERT(entry->users);
entry->users--;
if(oldactions & CURL_POLL_OUT)
entry->writers--;
if(oldactions & CURL_POLL_IN)
entry->readers--;
if(!entry->users) {
- bool dead = FALSE;
if(multi->socket_cb) {
set_in_callback(multi, TRUE);
rc = multi->socket_cb(data, s, CURL_POLL_REMOVE,
multi->socket_userp, entry->socketp);
set_in_callback(multi, FALSE);
- if(rc == -1)
- dead = TRUE;
+ if(rc == -1) {
+ multi->dead = TRUE;
+ return CURLM_ABORTED_BY_CALLBACK;
+ }
}
sh_delentry(entry, &multi->sockhash, s);
- if(dead) {
- multi->dead = TRUE;
- return CURLM_ABORTED_BY_CALLBACK;
- }
}
else {
/* still users, but remove this handle as a user of this socket */
@@ -2993,6 +2999,8 @@ CURLMcode Curl_multi_pollset_ev(struct Curl_multi *multi,
}
} /* for loop over num */
+ /* Remember for next time */
+ memcpy(&data->last_poll, &cur_poll, sizeof(data->last_poll));
return CURLM_OK;
}
@@ -3008,7 +3016,7 @@ CURLcode Curl_updatesocket(struct Curl_easy *data)
* Curl_multi_closed()
*
* Used by the connect code to tell the multi_socket code that one of the
- * sockets we were using is about to be closed. This function will then
+ * sockets we were using is about to be closed. This function will then
* remove it from the sockethash for this handle to make the multi_socket API
* behave properly, especially for the case when libcurl will create another
* socket again and it gets the same file descriptor number.
@@ -3017,17 +3025,13 @@ CURLcode Curl_updatesocket(struct Curl_easy *data)
void Curl_multi_closed(struct Curl_easy *data, curl_socket_t s)
{
if(data) {
- /* if there is still an easy handle associated with this connection */
+ /* if there's still an easy handle associated with this connection */
struct Curl_multi *multi = data->multi;
- DEBUGF(infof(data, "Curl_multi_closed, fd=%" FMT_SOCKET_T
- " multi is %p", s, (void *)multi));
if(multi) {
/* this is set if this connection is part of a handle that is added to
a multi handle, and only then this is necessary */
struct Curl_sh_entry *entry = sh_getentry(&multi->sockhash, s);
- DEBUGF(infof(data, "Curl_multi_closed, fd=%" FMT_SOCKET_T
- " entry is %p", s, (void *)entry));
if(entry) {
int rc = 0;
if(multi->socket_cb) {
@@ -3067,24 +3071,26 @@ static CURLMcode add_next_timeout(struct curltime now,
{
struct curltime *tv = &d->state.expiretime;
struct Curl_llist *list = &d->state.timeoutlist;
- struct Curl_llist_node *e;
+ struct Curl_llist_element *e;
+ struct time_node *node = NULL;
/* move over the timeout list for this specific handle and remove all
timeouts that are now passed tense and store the next pending
timeout in *tv */
- for(e = Curl_llist_head(list); e;) {
- struct Curl_llist_node *n = Curl_node_next(e);
- struct time_node *node = Curl_node_elem(e);
- timediff_t diff = Curl_timediff_us(node->time, now);
+ for(e = list->head; e;) {
+ struct Curl_llist_element *n = e->next;
+ timediff_t diff;
+ node = (struct time_node *)e->ptr;
+ diff = Curl_timediff_us(node->time, now);
if(diff <= 0)
/* remove outdated entry */
- Curl_node_remove(e);
+ Curl_llist_remove(list, e, NULL);
else
/* the list is sorted so get out on the first mismatch */
break;
e = n;
}
- e = Curl_llist_head(list);
+ e = list->head;
if(!e) {
/* clear the expire times within the handles that we remove from the
splay tree */
@@ -3092,11 +3098,10 @@ static CURLMcode add_next_timeout(struct curltime now,
tv->tv_usec = 0;
}
else {
- struct time_node *node = Curl_node_elem(e);
/* copy the first entry to 'tv' */
memcpy(tv, &node->time, sizeof(*tv));
- /* Insert this node again into the splay. Keep the timer in the list in
+ /* Insert this node again into the splay. Keep the timer in the list in
case we need to recompute future timers. */
multi->timetree = Curl_splayinsert(*tv, multi->timetree,
&d->state.timenode);
@@ -3104,59 +3109,6 @@ static CURLMcode add_next_timeout(struct curltime now,
return CURLM_OK;
}
-struct multi_run_ctx {
- struct Curl_multi *multi;
- struct curltime now;
- size_t run_xfers;
- SIGPIPE_MEMBER(pipe_st);
- bool run_cpool;
-};
-
-static CURLMcode multi_run_expired(struct multi_run_ctx *mrc)
-{
- struct Curl_multi *multi = mrc->multi;
- struct Curl_easy *data = NULL;
- struct Curl_tree *t = NULL;
- CURLMcode result = CURLM_OK;
-
- /*
- * The loop following here will go on as long as there are expire-times left
- * to process (compared to mrc->now) in the splay and 'data' will be
- * re-assigned for every expired handle we deal with.
- */
- while(1) {
- /* Check if there is one (more) expired timer to deal with! This function
- extracts a matching node if there is one */
- multi->timetree = Curl_splaygetbest(mrc->now, multi->timetree, &t);
- if(!t)
- goto out;
-
- data = Curl_splayget(t); /* assign this for next loop */
- if(!data)
- continue;
-
- (void)add_next_timeout(mrc->now, multi, data);
- if(data == multi->cpool.idata) {
- mrc->run_cpool = TRUE;
- continue;
- }
-
- mrc->run_xfers++;
- sigpipe_apply(data, &mrc->pipe_st);
- result = multi_runsingle(multi, &mrc->now, data);
-
- if(CURLM_OK >= result) {
- /* get the socket(s) and check if the state has been changed since
- last */
- result = singlesocket(multi, data);
- if(result)
- goto out;
- }
- }
-
-out:
- return result;
-}
static CURLMcode multi_socket(struct Curl_multi *multi,
bool checkall,
curl_socket_t s,
@@ -3165,44 +3117,39 @@ static CURLMcode multi_socket(struct Curl_multi *multi,
{
CURLMcode result = CURLM_OK;
struct Curl_easy *data = NULL;
- struct multi_run_ctx mrc;
-
- (void)ev_bitmask;
- memset(&mrc, 0, sizeof(mrc));
- mrc.multi = multi;
- mrc.now = Curl_now();
- sigpipe_init(&mrc.pipe_st);
+ struct Curl_tree *t;
+ struct curltime now = Curl_now();
+ bool first = FALSE;
+ bool nosig = FALSE;
+ SIGPIPE_VARIABLE(pipe_st);
if(checkall) {
- struct Curl_llist_node *e;
/* *perform() deals with running_handles on its own */
result = curl_multi_perform(multi, running_handles);
/* walk through each easy handle and do the socket state change magic
and callbacks */
if(result != CURLM_BAD_HANDLE) {
- for(e = Curl_llist_head(&multi->process); e && !result;
- e = Curl_node_next(e)) {
- result = singlesocket(multi, Curl_node_elem(e));
+ data = multi->easyp;
+ while(data && !result) {
+ result = singlesocket(multi, data);
+ data = data->next;
}
}
- mrc.run_cpool = TRUE;
- goto out;
- }
+ /* or should we fall-through and do the timer-based stuff? */
+ return result;
+ }
if(s != CURL_SOCKET_TIMEOUT) {
struct Curl_sh_entry *entry = sh_getentry(&multi->sockhash, s);
- if(!entry) {
- /* Unmatched socket, we cannot act on it but we ignore this fact. In
+ if(!entry)
+ /* Unmatched socket, we can't act on it but we ignore this fact. In
real-world tests it has been proved that libevent can in fact give
the application actions even though the socket was just previously
asked to get removed, so thus we better survive stray socket actions
and just move on. */
- /* The socket might come from a connection that is being shut down
- * by the multi's connection pool. */
- Curl_cpool_multi_socket(multi, s, ev_bitmask);
- }
+ ;
else {
struct Curl_hash_iterator iter;
struct Curl_hash_element *he;
@@ -3215,43 +3162,75 @@ static CURLMcode multi_socket(struct Curl_multi *multi,
DEBUGASSERT(data);
DEBUGASSERT(data->magic == CURLEASY_MAGIC_NUMBER);
- if(data == multi->cpool.idata)
- mrc.run_cpool = TRUE;
- else {
- /* Expire with out current now, so we will get it below when
- * asking the splaytree for expired transfers. */
- Curl_expire_ex(data, &mrc.now, 0, EXPIRE_RUN_NOW);
- }
+ if(data->conn && !(data->conn->handler->flags & PROTOPT_DIRLOCK))
+ /* set socket event bitmask if they're not locked */
+ data->conn->cselect_bits = (unsigned char)ev_bitmask;
+
+ Curl_expire(data, 0, EXPIRE_RUN_NOW);
}
+
+ /* Now we fall-through and do the timer-based stuff, since we don't want
+ to force the user to have to deal with timeouts as long as at least
+ one connection in fact has traffic. */
+
+ data = NULL; /* set data to NULL again to avoid calling
+ multi_runsingle() in case there's no need to */
+ now = Curl_now(); /* get a newer time since the multi_runsingle() loop
+ may have taken some time */
}
}
+ else {
+ /* Asked to run due to time-out. Clear the 'lastcall' variable to force
+ Curl_update_timer() to trigger a callback to the app again even if the
+ same timeout is still the one to run after this call. That handles the
+ case when the application asks libcurl to run the timeout
+ prematurely. */
+ memset(&multi->timer_lastcall, 0, sizeof(multi->timer_lastcall));
+ }
- result = multi_run_expired(&mrc);
- if(result)
- goto out;
+ /*
+ * The loop following here will go on as long as there are expire-times left
+ * to process in the splay and 'data' will be re-assigned for every expired
+ * handle we deal with.
+ */
+ do {
+ /* the first loop lap 'data' can be NULL */
+ if(data) {
+ if(!first) {
+ first = TRUE;
+ nosig = data->set.no_signal; /* initial state */
+ sigpipe_ignore(data, &pipe_st);
+ }
+ else if(data->set.no_signal != nosig) {
+ sigpipe_restore(&pipe_st);
+ sigpipe_ignore(data, &pipe_st);
+ nosig = data->set.no_signal; /* remember new state */
+ }
+ result = multi_runsingle(multi, &now, data);
- if(mrc.run_xfers) {
- /* Running transfers takes time. With a new timestamp, we might catch
- * other expires which are due now. Instead of telling the application
- * to set a 0 timeout and call us again, we run them here.
- * Do that only once or it might be unfair to transfers on other
- * sockets. */
- mrc.now = Curl_now();
- result = multi_run_expired(&mrc);
- }
+ if(CURLM_OK >= result) {
+ /* get the socket(s) and check if the state has been changed since
+ last */
+ result = singlesocket(multi, data);
+ if(result)
+ break;
+ }
+ }
-out:
- if(mrc.run_cpool) {
- sigpipe_apply(multi->cpool.idata, &mrc.pipe_st);
- Curl_cpool_multi_perform(multi);
- }
- sigpipe_restore(&mrc.pipe_st);
+ /* Check if there's one (more) expired timer to deal with! This function
+ extracts a matching node if there is one */
- if(running_handles)
- *running_handles = (int)multi->num_alive;
+ multi->timetree = Curl_splaygetbest(now, multi->timetree, &t);
+ if(t) {
+ data = t->payload; /* assign this for next loop */
+ (void)add_next_timeout(now, multi, t->payload);
+ }
- if(CURLM_OK >= result)
- result = Curl_update_timer(multi);
+ } while(t);
+ if(first)
+ sigpipe_restore(&pipe_st);
+
+ *running_handles = multi->num_alive;
return result;
}
@@ -3303,9 +3282,6 @@ CURLMcode curl_multi_setopt(struct Curl_multi *multi,
break;
case CURLMOPT_MAX_TOTAL_CONNECTIONS:
multi->max_total_connections = va_arg(param, long);
- /* for now, let this also decide the max number of connections
- * in shutdown handling */
- multi->max_shutdown_connections = va_arg(param, long);
break;
/* options formerly used for pipelining */
case CURLMOPT_MAX_PIPELINE_LENGTH:
@@ -3340,28 +3316,39 @@ CURLMcode curl_multi_setopt(struct Curl_multi *multi,
CURLMcode curl_multi_socket(struct Curl_multi *multi, curl_socket_t s,
int *running_handles)
{
+ CURLMcode result;
if(multi->in_callback)
return CURLM_RECURSIVE_API_CALL;
- return multi_socket(multi, FALSE, s, 0, running_handles);
+ result = multi_socket(multi, FALSE, s, 0, running_handles);
+ if(CURLM_OK >= result)
+ result = Curl_update_timer(multi);
+ return result;
}
CURLMcode curl_multi_socket_action(struct Curl_multi *multi, curl_socket_t s,
int ev_bitmask, int *running_handles)
{
+ CURLMcode result;
if(multi->in_callback)
return CURLM_RECURSIVE_API_CALL;
- return multi_socket(multi, FALSE, s, ev_bitmask, running_handles);
+ result = multi_socket(multi, FALSE, s, ev_bitmask, running_handles);
+ if(CURLM_OK >= result)
+ result = Curl_update_timer(multi);
+ return result;
}
CURLMcode curl_multi_socket_all(struct Curl_multi *multi, int *running_handles)
{
+ CURLMcode result;
if(multi->in_callback)
return CURLM_RECURSIVE_API_CALL;
- return multi_socket(multi, TRUE, CURL_SOCKET_BAD, 0, running_handles);
+ result = multi_socket(multi, TRUE, CURL_SOCKET_BAD, 0, running_handles);
+ if(CURLM_OK >= result)
+ result = Curl_update_timer(multi);
+ return result;
}
static CURLMcode multi_timeout(struct Curl_multi *multi,
- struct curltime *expire_time,
long *timeout_ms)
{
static const struct curltime tv_zero = {0, 0};
@@ -3377,29 +3364,20 @@ static CURLMcode multi_timeout(struct Curl_multi *multi,
/* splay the lowest to the bottom */
multi->timetree = Curl_splay(tv_zero, multi->timetree);
- /* this will not return NULL from a non-emtpy tree, but some compilers
- * are not convinced of that. Analyzers are hard. */
- *expire_time = multi->timetree? multi->timetree->key : tv_zero;
-
- /* 'multi->timetree' will be non-NULL here but the compilers sometimes
- yell at us if we assume so */
- if(multi->timetree &&
- Curl_timediff_us(multi->timetree->key, now) > 0) {
+
+ if(Curl_splaycomparekeys(multi->timetree->key, now) > 0) {
/* some time left before expiration */
timediff_t diff = Curl_timediff_ceil(multi->timetree->key, now);
- /* this should be safe even on 32-bit archs, as we do not use that
+ /* this should be safe even on 32 bit archs, as we don't use that
overly long timeouts */
*timeout_ms = (long)diff;
}
- else {
+ else
/* 0 means immediately */
*timeout_ms = 0;
- }
}
- else {
- *expire_time = tv_zero;
+ else
*timeout_ms = -1;
- }
return CURLM_OK;
}
@@ -3407,8 +3385,6 @@ static CURLMcode multi_timeout(struct Curl_multi *multi,
CURLMcode curl_multi_timeout(struct Curl_multi *multi,
long *timeout_ms)
{
- struct curltime expire_time;
-
/* First, make some basic checks that the CURLM handle is a good handle */
if(!GOOD_MULTI_HANDLE(multi))
return CURLM_BAD_HANDLE;
@@ -3416,79 +3392,56 @@ CURLMcode curl_multi_timeout(struct Curl_multi *multi,
if(multi->in_callback)
return CURLM_RECURSIVE_API_CALL;
- return multi_timeout(multi, &expire_time, timeout_ms);
+ return multi_timeout(multi, timeout_ms);
}
-#define DEBUG_UPDATE_TIMER 0
-
/*
* Tell the application it should update its timers, if it subscribes to the
* update timer callback.
*/
CURLMcode Curl_update_timer(struct Curl_multi *multi)
{
- struct curltime expire_ts;
long timeout_ms;
int rc;
- bool set_value = FALSE;
if(!multi->timer_cb || multi->dead)
return CURLM_OK;
- if(multi_timeout(multi, &expire_ts, &timeout_ms)) {
+ if(multi_timeout(multi, &timeout_ms)) {
return CURLM_OK;
}
-
- if(timeout_ms < 0 && multi->last_timeout_ms < 0) {
-#if DEBUG_UPDATE_TIMER
- fprintf(stderr, "Curl_update_timer(), still no timeout, no change\n");
-#endif
- }
- else if(timeout_ms < 0) {
- /* there is no timeout now but there was one previously */
-#if DEBUG_UPDATE_TIMER
- fprintf(stderr, "Curl_update_timer(), remove timeout, "
- " last_timeout=%ldms\n", multi->last_timeout_ms);
-#endif
- timeout_ms = -1; /* normalize */
- set_value = TRUE;
- }
- else if(multi->last_timeout_ms < 0) {
-#if DEBUG_UPDATE_TIMER
- fprintf(stderr, "Curl_update_timer(), had no timeout, set now\n");
-#endif
- set_value = TRUE;
- }
- else if(Curl_timediff_us(multi->last_expire_ts, expire_ts)) {
- /* We had a timeout before and have one now, the absolute timestamp
- * differs. The relative timeout_ms may be the same, but the starting
- * point differs. Let the application restart its timer. */
-#if DEBUG_UPDATE_TIMER
- fprintf(stderr, "Curl_update_timer(), expire timestamp changed\n");
-#endif
- set_value = TRUE;
- }
- else {
- /* We have same expire time as previously. Our relative 'timeout_ms'
- * may be different now, but the application has the timer running
- * and we do not to tell it to start this again. */
-#if DEBUG_UPDATE_TIMER
- fprintf(stderr, "Curl_update_timer(), same expire timestamp, no change\n");
-#endif
+ if(timeout_ms < 0) {
+ static const struct curltime none = {0, 0};
+ if(Curl_splaycomparekeys(none, multi->timer_lastcall)) {
+ multi->timer_lastcall = none;
+ /* there's no timeout now but there was one previously, tell the app to
+ disable it */
+ set_in_callback(multi, TRUE);
+ rc = multi->timer_cb(multi, -1, multi->timer_userp);
+ set_in_callback(multi, FALSE);
+ if(rc == -1) {
+ multi->dead = TRUE;
+ return CURLM_ABORTED_BY_CALLBACK;
+ }
+ return CURLM_OK;
+ }
+ return CURLM_OK;
}
- if(set_value) {
-#if DEBUG_UPDATE_TIMER
- fprintf(stderr, "Curl_update_timer(), set timeout %ldms\n", timeout_ms);
-#endif
- multi->last_expire_ts = expire_ts;
- multi->last_timeout_ms = timeout_ms;
- set_in_callback(multi, TRUE);
- rc = multi->timer_cb(multi, timeout_ms, multi->timer_userp);
- set_in_callback(multi, FALSE);
- if(rc == -1) {
- multi->dead = TRUE;
- return CURLM_ABORTED_BY_CALLBACK;
- }
+ /* When multi_timeout() is done, multi->timetree points to the node with the
+ * timeout we got the (relative) time-out time for. We can thus easily check
+ * if this is the same (fixed) time as we got in a previous call and then
+ * avoid calling the callback again. */
+ if(Curl_splaycomparekeys(multi->timetree->key, multi->timer_lastcall) == 0)
+ return CURLM_OK;
+
+ multi->timer_lastcall = multi->timetree->key;
+
+ set_in_callback(multi, TRUE);
+ rc = multi->timer_cb(multi, timeout_ms, multi->timer_userp);
+ set_in_callback(multi, FALSE);
+ if(rc == -1) {
+ multi->dead = TRUE;
+ return CURLM_ABORTED_BY_CALLBACK;
}
return CURLM_OK;
}
@@ -3501,13 +3454,13 @@ CURLMcode Curl_update_timer(struct Curl_multi *multi)
static void
multi_deltimeout(struct Curl_easy *data, expire_id eid)
{
- struct Curl_llist_node *e;
+ struct Curl_llist_element *e;
struct Curl_llist *timeoutlist = &data->state.timeoutlist;
/* find and remove the specific node from the list */
- for(e = Curl_llist_head(timeoutlist); e; e = Curl_node_next(e)) {
- struct time_node *n = Curl_node_elem(e);
+ for(e = timeoutlist->head; e; e = e->next) {
+ struct time_node *n = (struct time_node *)e->ptr;
if(n->eid == eid) {
- Curl_node_remove(e);
+ Curl_llist_remove(timeoutlist, e, NULL);
return;
}
}
@@ -3525,9 +3478,9 @@ multi_addtimeout(struct Curl_easy *data,
struct curltime *stamp,
expire_id eid)
{
- struct Curl_llist_node *e;
+ struct Curl_llist_element *e;
struct time_node *node;
- struct Curl_llist_node *prev = NULL;
+ struct Curl_llist_element *prev = NULL;
size_t n;
struct Curl_llist *timeoutlist = &data->state.timeoutlist;
@@ -3540,8 +3493,8 @@ multi_addtimeout(struct Curl_easy *data,
n = Curl_llist_count(timeoutlist);
if(n) {
/* find the correct spot in the list */
- for(e = Curl_llist_head(timeoutlist); e; e = Curl_node_next(e)) {
- struct time_node *check = Curl_node_elem(e);
+ for(e = timeoutlist->head; e; e = e->next) {
+ struct time_node *check = (struct time_node *)e->ptr;
timediff_t diff = Curl_timediff(check->time, node->time);
if(diff > 0)
break;
@@ -3567,12 +3520,10 @@ multi_addtimeout(struct Curl_easy *data,
*
* Expire replaces a former timeout using the same id if already set.
*/
-static void Curl_expire_ex(struct Curl_easy *data,
- const struct curltime *nowp,
- timediff_t milli, expire_id id)
+void Curl_expire(struct Curl_easy *data, timediff_t milli, expire_id id)
{
struct Curl_multi *multi = data->multi;
- struct curltime *curr_expire = &data->state.expiretime;
+ struct curltime *nowp = &data->state.expiretime;
struct curltime set;
/* this is only interesting while there is still an associated multi struct
@@ -3582,9 +3533,9 @@ static void Curl_expire_ex(struct Curl_easy *data,
DEBUGASSERT(id < EXPIRE_LAST);
- set = *nowp;
- set.tv_sec += (time_t)(milli/1000); /* might be a 64 to 32 bits conversion */
- set.tv_usec += (int)(milli%1000)*1000;
+ set = Curl_now();
+ set.tv_sec += (time_t)(milli/1000); /* might be a 64 to 32 bit conversion */
+ set.tv_usec += (unsigned int)(milli%1000)*1000;
if(set.tv_usec >= 1000000) {
set.tv_sec++;
@@ -3594,20 +3545,20 @@ static void Curl_expire_ex(struct Curl_easy *data,
/* Remove any timer with the same id just in case. */
multi_deltimeout(data, id);
- /* Add it to the timer list. It must stay in the list until it has expired
+ /* Add it to the timer list. It must stay in the list until it has expired
in case we need to recompute the minimum timer later. */
multi_addtimeout(data, &set, id);
- if(curr_expire->tv_sec || curr_expire->tv_usec) {
+ if(nowp->tv_sec || nowp->tv_usec) {
/* This means that the struct is added as a node in the splay tree.
Compare if the new time is earlier, and only remove-old/add-new if it
is. */
- timediff_t diff = Curl_timediff(set, *curr_expire);
+ timediff_t diff = Curl_timediff(set, *nowp);
int rc;
if(diff > 0) {
/* The current splay tree entry is sooner than this new expiry time.
- We do not need to update our splay tree entry. */
+ We don't need to update our splay tree entry. */
return;
}
@@ -3621,18 +3572,12 @@ static void Curl_expire_ex(struct Curl_easy *data,
/* Indicate that we are in the splay tree and insert the new timer expiry
value since it is our local minimum. */
- *curr_expire = set;
- Curl_splayset(&data->state.timenode, data);
- multi->timetree = Curl_splayinsert(*curr_expire, multi->timetree,
+ *nowp = set;
+ data->state.timenode.payload = data;
+ multi->timetree = Curl_splayinsert(*nowp, multi->timetree,
&data->state.timenode);
}
-void Curl_expire(struct Curl_easy *data, timediff_t milli, expire_id id)
-{
- struct curltime now = Curl_now();
- Curl_expire_ex(data, &now, milli, id);
-}
-
/*
* Curl_expire_done()
*
@@ -3650,7 +3595,7 @@ void Curl_expire_done(struct Curl_easy *data, expire_id id)
*
* Clear ALL timeout values for this handle.
*/
-bool Curl_expire_clear(struct Curl_easy *data)
+void Curl_expire_clear(struct Curl_easy *data)
{
struct Curl_multi *multi = data->multi;
struct curltime *nowp = &data->state.expiretime;
@@ -3658,7 +3603,7 @@ bool Curl_expire_clear(struct Curl_easy *data)
/* this is only interesting while there is still an associated multi struct
remaining! */
if(!multi)
- return FALSE;
+ return;
if(nowp->tv_sec || nowp->tv_usec) {
/* Since this is an cleared time, we must remove the previous entry from
@@ -3671,25 +3616,26 @@ bool Curl_expire_clear(struct Curl_easy *data)
if(rc)
infof(data, "Internal error clearing splay node = %d", rc);
- /* clear the timeout list too */
- Curl_llist_destroy(list, NULL);
+ /* flush the timeout list too */
+ while(list->size > 0) {
+ Curl_llist_remove(list, list->tail, NULL);
+ }
#ifdef DEBUGBUILD
infof(data, "Expire cleared");
#endif
nowp->tv_sec = 0;
nowp->tv_usec = 0;
- return TRUE;
}
- return FALSE;
}
+
+
+
CURLMcode curl_multi_assign(struct Curl_multi *multi, curl_socket_t s,
void *hashp)
{
struct Curl_sh_entry *there = NULL;
- if(!GOOD_MULTI_HANDLE(multi))
- return CURLM_BAD_HANDLE;
there = sh_getentry(&multi->sockhash, s);
@@ -3701,55 +3647,75 @@ CURLMcode curl_multi_assign(struct Curl_multi *multi, curl_socket_t s,
return CURLM_OK;
}
-static void move_pending_to_connect(struct Curl_multi *multi,
- struct Curl_easy *data)
+size_t Curl_multi_max_host_connections(struct Curl_multi *multi)
{
- DEBUGASSERT(data->mstate == MSTATE_PENDING);
-
- /* Remove this node from the pending list */
- Curl_node_remove(&data->multi_queue);
-
- /* put it into the process list */
- Curl_llist_append(&multi->process, data, &data->multi_queue);
-
- multistate(data, MSTATE_CONNECT);
+ return multi ? multi->max_host_connections : 0;
+}
- /* Make sure that the handle will be processed soonish. */
- Curl_expire(data, 0, EXPIRE_RUN_NOW);
+size_t Curl_multi_max_total_connections(struct Curl_multi *multi)
+{
+ return multi ? multi->max_total_connections : 0;
}
-/* process_pending_handles() moves a handle from PENDING back into the process
- list and change state to CONNECT.
+/*
+ * When information about a connection has appeared, call this!
+ */
- We do not move all transfers because that can be a significant amount.
- Since this is tried every now and then doing too many too often becomes a
- performance problem.
+void Curl_multiuse_state(struct Curl_easy *data,
+ int bundlestate) /* use BUNDLE_* defines */
+{
+ struct connectdata *conn;
+ DEBUGASSERT(data);
+ DEBUGASSERT(data->multi);
+ conn = data->conn;
+ DEBUGASSERT(conn);
+ DEBUGASSERT(conn->bundle);
- When there is a change for connection limits like max host connections etc,
- this likely only allows one new transfer. When there is a pipewait change,
- it can potentially allow hundreds of new transfers.
+ conn->bundle->multiuse = bundlestate;
+ process_pending_handles(data->multi);
+}
- We could consider an improvement where we store the queue reason and allow
- more pipewait rechecks than others.
-*/
+/* process_pending_handles() moves all handles from PENDING
+ back into the main list and change state to CONNECT */
static void process_pending_handles(struct Curl_multi *multi)
{
- struct Curl_llist_node *e = Curl_llist_head(&multi->pending);
+ struct Curl_llist_element *e = multi->pending.head;
if(e) {
- struct Curl_easy *data = Curl_node_elem(e);
- move_pending_to_connect(multi, data);
+ struct Curl_easy *data = e->ptr;
+
+ DEBUGASSERT(data->mstate == MSTATE_PENDING);
+
+ /* put it back into the main list */
+ link_easy(multi, data);
+
+ multistate(data, MSTATE_CONNECT);
+
+ /* Remove this node from the list */
+ Curl_llist_remove(&multi->pending, e, NULL);
+
+ /* Make sure that the handle will be processed soonish. */
+ Curl_expire(data, 0, EXPIRE_RUN_NOW);
+
+ /* mark this as having been in the pending queue */
+ data->state.previouslypending = TRUE;
}
}
void Curl_set_in_callback(struct Curl_easy *data, bool value)
{
- if(data && data->multi)
- data->multi->in_callback = value;
+ /* might get called when there is no data pointer! */
+ if(data) {
+ if(data->multi_easy)
+ data->multi_easy->in_callback = value;
+ else if(data->multi)
+ data->multi->in_callback = value;
+ }
}
-bool Curl_is_in_callback(struct Curl_easy *data)
+bool Curl_is_in_callback(struct Curl_easy *easy)
{
- return (data && data->multi && data->multi->in_callback);
+ return ((easy->multi && easy->multi->in_callback) ||
+ (easy->multi_easy && easy->multi_easy->in_callback));
}
unsigned int Curl_multi_max_concurrent_streams(struct Curl_multi *multi)
@@ -3764,160 +3730,14 @@ struct Curl_easy **curl_multi_get_handles(struct Curl_multi *multi)
(multi->num_easy + 1));
if(a) {
unsigned int i = 0;
- struct Curl_llist_node *e;
- for(e = Curl_llist_head(&multi->process); e; e = Curl_node_next(e)) {
- struct Curl_easy *data = Curl_node_elem(e);
+ struct Curl_easy *e = multi->easyp;
+ while(e) {
DEBUGASSERT(i < multi->num_easy);
- if(!data->state.internal)
- a[i++] = data;
+ if(!e->state.internal)
+ a[i++] = e;
+ e = e->next;
}
a[i] = NULL; /* last entry is a NULL */
}
return a;
}
-
-CURLcode Curl_multi_xfer_buf_borrow(struct Curl_easy *data,
- char **pbuf, size_t *pbuflen)
-{
- DEBUGASSERT(data);
- DEBUGASSERT(data->multi);
- *pbuf = NULL;
- *pbuflen = 0;
- if(!data->multi) {
- failf(data, "transfer has no multi handle");
- return CURLE_FAILED_INIT;
- }
- if(!data->set.buffer_size) {
- failf(data, "transfer buffer size is 0");
- return CURLE_FAILED_INIT;
- }
- if(data->multi->xfer_buf_borrowed) {
- failf(data, "attempt to borrow xfer_buf when already borrowed");
- return CURLE_AGAIN;
- }
-
- if(data->multi->xfer_buf &&
- data->set.buffer_size > data->multi->xfer_buf_len) {
- /* not large enough, get a new one */
- free(data->multi->xfer_buf);
- data->multi->xfer_buf = NULL;
- data->multi->xfer_buf_len = 0;
- }
-
- if(!data->multi->xfer_buf) {
- data->multi->xfer_buf = malloc((size_t)data->set.buffer_size);
- if(!data->multi->xfer_buf) {
- failf(data, "could not allocate xfer_buf of %zu bytes",
- (size_t)data->set.buffer_size);
- return CURLE_OUT_OF_MEMORY;
- }
- data->multi->xfer_buf_len = data->set.buffer_size;
- }
-
- data->multi->xfer_buf_borrowed = TRUE;
- *pbuf = data->multi->xfer_buf;
- *pbuflen = data->multi->xfer_buf_len;
- return CURLE_OK;
-}
-
-void Curl_multi_xfer_buf_release(struct Curl_easy *data, char *buf)
-{
- (void)buf;
- DEBUGASSERT(data);
- DEBUGASSERT(data->multi);
- DEBUGASSERT(!buf || data->multi->xfer_buf == buf);
- data->multi->xfer_buf_borrowed = FALSE;
-}
-
-CURLcode Curl_multi_xfer_ulbuf_borrow(struct Curl_easy *data,
- char **pbuf, size_t *pbuflen)
-{
- DEBUGASSERT(data);
- DEBUGASSERT(data->multi);
- *pbuf = NULL;
- *pbuflen = 0;
- if(!data->multi) {
- failf(data, "transfer has no multi handle");
- return CURLE_FAILED_INIT;
- }
- if(!data->set.upload_buffer_size) {
- failf(data, "transfer upload buffer size is 0");
- return CURLE_FAILED_INIT;
- }
- if(data->multi->xfer_ulbuf_borrowed) {
- failf(data, "attempt to borrow xfer_ulbuf when already borrowed");
- return CURLE_AGAIN;
- }
-
- if(data->multi->xfer_ulbuf &&
- data->set.upload_buffer_size > data->multi->xfer_ulbuf_len) {
- /* not large enough, get a new one */
- free(data->multi->xfer_ulbuf);
- data->multi->xfer_ulbuf = NULL;
- data->multi->xfer_ulbuf_len = 0;
- }
-
- if(!data->multi->xfer_ulbuf) {
- data->multi->xfer_ulbuf = malloc((size_t)data->set.upload_buffer_size);
- if(!data->multi->xfer_ulbuf) {
- failf(data, "could not allocate xfer_ulbuf of %zu bytes",
- (size_t)data->set.upload_buffer_size);
- return CURLE_OUT_OF_MEMORY;
- }
- data->multi->xfer_ulbuf_len = data->set.upload_buffer_size;
- }
-
- data->multi->xfer_ulbuf_borrowed = TRUE;
- *pbuf = data->multi->xfer_ulbuf;
- *pbuflen = data->multi->xfer_ulbuf_len;
- return CURLE_OK;
-}
-
-void Curl_multi_xfer_ulbuf_release(struct Curl_easy *data, char *buf)
-{
- (void)buf;
- DEBUGASSERT(data);
- DEBUGASSERT(data->multi);
- DEBUGASSERT(!buf || data->multi->xfer_ulbuf == buf);
- data->multi->xfer_ulbuf_borrowed = FALSE;
-}
-
-static void multi_xfer_bufs_free(struct Curl_multi *multi)
-{
- DEBUGASSERT(multi);
- Curl_safefree(multi->xfer_buf);
- multi->xfer_buf_len = 0;
- multi->xfer_buf_borrowed = FALSE;
- Curl_safefree(multi->xfer_ulbuf);
- multi->xfer_ulbuf_len = 0;
- multi->xfer_ulbuf_borrowed = FALSE;
-}
-
-struct Curl_easy *Curl_multi_get_handle(struct Curl_multi *multi,
- curl_off_t mid)
-{
-
- if(mid >= 0) {
- struct Curl_easy *data;
- struct Curl_llist_node *e;
-
- for(e = Curl_llist_head(&multi->process); e; e = Curl_node_next(e)) {
- data = Curl_node_elem(e);
- if(data->mid == mid)
- return data;
- }
- /* may be in msgsent queue */
- for(e = Curl_llist_head(&multi->msgsent); e; e = Curl_node_next(e)) {
- data = Curl_node_elem(e);
- if(data->mid == mid)
- return data;
- }
- /* may be in pending queue */
- for(e = Curl_llist_head(&multi->pending); e; e = Curl_node_next(e)) {
- data = Curl_node_elem(e);
- if(data->mid == mid)
- return data;
- }
- }
- return NULL;
-}
diff --git a/contrib/libs/curl/lib/multihandle.h b/contrib/libs/curl/lib/multihandle.h
index fef117c067..e03e382e28 100644
--- a/contrib/libs/curl/lib/multihandle.h
+++ b/contrib/libs/curl/lib/multihandle.h
@@ -33,7 +33,7 @@
struct connectdata;
struct Curl_message {
- struct Curl_llist_node list;
+ struct Curl_llist_element list;
/* the 'CURLMsg' is the part that is visible to the external user */
struct CURLMsg extmsg;
};
@@ -44,25 +44,24 @@ struct Curl_message {
typedef enum {
MSTATE_INIT, /* 0 - start in this state */
MSTATE_PENDING, /* 1 - no connections, waiting for one */
- MSTATE_SETUP, /* 2 - start a new transfer */
- MSTATE_CONNECT, /* 3 - resolve/connect has been sent off */
- MSTATE_RESOLVING, /* 4 - awaiting the resolve to finalize */
- MSTATE_CONNECTING, /* 5 - awaiting the TCP connect to finalize */
- MSTATE_TUNNELING, /* 6 - awaiting HTTPS proxy SSL initialization to
+ MSTATE_CONNECT, /* 2 - resolve/connect has been sent off */
+ MSTATE_RESOLVING, /* 3 - awaiting the resolve to finalize */
+ MSTATE_CONNECTING, /* 4 - awaiting the TCP connect to finalize */
+ MSTATE_TUNNELING, /* 5 - awaiting HTTPS proxy SSL initialization to
complete and/or proxy CONNECT to finalize */
- MSTATE_PROTOCONNECT, /* 7 - initiate protocol connect procedure */
- MSTATE_PROTOCONNECTING, /* 8 - completing the protocol-specific connect
+ MSTATE_PROTOCONNECT, /* 6 - initiate protocol connect procedure */
+ MSTATE_PROTOCONNECTING, /* 7 - completing the protocol-specific connect
phase */
- MSTATE_DO, /* 9 - start send off the request (part 1) */
- MSTATE_DOING, /* 10 - sending off the request (part 1) */
- MSTATE_DOING_MORE, /* 11 - send off the request (part 2) */
- MSTATE_DID, /* 12 - done sending off request */
- MSTATE_PERFORMING, /* 13 - transfer data */
- MSTATE_RATELIMITING, /* 14 - wait because limit-rate exceeded */
- MSTATE_DONE, /* 15 - post data transfer operation */
- MSTATE_COMPLETED, /* 16 - operation complete */
- MSTATE_MSGSENT, /* 17 - the operation complete message is sent */
- MSTATE_LAST /* 18 - not a true state, never use this */
+ MSTATE_DO, /* 8 - start send off the request (part 1) */
+ MSTATE_DOING, /* 9 - sending off the request (part 1) */
+ MSTATE_DOING_MORE, /* 10 - send off the request (part 2) */
+ MSTATE_DID, /* 11 - done sending off request */
+ MSTATE_PERFORMING, /* 12 - transfer data */
+ MSTATE_RATELIMITING, /* 13 - wait because limit-rate exceeded */
+ MSTATE_DONE, /* 14 - post data transfer operation */
+ MSTATE_COMPLETED, /* 15 - operation complete */
+ MSTATE_MSGSENT, /* 16 - the operation complete message is sent */
+ MSTATE_LAST /* 17 - not a true state, never use this */
} CURLMstate;
/* we support N sockets per easy handle. Set the corresponding bit to what
@@ -80,23 +79,30 @@ typedef enum {
/* value for MAXIMUM CONCURRENT STREAMS upper limit */
#define INITIAL_MAX_CONCURRENT_STREAMS ((1U << 31) - 1)
+/* Curl_multi SSL backend-specific data; declared differently by each SSL
+ backend */
+struct multi_ssl_backend_data;
+
/* This is the struct known as CURLM on the outside */
struct Curl_multi {
/* First a simple identifier to easier detect if a user mix up
this multi handle with an easy handle. Set this to CURL_MULTI_HANDLE. */
unsigned int magic;
+ /* We have a doubly-linked list with easy handles */
+ struct Curl_easy *easyp;
+ struct Curl_easy *easylp; /* last node */
+
unsigned int num_easy; /* amount of entries in the linked list above. */
unsigned int num_alive; /* amount of easy handles that are added but have
not yet reached COMPLETE state */
struct Curl_llist msglist; /* a list of messages from completed transfers */
- /* Each added easy handle is added to ONE of these three lists */
- struct Curl_llist process; /* not in PENDING or MSGSENT */
- struct Curl_llist pending; /* in PENDING */
- struct Curl_llist msgsent; /* in MSGSENT */
- curl_off_t next_easy_mid; /* next multi-id for easy handle added */
+ struct Curl_llist pending; /* Curl_easys that are in the
+ MSTATE_PENDING state */
+ struct Curl_llist msgsent; /* Curl_easys that are in the
+ MSTATE_MSGSENT state */
/* callback function and user data pointer for the *socket() API */
curl_socket_callback socket_cb;
@@ -118,54 +124,40 @@ struct Curl_multi {
times of all currently set timers */
struct Curl_tree *timetree;
- /* buffer used for transfer data, lazy initialized */
- char *xfer_buf; /* the actual buffer */
- size_t xfer_buf_len; /* the allocated length */
- /* buffer used for upload data, lazy initialized */
- char *xfer_ulbuf; /* the actual buffer */
- size_t xfer_ulbuf_len; /* the allocated length */
+#if defined(USE_SSL)
+ struct multi_ssl_backend_data *ssl_backend_data;
+#endif
/* 'sockhash' is the lookup hash for socket descriptor => easy handles (note
the pluralis form, there can be more than one easy handle waiting on the
same actual socket) */
struct Curl_hash sockhash;
- /* `proto_hash` is a general key-value store for protocol implementations
- * with the lifetime of the multi handle. The number of elements kept here
- * should be in the order of supported protocols (and sub-protocols like
- * TLS), *not* in the order of connections or current transfers!
- * Elements need to be added with their own destructor to be invoked when
- * the multi handle is cleaned up (see Curl_hash_add2()).*/
- struct Curl_hash proto_hash;
/* Shared connection cache (bundles)*/
- struct cpool cpool;
+ struct conncache conn_cache;
long max_host_connections; /* if >0, a fixed limit of the maximum number
of connections per host */
long max_total_connections; /* if >0, a fixed limit of the maximum number
of connections in total */
- long max_shutdown_connections; /* if >0, a fixed limit of the maximum number
- of connections in shutdown handling */
/* timer callback and user data pointer for the *socket() API */
curl_multi_timer_callback timer_cb;
void *timer_userp;
- long last_timeout_ms; /* the last timeout value set via timer_cb */
- struct curltime last_expire_ts; /* timestamp of last expiry */
-
+ struct curltime timer_lastcall; /* the fixed time for the timeout for the
+ previous callback */
#ifdef USE_WINSOCK
- WSAEVENT wsa_event; /* Winsock event used for waits */
+ WSAEVENT wsa_event; /* winsock event used for waits */
#else
#ifdef ENABLE_WAKEUP
- curl_socket_t wakeup_pair[2]; /* eventfd()/pipe()/socketpair() used for
- wakeup 0 is used for read, 1 is used
- for write */
+ curl_socket_t wakeup_pair[2]; /* socketpair() used for wakeup
+ 0 is used for read, 1 is used for write */
#endif
#endif
unsigned int max_concurrent_streams;
unsigned int maxconnects; /* if >0, a fixed limit of the maximum number of
- entries we are allowed to grow the connection
+ entries we're allowed to grow the connection
cache to */
#define IPV6_UNKNOWN 0
#define IPV6_DEAD 1
@@ -179,8 +171,6 @@ struct Curl_multi {
#endif
BIT(dead); /* a callback returned error, everything needs to crash and
burn */
- BIT(xfer_buf_borrowed); /* xfer_buf is currently being borrowed */
- BIT(xfer_ulbuf_borrowed); /* xfer_ulbuf is currently being borrowed */
#ifdef DEBUGBUILD
BIT(warned); /* true after user warned of DEBUGBUILD */
#endif
diff --git a/contrib/libs/curl/lib/multiif.h b/contrib/libs/curl/lib/multiif.h
index e5872cd6dc..7a344fa9fd 100644
--- a/contrib/libs/curl/lib/multiif.h
+++ b/contrib/libs/curl/lib/multiif.h
@@ -30,7 +30,7 @@
CURLcode Curl_updatesocket(struct Curl_easy *data);
void Curl_expire(struct Curl_easy *data, timediff_t milli, expire_id);
-bool Curl_expire_clear(struct Curl_easy *data);
+void Curl_expire_clear(struct Curl_easy *data);
void Curl_expire_done(struct Curl_easy *data, expire_id id);
CURLMcode Curl_update_timer(struct Curl_multi *multi) WARN_UNUSED_RESULT;
void Curl_attach_connection(struct Curl_easy *data,
@@ -38,16 +38,15 @@ void Curl_attach_connection(struct Curl_easy *data,
void Curl_detach_connection(struct Curl_easy *data);
bool Curl_multiplex_wanted(const struct Curl_multi *multi);
void Curl_set_in_callback(struct Curl_easy *data, bool value);
-bool Curl_is_in_callback(struct Curl_easy *data);
+bool Curl_is_in_callback(struct Curl_easy *easy);
CURLcode Curl_preconnect(struct Curl_easy *data);
void Curl_multi_connchanged(struct Curl_multi *multi);
/* Internal version of curl_multi_init() accepts size parameters for the
socket, connection and dns hashes */
-struct Curl_multi *Curl_multi_handle(size_t hashsize,
- size_t chashsize,
- size_t dnssize);
+struct Curl_multi *Curl_multi_handle(int hashsize, int chashsize,
+ int dnssize);
/* the write bits start at bit 16 for the *getsock() bitmap */
#define GETSOCK_WRITEBITSTART 16
@@ -63,11 +62,20 @@ struct Curl_multi *Curl_multi_handle(size_t hashsize,
/* mask for checking if read and/or write is set for index x */
#define GETSOCK_MASK_RW(x) (GETSOCK_READSOCK(x)|GETSOCK_WRITESOCK(x))
+/* Return the value of the CURLMOPT_MAX_HOST_CONNECTIONS option */
+size_t Curl_multi_max_host_connections(struct Curl_multi *multi);
+
+/* Return the value of the CURLMOPT_MAX_TOTAL_CONNECTIONS option */
+size_t Curl_multi_max_total_connections(struct Curl_multi *multi);
+
+void Curl_multiuse_state(struct Curl_easy *data,
+ int bundlestate); /* use BUNDLE_* defines */
+
/*
* Curl_multi_closed()
*
* Used by the connect code to tell the multi_socket code that one of the
- * sockets we were using is about to be closed. This function will then
+ * sockets we were using is about to be closed. This function will then
* remove it from the sockethash for this handle to make the multi_socket API
* behave properly, especially for the case when libcurl will create another
* socket again and it gets the same file descriptor number.
@@ -75,15 +83,6 @@ struct Curl_multi *Curl_multi_handle(size_t hashsize,
void Curl_multi_closed(struct Curl_easy *data, curl_socket_t s);
-/* Compare the two pollsets to notify the multi_socket API of changes
- * in socket polling, e.g calling multi->socket_cb() with the changes if
- * differences are seen.
- */
-CURLMcode Curl_multi_pollset_ev(struct Curl_multi *multi,
- struct Curl_easy *data,
- struct easy_pollset *ps,
- struct easy_pollset *last_ps);
-
/*
* Add a handle and move it into PERFORM state at once. For pushed streams.
*/
@@ -95,59 +94,4 @@ CURLMcode Curl_multi_add_perform(struct Curl_multi *multi,
/* Return the value of the CURLMOPT_MAX_CONCURRENT_STREAMS option */
unsigned int Curl_multi_max_concurrent_streams(struct Curl_multi *multi);
-/**
- * Borrow the transfer buffer from the multi, suitable
- * for the given transfer `data`. The buffer may only be used in one
- * multi processing of the easy handle. It MUST be returned to the
- * multi before it can be borrowed again.
- * Pointers into the buffer remain only valid as long as it is borrowed.
- *
- * @param data the easy handle
- * @param pbuf on return, the buffer to use or NULL on error
- * @param pbuflen on return, the size of *pbuf or 0 on error
- * @return CURLE_OK when buffer is available and is returned.
- * CURLE_OUT_OF_MEMORy on failure to allocate the buffer,
- * CURLE_FAILED_INIT if the easy handle is without multi.
- * CURLE_AGAIN if the buffer is borrowed already.
- */
-CURLcode Curl_multi_xfer_buf_borrow(struct Curl_easy *data,
- char **pbuf, size_t *pbuflen);
-/**
- * Release the borrowed buffer. All references into the buffer become
- * invalid after this.
- * @param buf the buffer pointer borrowed for coding error checks.
- */
-void Curl_multi_xfer_buf_release(struct Curl_easy *data, char *buf);
-
-/**
- * Borrow the upload buffer from the multi, suitable
- * for the given transfer `data`. The buffer may only be used in one
- * multi processing of the easy handle. It MUST be returned to the
- * multi before it can be borrowed again.
- * Pointers into the buffer remain only valid as long as it is borrowed.
- *
- * @param data the easy handle
- * @param pbuf on return, the buffer to use or NULL on error
- * @param pbuflen on return, the size of *pbuf or 0 on error
- * @return CURLE_OK when buffer is available and is returned.
- * CURLE_OUT_OF_MEMORy on failure to allocate the buffer,
- * CURLE_FAILED_INIT if the easy handle is without multi.
- * CURLE_AGAIN if the buffer is borrowed already.
- */
-CURLcode Curl_multi_xfer_ulbuf_borrow(struct Curl_easy *data,
- char **pbuf, size_t *pbuflen);
-
-/**
- * Release the borrowed upload buffer. All references into the buffer become
- * invalid after this.
- * @param buf the upload buffer pointer borrowed for coding error checks.
- */
-void Curl_multi_xfer_ulbuf_release(struct Curl_easy *data, char *buf);
-
-/**
- * Get the transfer handle for the given id. Returns NULL if not found.
- */
-struct Curl_easy *Curl_multi_get_handle(struct Curl_multi *multi,
- curl_off_t id);
-
#endif /* HEADER_CURL_MULTIIF_H */
diff --git a/contrib/libs/curl/lib/netrc.c b/contrib/libs/curl/lib/netrc.c
index 490efb64ca..038c6dca6a 100644
--- a/contrib/libs/curl/lib/netrc.c
+++ b/contrib/libs/curl/lib/netrc.c
@@ -53,8 +53,6 @@ enum host_lookup_state {
#define NETRC_FAILED -1
#define NETRC_SUCCESS 0
-#define MAX_NETRC_LINE 4096
-
/*
* Returns zero on success.
*/
@@ -82,14 +80,13 @@ static int parsenetrc(const char *host,
file = fopen(netrcfile, FOPEN_READTEXT);
if(file) {
bool done = FALSE;
- struct dynbuf buf;
- Curl_dyn_init(&buf, MAX_NETRC_LINE);
+ char netrcbuffer[4096];
+ int netrcbuffsize = (int)sizeof(netrcbuffer);
- while(!done && Curl_get_line(&buf, file)) {
+ while(!done && Curl_get_line(netrcbuffer, netrcbuffsize, file)) {
char *tok;
char *tok_end;
bool quoted;
- char *netrcbuffer = Curl_dyn_ptr(&buf);
if(state == MACDEF) {
if((netrcbuffer[0] == '\n') || (netrcbuffer[0] == '\r'))
state = NOTHING;
@@ -237,7 +234,7 @@ static int parsenetrc(const char *host,
else if(strcasecompare("password", tok))
state_password = 1;
else if(strcasecompare("machine", tok)) {
- /* ok, there is machine here go => */
+ /* ok, there's machine here go => */
state = HOSTFOUND;
state_our_login = FALSE;
}
@@ -248,7 +245,6 @@ static int parsenetrc(const char *host,
} /* while Curl_get_line() */
out:
- Curl_dyn_free(&buf);
if(!retcode) {
/* success */
if(login_alloc) {
@@ -277,7 +273,7 @@ out:
/*
* @unittest: 1304
*
- * *loginp and *passwordp MUST be allocated if they are not NULL when passed
+ * *loginp and *passwordp MUST be allocated if they aren't NULL when passed
* in.
*/
int Curl_parsenetrc(const char *host, char **loginp, char **passwordp,
@@ -324,7 +320,7 @@ int Curl_parsenetrc(const char *host, char **loginp, char **passwordp,
return retcode; /* no home directory found (or possibly out of
memory) */
- filealloc = aprintf("%s%s.netrc", home, DIR_CHAR);
+ filealloc = curl_maprintf("%s%s.netrc", home, DIR_CHAR);
if(!filealloc) {
free(homea);
return -1;
@@ -334,7 +330,7 @@ int Curl_parsenetrc(const char *host, char **loginp, char **passwordp,
#ifdef _WIN32
if(retcode == NETRC_FILE_MISSING) {
/* fallback to the old-style "_netrc" file */
- filealloc = aprintf("%s%s_netrc", home, DIR_CHAR);
+ filealloc = curl_maprintf("%s%s_netrc", home, DIR_CHAR);
if(!filealloc) {
free(homea);
return -1;
diff --git a/contrib/libs/curl/lib/netrc.h b/contrib/libs/curl/lib/netrc.h
index 37c95db5e4..9f2815f3bb 100644
--- a/contrib/libs/curl/lib/netrc.h
+++ b/contrib/libs/curl/lib/netrc.h
@@ -27,7 +27,7 @@
#include "curl_setup.h"
#ifndef CURL_DISABLE_NETRC
-/* returns -1 on failure, 0 if the host is found, 1 is the host is not found */
+/* returns -1 on failure, 0 if the host is found, 1 is the host isn't found */
int Curl_parsenetrc(const char *host, char **loginp,
char **passwordp, char *filename);
/* Assume: (*passwordp)[0]=0, host[0] != 0.
diff --git a/contrib/libs/curl/lib/nonblock.c b/contrib/libs/curl/lib/nonblock.c
index 6dcf42a7ea..f4eb656128 100644
--- a/contrib/libs/curl/lib/nonblock.c
+++ b/contrib/libs/curl/lib/nonblock.c
@@ -47,25 +47,16 @@ int curlx_nonblock(curl_socket_t sockfd, /* operate on this */
int nonblock /* TRUE or FALSE */)
{
#if defined(HAVE_FCNTL_O_NONBLOCK)
- /* most recent Unix versions */
+ /* most recent unix versions */
int flags;
flags = sfcntl(sockfd, F_GETFL, 0);
- if(flags < 0)
- return -1;
- /* Check if the current file status flags have already satisfied
- * the request, if so, it is no need to call fcntl() to replicate it.
- */
- if(!!(flags & O_NONBLOCK) == !!nonblock)
- return 0;
if(nonblock)
- flags |= O_NONBLOCK;
- else
- flags &= ~O_NONBLOCK;
- return sfcntl(sockfd, F_SETFL, flags);
+ return sfcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
+ return sfcntl(sockfd, F_SETFL, flags & (~O_NONBLOCK));
#elif defined(HAVE_IOCTL_FIONBIO)
- /* older Unix versions */
+ /* older unix versions */
int flags = nonblock ? 1 : 0;
return ioctl(sockfd, FIONBIO, &flags);
@@ -73,7 +64,7 @@ int curlx_nonblock(curl_socket_t sockfd, /* operate on this */
/* Windows */
unsigned long flags = nonblock ? 1UL : 0UL;
- return ioctlsocket(sockfd, (long)FIONBIO, &flags);
+ return ioctlsocket(sockfd, FIONBIO, &flags);
#elif defined(HAVE_IOCTLSOCKET_CAMEL_FIONBIO)
diff --git a/contrib/libs/curl/lib/noproxy.c b/contrib/libs/curl/lib/noproxy.c
index dbfafc93eb..2b9908d894 100644
--- a/contrib/libs/curl/lib/noproxy.c
+++ b/contrib/libs/curl/lib/noproxy.c
@@ -78,23 +78,23 @@ UNITTEST bool Curl_cidr6_match(const char *ipv6,
const char *network,
unsigned int bits)
{
-#ifdef USE_IPV6
- unsigned int bytes;
- unsigned int rest;
+#ifdef ENABLE_IPV6
+ int bytes;
+ int rest;
unsigned char address[16];
unsigned char check[16];
if(!bits)
bits = 128;
- bytes = bits / 8;
+ bytes = bits/8;
rest = bits & 0x07;
- if((bytes > 16) || ((bytes == 16) && rest))
- return FALSE;
if(1 != Curl_inet_pton(AF_INET6, ipv6, address))
return FALSE;
if(1 != Curl_inet_pton(AF_INET6, network, check))
return FALSE;
+ if((bytes > 16) || ((bytes == 16) && rest))
+ return FALSE;
if(bytes && memcmp(address, check, bytes))
return FALSE;
if(rest && !((address[bytes] ^ check[bytes]) & (0xff << (8 - rest))))
@@ -119,12 +119,13 @@ enum nametype {
* Checks if the host is in the noproxy list. returns TRUE if it matches and
* therefore the proxy should NOT be used.
****************************************************************/
-bool Curl_check_noproxy(const char *name, const char *no_proxy)
+bool Curl_check_noproxy(const char *name, const char *no_proxy,
+ bool *spacesep)
{
char hostip[128];
-
+ *spacesep = FALSE;
/*
- * If we do not have a hostname at all, like for example with a FILE
+ * If we don't have a hostname at all, like for example with a FILE
* transfer, we have nothing to interrogate the noproxy list with.
*/
if(!name || name[0] == '\0')
@@ -142,7 +143,7 @@ bool Curl_check_noproxy(const char *name, const char *no_proxy)
if(!strcmp("*", no_proxy))
return TRUE;
- /* NO_PROXY was specified and it was not just an asterisk */
+ /* NO_PROXY was specified and it wasn't just an asterisk */
if(name[0] == '[') {
char *endptr;
@@ -165,7 +166,7 @@ bool Curl_check_noproxy(const char *name, const char *no_proxy)
if(1 == Curl_inet_pton(AF_INET, name, &address))
type = TYPE_IPV4;
else {
- /* ignore trailing dots in the hostname */
+ /* ignore trailing dots in the host name */
if(name[namelen - 1] == '.')
namelen--;
}
@@ -215,6 +216,7 @@ bool Curl_check_noproxy(const char *name, const char *no_proxy)
/* case C passes through, not a match */
break;
case TYPE_IPV4:
+ /* FALLTHROUGH */
case TYPE_IPV6: {
const char *check = token;
char *slash;
@@ -231,9 +233,7 @@ bool Curl_check_noproxy(const char *name, const char *no_proxy)
slash = strchr(check, '/');
/* if the slash is part of this token, use it */
if(slash) {
- /* if the bits variable gets a crazy value here, that is fine as
- the value will then be rejected in the cidr function */
- bits = (unsigned int)atoi(slash + 1);
+ bits = atoi(slash + 1);
*slash = 0; /* null terminate there */
}
if(type == TYPE_IPV6)
@@ -249,14 +249,16 @@ bool Curl_check_noproxy(const char *name, const char *no_proxy)
/* pass blanks after pattern */
while(ISBLANK(*p))
p++;
- /* if not a comma, this ends the loop */
- if(*p != ',')
- break;
+ /* if not a comma! */
+ if(*p && (*p != ',')) {
+ *spacesep = TRUE;
+ continue;
+ }
/* pass any number of commas */
while(*p == ',')
p++;
} /* while(*p) */
- } /* NO_PROXY was specified and it was not just an asterisk */
+ } /* NO_PROXY was specified and it wasn't just an asterisk */
return FALSE;
}
diff --git a/contrib/libs/curl/lib/noproxy.h b/contrib/libs/curl/lib/noproxy.h
index 71ae7eaafa..a3a6807722 100644
--- a/contrib/libs/curl/lib/noproxy.h
+++ b/contrib/libs/curl/lib/noproxy.h
@@ -27,7 +27,7 @@
#ifndef CURL_DISABLE_PROXY
-#ifdef UNITTESTS
+#ifdef DEBUGBUILD
UNITTEST bool Curl_cidr4_match(const char *ipv4, /* 1.2.3.4 address */
const char *network, /* 1.2.3.4 address */
@@ -37,7 +37,9 @@ UNITTEST bool Curl_cidr6_match(const char *ipv6,
unsigned int bits);
#endif
-bool Curl_check_noproxy(const char *name, const char *no_proxy);
+bool Curl_check_noproxy(const char *name, const char *no_proxy,
+ bool *spacesep);
+
#endif
#endif /* HEADER_CURL_NOPROXY_H */
diff --git a/contrib/libs/curl/lib/openldap.c b/contrib/libs/curl/lib/openldap.c
index 53b1415d6b..d853a90509 100644
--- a/contrib/libs/curl/lib/openldap.c
+++ b/contrib/libs/curl/lib/openldap.c
@@ -117,7 +117,7 @@ static Curl_recv oldap_recv;
*/
const struct Curl_handler Curl_handler_ldap = {
- "ldap", /* scheme */
+ "LDAP", /* scheme */
oldap_setup_connection, /* setup_connection */
oldap_do, /* do_it */
oldap_done, /* done */
@@ -130,8 +130,7 @@ const struct Curl_handler Curl_handler_ldap = {
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
oldap_disconnect, /* disconnect */
- ZERO_NULL, /* write_resp */
- ZERO_NULL, /* write_resp_hd */
+ ZERO_NULL, /* readwrite */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_LDAP, /* defport */
@@ -146,7 +145,7 @@ const struct Curl_handler Curl_handler_ldap = {
*/
const struct Curl_handler Curl_handler_ldaps = {
- "ldaps", /* scheme */
+ "LDAPS", /* scheme */
oldap_setup_connection, /* setup_connection */
oldap_do, /* do_it */
oldap_done, /* done */
@@ -159,8 +158,7 @@ const struct Curl_handler Curl_handler_ldaps = {
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
oldap_disconnect, /* disconnect */
- ZERO_NULL, /* write_resp */
- ZERO_NULL, /* write_resp_hd */
+ ZERO_NULL, /* readwrite */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_LDAPS, /* defport */
@@ -550,12 +548,9 @@ static CURLcode oldap_connect(struct Curl_easy *data, bool *done)
return result;
}
- hosturl = aprintf("%s://%s%s%s:%d",
- conn->handler->scheme,
- conn->bits.ipv6_ip? "[": "",
- conn->host.name,
- conn->bits.ipv6_ip? "]": "",
- conn->remote_port);
+ hosturl = aprintf("ldap%s://%s:%d",
+ conn->handler->flags & PROTOPT_SSL? "s": "",
+ conn->host.name, conn->remote_port);
if(!hosturl)
return CURLE_OUT_OF_MEMORY;
@@ -650,7 +645,7 @@ static CURLcode oldap_state_mechs_resp(struct Curl_easy *data,
switch(code) {
case LDAP_SIZELIMIT_EXCEEDED:
infof(data, "Too many authentication mechanisms\n");
- FALLTHROUGH();
+ /* FALLTHROUGH */
case LDAP_SUCCESS:
case LDAP_NO_RESULTS_RETURNED:
if(Curl_sasl_can_authenticate(&li->sasl, data))
@@ -798,13 +793,10 @@ static CURLcode oldap_connecting(struct Curl_easy *data, bool *done)
result = oldap_perform_bind(data, OLDAP_BIND);
break;
}
- result = Curl_ssl_cfilter_add(data, conn, FIRSTSOCKET);
- if(result)
- break;
- FALLTHROUGH();
+ /* FALLTHROUGH */
case OLDAP_TLS:
result = oldap_ssl_connect(data, OLDAP_TLS);
- if(result)
+ if(result && data->set.use_ssl != CURLUSESSL_TRY)
result = oldap_map_error(code, CURLE_USE_SSL_FAILED);
else if(ssl_installed(conn)) {
conn->bits.tls_upgraded = TRUE;
@@ -895,14 +887,10 @@ static CURLcode oldap_do(struct Curl_easy *data, bool *done)
result = oldap_url_parse(data, &lud);
if(!result) {
-#ifdef USE_SSL
- if(ssl_installed(conn)) {
- Sockbuf *sb;
- /* re-install the libcurl SSL handlers into the sockbuf. */
- ldap_get_option(li->ld, LDAP_OPT_SOCKBUF, &sb);
- ber_sockbuf_add_io(sb, &ldapsb_tls, LBER_SBIOD_LEVEL_TRANSPORT, data);
- }
-#endif
+ Sockbuf *sb;
+ /* re-install the libcurl SSL handlers into the sockbuf. */
+ ldap_get_option(li->ld, LDAP_OPT_SOCKBUF, &sb);
+ ber_sockbuf_add_io(sb, &ldapsb_tls, LBER_SBIOD_LEVEL_TRANSPORT, data);
rc = ldap_search_ext(li->ld, lud->lud_dn, lud->lud_scope,
lud->lud_filter, lud->lud_attrs, 0,
@@ -921,7 +909,7 @@ static CURLcode oldap_do(struct Curl_easy *data, bool *done)
else {
lr->msgid = msgid;
data->req.p.ldap = lr;
- Curl_xfer_setup1(data, CURL_XFER_RECV, -1, FALSE);
+ Curl_setup_transfer(data, FIRSTSOCKET, -1, FALSE, -1);
*done = TRUE;
}
}
@@ -1026,7 +1014,7 @@ static ssize_t oldap_recv(struct Curl_easy *data, int sockindex, char *buf,
switch(code) {
case LDAP_SIZELIMIT_EXCEEDED:
infof(data, "There are more than %d entries", lr->nument);
- FALLTHROUGH();
+ /* FALLTHROUGH */
case LDAP_SUCCESS:
data->req.size = data->req.bytecount;
break;
@@ -1152,7 +1140,7 @@ ldapsb_tls_remove(Sockbuf_IO_Desc *sbiod)
return 0;
}
-/* We do not need to do anything because libcurl does it already */
+/* We don't need to do anything because libcurl does it already */
static int
ldapsb_tls_close(Sockbuf_IO_Desc *sbiod)
{
@@ -1201,7 +1189,7 @@ ldapsb_tls_write(Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
if(conn) {
struct ldapconninfo *li = conn->proto.ldapc;
CURLcode err = CURLE_SEND_ERROR;
- ret = (li->send)(data, FIRSTSOCKET, buf, len, FALSE, &err);
+ ret = (li->send)(data, FIRSTSOCKET, buf, len, &err);
if(ret < 0 && err == CURLE_AGAIN) {
SET_SOCKERRNO(EWOULDBLOCK);
}
diff --git a/contrib/libs/curl/lib/parsedate.c b/contrib/libs/curl/lib/parsedate.c
index d35b58b0d4..1a7195b16a 100644
--- a/contrib/libs/curl/lib/parsedate.c
+++ b/contrib/libs/curl/lib/parsedate.c
@@ -244,7 +244,7 @@ static int checkmonth(const char *check, size_t len)
}
/* return the time zone offset between GMT and the input one, in number
- of seconds or -1 if the timezone was not found/legal */
+ of seconds or -1 if the timezone wasn't found/legal */
static int checktz(const char *check, size_t len)
{
@@ -265,7 +265,7 @@ static int checktz(const char *check, size_t len)
static void skip(const char **date)
{
- /* skip everything that are not letters or digits */
+ /* skip everything that aren't letters or digits */
while(**date && !ISALNUM(**date))
(*date)++;
}
@@ -277,7 +277,7 @@ enum assume {
};
/*
- * time2epoch: time stamp to seconds since epoch in GMT time zone. Similar to
+ * time2epoch: time stamp to seconds since epoch in GMT time zone. Similar to
* mktime but for GMT only.
*/
static time_t time2epoch(int sec, int min, int hour,
@@ -445,7 +445,7 @@ static int parsedate(const char *date, time_t *output)
((date[-1] == '+' || date[-1] == '-'))) {
/* four digits and a value less than or equal to 1400 (to take into
account all sorts of funny time zone diffs) and it is preceded
- with a plus or minus. This is a time zone indication. 1400 is
+ with a plus or minus. This is a time zone indication. 1400 is
picked since +1300 is frequently used and +1400 is mentioned as
an edge number in the document "ISO C 200X Proposal: Timezone
Functions" at http://david.tribble.com/text/c0xtimezone.html If
@@ -521,13 +521,13 @@ static int parsedate(const char *date, time_t *output)
#if (SIZEOF_TIME_T < 5)
#ifdef HAVE_TIME_T_UNSIGNED
- /* an unsigned 32-bit time_t can only hold dates to 2106 */
+ /* an unsigned 32 bit time_t can only hold dates to 2106 */
if(yearnum > 2105) {
*output = TIME_T_MAX;
return PARSEDATE_LATER;
}
#else
- /* a signed 32-bit time_t can only hold dates to the beginning of 2038 */
+ /* a signed 32 bit time_t can only hold dates to the beginning of 2038 */
if(yearnum > 2037) {
*output = TIME_T_MAX;
return PARSEDATE_LATER;
@@ -549,7 +549,7 @@ static int parsedate(const char *date, time_t *output)
return PARSEDATE_FAIL; /* clearly an illegal date */
/* time2epoch() returns a time_t. time_t is often 32 bits, sometimes even on
- architectures that feature a 64 bits 'long' but ultimately time_t is the
+ architectures that feature 64 bit 'long' but ultimately time_t is the
correct data type to use.
*/
t = time2epoch(secnum, minnum, hournum, mdaynum, monnum, yearnum);
diff --git a/contrib/libs/curl/lib/pingpong.c b/contrib/libs/curl/lib/pingpong.c
index 817e3f69a0..0081c9ca62 100644
--- a/contrib/libs/curl/lib/pingpong.c
+++ b/contrib/libs/curl/lib/pingpong.c
@@ -36,7 +36,6 @@
#include "pingpong.h"
#include "multiif.h"
#include "vtls/vtls.h"
-#include "strdup.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@@ -106,7 +105,7 @@ CURLcode Curl_pp_statemach(struct Curl_easy *data,
if(Curl_conn_data_pending(data, FIRSTSOCKET))
rc = 1;
- else if(pp->overflow)
+ else if(Curl_pp_moredata(pp))
/* We are receiving and there is data in the cache so just read it */
rc = 1;
else if(!pp->sendleft && Curl_conn_data_pending(data, FIRSTSOCKET))
@@ -119,7 +118,7 @@ CURLcode Curl_pp_statemach(struct Curl_easy *data,
interval_ms);
if(block) {
- /* if we did not wait, we do not have to spend time on this now */
+ /* if we didn't wait, we don't have to spend time on this now */
if(Curl_pgrsUpdate(data))
result = CURLE_ABORTED_BY_CALLBACK;
else
@@ -140,13 +139,19 @@ CURLcode Curl_pp_statemach(struct Curl_easy *data,
}
/* initialize stuff to prepare for reading a fresh new response */
-void Curl_pp_init(struct pingpong *pp)
+void Curl_pp_init(struct Curl_easy *data, struct pingpong *pp)
{
+ DEBUGASSERT(data);
pp->nread_resp = 0;
- pp->response = Curl_now(); /* start response time-out now! */
+ pp->linestart_resp = data->state.buffer;
pp->pending_resp = TRUE;
+ pp->response = Curl_now(); /* start response time-out now! */
+}
+
+/* setup for the coming transfer */
+void Curl_pp_setup(struct pingpong *pp)
+{
Curl_dyn_init(&pp->sendbuf, DYN_PINGPPONG_CMD);
- Curl_dyn_init(&pp->recvbuf, DYN_PINGPPONG_CMD);
}
/***********************************************************************
@@ -164,7 +169,7 @@ CURLcode Curl_pp_vsendf(struct Curl_easy *data,
const char *fmt,
va_list args)
{
- size_t bytes_written = 0;
+ ssize_t bytes_written = 0;
size_t write_len;
char *s;
CURLcode result;
@@ -179,7 +184,7 @@ CURLcode Curl_pp_vsendf(struct Curl_easy *data,
DEBUGASSERT(pp->sendthis == NULL);
if(!conn)
- /* cannot send without a connection! */
+ /* can't send without a connection! */
return CURLE_SEND_ERROR;
Curl_dyn_reset(&pp->sendbuf);
@@ -192,19 +197,15 @@ CURLcode Curl_pp_vsendf(struct Curl_easy *data,
if(result)
return result;
- pp->pending_resp = TRUE;
write_len = Curl_dyn_len(&pp->sendbuf);
s = Curl_dyn_ptr(&pp->sendbuf);
+ Curl_pp_init(data, pp);
#ifdef HAVE_GSSAPI
conn->data_prot = PROT_CMD;
#endif
- result = Curl_conn_send(data, FIRSTSOCKET, s, write_len, FALSE,
- &bytes_written);
- if(result == CURLE_AGAIN) {
- bytes_written = 0;
- }
- else if(result)
+ result = Curl_nwrite(data, FIRSTSOCKET, s, write_len, &bytes_written);
+ if(result)
return result;
#ifdef HAVE_GSSAPI
data_sec = conn->data_prot;
@@ -212,9 +213,9 @@ CURLcode Curl_pp_vsendf(struct Curl_easy *data,
conn->data_prot = (unsigned char)data_sec;
#endif
- Curl_debug(data, CURLINFO_HEADER_OUT, s, bytes_written);
+ Curl_debug(data, CURLINFO_HEADER_OUT, s, (size_t)bytes_written);
- if(bytes_written != write_len) {
+ if(bytes_written != (ssize_t)write_len) {
/* the whole chunk was not sent, keep it around and adjust sizes */
pp->sendthis = s;
pp->sendsize = write_len;
@@ -254,131 +255,192 @@ CURLcode Curl_pp_sendf(struct Curl_easy *data, struct pingpong *pp,
return result;
}
-static CURLcode pingpong_read(struct Curl_easy *data,
- int sockindex,
- char *buffer,
- size_t buflen,
- ssize_t *nread)
-{
- CURLcode result;
-#ifdef HAVE_GSSAPI
- enum protection_level prot = data->conn->data_prot;
- data->conn->data_prot = PROT_CLEAR;
-#endif
- result = Curl_conn_recv(data, sockindex, buffer, buflen, nread);
-#ifdef HAVE_GSSAPI
- DEBUGASSERT(prot > PROT_NONE && prot < PROT_LAST);
- data->conn->data_prot = (unsigned char)prot;
-#endif
- return result;
-}
-
/*
* Curl_pp_readresp()
*
* Reads a piece of a server response.
*/
CURLcode Curl_pp_readresp(struct Curl_easy *data,
- int sockindex,
+ curl_socket_t sockfd,
struct pingpong *pp,
int *code, /* return the server code if done */
size_t *size) /* size of the response */
{
+ ssize_t perline; /* count bytes per line */
+ bool keepon = TRUE;
+ ssize_t gotbytes;
+ char *ptr;
struct connectdata *conn = data->conn;
+ char * const buf = data->state.buffer;
CURLcode result = CURLE_OK;
- ssize_t gotbytes;
- char buffer[900];
*code = 0; /* 0 for errors or not done */
*size = 0;
- do {
- gotbytes = 0;
- if(pp->nfinal) {
- /* a previous call left this many bytes in the beginning of the buffer as
- that was the final line; now ditch that */
- size_t full = Curl_dyn_len(&pp->recvbuf);
-
- /* trim off the "final" leading part */
- Curl_dyn_tail(&pp->recvbuf, full - pp->nfinal);
-
- pp->nfinal = 0; /* now gone */
+ ptr = buf + pp->nread_resp;
+
+ /* number of bytes in the current line, so far */
+ perline = (ssize_t)(ptr-pp->linestart_resp);
+
+ while((pp->nread_resp < (size_t)data->set.buffer_size) &&
+ (keepon && !result)) {
+
+ if(pp->cache) {
+ /* we had data in the "cache", copy that instead of doing an actual
+ * read
+ *
+ * pp->cache_size is cast to ssize_t here. This should be safe, because
+ * it would have been populated with something of size int to begin
+ * with, even though its datatype may be larger than an int.
+ */
+ if((ptr + pp->cache_size) > (buf + data->set.buffer_size + 1)) {
+ failf(data, "cached response data too big to handle");
+ return CURLE_WEIRD_SERVER_REPLY;
+ }
+ memcpy(ptr, pp->cache, pp->cache_size);
+ gotbytes = (ssize_t)pp->cache_size;
+ free(pp->cache); /* free the cache */
+ pp->cache = NULL; /* clear the pointer */
+ pp->cache_size = 0; /* zero the size just in case */
}
- if(!pp->overflow) {
- result = pingpong_read(data, sockindex, buffer, sizeof(buffer),
- &gotbytes);
+ else {
+#ifdef HAVE_GSSAPI
+ enum protection_level prot = conn->data_prot;
+ conn->data_prot = PROT_CLEAR;
+#endif
+ DEBUGASSERT((ptr + data->set.buffer_size - pp->nread_resp) <=
+ (buf + data->set.buffer_size + 1));
+ result = Curl_read(data, sockfd, ptr,
+ data->set.buffer_size - pp->nread_resp,
+ &gotbytes);
+#ifdef HAVE_GSSAPI
+ DEBUGASSERT(prot > PROT_NONE && prot < PROT_LAST);
+ conn->data_prot = (unsigned char)prot;
+#endif
if(result == CURLE_AGAIN)
- return CURLE_OK;
+ return CURLE_OK; /* return */
if(result)
- return result;
-
- if(gotbytes <= 0) {
- failf(data, "response reading failed (errno: %d)", SOCKERRNO);
- return CURLE_RECV_ERROR;
- }
+ /* Set outer result variable to this error. */
+ keepon = FALSE;
+ }
- result = Curl_dyn_addn(&pp->recvbuf, buffer, gotbytes);
- if(result)
- return result;
+ if(!keepon)
+ ;
+ else if(gotbytes <= 0) {
+ keepon = FALSE;
+ result = CURLE_RECV_ERROR;
+ failf(data, "response reading failed (errno: %d)", SOCKERRNO);
+ }
+ else {
+ /* we got a whole chunk of data, which can be anything from one
+ * byte to a set of lines and possible just a piece of the last
+ * line */
+ ssize_t i;
+ ssize_t clipamount = 0;
+ bool restart = FALSE;
data->req.headerbytecount += (unsigned int)gotbytes;
pp->nread_resp += gotbytes;
- }
+ for(i = 0; i < gotbytes; ptr++, i++) {
+ perline++;
+ if(*ptr == '\n') {
+ /* a newline is CRLF in pp-talk, so the CR is ignored as
+ the line isn't really terminated until the LF comes */
- do {
- char *line = Curl_dyn_ptr(&pp->recvbuf);
- char *nl = memchr(line, '\n', Curl_dyn_len(&pp->recvbuf));
- if(nl) {
- /* a newline is CRLF in pp-talk, so the CR is ignored as
- the line is not really terminated until the LF comes */
- size_t length = nl - line + 1;
-
- /* output debug output if that is requested */
+ /* output debug output if that is requested */
#ifdef HAVE_GSSAPI
- if(!conn->sec_complete)
+ if(!conn->sec_complete)
#endif
- Curl_debug(data, CURLINFO_HEADER_IN, line, length);
-
- /*
- * Pass all response-lines to the callback function registered for
- * "headers". The response lines can be seen as a kind of headers.
- */
- result = Curl_client_write(data, CLIENTWRITE_INFO, line, length);
- if(result)
- return result;
-
- if(pp->endofresp(data, conn, line, length, code)) {
- /* When at "end of response", keep the endofresp line first in the
- buffer since it will be accessed outside (by pingpong
- parsers). Store the overflow counter to inform about additional
- data in this buffer after the endofresp line. */
- pp->nfinal = length;
- if(Curl_dyn_len(&pp->recvbuf) > length)
- pp->overflow = Curl_dyn_len(&pp->recvbuf) - length;
- else
- pp->overflow = 0;
- *size = pp->nread_resp; /* size of the response */
- pp->nread_resp = 0; /* restart */
- gotbytes = 0; /* force break out of outer loop */
- break;
+ Curl_debug(data, CURLINFO_HEADER_IN,
+ pp->linestart_resp, (size_t)perline);
+
+ /*
+ * We pass all response-lines to the callback function registered
+ * for "headers". The response lines can be seen as a kind of
+ * headers.
+ */
+ result = Curl_client_write(data, CLIENTWRITE_INFO,
+ pp->linestart_resp, perline);
+ if(result)
+ return result;
+
+ if(pp->endofresp(data, conn, pp->linestart_resp, perline, code)) {
+ /* This is the end of the last line, copy the last line to the
+ start of the buffer and null-terminate, for old times sake */
+ size_t n = ptr - pp->linestart_resp;
+ memmove(buf, pp->linestart_resp, n);
+ buf[n] = 0; /* null-terminate */
+ keepon = FALSE;
+ pp->linestart_resp = ptr + 1; /* advance pointer */
+ i++; /* skip this before getting out */
+
+ *size = pp->nread_resp; /* size of the response */
+ pp->nread_resp = 0; /* restart */
+ break;
+ }
+ perline = 0; /* line starts over here */
+ pp->linestart_resp = ptr + 1;
}
- if(Curl_dyn_len(&pp->recvbuf) > length)
- /* keep the remaining piece */
- Curl_dyn_tail((&pp->recvbuf), Curl_dyn_len(&pp->recvbuf) - length);
+ }
+
+ if(!keepon && (i != gotbytes)) {
+ /* We found the end of the response lines, but we didn't parse the
+ full chunk of data we have read from the server. We therefore need
+ to store the rest of the data to be checked on the next invoke as
+ it may actually contain another end of response already! */
+ clipamount = gotbytes - i;
+ restart = TRUE;
+ DEBUGF(infof(data, "Curl_pp_readresp_ %d bytes of trailing "
+ "server response left",
+ (int)clipamount));
+ }
+ else if(keepon) {
+
+ if((perline == gotbytes) &&
+ (gotbytes > (ssize_t)data->set.buffer_size/2)) {
+ /* We got an excessive line without newlines and we need to deal
+ with it. We keep the first bytes of the line then we throw
+ away the rest. */
+ infof(data, "Excessive server response line length received, "
+ "%zd bytes. Stripping", gotbytes);
+ restart = TRUE;
+
+ /* we keep 40 bytes since all our pingpong protocols are only
+ interested in the first piece */
+ clipamount = 40;
+ }
+ else if(pp->nread_resp > (size_t)data->set.buffer_size/2) {
+ /* We got a large chunk of data and there's potentially still
+ trailing data to take care of, so we put any such part in the
+ "cache", clear the buffer to make space and restart. */
+ clipamount = perline;
+ restart = TRUE;
+ }
+ }
+ else if(i == gotbytes)
+ restart = TRUE;
+
+ if(clipamount) {
+ pp->cache_size = clipamount;
+ pp->cache = malloc(pp->cache_size);
+ if(pp->cache)
+ memcpy(pp->cache, pp->linestart_resp, pp->cache_size);
else
- Curl_dyn_reset(&pp->recvbuf);
+ return CURLE_OUT_OF_MEMORY;
}
- else {
- /* without a newline, there is no overflow */
- pp->overflow = 0;
- break;
+ if(restart) {
+ /* now reset a few variables to start over nicely from the start of
+ the big buffer */
+ pp->nread_resp = 0; /* start over from scratch in the buffer */
+ ptr = pp->linestart_resp = buf;
+ perline = 0;
}
- } while(1); /* while there is buffer left to scan */
+ } /* there was data */
- } while(gotbytes == sizeof(buffer));
+ } /* while there's buffer left and loop is requested */
pp->pending_resp = FALSE;
@@ -400,34 +462,18 @@ int Curl_pp_getsock(struct Curl_easy *data,
return GETSOCK_READSOCK(0);
}
-bool Curl_pp_needs_flush(struct Curl_easy *data,
- struct pingpong *pp)
-{
- (void)data;
- return pp->sendleft > 0;
-}
-
CURLcode Curl_pp_flushsend(struct Curl_easy *data,
struct pingpong *pp)
{
/* we have a piece of a command still left to send */
- size_t written;
- CURLcode result;
-
- if(!Curl_pp_needs_flush(data, pp))
- return CURLE_OK;
-
- result = Curl_conn_send(data, FIRSTSOCKET,
- pp->sendthis + pp->sendsize - pp->sendleft,
- pp->sendleft, FALSE, &written);
- if(result == CURLE_AGAIN) {
- result = CURLE_OK;
- written = 0;
- }
+ ssize_t written;
+ CURLcode result = Curl_nwrite(data, FIRSTSOCKET,
+ pp->sendthis + pp->sendsize - pp->sendleft,
+ pp->sendleft, &written);
if(result)
return result;
- if(written != pp->sendleft) {
+ if(written != (ssize_t)pp->sendleft) {
/* only a fraction was sent */
pp->sendleft -= written;
}
@@ -442,13 +488,14 @@ CURLcode Curl_pp_flushsend(struct Curl_easy *data,
CURLcode Curl_pp_disconnect(struct pingpong *pp)
{
Curl_dyn_free(&pp->sendbuf);
- Curl_dyn_free(&pp->recvbuf);
+ Curl_safefree(pp->cache);
return CURLE_OK;
}
bool Curl_pp_moredata(struct pingpong *pp)
{
- return (!pp->sendleft && Curl_dyn_len(&pp->recvbuf) > pp->nfinal);
+ return (!pp->sendleft && pp->cache && pp->nread_resp < pp->cache_size) ?
+ TRUE : FALSE;
}
#endif
diff --git a/contrib/libs/curl/lib/pingpong.h b/contrib/libs/curl/lib/pingpong.h
index 72239ff059..80d3f7718c 100644
--- a/contrib/libs/curl/lib/pingpong.h
+++ b/contrib/libs/curl/lib/pingpong.h
@@ -37,7 +37,7 @@ struct connectdata;
typedef enum {
PPTRANSFER_BODY, /* yes do transfer a body */
PPTRANSFER_INFO, /* do still go through to get info/headers */
- PPTRANSFER_NONE /* do not get anything and do not get info */
+ PPTRANSFER_NONE /* don't get anything and don't get info */
} curl_pp_transfer;
/*
@@ -47,11 +47,16 @@ typedef enum {
* It holds response cache and non-blocking sending data.
*/
struct pingpong {
+ char *cache; /* data cache between getresponse()-calls */
+ size_t cache_size; /* size of cache in bytes */
size_t nread_resp; /* number of bytes currently read of a server response */
+ char *linestart_resp; /* line start pointer for the server response
+ reader function */
bool pending_resp; /* set TRUE when a server response is pending or in
progress, and is cleared once the last response is
read */
- char *sendthis; /* pointer to a buffer that is to be sent to the server */
+ char *sendthis; /* allocated pointer to a buffer that is to be sent to the
+ server */
size_t sendleft; /* number of bytes left to send from the sendthis buffer */
size_t sendsize; /* total size of the sendthis buffer */
struct curltime response; /* set to Curl_now() when a command has been sent
@@ -59,10 +64,6 @@ struct pingpong {
timediff_t response_time; /* When no timeout is given, this is the amount of
milliseconds we await for a server response. */
struct dynbuf sendbuf;
- struct dynbuf recvbuf;
- size_t overflow; /* number of bytes left after a final response line */
- size_t nfinal; /* number of bytes in the final response line, which
- after a match is first in the receice buffer */
/* Function pointers the protocols MUST implement and provide for the
pingpong layer to function */
@@ -83,13 +84,16 @@ struct pingpong {
* Curl_pp_statemach()
*
* called repeatedly until done. Set 'wait' to make it wait a while on the
- * socket if there is no traffic.
+ * socket if there's no traffic.
*/
CURLcode Curl_pp_statemach(struct Curl_easy *data, struct pingpong *pp,
bool block, bool disconnecting);
/* initialize stuff to prepare for reading a fresh new response */
-void Curl_pp_init(struct pingpong *pp);
+void Curl_pp_init(struct Curl_easy *data, struct pingpong *pp);
+
+/* setup for the transfer */
+void Curl_pp_setup(struct pingpong *pp);
/* Returns timeout in ms. 0 or negative number means the timeout has already
triggered */
@@ -109,7 +113,7 @@ timediff_t Curl_pp_state_timeout(struct Curl_easy *data,
*/
CURLcode Curl_pp_sendf(struct Curl_easy *data,
struct pingpong *pp,
- const char *fmt, ...) CURL_PRINTF(3, 4);
+ const char *fmt, ...);
/***********************************************************************
*
@@ -124,7 +128,7 @@ CURLcode Curl_pp_sendf(struct Curl_easy *data,
CURLcode Curl_pp_vsendf(struct Curl_easy *data,
struct pingpong *pp,
const char *fmt,
- va_list args) CURL_PRINTF(3, 0);
+ va_list args);
/*
* Curl_pp_readresp()
@@ -132,13 +136,11 @@ CURLcode Curl_pp_vsendf(struct Curl_easy *data,
* Reads a piece of a server response.
*/
CURLcode Curl_pp_readresp(struct Curl_easy *data,
- int sockindex,
+ curl_socket_t sockfd,
struct pingpong *pp,
int *code, /* return the server code if done */
size_t *size); /* size of the response */
-bool Curl_pp_needs_flush(struct Curl_easy *data,
- struct pingpong *pp);
CURLcode Curl_pp_flushsend(struct Curl_easy *data,
struct pingpong *pp);
diff --git a/contrib/libs/curl/lib/pop3.c b/contrib/libs/curl/lib/pop3.c
index 1f5334d917..3e0f20a690 100644
--- a/contrib/libs/curl/lib/pop3.c
+++ b/contrib/libs/curl/lib/pop3.c
@@ -77,16 +77,11 @@
#include "curl_sasl.h"
#include "curl_md5.h"
#include "warnless.h"
-#include "strdup.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
#include "curl_memory.h"
#include "memdebug.h"
-#ifndef ARRAYSIZE
-#define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
-#endif
-
/* Local API functions */
static CURLcode pop3_regular_transfer(struct Curl_easy *data, bool *done);
static CURLcode pop3_do(struct Curl_easy *data, bool *done);
@@ -111,17 +106,12 @@ static CURLcode pop3_continue_auth(struct Curl_easy *data, const char *mech,
static CURLcode pop3_cancel_auth(struct Curl_easy *data, const char *mech);
static CURLcode pop3_get_message(struct Curl_easy *data, struct bufref *out);
-/* This function scans the body after the end-of-body and writes everything
- * until the end is found */
-static CURLcode pop3_write(struct Curl_easy *data,
- const char *str, size_t nread, bool is_eos);
-
/*
* POP3 protocol handler.
*/
const struct Curl_handler Curl_handler_pop3 = {
- "pop3", /* scheme */
+ "POP3", /* scheme */
pop3_setup_connection, /* setup_connection */
pop3_do, /* do_it */
pop3_done, /* done */
@@ -134,8 +124,7 @@ const struct Curl_handler Curl_handler_pop3 = {
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
pop3_disconnect, /* disconnect */
- pop3_write, /* write_resp */
- ZERO_NULL, /* write_resp_hd */
+ ZERO_NULL, /* readwrite */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_POP3, /* defport */
@@ -151,7 +140,7 @@ const struct Curl_handler Curl_handler_pop3 = {
*/
const struct Curl_handler Curl_handler_pop3s = {
- "pop3s", /* scheme */
+ "POP3S", /* scheme */
pop3_setup_connection, /* setup_connection */
pop3_do, /* do_it */
pop3_done, /* done */
@@ -164,8 +153,7 @@ const struct Curl_handler Curl_handler_pop3s = {
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
pop3_disconnect, /* disconnect */
- pop3_write, /* write_resp */
- ZERO_NULL, /* write_resp_hd */
+ ZERO_NULL, /* readwrite */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_POP3S, /* defport */
@@ -203,53 +191,6 @@ static void pop3_to_pop3s(struct connectdata *conn)
#define pop3_to_pop3s(x) Curl_nop_stmt
#endif
-struct pop3_cmd {
- const char *name;
- unsigned short nlen;
- BIT(multiline); /* response is multi-line with last '.' line */
- BIT(multiline_with_args); /* is multi-line when command has args */
-};
-
-static const struct pop3_cmd pop3cmds[] = {
- { "APOP", 4, FALSE, FALSE },
- { "AUTH", 4, FALSE, FALSE },
- { "CAPA", 4, TRUE, TRUE },
- { "DELE", 4, FALSE, FALSE },
- { "LIST", 4, TRUE, FALSE },
- { "MSG", 3, TRUE, TRUE },
- { "NOOP", 4, FALSE, FALSE },
- { "PASS", 4, FALSE, FALSE },
- { "QUIT", 4, FALSE, FALSE },
- { "RETR", 4, TRUE, TRUE },
- { "RSET", 4, FALSE, FALSE },
- { "STAT", 4, FALSE, FALSE },
- { "STLS", 4, FALSE, FALSE },
- { "TOP", 3, TRUE, TRUE },
- { "UIDL", 4, TRUE, FALSE },
- { "USER", 4, FALSE, FALSE },
- { "UTF8", 4, FALSE, FALSE },
- { "XTND", 4, TRUE, TRUE },
-};
-
-/* Return iff a command is defined as "multi-line" (RFC 1939),
- * has a response terminated by a last line with a '.'.
- */
-static bool pop3_is_multiline(const char *cmdline)
-{
- size_t i;
- for(i = 0; i < ARRAYSIZE(pop3cmds); ++i) {
- if(strncasecompare(pop3cmds[i].name, cmdline, pop3cmds[i].nlen)) {
- if(!cmdline[pop3cmds[i].nlen])
- return pop3cmds[i].multiline;
- else if(cmdline[pop3cmds[i].nlen] == ' ')
- return pop3cmds[i].multiline_with_args;
- }
- }
- /* Unknown command, assume multi-line for backward compatibility with
- * earlier curl versions that only could do multi-line responses. */
- return TRUE;
-}
-
/***********************************************************************
*
* pop3_endofresp()
@@ -310,8 +251,8 @@ static bool pop3_endofresp(struct Curl_easy *data, struct connectdata *conn,
*/
static CURLcode pop3_get_message(struct Curl_easy *data, struct bufref *out)
{
- char *message = Curl_dyn_ptr(&data->conn->proto.pop3c.pp.recvbuf);
- size_t len = data->conn->proto.pop3c.pp.nfinal;
+ char *message = data->state.buffer;
+ size_t len = strlen(message);
if(len > 2) {
/* Find the start of the message */
@@ -462,7 +403,7 @@ static CURLcode pop3_perform_user(struct Curl_easy *data,
CURLcode result = CURLE_OK;
/* Check we have a username and password to authenticate with and end the
- connect phase if we do not */
+ connect phase if we don't */
if(!data->state.aptr.user) {
pop3_state(data, POP3_STOP);
@@ -496,7 +437,7 @@ static CURLcode pop3_perform_apop(struct Curl_easy *data,
char secret[2 * MD5_DIGEST_LEN + 1];
/* Check we have a username and password to authenticate with and end the
- connect phase if we do not */
+ connect phase if we don't */
if(!data->state.aptr.user) {
pop3_state(data, POP3_STOP);
@@ -606,7 +547,7 @@ static CURLcode pop3_perform_authentication(struct Curl_easy *data,
saslprogress progress = SASL_IDLE;
/* Check we have enough data to authenticate with and end the
- connect phase if we do not */
+ connect phase if we don't */
if(!Curl_sasl_can_authenticate(&pop3c->sasl, data)) {
pop3_state(data, POP3_STOP);
return result;
@@ -665,20 +606,18 @@ static CURLcode pop3_perform_command(struct Curl_easy *data)
else
command = "RETR";
- if(pop3->custom && pop3->custom[0] != '\0')
- command = pop3->custom;
-
/* Send the command */
if(pop3->id[0] != '\0')
result = Curl_pp_sendf(data, &conn->proto.pop3c.pp, "%s %s",
- command, pop3->id);
+ (pop3->custom && pop3->custom[0] != '\0' ?
+ pop3->custom : command), pop3->id);
else
- result = Curl_pp_sendf(data, &conn->proto.pop3c.pp, "%s", command);
+ result = Curl_pp_sendf(data, &conn->proto.pop3c.pp, "%s",
+ (pop3->custom && pop3->custom[0] != '\0' ?
+ pop3->custom : command));
- if(!result) {
+ if(!result)
pop3_state(data, POP3_COMMAND);
- data->req.no_body = !pop3_is_multiline(command);
- }
return result;
}
@@ -709,8 +648,8 @@ static CURLcode pop3_state_servergreet_resp(struct Curl_easy *data,
CURLcode result = CURLE_OK;
struct connectdata *conn = data->conn;
struct pop3_conn *pop3c = &conn->proto.pop3c;
- const char *line = Curl_dyn_ptr(&data->conn->proto.pop3c.pp.recvbuf);
- size_t len = data->conn->proto.pop3c.pp.nfinal;
+ const char *line = data->state.buffer;
+ size_t len = strlen(line);
(void)instate; /* no use for this yet */
@@ -718,35 +657,44 @@ static CURLcode pop3_state_servergreet_resp(struct Curl_easy *data,
failf(data, "Got unexpected pop3-server response");
result = CURLE_WEIRD_SERVER_REPLY;
}
- else if(len > 3) {
+ else {
/* Does the server support APOP authentication? */
- char *lt;
- char *gt = NULL;
-
- /* Look for the APOP timestamp */
- lt = memchr(line, '<', len);
- if(lt)
- /* search the remainder for '>' */
- gt = memchr(lt, '>', len - (lt - line));
- if(gt) {
- /* the length of the timestamp, including the brackets */
- size_t timestamplen = gt - lt + 1;
- char *at = memchr(lt, '@', timestamplen);
- /* If the timestamp does not contain '@' it is not (as required by
- RFC-1939) conformant to the RFC-822 message id syntax, and we
- therefore do not use APOP authentication. */
- if(at) {
- /* dupe the timestamp */
- pop3c->apoptimestamp = Curl_memdup0(lt, timestamplen);
- if(!pop3c->apoptimestamp)
- return CURLE_OUT_OF_MEMORY;
- /* Store the APOP capability */
- pop3c->authtypes |= POP3_TYPE_APOP;
+ if(len >= 4 && line[len - 2] == '>') {
+ /* Look for the APOP timestamp */
+ size_t i;
+ for(i = 3; i < len - 2; ++i) {
+ if(line[i] == '<') {
+ /* Calculate the length of the timestamp */
+ size_t timestamplen = len - 1 - i;
+ char *at;
+ if(!timestamplen)
+ break;
+
+ /* Allocate some memory for the timestamp */
+ pop3c->apoptimestamp = (char *)calloc(1, timestamplen + 1);
+
+ if(!pop3c->apoptimestamp)
+ break;
+
+ /* Copy the timestamp */
+ memcpy(pop3c->apoptimestamp, line + i, timestamplen);
+ pop3c->apoptimestamp[timestamplen] = '\0';
+
+ /* If the timestamp does not contain '@' it is not (as required by
+ RFC-1939) conformant to the RFC-822 message id syntax, and we
+ therefore do not use APOP authentication. */
+ at = strchr(pop3c->apoptimestamp, '@');
+ if(!at)
+ Curl_safefree(pop3c->apoptimestamp);
+ else
+ /* Store the APOP capability */
+ pop3c->authtypes |= POP3_TYPE_APOP;
+ break;
+ }
}
}
- if(!result)
- result = pop3_perform_capa(data, conn);
+ result = pop3_perform_capa(data, conn);
}
return result;
@@ -759,8 +707,8 @@ static CURLcode pop3_state_capa_resp(struct Curl_easy *data, int pop3code,
CURLcode result = CURLE_OK;
struct connectdata *conn = data->conn;
struct pop3_conn *pop3c = &conn->proto.pop3c;
- const char *line = Curl_dyn_ptr(&data->conn->proto.pop3c.pp.recvbuf);
- size_t len = data->conn->proto.pop3c.pp.nfinal;
+ const char *line = data->state.buffer;
+ size_t len = strlen(line);
(void)instate; /* no use for this yet */
@@ -816,7 +764,7 @@ static CURLcode pop3_state_capa_resp(struct Curl_easy *data, int pop3code,
}
}
else {
- /* Clear text is supported when CAPA is not recognised */
+ /* Clear text is supported when CAPA isn't recognised */
if(pop3code != '+')
pop3c->authtypes |= POP3_TYPE_CLEARTEXT;
@@ -847,7 +795,7 @@ static CURLcode pop3_state_starttls_resp(struct Curl_easy *data,
(void)instate; /* no use for this yet */
/* Pipelining in response is forbidden. */
- if(data->conn->proto.pop3c.pp.overflow)
+ if(data->conn->proto.pop3c.pp.cache_size)
return CURLE_WEIRD_SERVER_REPLY;
if(pop3code != '+') {
@@ -989,36 +937,31 @@ static CURLcode pop3_state_command_resp(struct Curl_easy *data,
pop3c->eob = 2;
/* But since this initial CR LF pair is not part of the actual body, we set
- the strip counter here so that these bytes will not be delivered. */
+ the strip counter here so that these bytes won't be delivered. */
pop3c->strip = 2;
if(pop3->transfer == PPTRANSFER_BODY) {
/* POP3 download */
- Curl_xfer_setup1(data, CURL_XFER_RECV, -1, FALSE);
+ Curl_setup_transfer(data, FIRSTSOCKET, -1, FALSE, -1);
- if(pp->overflow) {
- /* The recv buffer contains data that is actually body content so send
- it as such. Note that there may even be additional "headers" after
- the body */
-
- /* keep only the overflow */
- Curl_dyn_tail(&pp->recvbuf, pp->overflow);
- pp->nfinal = 0; /* done */
+ if(pp->cache) {
+ /* The header "cache" contains a bunch of data that is actually body
+ content so send it as such. Note that there may even be additional
+ "headers" after the body */
if(!data->req.no_body) {
- result = pop3_write(data, Curl_dyn_ptr(&pp->recvbuf),
- Curl_dyn_len(&pp->recvbuf), FALSE);
+ result = Curl_pop3_write(data, pp->cache, pp->cache_size);
if(result)
return result;
}
- /* reset the buffer */
- Curl_dyn_reset(&pp->recvbuf);
- pp->overflow = 0;
+ /* Free the cache */
+ Curl_safefree(pp->cache);
+
+ /* Reset the cache size */
+ pp->cache_size = 0;
}
}
- else
- pp->overflow = 0;
/* End of DO phase */
pop3_state(data, POP3_STOP);
@@ -1030,6 +973,7 @@ static CURLcode pop3_statemachine(struct Curl_easy *data,
struct connectdata *conn)
{
CURLcode result = CURLE_OK;
+ curl_socket_t sock = conn->sock[FIRSTSOCKET];
int pop3code;
struct pop3_conn *pop3c = &conn->proto.pop3c;
struct pingpong *pp = &pop3c->pp;
@@ -1046,7 +990,7 @@ static CURLcode pop3_statemachine(struct Curl_easy *data,
do {
/* Read the response from the server */
- result = Curl_pp_readresp(data, FIRSTSOCKET, pp, &pop3code, &nread);
+ result = Curl_pp_readresp(data, sock, pp, &pop3code, &nread);
if(result)
return result;
@@ -1187,7 +1131,8 @@ static CURLcode pop3_connect(struct Curl_easy *data, bool *done)
Curl_sasl_init(&pop3c->sasl, data, &saslpop3);
/* Initialise the pingpong layer */
- Curl_pp_init(pp);
+ Curl_pp_setup(pp);
+ Curl_pp_init(data, pp);
/* Parse the URL options */
result = pop3_parse_url_options(conn);
@@ -1505,13 +1450,12 @@ static CURLcode pop3_parse_custom_request(struct Curl_easy *data)
/***********************************************************************
*
- * pop3_write()
+ * Curl_pop3_write()
*
* This function scans the body after the end-of-body and writes everything
* until the end is found.
*/
-static CURLcode pop3_write(struct Curl_easy *data, const char *str,
- size_t nread, bool is_eos)
+CURLcode Curl_pop3_write(struct Curl_easy *data, char *str, size_t nread)
{
/* This code could be made into a special function in the handler struct */
CURLcode result = CURLE_OK;
@@ -1521,7 +1465,6 @@ static CURLcode pop3_write(struct Curl_easy *data, const char *str,
bool strip_dot = FALSE;
size_t last = 0;
size_t i;
- (void)is_eos;
/* Search through the buffer looking for the end-of-body marker which is
5 bytes (0d 0a 2e 0d 0a). Note that a line starting with a dot matches
@@ -1537,7 +1480,7 @@ static CURLcode pop3_write(struct Curl_easy *data, const char *str,
pop3c->eob++;
if(i) {
- /* Write out the body part that did not match */
+ /* Write out the body part that didn't match */
result = Curl_client_write(data, CLIENTWRITE_BODY, &str[last],
i - last);
@@ -1550,7 +1493,7 @@ static CURLcode pop3_write(struct Curl_easy *data, const char *str,
else if(pop3c->eob == 3)
pop3c->eob++;
else
- /* If the character match was not at position 0 or 3 then restart the
+ /* If the character match wasn't at position 0 or 3 then restart the
pattern matching */
pop3c->eob = 1;
break;
@@ -1559,7 +1502,7 @@ static CURLcode pop3_write(struct Curl_easy *data, const char *str,
if(pop3c->eob == 1 || pop3c->eob == 4)
pop3c->eob++;
else
- /* If the character match was not at position 1 or 4 then start the
+ /* If the character match wasn't at position 1 or 4 then start the
search again */
pop3c->eob = 0;
break;
@@ -1573,7 +1516,7 @@ static CURLcode pop3_write(struct Curl_easy *data, const char *str,
pop3c->eob = 0;
}
else
- /* If the character match was not at position 2 then start the search
+ /* If the character match wasn't at position 2 then start the search
again */
pop3c->eob = 0;
break;
diff --git a/contrib/libs/curl/lib/pop3.h b/contrib/libs/curl/lib/pop3.h
index 3d08dafa19..83f0f831e6 100644
--- a/contrib/libs/curl/lib/pop3.h
+++ b/contrib/libs/curl/lib/pop3.h
@@ -90,4 +90,8 @@ extern const struct Curl_handler Curl_handler_pop3s;
#define POP3_EOB "\x0d\x0a\x2e\x0d\x0a"
#define POP3_EOB_LEN 5
+/* This function scans the body after the end-of-body and writes everything
+ * until the end is found */
+CURLcode Curl_pop3_write(struct Curl_easy *data, char *str, size_t nread);
+
#endif /* HEADER_CURL_POP3_H */
diff --git a/contrib/libs/curl/lib/progress.c b/contrib/libs/curl/lib/progress.c
index cb9829c31f..e96cbf7af4 100644
--- a/contrib/libs/curl/lib/progress.c
+++ b/contrib/libs/curl/lib/progress.c
@@ -48,7 +48,8 @@ static void time2str(char *r, curl_off_t seconds)
if(h <= CURL_OFF_T_C(99)) {
curl_off_t m = (seconds - (h*CURL_OFF_T_C(3600))) / CURL_OFF_T_C(60);
curl_off_t s = (seconds - (h*CURL_OFF_T_C(3600))) - (m*CURL_OFF_T_C(60));
- msnprintf(r, 9, "%2" FMT_OFF_T ":%02" FMT_OFF_T ":%02" FMT_OFF_T, h, m, s);
+ msnprintf(r, 9, "%2" CURL_FORMAT_CURL_OFF_T ":%02" CURL_FORMAT_CURL_OFF_T
+ ":%02" CURL_FORMAT_CURL_OFF_T, h, m, s);
}
else {
/* this equals to more than 99 hours, switch to a more suitable output
@@ -56,9 +57,10 @@ static void time2str(char *r, curl_off_t seconds)
curl_off_t d = seconds / CURL_OFF_T_C(86400);
h = (seconds - (d*CURL_OFF_T_C(86400))) / CURL_OFF_T_C(3600);
if(d <= CURL_OFF_T_C(999))
- msnprintf(r, 9, "%3" FMT_OFF_T "d %02" FMT_OFF_T "h", d, h);
+ msnprintf(r, 9, "%3" CURL_FORMAT_CURL_OFF_T
+ "d %02" CURL_FORMAT_CURL_OFF_T "h", d, h);
else
- msnprintf(r, 9, "%7" FMT_OFF_T "d", d);
+ msnprintf(r, 9, "%7" CURL_FORMAT_CURL_OFF_T "d", d);
}
}
@@ -74,40 +76,40 @@ static char *max5data(curl_off_t bytes, char *max5)
#define ONE_PETABYTE (CURL_OFF_T_C(1024) * ONE_TERABYTE)
if(bytes < CURL_OFF_T_C(100000))
- msnprintf(max5, 6, "%5" FMT_OFF_T, bytes);
+ msnprintf(max5, 6, "%5" CURL_FORMAT_CURL_OFF_T, bytes);
else if(bytes < CURL_OFF_T_C(10000) * ONE_KILOBYTE)
- msnprintf(max5, 6, "%4" FMT_OFF_T "k", bytes/ONE_KILOBYTE);
+ msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "k", bytes/ONE_KILOBYTE);
else if(bytes < CURL_OFF_T_C(100) * ONE_MEGABYTE)
- /* 'XX.XM' is good as long as we are less than 100 megs */
- msnprintf(max5, 6, "%2" FMT_OFF_T ".%0"
- FMT_OFF_T "M", bytes/ONE_MEGABYTE,
+ /* 'XX.XM' is good as long as we're less than 100 megs */
+ msnprintf(max5, 6, "%2" CURL_FORMAT_CURL_OFF_T ".%0"
+ CURL_FORMAT_CURL_OFF_T "M", bytes/ONE_MEGABYTE,
(bytes%ONE_MEGABYTE) / (ONE_MEGABYTE/CURL_OFF_T_C(10)) );
else if(bytes < CURL_OFF_T_C(10000) * ONE_MEGABYTE)
- /* 'XXXXM' is good until we are at 10000MB or above */
- msnprintf(max5, 6, "%4" FMT_OFF_T "M", bytes/ONE_MEGABYTE);
+ /* 'XXXXM' is good until we're at 10000MB or above */
+ msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "M", bytes/ONE_MEGABYTE);
else if(bytes < CURL_OFF_T_C(100) * ONE_GIGABYTE)
/* 10000 MB - 100 GB, we show it as XX.XG */
- msnprintf(max5, 6, "%2" FMT_OFF_T ".%0"
- FMT_OFF_T "G", bytes/ONE_GIGABYTE,
+ msnprintf(max5, 6, "%2" CURL_FORMAT_CURL_OFF_T ".%0"
+ CURL_FORMAT_CURL_OFF_T "G", bytes/ONE_GIGABYTE,
(bytes%ONE_GIGABYTE) / (ONE_GIGABYTE/CURL_OFF_T_C(10)) );
else if(bytes < CURL_OFF_T_C(10000) * ONE_GIGABYTE)
/* up to 10000GB, display without decimal: XXXXG */
- msnprintf(max5, 6, "%4" FMT_OFF_T "G", bytes/ONE_GIGABYTE);
+ msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "G", bytes/ONE_GIGABYTE);
else if(bytes < CURL_OFF_T_C(10000) * ONE_TERABYTE)
/* up to 10000TB, display without decimal: XXXXT */
- msnprintf(max5, 6, "%4" FMT_OFF_T "T", bytes/ONE_TERABYTE);
+ msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "T", bytes/ONE_TERABYTE);
else
/* up to 10000PB, display without decimal: XXXXP */
- msnprintf(max5, 6, "%4" FMT_OFF_T "P", bytes/ONE_PETABYTE);
+ msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "P", bytes/ONE_PETABYTE);
- /* 16384 petabytes (16 exabytes) is the maximum a 64-bit unsigned number can
+ /* 16384 petabytes (16 exabytes) is the maximum a 64 bit unsigned number can
hold, but our data type is signed so 8192PB will be the maximum. */
return max5;
@@ -138,7 +140,7 @@ int Curl_pgrsDone(struct Curl_easy *data)
if(!(data->progress.flags & PGRS_HIDE) &&
!data->progress.callback)
- /* only output if we do not use a progress callback and we are not
+ /* only output if we don't use a progress callback and we're not
* hidden */
fprintf(data->set.err, "\n");
@@ -172,18 +174,10 @@ void Curl_pgrsTimeWas(struct Curl_easy *data, timerid timer,
data->progress.t_startop = timestamp;
break;
case TIMER_STARTSINGLE:
- /* This is set at the start of each single transfer */
+ /* This is set at the start of each single fetch */
data->progress.t_startsingle = timestamp;
data->progress.is_t_startransfer_set = false;
break;
- case TIMER_POSTQUEUE:
- /* Set when the transfer starts (after potentially having been brought
- back from the waiting queue). It needs to count from t_startop and not
- t_startsingle since the latter is reset when a connection is brought
- back from the pending queue. */
- data->progress.t_postqueue =
- Curl_timediff_us(timestamp, data->progress.t_startop);
- break;
case TIMER_STARTACCEPT:
data->progress.t_acceptdata = timestamp;
break;
@@ -202,7 +196,7 @@ void Curl_pgrsTimeWas(struct Curl_easy *data, timerid timer,
case TIMER_STARTTRANSFER:
delta = &data->progress.t_starttransfer;
/* prevent updating t_starttransfer unless:
- * 1) this is the first time we are setting t_starttransfer
+ * 1) this is the first time we're setting t_starttransfer
* 2) a redirect has occurred since the last time t_starttransfer was set
* This prevents repeated invocations of the function from incorrectly
* changing the t_starttransfer time.
@@ -215,7 +209,7 @@ void Curl_pgrsTimeWas(struct Curl_easy *data, timerid timer,
break;
}
case TIMER_POSTRANSFER:
- delta = &data->progress.t_posttransfer;
+ /* this is the normal end-of-transfer thing */
break;
case TIMER_REDIRECT:
data->progress.t_redirect = Curl_timediff_us(timestamp,
@@ -250,12 +244,12 @@ void Curl_pgrsStartNow(struct Curl_easy *data)
data->progress.speeder_c = 0; /* reset the progress meter display */
data->progress.start = Curl_now();
data->progress.is_t_startransfer_set = false;
- data->progress.ul.limit.start = data->progress.start;
- data->progress.dl.limit.start = data->progress.start;
- data->progress.ul.limit.start_size = 0;
- data->progress.dl.limit.start_size = 0;
- data->progress.dl.cur_size = 0;
- data->progress.ul.cur_size = 0;
+ data->progress.ul_limit_start = data->progress.start;
+ data->progress.dl_limit_start = data->progress.start;
+ data->progress.ul_limit_size = 0;
+ data->progress.dl_limit_size = 0;
+ data->progress.downloaded = 0;
+ data->progress.uploaded = 0;
/* clear all bits except HIDE and HEADERS_OUT */
data->progress.flags &= PGRS_HIDE|PGRS_HEADERS_OUT;
Curl_ratelimit(data, data->progress.start);
@@ -263,11 +257,11 @@ void Curl_pgrsStartNow(struct Curl_easy *data)
/*
* This is used to handle speed limits, calculating how many milliseconds to
- * wait until we are back under the speed limit, if needed.
+ * wait until we're back under the speed limit, if needed.
*
* The way it works is by having a "starting point" (time & amount of data
* transferred by then) used in the speed computation, to be used instead of
- * the start of the transfer. This starting point is regularly moved as
+ * the start of the transfer. This starting point is regularly moved as
* transfer goes on, to keep getting accurate values (instead of average over
* the entire transfer).
*
@@ -279,15 +273,17 @@ void Curl_pgrsStartNow(struct Curl_easy *data)
* starting point should be reset (to current); or the number of milliseconds
* to wait to get back under the speed limit.
*/
-timediff_t Curl_pgrsLimitWaitTime(struct pgrs_dir *d,
- curl_off_t speed_limit,
+timediff_t Curl_pgrsLimitWaitTime(curl_off_t cursize,
+ curl_off_t startsize,
+ curl_off_t limit,
+ struct curltime start,
struct curltime now)
{
- curl_off_t size = d->cur_size - d->limit.start_size;
+ curl_off_t size = cursize - startsize;
timediff_t minimum;
timediff_t actual;
- if(!speed_limit || !size)
+ if(!limit || !size)
return 0;
/*
@@ -295,9 +291,9 @@ timediff_t Curl_pgrsLimitWaitTime(struct pgrs_dir *d,
* stay below 'limit'.
*/
if(size < CURL_OFF_T_MAX/1000)
- minimum = (timediff_t) (CURL_OFF_T_C(1000) * size / speed_limit);
+ minimum = (timediff_t) (CURL_OFF_T_C(1000) * size / limit);
else {
- minimum = (timediff_t) (size / speed_limit);
+ minimum = (timediff_t) (size / limit);
if(minimum < TIMEDIFF_T_MAX/1000)
minimum *= 1000;
else
@@ -308,7 +304,7 @@ timediff_t Curl_pgrsLimitWaitTime(struct pgrs_dir *d,
* 'actual' is the time in milliseconds it took to actually download the
* last 'size' bytes.
*/
- actual = Curl_timediff_ceil(now, d->limit.start);
+ actual = Curl_timediff_ceil(now, start);
if(actual < minimum) {
/* if it downloaded the data faster than the limit, make it wait the
difference */
@@ -323,7 +319,7 @@ timediff_t Curl_pgrsLimitWaitTime(struct pgrs_dir *d,
*/
CURLcode Curl_pgrsSetDownloadCounter(struct Curl_easy *data, curl_off_t size)
{
- data->progress.dl.cur_size = size;
+ data->progress.downloaded = size;
return CURLE_OK;
}
@@ -332,19 +328,19 @@ CURLcode Curl_pgrsSetDownloadCounter(struct Curl_easy *data, curl_off_t size)
*/
void Curl_ratelimit(struct Curl_easy *data, struct curltime now)
{
- /* do not set a new stamp unless the time since last update is long enough */
+ /* don't set a new stamp unless the time since last update is long enough */
if(data->set.max_recv_speed) {
- if(Curl_timediff(now, data->progress.dl.limit.start) >=
+ if(Curl_timediff(now, data->progress.dl_limit_start) >=
MIN_RATE_LIMIT_PERIOD) {
- data->progress.dl.limit.start = now;
- data->progress.dl.limit.start_size = data->progress.dl.cur_size;
+ data->progress.dl_limit_start = now;
+ data->progress.dl_limit_size = data->progress.downloaded;
}
}
if(data->set.max_send_speed) {
- if(Curl_timediff(now, data->progress.ul.limit.start) >=
+ if(Curl_timediff(now, data->progress.ul_limit_start) >=
MIN_RATE_LIMIT_PERIOD) {
- data->progress.ul.limit.start = now;
- data->progress.ul.limit.start_size = data->progress.ul.cur_size;
+ data->progress.ul_limit_start = now;
+ data->progress.ul_limit_size = data->progress.uploaded;
}
}
}
@@ -354,17 +350,17 @@ void Curl_ratelimit(struct Curl_easy *data, struct curltime now)
*/
void Curl_pgrsSetUploadCounter(struct Curl_easy *data, curl_off_t size)
{
- data->progress.ul.cur_size = size;
+ data->progress.uploaded = size;
}
void Curl_pgrsSetDownloadSize(struct Curl_easy *data, curl_off_t size)
{
if(size >= 0) {
- data->progress.dl.total_size = size;
+ data->progress.size_dl = size;
data->progress.flags |= PGRS_DL_SIZE_KNOWN;
}
else {
- data->progress.dl.total_size = 0;
+ data->progress.size_dl = 0;
data->progress.flags &= ~PGRS_DL_SIZE_KNOWN;
}
}
@@ -372,11 +368,11 @@ void Curl_pgrsSetDownloadSize(struct Curl_easy *data, curl_off_t size)
void Curl_pgrsSetUploadSize(struct Curl_easy *data, curl_off_t size)
{
if(size >= 0) {
- data->progress.ul.total_size = size;
+ data->progress.size_ul = size;
data->progress.flags |= PGRS_UL_SIZE_KNOWN;
}
else {
- data->progress.ul.total_size = 0;
+ data->progress.size_ul = 0;
data->progress.flags &= ~PGRS_UL_SIZE_KNOWN;
}
}
@@ -395,7 +391,7 @@ static curl_off_t trspeed(curl_off_t size, /* number of bytes */
return CURL_OFF_T_MAX;
}
-/* returns TRUE if it is time to show the progress meter */
+/* returns TRUE if it's time to show the progress meter */
static bool progress_calc(struct Curl_easy *data, struct curltime now)
{
bool timetoshow = FALSE;
@@ -403,8 +399,8 @@ static bool progress_calc(struct Curl_easy *data, struct curltime now)
/* The time spent so far (from the start) in microseconds */
p->timespent = Curl_timediff_us(now, p->start);
- p->dl.speed = trspeed(p->dl.cur_size, p->timespent);
- p->ul.speed = trspeed(p->ul.cur_size, p->timespent);
+ p->dlspeed = trspeed(p->downloaded, p->timespent);
+ p->ulspeed = trspeed(p->uploaded, p->timespent);
/* Calculations done at most once a second, unless end is reached */
if(p->lastshow != now.tv_sec) {
@@ -415,7 +411,7 @@ static bool progress_calc(struct Curl_easy *data, struct curltime now)
/* Let's do the "current speed" thing, with the dl + ul speeds
combined. Store the speed at entry 'nowindex'. */
- p->speeder[ nowindex ] = p->dl.cur_size + p->ul.cur_size;
+ p->speeder[ nowindex ] = p->downloaded + p->uploaded;
/* remember the exact time for this moment */
p->speeder_time [ nowindex ] = now;
@@ -427,10 +423,10 @@ static bool progress_calc(struct Curl_easy *data, struct curltime now)
/* figure out how many index entries of data we have stored in our speeder
array. With N_ENTRIES filled in, we have about N_ENTRIES-1 seconds of
transfer. Imagine, after one second we have filled in two entries,
- after two seconds we have filled in three entries etc. */
+ after two seconds we've filled in three entries etc. */
countindex = ((p->speeder_c >= CURR_TIME)? CURR_TIME:p->speeder_c) - 1;
- /* first of all, we do not do this if there is no counted seconds yet */
+ /* first of all, we don't do this if there's no counted seconds yet */
if(countindex) {
int checkindex;
timediff_t span_ms;
@@ -461,107 +457,113 @@ static bool progress_calc(struct Curl_easy *data, struct curltime now)
}
else
/* the first second we use the average */
- p->current_speed = p->ul.speed + p->dl.speed;
+ p->current_speed = p->ulspeed + p->dlspeed;
} /* Calculations end */
return timetoshow;
}
#ifndef CURL_DISABLE_PROGRESS_METER
-
-struct pgrs_estimate {
- curl_off_t secs;
- curl_off_t percent;
-};
-
-static curl_off_t pgrs_est_percent(curl_off_t total, curl_off_t cur)
-{
- if(total > CURL_OFF_T_C(10000))
- return cur / (total/CURL_OFF_T_C(100));
- else if(total > CURL_OFF_T_C(0))
- return (cur*100) / total;
- return 0;
-}
-
-static void pgrs_estimates(struct pgrs_dir *d,
- bool total_known,
- struct pgrs_estimate *est)
-{
- est->secs = 0;
- est->percent = 0;
- if(total_known && (d->speed > CURL_OFF_T_C(0))) {
- est->secs = d->total_size / d->speed;
- est->percent = pgrs_est_percent(d->total_size, d->cur_size);
- }
-}
-
static void progress_meter(struct Curl_easy *data)
{
- struct Progress *p = &data->progress;
char max5[6][10];
- struct pgrs_estimate dl_estm;
- struct pgrs_estimate ul_estm;
- struct pgrs_estimate total_estm;
- curl_off_t total_cur_size;
- curl_off_t total_expected_size;
+ curl_off_t dlpercen = 0;
+ curl_off_t ulpercen = 0;
+ curl_off_t total_percen = 0;
+ curl_off_t total_transfer;
+ curl_off_t total_expected_transfer;
char time_left[10];
char time_total[10];
char time_spent[10];
- curl_off_t cur_secs = (curl_off_t)p->timespent/1000000; /* seconds */
+ curl_off_t ulestimate = 0;
+ curl_off_t dlestimate = 0;
+ curl_off_t total_estimate;
+ curl_off_t timespent =
+ (curl_off_t)data->progress.timespent/1000000; /* seconds */
- if(!(p->flags & PGRS_HEADERS_OUT)) {
+ if(!(data->progress.flags & PGRS_HEADERS_OUT)) {
if(data->state.resume_from) {
fprintf(data->set.err,
- "** Resuming transfer from byte position %" FMT_OFF_T "\n",
- data->state.resume_from);
+ "** Resuming transfer from byte position %"
+ CURL_FORMAT_CURL_OFF_T "\n", data->state.resume_from);
}
fprintf(data->set.err,
" %% Total %% Received %% Xferd Average Speed "
"Time Time Time Current\n"
" Dload Upload "
"Total Spent Left Speed\n");
- p->flags |= PGRS_HEADERS_OUT; /* headers are shown */
+ data->progress.flags |= PGRS_HEADERS_OUT; /* headers are shown */
+ }
+
+ /* Figure out the estimated time of arrival for the upload */
+ if((data->progress.flags & PGRS_UL_SIZE_KNOWN) &&
+ (data->progress.ulspeed > CURL_OFF_T_C(0))) {
+ ulestimate = data->progress.size_ul / data->progress.ulspeed;
+
+ if(data->progress.size_ul > CURL_OFF_T_C(10000))
+ ulpercen = data->progress.uploaded /
+ (data->progress.size_ul/CURL_OFF_T_C(100));
+ else if(data->progress.size_ul > CURL_OFF_T_C(0))
+ ulpercen = (data->progress.uploaded*100) /
+ data->progress.size_ul;
+ }
+
+ /* ... and the download */
+ if((data->progress.flags & PGRS_DL_SIZE_KNOWN) &&
+ (data->progress.dlspeed > CURL_OFF_T_C(0))) {
+ dlestimate = data->progress.size_dl / data->progress.dlspeed;
+
+ if(data->progress.size_dl > CURL_OFF_T_C(10000))
+ dlpercen = data->progress.downloaded /
+ (data->progress.size_dl/CURL_OFF_T_C(100));
+ else if(data->progress.size_dl > CURL_OFF_T_C(0))
+ dlpercen = (data->progress.downloaded*100) /
+ data->progress.size_dl;
}
- /* Figure out the estimated time of arrival for upload and download */
- pgrs_estimates(&p->ul, (p->flags & PGRS_UL_SIZE_KNOWN), &ul_estm);
- pgrs_estimates(&p->dl, (p->flags & PGRS_DL_SIZE_KNOWN), &dl_estm);
+ /* Now figure out which of them is slower and use that one for the
+ total estimate! */
+ total_estimate = ulestimate>dlestimate?ulestimate:dlestimate;
- /* Since both happen at the same time, total expected duration is max. */
- total_estm.secs = CURLMAX(ul_estm.secs, dl_estm.secs);
/* create the three time strings */
- time2str(time_left, total_estm.secs > 0?(total_estm.secs - cur_secs):0);
- time2str(time_total, total_estm.secs);
- time2str(time_spent, cur_secs);
+ time2str(time_left, total_estimate > 0?(total_estimate - timespent):0);
+ time2str(time_total, total_estimate);
+ time2str(time_spent, timespent);
/* Get the total amount of data expected to get transferred */
- total_expected_size =
- ((p->flags & PGRS_UL_SIZE_KNOWN)? p->ul.total_size:p->ul.cur_size) +
- ((p->flags & PGRS_DL_SIZE_KNOWN)? p->dl.total_size:p->dl.cur_size);
+ total_expected_transfer =
+ ((data->progress.flags & PGRS_UL_SIZE_KNOWN)?
+ data->progress.size_ul:data->progress.uploaded)+
+ ((data->progress.flags & PGRS_DL_SIZE_KNOWN)?
+ data->progress.size_dl:data->progress.downloaded);
/* We have transferred this much so far */
- total_cur_size = p->dl.cur_size + p->ul.cur_size;
+ total_transfer = data->progress.downloaded + data->progress.uploaded;
/* Get the percentage of data transferred so far */
- total_estm.percent = pgrs_est_percent(total_expected_size, total_cur_size);
+ if(total_expected_transfer > CURL_OFF_T_C(10000))
+ total_percen = total_transfer /
+ (total_expected_transfer/CURL_OFF_T_C(100));
+ else if(total_expected_transfer > CURL_OFF_T_C(0))
+ total_percen = (total_transfer*100) / total_expected_transfer;
fprintf(data->set.err,
"\r"
- "%3" FMT_OFF_T " %s "
- "%3" FMT_OFF_T " %s "
- "%3" FMT_OFF_T " %s %s %s %s %s %s %s",
- total_estm.percent, /* 3 letters */ /* total % */
- max5data(total_expected_size, max5[2]), /* total size */
- dl_estm.percent, /* 3 letters */ /* rcvd % */
- max5data(p->dl.cur_size, max5[0]), /* rcvd size */
- ul_estm.percent, /* 3 letters */ /* xfer % */
- max5data(p->ul.cur_size, max5[1]), /* xfer size */
- max5data(p->dl.speed, max5[3]), /* avrg dl speed */
- max5data(p->ul.speed, max5[4]), /* avrg ul speed */
+ "%3" CURL_FORMAT_CURL_OFF_T " %s "
+ "%3" CURL_FORMAT_CURL_OFF_T " %s "
+ "%3" CURL_FORMAT_CURL_OFF_T " %s %s %s %s %s %s %s",
+ total_percen, /* 3 letters */ /* total % */
+ max5data(total_expected_transfer, max5[2]), /* total size */
+ dlpercen, /* 3 letters */ /* rcvd % */
+ max5data(data->progress.downloaded, max5[0]), /* rcvd size */
+ ulpercen, /* 3 letters */ /* xfer % */
+ max5data(data->progress.uploaded, max5[1]), /* xfer size */
+ max5data(data->progress.dlspeed, max5[3]), /* avrg dl speed */
+ max5data(data->progress.ulspeed, max5[4]), /* avrg ul speed */
time_total, /* 8 letters */ /* total time */
time_spent, /* 8 letters */ /* time spent */
time_left, /* 8 letters */ /* time left */
- max5data(p->current_speed, max5[5])
+ max5data(data->progress.current_speed, max5[5])
);
/* we flush the output stream to make it appear as soon as possible */
@@ -577,18 +579,20 @@ static void progress_meter(struct Curl_easy *data)
* Curl_pgrsUpdate() returns 0 for success or the value returned by the
* progress callback!
*/
-static int pgrsupdate(struct Curl_easy *data, bool showprogress)
+int Curl_pgrsUpdate(struct Curl_easy *data)
{
+ struct curltime now = Curl_now(); /* what time is it */
+ bool showprogress = progress_calc(data, now);
if(!(data->progress.flags & PGRS_HIDE)) {
if(data->set.fxferinfo) {
int result;
- /* There is a callback set, call that */
+ /* There's a callback set, call that */
Curl_set_in_callback(data, true);
result = data->set.fxferinfo(data->set.progress_client,
- data->progress.dl.total_size,
- data->progress.dl.cur_size,
- data->progress.ul.total_size,
- data->progress.ul.cur_size);
+ data->progress.size_dl,
+ data->progress.downloaded,
+ data->progress.size_ul,
+ data->progress.uploaded);
Curl_set_in_callback(data, false);
if(result != CURL_PROGRESSFUNC_CONTINUE) {
if(result)
@@ -601,10 +605,10 @@ static int pgrsupdate(struct Curl_easy *data, bool showprogress)
/* The older deprecated callback is set, call that */
Curl_set_in_callback(data, true);
result = data->set.fprogress(data->set.progress_client,
- (double)data->progress.dl.total_size,
- (double)data->progress.dl.cur_size,
- (double)data->progress.ul.total_size,
- (double)data->progress.ul.cur_size);
+ (double)data->progress.size_dl,
+ (double)data->progress.downloaded,
+ (double)data->progress.size_ul,
+ (double)data->progress.uploaded);
Curl_set_in_callback(data, false);
if(result != CURL_PROGRESSFUNC_CONTINUE) {
if(result)
@@ -619,19 +623,3 @@ static int pgrsupdate(struct Curl_easy *data, bool showprogress)
return 0;
}
-
-int Curl_pgrsUpdate(struct Curl_easy *data)
-{
- struct curltime now = Curl_now(); /* what time is it */
- bool showprogress = progress_calc(data, now);
- return pgrsupdate(data, showprogress);
-}
-
-/*
- * Update all progress, do not do progress meter/callbacks.
- */
-void Curl_pgrsUpdate_nometer(struct Curl_easy *data)
-{
- struct curltime now = Curl_now(); /* what time is it */
- (void)progress_calc(data, now);
-}
diff --git a/contrib/libs/curl/lib/progress.h b/contrib/libs/curl/lib/progress.h
index 04a8f5bce9..fc39e34d20 100644
--- a/contrib/libs/curl/lib/progress.h
+++ b/contrib/libs/curl/lib/progress.h
@@ -30,8 +30,7 @@
typedef enum {
TIMER_NONE,
TIMER_STARTOP,
- TIMER_STARTSINGLE, /* start of transfer, might get queued */
- TIMER_POSTQUEUE, /* start, immediately after dequeue */
+ TIMER_STARTSINGLE,
TIMER_NAMELOOKUP,
TIMER_CONNECT,
TIMER_APPCONNECT,
@@ -54,12 +53,12 @@ CURLcode Curl_pgrsSetDownloadCounter(struct Curl_easy *data, curl_off_t size);
void Curl_pgrsSetUploadCounter(struct Curl_easy *data, curl_off_t size);
void Curl_ratelimit(struct Curl_easy *data, struct curltime now);
int Curl_pgrsUpdate(struct Curl_easy *data);
-void Curl_pgrsUpdate_nometer(struct Curl_easy *data);
-
void Curl_pgrsResetTransferSizes(struct Curl_easy *data);
struct curltime Curl_pgrsTime(struct Curl_easy *data, timerid timer);
-timediff_t Curl_pgrsLimitWaitTime(struct pgrs_dir *d,
- curl_off_t speed_limit,
+timediff_t Curl_pgrsLimitWaitTime(curl_off_t cursize,
+ curl_off_t startsize,
+ curl_off_t limit,
+ struct curltime start,
struct curltime now);
/**
* Update progress timer with the elapsed time from its start to `timestamp`.
diff --git a/contrib/libs/curl/lib/rand.c b/contrib/libs/curl/lib/rand.c
index 63aebdc8f9..3383c490b6 100644
--- a/contrib/libs/curl/lib/rand.c
+++ b/contrib/libs/curl/lib/rand.c
@@ -48,8 +48,7 @@
#ifdef _WIN32
-#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x600 && \
- !defined(CURL_WINDOWS_APP)
+#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x600
# define HAVE_WIN_BCRYPTGENRANDOM
# include <bcrypt.h>
# ifdef _MSC_VER
@@ -100,91 +99,86 @@ CURLcode Curl_win32_random(unsigned char *entropy, size_t length)
}
#endif
-#if !defined(USE_SSL)
-/* ---- possibly non-cryptographic version following ---- */
-static CURLcode weak_random(struct Curl_easy *data,
- unsigned char *entropy,
- size_t length) /* always 4, size of int */
+static CURLcode randit(struct Curl_easy *data, unsigned int *rnd)
{
- unsigned int r;
- DEBUGASSERT(length == sizeof(int));
-
- /* Trying cryptographically secure functions first */
-#ifdef _WIN32
- (void)data;
- {
- CURLcode result = Curl_win32_random(entropy, length);
- if(result != CURLE_NOT_BUILT_IN)
- return result;
- }
-#endif
+ CURLcode result = CURLE_OK;
+ static unsigned int randseed;
+ static bool seeded = FALSE;
-#if defined(HAVE_ARC4RANDOM)
- (void)data;
- r = (unsigned int)arc4random();
- memcpy(entropy, &r, length);
-#else
- infof(data, "WARNING: using weak random seed");
- {
- static unsigned int randseed;
- static bool seeded = FALSE;
- unsigned int rnd;
+#ifdef CURLDEBUG
+ char *force_entropy = getenv("CURL_ENTROPY");
+ if(force_entropy) {
if(!seeded) {
- struct curltime now = Curl_now();
- randseed += (unsigned int)now.tv_usec + (unsigned int)now.tv_sec;
- randseed = randseed * 1103515245 + 12345;
- randseed = randseed * 1103515245 + 12345;
- randseed = randseed * 1103515245 + 12345;
+ unsigned int seed = 0;
+ size_t elen = strlen(force_entropy);
+ size_t clen = sizeof(seed);
+ size_t min = elen < clen ? elen : clen;
+ memcpy((char *)&seed, force_entropy, min);
+ randseed = ntohl(seed);
seeded = TRUE;
}
-
- /* Return an unsigned 32-bit pseudo-random number. */
- r = randseed = randseed * 1103515245 + 12345;
- rnd = (r << 16) | ((r >> 16) & 0xFFFF);
- memcpy(entropy, &rnd, length);
+ else
+ randseed++;
+ *rnd = randseed;
+ return CURLE_OK;
}
#endif
- return CURLE_OK;
-}
+
+ /* data may be NULL! */
+ result = Curl_ssl_random(data, (unsigned char *)rnd, sizeof(*rnd));
+ if(result != CURLE_NOT_BUILT_IN)
+ /* only if there is no random function in the TLS backend do the non crypto
+ version, otherwise return result */
+ return result;
+
+ /* ---- non-cryptographic version following ---- */
+
+#ifdef _WIN32
+ if(!seeded) {
+ result = Curl_win32_random((unsigned char *)rnd, sizeof(*rnd));
+ if(result != CURLE_NOT_BUILT_IN)
+ return result;
+ }
#endif
-#ifdef USE_SSL
-#define _random(x,y,z) Curl_ssl_random(x,y,z)
-#else
-#define _random(x,y,z) weak_random(x,y,z)
+#if defined(HAVE_ARC4RANDOM) && !defined(USE_OPENSSL)
+ if(!seeded) {
+ *rnd = (unsigned int)arc4random();
+ return CURLE_OK;
+ }
#endif
-static CURLcode randit(struct Curl_easy *data, unsigned int *rnd,
- bool env_override)
-{
-#ifdef DEBUGBUILD
- if(env_override) {
- char *force_entropy = getenv("CURL_ENTROPY");
- if(force_entropy) {
- static unsigned int randseed;
- static bool seeded = FALSE;
-
- if(!seeded) {
- unsigned int seed = 0;
- size_t elen = strlen(force_entropy);
- size_t clen = sizeof(seed);
- size_t min = elen < clen ? elen : clen;
- memcpy((char *)&seed, force_entropy, min);
- randseed = ntohl(seed);
+#if defined(RANDOM_FILE) && !defined(_WIN32)
+ if(!seeded) {
+ /* if there's a random file to read a seed from, use it */
+ int fd = open(RANDOM_FILE, O_RDONLY);
+ if(fd > -1) {
+ /* read random data into the randseed variable */
+ ssize_t nread = read(fd, &randseed, sizeof(randseed));
+ if(nread == sizeof(randseed))
seeded = TRUE;
- }
- else
- randseed++;
- *rnd = randseed;
- return CURLE_OK;
+ close(fd);
}
}
-#else
- (void)env_override;
#endif
- /* data may be NULL! */
- return _random(data, (unsigned char *)rnd, sizeof(*rnd));
+ if(!seeded) {
+ struct curltime now = Curl_now();
+ infof(data, "WARNING: using weak random seed");
+ randseed += (unsigned int)now.tv_usec + (unsigned int)now.tv_sec;
+ randseed = randseed * 1103515245 + 12345;
+ randseed = randseed * 1103515245 + 12345;
+ randseed = randseed * 1103515245 + 12345;
+ seeded = TRUE;
+ }
+
+ {
+ unsigned int r;
+ /* Return an unsigned 32-bit pseudo-random number. */
+ r = randseed = randseed * 1103515245 + 12345;
+ *rnd = (r << 16) | ((r >> 16) & 0xFFFF);
+ }
+ return CURLE_OK;
}
/*
@@ -192,7 +186,7 @@ static CURLcode randit(struct Curl_easy *data, unsigned int *rnd,
* 'rnd' points to.
*
* If libcurl is built without TLS support or with a TLS backend that lacks a
- * proper random API (Rustls or mbedTLS), this function will use "weak"
+ * proper random API (rustls or mbedTLS), this function will use "weak"
* random.
*
* When built *with* TLS support and a backend that offers strong random, it
@@ -203,24 +197,17 @@ static CURLcode randit(struct Curl_easy *data, unsigned int *rnd,
*
*/
-CURLcode Curl_rand_bytes(struct Curl_easy *data,
-#ifdef DEBUGBUILD
- bool env_override,
-#endif
- unsigned char *rnd, size_t num)
+CURLcode Curl_rand(struct Curl_easy *data, unsigned char *rnd, size_t num)
{
CURLcode result = CURLE_BAD_FUNCTION_ARGUMENT;
-#ifndef DEBUGBUILD
- const bool env_override = FALSE;
-#endif
- DEBUGASSERT(num);
+ DEBUGASSERT(num > 0);
while(num) {
unsigned int r;
size_t left = num < sizeof(unsigned int) ? num : sizeof(unsigned int);
- result = randit(data, &r, env_override);
+ result = randit(data, &r);
if(result)
return result;
@@ -254,11 +241,9 @@ CURLcode Curl_rand_hex(struct Curl_easy *data, unsigned char *rnd,
memset(buffer, 0, sizeof(buffer));
#endif
- if((num/2 >= sizeof(buffer)) || !(num&1)) {
+ if((num/2 >= sizeof(buffer)) || !(num&1))
/* make sure it fits in the local buffer and that it is an odd number! */
- DEBUGF(infof(data, "invalid buffer size with Curl_rand_hex"));
return CURLE_BAD_FUNCTION_ARGUMENT;
- }
num--; /* save one for null-termination */
@@ -282,7 +267,7 @@ CURLcode Curl_rand_alnum(struct Curl_easy *data, unsigned char *rnd,
size_t num)
{
CURLcode result = CURLE_OK;
- const unsigned int alnumspace = sizeof(alnum) - 1;
+ const int alnumspace = sizeof(alnum) - 1;
unsigned int r;
DEBUGASSERT(num > 1);
@@ -290,12 +275,12 @@ CURLcode Curl_rand_alnum(struct Curl_easy *data, unsigned char *rnd,
while(num) {
do {
- result = randit(data, &r, TRUE);
+ result = randit(data, &r);
if(result)
return result;
} while(r >= (UINT_MAX - UINT_MAX % alnumspace));
- *rnd++ = (unsigned char)alnum[r % alnumspace];
+ *rnd++ = alnum[r % alnumspace];
num--;
}
*rnd = 0;
diff --git a/contrib/libs/curl/lib/rand.h b/contrib/libs/curl/lib/rand.h
index 2ba60e7297..bc05239e45 100644
--- a/contrib/libs/curl/lib/rand.h
+++ b/contrib/libs/curl/lib/rand.h
@@ -24,17 +24,7 @@
*
***************************************************************************/
-CURLcode Curl_rand_bytes(struct Curl_easy *data,
-#ifdef DEBUGBUILD
- bool allow_env_override,
-#endif
- unsigned char *rnd, size_t num);
-
-#ifdef DEBUGBUILD
-#define Curl_rand(a,b,c) Curl_rand_bytes((a), TRUE, (b), (c))
-#else
-#define Curl_rand(a,b,c) Curl_rand_bytes((a), (b), (c))
-#endif
+CURLcode Curl_rand(struct Curl_easy *data, unsigned char *rnd, size_t num);
/*
* Curl_rand_hex() fills the 'rnd' buffer with a given 'num' size with random
diff --git a/contrib/libs/curl/lib/rename.c b/contrib/libs/curl/lib/rename.c
index 8715a4306d..4c88698067 100644
--- a/contrib/libs/curl/lib/rename.c
+++ b/contrib/libs/curl/lib/rename.c
@@ -41,7 +41,7 @@
int Curl_rename(const char *oldpath, const char *newpath)
{
#ifdef _WIN32
- /* rename() on Windows does not overwrite, so we cannot use it here.
+ /* rename() on Windows doesn't overwrite, so we can't use it here.
MoveFileEx() will overwrite and is usually atomic, however it fails
when there are open handles to the file. */
const int max_wait_ms = 1000;
diff --git a/contrib/libs/curl/lib/request.c b/contrib/libs/curl/lib/request.c
deleted file mode 100644
index 1ddbdc9d0f..0000000000
--- a/contrib/libs/curl/lib/request.c
+++ /dev/null
@@ -1,472 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at https://curl.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * SPDX-License-Identifier: curl
- *
- ***************************************************************************/
-
-#include "curl_setup.h"
-
-#include "urldata.h"
-#include "cfilters.h"
-#include "dynbuf.h"
-#include "doh.h"
-#include "multiif.h"
-#include "progress.h"
-#include "request.h"
-#include "sendf.h"
-#include "transfer.h"
-#include "url.h"
-
-/* The last 3 #include files should be in this order */
-#include "curl_printf.h"
-#include "curl_memory.h"
-#include "memdebug.h"
-
-void Curl_req_init(struct SingleRequest *req)
-{
- memset(req, 0, sizeof(*req));
-}
-
-CURLcode Curl_req_soft_reset(struct SingleRequest *req,
- struct Curl_easy *data)
-{
- CURLcode result;
-
- req->done = FALSE;
- req->upload_done = FALSE;
- req->upload_aborted = FALSE;
- req->download_done = FALSE;
- req->eos_written = FALSE;
- req->eos_read = FALSE;
- req->eos_sent = FALSE;
- req->ignorebody = FALSE;
- req->shutdown = FALSE;
- req->bytecount = 0;
- req->writebytecount = 0;
- req->header = TRUE; /* assume header */
- req->headerline = 0;
- req->headerbytecount = 0;
- req->allheadercount = 0;
- req->deductheadercount = 0;
-
- result = Curl_client_start(data);
- if(result)
- return result;
-
- if(!req->sendbuf_init) {
- Curl_bufq_init2(&req->sendbuf, data->set.upload_buffer_size, 1,
- BUFQ_OPT_SOFT_LIMIT);
- req->sendbuf_init = TRUE;
- }
- else {
- Curl_bufq_reset(&req->sendbuf);
- if(data->set.upload_buffer_size != req->sendbuf.chunk_size) {
- Curl_bufq_free(&req->sendbuf);
- Curl_bufq_init2(&req->sendbuf, data->set.upload_buffer_size, 1,
- BUFQ_OPT_SOFT_LIMIT);
- }
- }
-
- return CURLE_OK;
-}
-
-CURLcode Curl_req_start(struct SingleRequest *req,
- struct Curl_easy *data)
-{
- req->start = Curl_now();
- return Curl_req_soft_reset(req, data);
-}
-
-static CURLcode req_flush(struct Curl_easy *data);
-
-CURLcode Curl_req_done(struct SingleRequest *req,
- struct Curl_easy *data, bool aborted)
-{
- (void)req;
- if(!aborted)
- (void)req_flush(data);
- Curl_client_reset(data);
-#ifndef CURL_DISABLE_DOH
- Curl_doh_close(data);
-#endif
- return CURLE_OK;
-}
-
-void Curl_req_hard_reset(struct SingleRequest *req, struct Curl_easy *data)
-{
- struct curltime t0 = {0, 0};
-
- /* This is a bit ugly. `req->p` is a union and we assume we can
- * free this safely without leaks. */
- Curl_safefree(req->p.ftp);
- Curl_safefree(req->newurl);
- Curl_client_reset(data);
- if(req->sendbuf_init)
- Curl_bufq_reset(&req->sendbuf);
-
-#ifndef CURL_DISABLE_DOH
- Curl_doh_close(data);
-#endif
- /* Can no longer memset() this struct as we need to keep some state */
- req->size = -1;
- req->maxdownload = -1;
- req->bytecount = 0;
- req->writebytecount = 0;
- req->start = t0;
- req->headerbytecount = 0;
- req->allheadercount = 0;
- req->deductheadercount = 0;
- req->headerline = 0;
- req->offset = 0;
- req->httpcode = 0;
- req->keepon = 0;
- req->upgr101 = UPGR101_INIT;
- req->timeofdoc = 0;
- req->location = NULL;
- req->newurl = NULL;
-#ifndef CURL_DISABLE_COOKIES
- req->setcookies = 0;
-#endif
- req->header = FALSE;
- req->content_range = FALSE;
- req->download_done = FALSE;
- req->eos_written = FALSE;
- req->eos_read = FALSE;
- req->eos_sent = FALSE;
- req->upload_done = FALSE;
- req->upload_aborted = FALSE;
- req->ignorebody = FALSE;
- req->http_bodyless = FALSE;
- req->chunk = FALSE;
- req->ignore_cl = FALSE;
- req->upload_chunky = FALSE;
- req->getheader = FALSE;
- req->no_body = data->set.opt_no_body;
- req->authneg = FALSE;
- req->shutdown = FALSE;
-#ifdef USE_HYPER
- req->bodywritten = FALSE;
-#endif
-}
-
-void Curl_req_free(struct SingleRequest *req, struct Curl_easy *data)
-{
- /* This is a bit ugly. `req->p` is a union and we assume we can
- * free this safely without leaks. */
- Curl_safefree(req->p.ftp);
- Curl_safefree(req->newurl);
- if(req->sendbuf_init)
- Curl_bufq_free(&req->sendbuf);
- Curl_client_cleanup(data);
-
-#ifndef CURL_DISABLE_DOH
- Curl_doh_cleanup(data);
-#endif
-}
-
-static CURLcode xfer_send(struct Curl_easy *data,
- const char *buf, size_t blen,
- size_t hds_len, size_t *pnwritten)
-{
- CURLcode result = CURLE_OK;
- bool eos = FALSE;
-
- *pnwritten = 0;
- DEBUGASSERT(hds_len <= blen);
-#ifdef DEBUGBUILD
- {
- /* Allow debug builds to override this logic to force short initial
- sends */
- size_t body_len = blen - hds_len;
- char *p = getenv("CURL_SMALLREQSEND");
- if(p) {
- size_t body_small = (size_t)strtoul(p, NULL, 10);
- if(body_small && body_small < body_len)
- blen = hds_len + body_small;
- }
- }
-#endif
- /* Make sure this does not send more body bytes than what the max send
- speed says. The headers do not count to the max speed. */
- if(data->set.max_send_speed) {
- size_t body_bytes = blen - hds_len;
- if((curl_off_t)body_bytes > data->set.max_send_speed)
- blen = hds_len + (size_t)data->set.max_send_speed;
- }
-
- if(data->req.eos_read &&
- (Curl_bufq_is_empty(&data->req.sendbuf) ||
- Curl_bufq_len(&data->req.sendbuf) == blen)) {
- DEBUGF(infof(data, "sending last upload chunk of %zu bytes", blen));
- eos = TRUE;
- }
- result = Curl_xfer_send(data, buf, blen, eos, pnwritten);
- if(!result) {
- if(eos && (blen == *pnwritten))
- data->req.eos_sent = TRUE;
- if(*pnwritten) {
- if(hds_len)
- Curl_debug(data, CURLINFO_HEADER_OUT, (char *)buf,
- CURLMIN(hds_len, *pnwritten));
- if(*pnwritten > hds_len) {
- size_t body_len = *pnwritten - hds_len;
- Curl_debug(data, CURLINFO_DATA_OUT, (char *)buf + hds_len, body_len);
- data->req.writebytecount += body_len;
- Curl_pgrsSetUploadCounter(data, data->req.writebytecount);
- }
- }
- }
- return result;
-}
-
-static CURLcode req_send_buffer_flush(struct Curl_easy *data)
-{
- CURLcode result = CURLE_OK;
- const unsigned char *buf;
- size_t blen;
-
- while(Curl_bufq_peek(&data->req.sendbuf, &buf, &blen)) {
- size_t nwritten, hds_len = CURLMIN(data->req.sendbuf_hds_len, blen);
- result = xfer_send(data, (const char *)buf, blen, hds_len, &nwritten);
- if(result)
- break;
-
- Curl_bufq_skip(&data->req.sendbuf, nwritten);
- if(hds_len) {
- data->req.sendbuf_hds_len -= CURLMIN(hds_len, nwritten);
- }
- /* leave if we could not send all. Maybe network blocking or
- * speed limits on transfer */
- if(nwritten < blen)
- break;
- }
- return result;
-}
-
-CURLcode Curl_req_set_upload_done(struct Curl_easy *data)
-{
- DEBUGASSERT(!data->req.upload_done);
- data->req.upload_done = TRUE;
- data->req.keepon &= ~(KEEP_SEND|KEEP_SEND_TIMED); /* we are done sending */
-
- Curl_pgrsTime(data, TIMER_POSTRANSFER);
- Curl_creader_done(data, data->req.upload_aborted);
-
- if(data->req.upload_aborted) {
- Curl_bufq_reset(&data->req.sendbuf);
- if(data->req.writebytecount)
- infof(data, "abort upload after having sent %" FMT_OFF_T " bytes",
- data->req.writebytecount);
- else
- infof(data, "abort upload");
- }
- else if(data->req.writebytecount)
- infof(data, "upload completely sent off: %" FMT_OFF_T " bytes",
- data->req.writebytecount);
- else if(!data->req.download_done) {
- DEBUGASSERT(Curl_bufq_is_empty(&data->req.sendbuf));
- infof(data, Curl_creader_total_length(data)?
- "We are completely uploaded and fine" :
- "Request completely sent off");
- }
-
- return Curl_xfer_send_close(data);
-}
-
-static CURLcode req_flush(struct Curl_easy *data)
-{
- CURLcode result;
-
- if(!data || !data->conn)
- return CURLE_FAILED_INIT;
-
- if(!Curl_bufq_is_empty(&data->req.sendbuf)) {
- result = req_send_buffer_flush(data);
- if(result)
- return result;
- if(!Curl_bufq_is_empty(&data->req.sendbuf)) {
- DEBUGF(infof(data, "Curl_req_flush(len=%zu) -> EAGAIN",
- Curl_bufq_len(&data->req.sendbuf)));
- return CURLE_AGAIN;
- }
- }
- else if(Curl_xfer_needs_flush(data)) {
- DEBUGF(infof(data, "Curl_req_flush(), xfer send_pending"));
- return Curl_xfer_flush(data);
- }
-
- if(data->req.eos_read && !data->req.eos_sent) {
- char tmp;
- size_t nwritten;
- result = xfer_send(data, &tmp, 0, 0, &nwritten);
- if(result)
- return result;
- DEBUGASSERT(data->req.eos_sent);
- }
-
- if(!data->req.upload_done && data->req.eos_read && data->req.eos_sent) {
- DEBUGASSERT(Curl_bufq_is_empty(&data->req.sendbuf));
- if(data->req.shutdown) {
- bool done;
- result = Curl_xfer_send_shutdown(data, &done);
- if(result)
- return result;
- if(!done)
- return CURLE_AGAIN;
- }
- return Curl_req_set_upload_done(data);
- }
- return CURLE_OK;
-}
-
-static ssize_t add_from_client(void *reader_ctx,
- unsigned char *buf, size_t buflen,
- CURLcode *err)
-{
- struct Curl_easy *data = reader_ctx;
- size_t nread;
- bool eos;
-
- *err = Curl_client_read(data, (char *)buf, buflen, &nread, &eos);
- if(*err)
- return -1;
- if(eos)
- data->req.eos_read = TRUE;
- return (ssize_t)nread;
-}
-
-#ifndef USE_HYPER
-
-static CURLcode req_send_buffer_add(struct Curl_easy *data,
- const char *buf, size_t blen,
- size_t hds_len)
-{
- CURLcode result = CURLE_OK;
- ssize_t n;
- n = Curl_bufq_write(&data->req.sendbuf,
- (const unsigned char *)buf, blen, &result);
- if(n < 0)
- return result;
- /* We rely on a SOFTLIMIT on sendbuf, so it can take all data in */
- DEBUGASSERT((size_t)n == blen);
- data->req.sendbuf_hds_len += hds_len;
- return CURLE_OK;
-}
-
-CURLcode Curl_req_send(struct Curl_easy *data, struct dynbuf *req)
-{
- CURLcode result;
- const char *buf;
- size_t blen, nwritten;
-
- if(!data || !data->conn)
- return CURLE_FAILED_INIT;
-
- buf = Curl_dyn_ptr(req);
- blen = Curl_dyn_len(req);
- if(!Curl_creader_total_length(data)) {
- /* Request without body. Try to send directly from the buf given. */
- data->req.eos_read = TRUE;
- result = xfer_send(data, buf, blen, blen, &nwritten);
- if(result)
- return result;
- buf += nwritten;
- blen -= nwritten;
- }
-
- if(blen) {
- /* Either we have a request body, or we could not send the complete
- * request in one go. Buffer the remainder and try to add as much
- * body bytes as room is left in the buffer. Then flush. */
- result = req_send_buffer_add(data, buf, blen, blen);
- if(result)
- return result;
-
- return Curl_req_send_more(data);
- }
- return CURLE_OK;
-}
-#endif /* !USE_HYPER */
-
-bool Curl_req_sendbuf_empty(struct Curl_easy *data)
-{
- return !data->req.sendbuf_init || Curl_bufq_is_empty(&data->req.sendbuf);
-}
-
-bool Curl_req_want_send(struct Curl_easy *data)
-{
- /* Not done and
- * - KEEP_SEND and not PAUSEd.
- * - or request has buffered data to send
- * - or transfer connection has pending data to send */
- return !data->req.done &&
- (((data->req.keepon & KEEP_SENDBITS) == KEEP_SEND) ||
- !Curl_req_sendbuf_empty(data) ||
- Curl_xfer_needs_flush(data));
-}
-
-bool Curl_req_done_sending(struct Curl_easy *data)
-{
- return data->req.upload_done && !Curl_req_want_send(data);
-}
-
-CURLcode Curl_req_send_more(struct Curl_easy *data)
-{
- CURLcode result;
-
- /* Fill our send buffer if more from client can be read. */
- if(!data->req.upload_aborted &&
- !data->req.eos_read &&
- !(data->req.keepon & KEEP_SEND_PAUSE) &&
- !Curl_bufq_is_full(&data->req.sendbuf)) {
- ssize_t nread = Curl_bufq_sipn(&data->req.sendbuf, 0,
- add_from_client, data, &result);
- if(nread < 0 && result != CURLE_AGAIN)
- return result;
- }
-
- result = req_flush(data);
- if(result == CURLE_AGAIN)
- result = CURLE_OK;
-
- return result;
-}
-
-CURLcode Curl_req_abort_sending(struct Curl_easy *data)
-{
- if(!data->req.upload_done) {
- Curl_bufq_reset(&data->req.sendbuf);
- data->req.upload_aborted = TRUE;
- /* no longer KEEP_SEND and KEEP_SEND_PAUSE */
- data->req.keepon &= ~KEEP_SENDBITS;
- return Curl_req_set_upload_done(data);
- }
- return CURLE_OK;
-}
-
-CURLcode Curl_req_stop_send_recv(struct Curl_easy *data)
-{
- /* stop receiving and ALL sending as well, including PAUSE and HOLD.
- * We might still be paused on receive client writes though, so
- * keep those bits around. */
- data->req.keepon &= ~(KEEP_RECV|KEEP_SENDBITS);
- return Curl_req_abort_sending(data);
-}
diff --git a/contrib/libs/curl/lib/request.h b/contrib/libs/curl/lib/request.h
deleted file mode 100644
index c53c3eb5ae..0000000000
--- a/contrib/libs/curl/lib/request.h
+++ /dev/null
@@ -1,250 +0,0 @@
-#ifndef HEADER_CURL_REQUEST_H
-#define HEADER_CURL_REQUEST_H
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at https://curl.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * SPDX-License-Identifier: curl
- *
- ***************************************************************************/
-
-/* This file is for lib internal stuff */
-
-#include "curl_setup.h"
-
-#include "bufq.h"
-
-/* forward declarations */
-struct UserDefined;
-#ifndef CURL_DISABLE_DOH
-struct doh_probes;
-#endif
-
-enum expect100 {
- EXP100_SEND_DATA, /* enough waiting, just send the body now */
- EXP100_AWAITING_CONTINUE, /* waiting for the 100 Continue header */
- EXP100_SENDING_REQUEST, /* still sending the request but will wait for
- the 100 header once done with the request */
- EXP100_FAILED /* used on 417 Expectation Failed */
-};
-
-enum upgrade101 {
- UPGR101_INIT, /* default state */
- UPGR101_WS, /* upgrade to WebSockets requested */
- UPGR101_H2, /* upgrade to HTTP/2 requested */
- UPGR101_RECEIVED, /* 101 response received */
- UPGR101_WORKING /* talking upgraded protocol */
-};
-
-
-/*
- * Request specific data in the easy handle (Curl_easy). Previously,
- * these members were on the connectdata struct but since a conn struct may
- * now be shared between different Curl_easys, we store connection-specific
- * data here. This struct only keeps stuff that is interesting for *this*
- * request, as it will be cleared between multiple ones
- */
-struct SingleRequest {
- curl_off_t size; /* -1 if unknown at this point */
- curl_off_t maxdownload; /* in bytes, the maximum amount of data to fetch,
- -1 means unlimited */
- curl_off_t bytecount; /* total number of bytes read */
- curl_off_t writebytecount; /* number of bytes written */
-
- struct curltime start; /* transfer started at this time */
- unsigned int headerbytecount; /* received server headers (not CONNECT
- headers) */
- unsigned int allheadercount; /* all received headers (server + CONNECT) */
- unsigned int deductheadercount; /* this amount of bytes does not count when
- we check if anything has been transferred
- at the end of a connection. We use this
- counter to make only a 100 reply (without
- a following second response code) result
- in a CURLE_GOT_NOTHING error code */
- int headerline; /* counts header lines to better track the
- first one */
- curl_off_t offset; /* possible resume offset read from the
- Content-Range: header */
- int httpversion; /* Version in response (09, 10, 11, etc.) */
- int httpcode; /* error code from the 'HTTP/1.? XXX' or
- 'RTSP/1.? XXX' line */
- int keepon;
- enum upgrade101 upgr101; /* 101 upgrade state */
-
- /* Client Writer stack, handles transfer- and content-encodings, protocol
- * checks, pausing by client callbacks. */
- struct Curl_cwriter *writer_stack;
- /* Client Reader stack, handles transfer- and content-encodings, protocol
- * checks, pausing by client callbacks. */
- struct Curl_creader *reader_stack;
- struct bufq sendbuf; /* data which needs to be send to the server */
- size_t sendbuf_hds_len; /* amount of header bytes in sendbuf */
- time_t timeofdoc;
- char *location; /* This points to an allocated version of the Location:
- header data */
- char *newurl; /* Set to the new URL to use when a redirect or a retry is
- wanted */
-
- /* Allocated protocol-specific data. Each protocol handler makes sure this
- points to data it needs. */
- union {
- struct FILEPROTO *file;
- struct FTP *ftp;
- struct IMAP *imap;
- struct ldapreqinfo *ldap;
- struct MQTT *mqtt;
- struct POP3 *pop3;
- struct RTSP *rtsp;
- struct smb_request *smb;
- struct SMTP *smtp;
- struct SSHPROTO *ssh;
- struct TELNET *telnet;
- } p;
-#ifndef CURL_DISABLE_DOH
- struct doh_probes *doh; /* DoH specific data for this request */
-#endif
-#ifndef CURL_DISABLE_COOKIES
- unsigned char setcookies;
-#endif
- BIT(header); /* incoming data has HTTP header */
- BIT(done); /* request is done, e.g. no more send/recv should
- * happen. This can be TRUE before `upload_done` or
- * `download_done` is TRUE. */
- BIT(content_range); /* set TRUE if Content-Range: was found */
- BIT(download_done); /* set to TRUE when download is complete */
- BIT(eos_written); /* iff EOS has been written to client */
- BIT(eos_read); /* iff EOS has been read from the client */
- BIT(eos_sent); /* iff EOS has been sent to the server */
- BIT(rewind_read); /* iff reader needs rewind at next start */
- BIT(upload_done); /* set to TRUE when all request data has been sent */
- BIT(upload_aborted); /* set to TRUE when upload was aborted. Will also
- * show `upload_done` as TRUE. */
- BIT(ignorebody); /* we read a response-body but we ignore it! */
- BIT(http_bodyless); /* HTTP response status code is between 100 and 199,
- 204 or 304 */
- BIT(chunk); /* if set, this is a chunked transfer-encoding */
- BIT(resp_trailer); /* response carried 'Trailer:' header field */
- BIT(ignore_cl); /* ignore content-length */
- BIT(upload_chunky); /* set TRUE if we are doing chunked transfer-encoding
- on upload */
- BIT(getheader); /* TRUE if header parsing is wanted */
- BIT(no_body); /* the response has no body */
- BIT(authneg); /* TRUE when the auth phase has started, which means
- that we are creating a request with an auth header,
- but it is not the final request in the auth
- negotiation. */
- BIT(sendbuf_init); /* sendbuf is initialized */
- BIT(shutdown); /* request end will shutdown connection */
-#ifdef USE_HYPER
- BIT(bodywritten);
-#endif
-};
-
-/**
- * Initialize the state of the request for first use.
- */
-void Curl_req_init(struct SingleRequest *req);
-
-/**
- * The request is about to start. Record time and do a soft reset.
- */
-CURLcode Curl_req_start(struct SingleRequest *req,
- struct Curl_easy *data);
-
-/**
- * The request may continue with a follow up. Reset
- * members, but keep start time for overall duration calc.
- */
-CURLcode Curl_req_soft_reset(struct SingleRequest *req,
- struct Curl_easy *data);
-
-/**
- * The request is done. If not aborted, make sure that buffers are
- * flushed to the client.
- * @param req the request
- * @param data the transfer
- * @param aborted TRUE iff the request was aborted/errored
- */
-CURLcode Curl_req_done(struct SingleRequest *req,
- struct Curl_easy *data, bool aborted);
-
-/**
- * Free the state of the request, not usable afterwards.
- */
-void Curl_req_free(struct SingleRequest *req, struct Curl_easy *data);
-
-/**
- * Hard reset the state of the request to virgin state base on
- * transfer settings.
- */
-void Curl_req_hard_reset(struct SingleRequest *req, struct Curl_easy *data);
-
-#ifndef USE_HYPER
-/**
- * Send request headers. If not all could be sent
- * they will be buffered. Use `Curl_req_flush()` to make sure
- * bytes are really send.
- * @param data the transfer making the request
- * @param buf the complete header bytes, no body
- * @return CURLE_OK (on blocking with *pnwritten == 0) or error.
- */
-CURLcode Curl_req_send(struct Curl_easy *data, struct dynbuf *buf);
-
-#endif /* !USE_HYPER */
-
-/**
- * TRUE iff the request has sent all request headers and data.
- */
-bool Curl_req_done_sending(struct Curl_easy *data);
-
-/*
- * Read more from client and flush all buffered request bytes.
- * @return CURLE_OK on success or the error on the sending.
- * Never returns CURLE_AGAIN.
- */
-CURLcode Curl_req_send_more(struct Curl_easy *data);
-
-/**
- * TRUE iff the request wants to send, e.g. has buffered bytes.
- */
-bool Curl_req_want_send(struct Curl_easy *data);
-
-/**
- * TRUE iff the request has no buffered bytes yet to send.
- */
-bool Curl_req_sendbuf_empty(struct Curl_easy *data);
-
-/**
- * Stop sending any more request data to the server.
- * Will clear the send buffer and mark request sending as done.
- */
-CURLcode Curl_req_abort_sending(struct Curl_easy *data);
-
-/**
- * Stop sending and receiving any more request data.
- * Will abort sending if not done.
- */
-CURLcode Curl_req_stop_send_recv(struct Curl_easy *data);
-
-/**
- * Invoked when all request data has been uploaded.
- */
-CURLcode Curl_req_set_upload_done(struct Curl_easy *data);
-
-#endif /* HEADER_CURL_REQUEST_H */
diff --git a/contrib/libs/curl/lib/rtsp.c b/contrib/libs/curl/lib/rtsp.c
index c9b1bc0d67..e673bb8dc0 100644
--- a/contrib/libs/curl/lib/rtsp.c
+++ b/contrib/libs/curl/lib/rtsp.c
@@ -58,19 +58,21 @@ static int rtsp_getsock_do(struct Curl_easy *data,
struct connectdata *conn, curl_socket_t *socks);
/*
- * Parse and write out an RTSP response.
+ * Parse and write out any available RTP data.
* @param data the transfer
* @param conn the connection
* @param buf data read from connection
* @param blen amount of data in buf
- * @param is_eos TRUE iff this is the last write
+ * @param consumed out, number of blen consumed
* @param readmore out, TRUE iff complete buf was consumed and more data
* is needed
*/
-static CURLcode rtsp_rtp_write_resp(struct Curl_easy *data,
- const char *buf,
- size_t blen,
- bool is_eos);
+static CURLcode rtsp_rtp_readwrite(struct Curl_easy *data,
+ struct connectdata *conn,
+ const char *buf,
+ size_t blen,
+ size_t *pconsumed,
+ bool *readmore);
static CURLcode rtsp_setup_connection(struct Curl_easy *data,
struct connectdata *conn);
@@ -79,7 +81,7 @@ static unsigned int rtsp_conncheck(struct Curl_easy *data,
unsigned int checks_to_perform);
/* this returns the socket to wait for in the DO and DOING state for the multi
- interface and then we are always _sending_ a request and thus we wait for
+ interface and then we're always _sending_ a request and thus we wait for
the single socket to become writable only */
static int rtsp_getsock_do(struct Curl_easy *data, struct connectdata *conn,
curl_socket_t *socks)
@@ -93,14 +95,14 @@ static int rtsp_getsock_do(struct Curl_easy *data, struct connectdata *conn,
static
CURLcode rtp_client_write(struct Curl_easy *data, const char *ptr, size_t len);
static
-CURLcode rtsp_parse_transport(struct Curl_easy *data, const char *transport);
+CURLcode rtsp_parse_transport(struct Curl_easy *data, char *transport);
/*
* RTSP handler interface.
*/
const struct Curl_handler Curl_handler_rtsp = {
- "rtsp", /* scheme */
+ "RTSP", /* scheme */
rtsp_setup_connection, /* setup_connection */
rtsp_do, /* do_it */
rtsp_done, /* done */
@@ -113,8 +115,7 @@ const struct Curl_handler Curl_handler_rtsp = {
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
rtsp_disconnect, /* disconnect */
- rtsp_rtp_write_resp, /* write_resp */
- ZERO_NULL, /* write_resp_hd */
+ rtsp_rtp_readwrite, /* readwrite */
rtsp_conncheck, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_RTSP, /* defport */
@@ -225,6 +226,8 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done)
Curl_RtspReq rtspreq = data->set.rtspreq;
struct RTSP *rtsp = data->req.p.rtsp;
struct dynbuf req_buffer;
+ curl_off_t postsize = 0; /* for ANNOUNCE and SET_PARAMETER */
+ curl_off_t putsize = 0; /* for ANNOUNCE and SET_PARAMETER */
const char *p_request = NULL;
const char *p_session_id = NULL;
@@ -239,8 +242,6 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done)
const char *p_userpwd = NULL;
*done = TRUE;
- /* Initialize a dynamic send buffer */
- Curl_dyn_init(&req_buffer, DYN_RTSP_REQ_HEADER);
rtsp->CSeq_sent = data->state.rtsp_next_client_CSeq;
rtsp->CSeq_recv = 0;
@@ -261,7 +262,7 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done)
* Since all RTSP requests are included here, there is no need to
* support custom requests like HTTP.
**/
- data->req.no_body = TRUE; /* most requests do not contain a body */
+ data->req.no_body = TRUE; /* most requests don't contain a body */
switch(rtspreq) {
default:
failf(data, "Got invalid RTSP request");
@@ -310,19 +311,17 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done)
}
if(rtspreq == RTSPREQ_RECEIVE) {
- Curl_xfer_setup1(data, CURL_XFER_RECV, -1, TRUE);
- goto out;
+ Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE, -1);
+
+ return result;
}
p_session_id = data->set.str[STRING_RTSP_SESSION_ID];
if(!p_session_id &&
- (rtspreq & ~(Curl_RtspReq)(RTSPREQ_OPTIONS |
- RTSPREQ_DESCRIBE |
- RTSPREQ_SETUP))) {
+ (rtspreq & ~(RTSPREQ_OPTIONS | RTSPREQ_DESCRIBE | RTSPREQ_SETUP))) {
failf(data, "Refusing to issue an RTSP request [%s] without a session ID.",
p_request);
- result = CURLE_BAD_FUNCTION_ARGUMENT;
- goto out;
+ return CURLE_BAD_FUNCTION_ARGUMENT;
}
/* Stream URI. Default to server '*' if not specified */
@@ -349,8 +348,7 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done)
else {
failf(data,
"Refusing to issue an RTSP SETUP without a Transport: header.");
- result = CURLE_BAD_FUNCTION_ARGUMENT;
- goto out;
+ return CURLE_BAD_FUNCTION_ARGUMENT;
}
p_transport = data->state.aptr.rtsp_transport;
@@ -369,10 +367,9 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done)
data->state.aptr.accept_encoding =
aprintf("Accept-Encoding: %s\r\n", data->set.str[STRING_ENCODING]);
- if(!data->state.aptr.accept_encoding) {
- result = CURLE_OUT_OF_MEMORY;
- goto out;
- }
+ if(!data->state.aptr.accept_encoding)
+ return CURLE_OUT_OF_MEMORY;
+
p_accept_encoding = data->state.aptr.accept_encoding;
}
}
@@ -394,11 +391,9 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done)
result = Curl_http_output_auth(data, conn, p_request, HTTPREQ_GET,
p_stream_uri, FALSE);
if(result)
- goto out;
+ return result;
-#ifndef CURL_DISABLE_PROXY
p_proxyuserpwd = data->state.aptr.proxyuserpwd;
-#endif
p_userpwd = data->state.aptr.userpwd;
/* Referrer */
@@ -430,22 +425,23 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done)
*/
if(Curl_checkheaders(data, STRCONST("CSeq"))) {
failf(data, "CSeq cannot be set as a custom header.");
- result = CURLE_RTSP_CSEQ_ERROR;
- goto out;
+ return CURLE_RTSP_CSEQ_ERROR;
}
if(Curl_checkheaders(data, STRCONST("Session"))) {
failf(data, "Session ID cannot be set as a custom header.");
- result = CURLE_BAD_FUNCTION_ARGUMENT;
- goto out;
+ return CURLE_BAD_FUNCTION_ARGUMENT;
}
+ /* Initialize a dynamic send buffer */
+ Curl_dyn_init(&req_buffer, DYN_RTSP_REQ_HEADER);
+
result =
Curl_dyn_addf(&req_buffer,
"%s %s RTSP/1.0\r\n" /* Request Stream-URI RTSP/1.0 */
"CSeq: %ld\r\n", /* CSeq */
p_request, p_stream_uri, rtsp->CSeq_sent);
if(result)
- goto out;
+ return result;
/*
* Rather than do a normal alloc line, keep the session_id unformatted
@@ -454,7 +450,7 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done)
if(p_session_id) {
result = Curl_dyn_addf(&req_buffer, "Session: %s\r\n", p_session_id);
if(result)
- goto out;
+ return result;
}
/*
@@ -486,57 +482,44 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done)
Curl_safefree(data->state.aptr.userpwd);
if(result)
- goto out;
+ return result;
if((rtspreq == RTSPREQ_SETUP) || (rtspreq == RTSPREQ_DESCRIBE)) {
result = Curl_add_timecondition(data, &req_buffer);
if(result)
- goto out;
+ return result;
}
result = Curl_add_custom_headers(data, FALSE, &req_buffer);
if(result)
- goto out;
+ return result;
if(rtspreq == RTSPREQ_ANNOUNCE ||
rtspreq == RTSPREQ_SET_PARAMETER ||
rtspreq == RTSPREQ_GET_PARAMETER) {
- curl_off_t req_clen; /* request content length */
if(data->state.upload) {
- req_clen = data->state.infilesize;
+ putsize = data->state.infilesize;
data->state.httpreq = HTTPREQ_PUT;
- result = Curl_creader_set_fread(data, req_clen);
- if(result)
- goto out;
+
}
else {
- if(data->set.postfields) {
- size_t plen = strlen(data->set.postfields);
- req_clen = (curl_off_t)plen;
- result = Curl_creader_set_buf(data, data->set.postfields, plen);
- }
- else if(data->state.infilesize >= 0) {
- req_clen = data->state.infilesize;
- result = Curl_creader_set_fread(data, req_clen);
- }
- else {
- req_clen = 0;
- result = Curl_creader_set_null(data);
- }
- if(result)
- goto out;
+ postsize = (data->state.infilesize != -1)?
+ data->state.infilesize:
+ (data->set.postfields? (curl_off_t)strlen(data->set.postfields):0);
+ data->state.httpreq = HTTPREQ_POST;
}
- if(req_clen > 0) {
+ if(putsize > 0 || postsize > 0) {
/* As stated in the http comments, it is probably not wise to
* actually set a custom Content-Length in the headers */
if(!Curl_checkheaders(data, STRCONST("Content-Length"))) {
result =
- Curl_dyn_addf(&req_buffer, "Content-Length: %" FMT_OFF_T"\r\n",
- req_clen);
+ Curl_dyn_addf(&req_buffer,
+ "Content-Length: %" CURL_FORMAT_CURL_OFF_T"\r\n",
+ (data->state.upload ? putsize : postsize));
if(result)
- goto out;
+ return result;
}
if(rtspreq == RTSPREQ_SET_PARAMETER ||
@@ -546,7 +529,7 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done)
STRCONST("Content-Type: "
"text/parameters\r\n"));
if(result)
- goto out;
+ return result;
}
}
@@ -556,9 +539,11 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done)
STRCONST("Content-Type: "
"application/sdp\r\n"));
if(result)
- goto out;
+ return result;
}
}
+
+ data->state.expect100header = FALSE; /* RTSP posts are simple/small */
}
else if(rtspreq == RTSPREQ_GET_PARAMETER) {
/* Check for an empty GET_PARAMETER (heartbeat) request */
@@ -566,26 +551,31 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done)
data->req.no_body = TRUE;
}
}
- else {
- result = Curl_creader_set_null(data);
- if(result)
- goto out;
- }
+ /* RTSP never allows chunked transfer */
+ data->req.forbidchunk = TRUE;
/* Finish the request buffer */
result = Curl_dyn_addn(&req_buffer, STRCONST("\r\n"));
if(result)
- goto out;
+ return result;
- Curl_xfer_setup1(data, CURL_XFER_SENDRECV, -1, TRUE);
+ if(postsize > 0) {
+ result = Curl_dyn_addn(&req_buffer, data->set.postfields,
+ (size_t)postsize);
+ if(result)
+ return result;
+ }
/* issue the request */
- result = Curl_req_send(data, &req_buffer);
+ result = Curl_buffer_send(&req_buffer, data, data->req.p.http,
+ &data->info.request_size, 0, FIRSTSOCKET);
if(result) {
failf(data, "Failed sending RTSP request");
- goto out;
+ return result;
}
+ Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE, putsize?FIRSTSOCKET:-1);
+
/* Increment the CSeq on success */
data->state.rtsp_next_client_CSeq++;
@@ -596,53 +586,30 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done)
if(Curl_pgrsUpdate(data))
result = CURLE_ABORTED_BY_CALLBACK;
}
-out:
- Curl_dyn_free(&req_buffer);
- return result;
-}
-
-/**
- * write any BODY bytes missing to the client, ignore the rest.
- */
-static CURLcode rtp_write_body_junk(struct Curl_easy *data,
- const char *buf,
- size_t blen)
-{
- struct rtsp_conn *rtspc = &(data->conn->proto.rtspc);
- curl_off_t body_remain;
- bool in_body;
- in_body = (data->req.headerline && !rtspc->in_header) &&
- (data->req.size >= 0) &&
- (data->req.bytecount < data->req.size);
- body_remain = in_body? (data->req.size - data->req.bytecount) : 0;
- DEBUGASSERT(body_remain >= 0);
- if(body_remain) {
- if((curl_off_t)blen > body_remain)
- blen = (size_t)body_remain;
- return Curl_client_write(data, CLIENTWRITE_BODY, (char *)buf, blen);
- }
- return CURLE_OK;
+ return result;
}
static CURLcode rtsp_filter_rtp(struct Curl_easy *data,
+ struct connectdata *conn,
const char *buf,
size_t blen,
+ bool in_body,
size_t *pconsumed)
{
- struct rtsp_conn *rtspc = &(data->conn->proto.rtspc);
+ struct rtsp_conn *rtspc = &(conn->proto.rtspc);
CURLcode result = CURLE_OK;
- size_t skip_len = 0;
*pconsumed = 0;
while(blen) {
- bool in_body = (data->req.headerline && !rtspc->in_header) &&
- (data->req.size >= 0) &&
- (data->req.bytecount < data->req.size);
switch(rtspc->state) {
case RTP_PARSE_SKIP: {
DEBUGASSERT(Curl_dyn_len(&rtspc->buf) == 0);
+ if(in_body && buf[0] != '$') {
+ /* in BODY and no valid start, do not consume and return */
+ goto out;
+ }
while(blen && buf[0] != '$') {
if(!in_body && buf[0] == 'R' &&
data->set.rtspreq != RTSPREQ_RECEIVE) {
@@ -657,22 +624,13 @@ static CURLcode rtsp_filter_rtp(struct Curl_easy *data,
goto out;
}
}
- /* junk/BODY, consume without buffering */
+ /* junk, consume without buffering */
*pconsumed += 1;
++buf;
--blen;
- ++skip_len;
}
if(blen && buf[0] == '$') {
/* possible start of an RTP message, buffer */
- if(skip_len) {
- /* end of junk/BODY bytes, flush */
- result = rtp_write_body_junk(data,
- (char *)(buf - skip_len), skip_len);
- skip_len = 0;
- if(result)
- goto out;
- }
if(Curl_dyn_addn(&rtspc->buf, buf, 1)) {
result = CURLE_OUT_OF_MEMORY;
goto out;
@@ -692,22 +650,35 @@ static CURLcode rtsp_filter_rtp(struct Curl_easy *data,
if(!(data->state.rtp_channel_mask[idx] & (1 << off))) {
/* invalid channel number, junk or BODY data */
rtspc->state = RTP_PARSE_SKIP;
- DEBUGASSERT(skip_len == 0);
- /* we do not consume this byte, it is BODY data */
- DEBUGF(infof(data, "RTSP: invalid RTP channel %d, skipping", idx));
- if(*pconsumed == 0) {
- /* We did not consume the initial '$' in our buffer, but had
- * it from an earlier call. We cannot un-consume it and have
- * to write it directly as BODY data */
- result = rtp_write_body_junk(data, Curl_dyn_ptr(&rtspc->buf), 1);
- if(result)
+ if(in_body) {
+ /* we do not consume this byte, it is BODY data */
+ DEBUGF(infof(data, "RTSP: invalid RTP channel %d in BODY, "
+ "treating as BODY data", idx));
+ if(*pconsumed == 0) {
+ /* We did not consume the initial '$' in our buffer, but had
+ * it from an earlier call. We cannot un-consume it and have
+ * to write it directly as BODY data */
+ result = Curl_client_write(data, CLIENTWRITE_BODY,
+ Curl_dyn_ptr(&rtspc->buf), 1);
+ Curl_dyn_free(&rtspc->buf);
+ if(result)
+ goto out;
+ }
+ else {
+ /* un-consume the '$' and leave */
+ Curl_dyn_free(&rtspc->buf);
+ *pconsumed -= 1;
+ --buf;
+ ++blen;
goto out;
+ }
}
else {
- /* count the '$' as skip and continue */
- skip_len = 1;
+ /* not BODY, forget the junk '$'. Do not consume this byte,
+ * it might be a start */
+ infof(data, "RTSP: invalid RTP channel %d, skipping", idx);
+ Curl_dyn_free(&rtspc->buf);
}
- Curl_dyn_free(&rtspc->buf);
break;
}
/* a valid channel, so we expect this to be a real RTP message */
@@ -783,49 +754,52 @@ static CURLcode rtsp_filter_rtp(struct Curl_easy *data,
}
}
out:
- if(!result && skip_len)
- result = rtp_write_body_junk(data, (char *)(buf - skip_len), skip_len);
return result;
}
-static CURLcode rtsp_rtp_write_resp(struct Curl_easy *data,
- const char *buf,
- size_t blen,
- bool is_eos)
+static CURLcode rtsp_rtp_readwrite(struct Curl_easy *data,
+ struct connectdata *conn,
+ const char *buf,
+ size_t blen,
+ size_t *pconsumed,
+ bool *readmore)
{
- struct rtsp_conn *rtspc = &(data->conn->proto.rtspc);
+ struct rtsp_conn *rtspc = &(conn->proto.rtspc);
CURLcode result = CURLE_OK;
size_t consumed = 0;
+ bool in_body;
if(!data->req.header)
rtspc->in_header = FALSE;
+ in_body = (data->req.headerline && !rtspc->in_header) &&
+ (data->req.size >= 0) &&
+ (data->req.bytecount < data->req.size);
+
+ *readmore = FALSE;
+ *pconsumed = 0;
if(!blen) {
goto out;
}
- DEBUGF(infof(data, "rtsp_rtp_write_resp(len=%zu, in_header=%d, eos=%d)",
- blen, rtspc->in_header, is_eos));
-
- /* If header parsing is not ongoing, extract RTP messages */
+ /* If header parsing is not onging, extract RTP messages */
if(!rtspc->in_header) {
- result = rtsp_filter_rtp(data, buf, blen, &consumed);
+ result = rtsp_filter_rtp(data, conn, buf, blen, in_body, &consumed);
if(result)
goto out;
+ *pconsumed += consumed;
buf += consumed;
blen -= consumed;
- /* either we consumed all or are at the start of header parsing */
- if(blen && !data->req.header)
- DEBUGF(infof(data, "RTSP: %zu bytes, possibly excess in response body",
- blen));
}
/* we want to parse headers, do so */
if(data->req.header && blen) {
rtspc->in_header = TRUE;
- result = Curl_http_write_resp_hds(data, buf, blen, &consumed);
+ result = Curl_http_readwrite_headers(data, conn, buf, blen,
+ &consumed);
if(result)
goto out;
+ *pconsumed += consumed;
buf += consumed;
blen -= consumed;
@@ -833,42 +807,26 @@ static CURLcode rtsp_rtp_write_resp(struct Curl_easy *data,
rtspc->in_header = FALSE;
if(!rtspc->in_header) {
- /* If header parsing is done, extract interleaved RTP messages */
- if(data->req.size <= -1) {
- /* Respect section 4.4 of rfc2326: If the Content-Length header is
- absent, a length 0 must be assumed. */
- data->req.size = 0;
- data->req.download_done = TRUE;
- }
- result = rtsp_filter_rtp(data, buf, blen, &consumed);
+ /* If header parsing is done and data left, extract RTP messages */
+ in_body = (data->req.headerline && !rtspc->in_header) &&
+ (data->req.size >= 0) &&
+ (data->req.bytecount < data->req.size);
+ result = rtsp_filter_rtp(data, conn, buf, blen, in_body, &consumed);
if(result)
goto out;
- blen -= consumed;
+ *pconsumed += consumed;
}
}
if(rtspc->state != RTP_PARSE_SKIP)
- data->req.done = FALSE;
- /* we SHOULD have consumed all bytes, unless the response is borked.
- * In which case we write out the left over bytes, letting the client
- * writer deal with it (it will report EXCESS and fail the transfer). */
- DEBUGF(infof(data, "rtsp_rtp_write_resp(len=%zu, in_header=%d, done=%d "
- " rtspc->state=%d, req.size=%" FMT_OFF_T ")",
- blen, rtspc->in_header, data->req.done, rtspc->state,
- data->req.size));
- if(!result && (is_eos || blen)) {
- result = Curl_client_write(data, CLIENTWRITE_BODY|
- (is_eos? CLIENTWRITE_EOS:0),
- (char *)buf, blen);
- }
+ *readmore = TRUE;
out:
- if((data->set.rtspreq == RTSPREQ_RECEIVE) &&
- (rtspc->state == RTP_PARSE_SKIP)) {
+ if(!*readmore && data->set.rtspreq == RTSPREQ_RECEIVE) {
/* In special mode RECEIVE, we just process one chunk of network
* data, so we stop the transfer here, if we have no incomplete
* RTP message pending. */
- data->req.download_done = TRUE;
+ data->req.keepon &= ~KEEP_RECV;
}
return result;
}
@@ -915,12 +873,12 @@ CURLcode rtp_client_write(struct Curl_easy *data, const char *ptr, size_t len)
return CURLE_OK;
}
-CURLcode Curl_rtsp_parseheader(struct Curl_easy *data, const char *header)
+CURLcode Curl_rtsp_parseheader(struct Curl_easy *data, char *header)
{
if(checkprefix("CSeq:", header)) {
long CSeq = 0;
char *endp;
- const char *p = &header[5];
+ char *p = &header[5];
while(ISBLANK(*p))
p++;
CSeq = strtol(p, &endp, 10);
@@ -935,7 +893,8 @@ CURLcode Curl_rtsp_parseheader(struct Curl_easy *data, const char *header)
}
}
else if(checkprefix("Session:", header)) {
- const char *start, *end;
+ char *start;
+ char *end;
size_t idlen;
/* Find the first non-space letter */
@@ -951,7 +910,7 @@ CURLcode Curl_rtsp_parseheader(struct Curl_easy *data, const char *header)
/* Find the end of Session ID
*
* Allow any non whitespace content, up to the field separator or end of
- * line. RFC 2326 is not 100% clear on the session ID and for example
+ * line. RFC 2326 isn't 100% clear on the session ID and for example
* gstreamer does url-encoded session ID's not covered by the standard.
*/
end = start;
@@ -963,7 +922,7 @@ CURLcode Curl_rtsp_parseheader(struct Curl_easy *data, const char *header)
/* If the Session ID is set, then compare */
if(strlen(data->set.str[STRING_RTSP_SESSION_ID]) != idlen ||
- strncmp(start, data->set.str[STRING_RTSP_SESSION_ID], idlen)) {
+ strncmp(start, data->set.str[STRING_RTSP_SESSION_ID], idlen) != 0) {
failf(data, "Got RTSP Session ID Line [%s], but wanted ID [%s]",
start, data->set.str[STRING_RTSP_SESSION_ID]);
return CURLE_RTSP_SESSION_ERROR;
@@ -975,9 +934,11 @@ CURLcode Curl_rtsp_parseheader(struct Curl_easy *data, const char *header)
*/
/* Copy the id substring into a new buffer */
- data->set.str[STRING_RTSP_SESSION_ID] = Curl_memdup0(start, idlen);
+ data->set.str[STRING_RTSP_SESSION_ID] = malloc(idlen + 1);
if(!data->set.str[STRING_RTSP_SESSION_ID])
return CURLE_OUT_OF_MEMORY;
+ memcpy(data->set.str[STRING_RTSP_SESSION_ID], start, idlen);
+ (data->set.str[STRING_RTSP_SESSION_ID])[idlen] = '\0';
}
}
else if(checkprefix("Transport:", header)) {
@@ -990,13 +951,14 @@ CURLcode Curl_rtsp_parseheader(struct Curl_easy *data, const char *header)
}
static
-CURLcode rtsp_parse_transport(struct Curl_easy *data, const char *transport)
+CURLcode rtsp_parse_transport(struct Curl_easy *data, char *transport)
{
/* If we receive multiple Transport response-headers, the linterleaved
channels of each response header is recorded and used together for
subsequent data validity checks.*/
/* e.g.: ' RTP/AVP/TCP;unicast;interleaved=5-6' */
- const char *start, *end;
+ char *start;
+ char *end;
start = transport;
while(start && *start) {
while(*start && ISBLANK(*start) )
@@ -1005,7 +967,7 @@ CURLcode rtsp_parse_transport(struct Curl_easy *data, const char *transport)
if(checkprefix("interleaved=", start)) {
long chan1, chan2, chan;
char *endp;
- const char *p = start + 12;
+ char *p = start + 12;
chan1 = strtol(p, &endp, 10);
if(p != endp && chan1 >= 0 && chan1 <= 255) {
unsigned char *rtp_channel_mask = data->state.rtp_channel_mask;
diff --git a/contrib/libs/curl/lib/rtsp.h b/contrib/libs/curl/lib/rtsp.h
index 41b09503ff..237b80f809 100644
--- a/contrib/libs/curl/lib/rtsp.h
+++ b/contrib/libs/curl/lib/rtsp.h
@@ -31,7 +31,7 @@
extern const struct Curl_handler Curl_handler_rtsp;
-CURLcode Curl_rtsp_parseheader(struct Curl_easy *data, const char *header);
+CURLcode Curl_rtsp_parseheader(struct Curl_easy *data, char *header);
#else
/* disabled */
@@ -62,6 +62,16 @@ struct rtsp_conn {
* RTSP unique setup
***************************************************************************/
struct RTSP {
+ /*
+ * http_wrapper MUST be the first element of this structure for the wrap
+ * logic to work. In this way, we get a cheap polymorphism because
+ * &(data->state.proto.rtsp) == &(data->state.proto.http) per the C spec
+ *
+ * HTTP functions can safely treat this as an HTTP struct, but RTSP aware
+ * functions can also index into the later elements.
+ */
+ struct HTTP http_wrapper; /* wrap HTTP to do the heavy lifting */
+
long CSeq_sent; /* CSeq of this request */
long CSeq_recv; /* CSeq received */
};
diff --git a/contrib/libs/curl/lib/select.c b/contrib/libs/curl/lib/select.c
index dae736b019..d92e745a7f 100644
--- a/contrib/libs/curl/lib/select.c
+++ b/contrib/libs/curl/lib/select.c
@@ -33,7 +33,7 @@
#endif
#if !defined(HAVE_SELECT) && !defined(HAVE_POLL_FINE)
-#error "We cannot compile without select() or poll() support."
+#error "We can't compile without select() or poll() support."
#endif
#ifdef MSDOS
@@ -47,16 +47,12 @@
#include "select.h"
#include "timediff.h"
#include "warnless.h"
-/* The last 3 #include files should be in this order */
-#include "curl_printf.h"
-#include "curl_memory.h"
-#include "memdebug.h"
/*
* Internal function used for waiting a specific amount of ms
* in Curl_socket_check() and Curl_poll() when no file descriptor
* is provided to wait on, just being used to delay execution.
- * Winsock select() and poll() timeout mechanisms need a valid
+ * WinSock select() and poll() timeout mechanisms need a valid
* socket descriptor in a not null file descriptor set to work.
* Waiting indefinitely with this function is not allowed, a
* zero or negative timeout value will return immediately.
@@ -85,7 +81,7 @@ int Curl_wait_ms(timediff_t timeout_ms)
#if TIMEDIFF_T_MAX >= ULONG_MAX
if(timeout_ms >= ULONG_MAX)
timeout_ms = ULONG_MAX-1;
- /* do not use ULONG_MAX, because that is equal to INFINITE */
+ /* don't use ULONG_MAX, because that is equal to INFINITE */
#endif
Sleep((ULONG)timeout_ms);
#else
@@ -135,7 +131,7 @@ static int our_select(curl_socket_t maxfd, /* highest socket number */
struct timeval *ptimeout;
#ifdef USE_WINSOCK
- /* Winsock select() cannot handle zero events. See the comment below. */
+ /* WinSock select() can't handle zero events. See the comment below. */
if((!fds_read || fds_read->fd_count == 0) &&
(!fds_write || fds_write->fd_count == 0) &&
(!fds_err || fds_err->fd_count == 0)) {
@@ -147,16 +143,16 @@ static int our_select(curl_socket_t maxfd, /* highest socket number */
ptimeout = curlx_mstotv(&pending_tv, timeout_ms);
#ifdef USE_WINSOCK
- /* Winsock select() must not be called with an fd_set that contains zero
- fd flags, or it will return WSAEINVAL. But, it also cannot be called
+ /* WinSock select() must not be called with an fd_set that contains zero
+ fd flags, or it will return WSAEINVAL. But, it also can't be called
with no fd_sets at all! From the documentation:
Any two of the parameters, readfds, writefds, or exceptfds, can be
given as null. At least one must be non-null, and any non-null
descriptor set must contain at least one handle to a socket.
- It is unclear why Winsock does not just handle this for us instead of
- calling this an error. Luckily, with Winsock, we can _also_ ask how
+ It is unclear why WinSock doesn't just handle this for us instead of
+ calling this an error. Luckily, with WinSock, we can _also_ ask how
many bits are set on an fd_set. So, let's just check it beforehand.
*/
return select((int)maxfd + 1,
@@ -173,7 +169,7 @@ static int our_select(curl_socket_t maxfd, /* highest socket number */
/*
* Wait for read or write events on a set of file descriptors. It uses poll()
* when a fine poll() is available, in order to avoid limits with FD_SETSIZE,
- * otherwise select() is used. An error is returned if select() is being used
+ * otherwise select() is used. An error is returned if select() is being used
* and a file descriptor is too large for FD_SETSIZE.
*
* A negative timeout value makes this function wait indefinitely,
@@ -230,7 +226,7 @@ int Curl_socket_check(curl_socket_t readfd0, /* two sockets to read from */
num++;
}
- r = Curl_poll(pfd, (unsigned int)num, timeout_ms);
+ r = Curl_poll(pfd, num, timeout_ms);
if(r <= 0)
return r;
@@ -261,8 +257,8 @@ int Curl_socket_check(curl_socket_t readfd0, /* two sockets to read from */
}
/*
- * This is a wrapper around poll(). If poll() does not exist, then
- * select() is used instead. An error is returned if select() is
+ * This is a wrapper around poll(). If poll() does not exist, then
+ * select() is used instead. An error is returned if select() is
* being used and a file descriptor is too large for FD_SETSIZE.
* A negative timeout value makes this function wait indefinitely,
* unless no valid file descriptor is given, when this happens the
@@ -361,8 +357,8 @@ int Curl_poll(struct pollfd ufds[], unsigned int nfds, timediff_t timeout_ms)
}
/*
- Note also that Winsock ignores the first argument, so we do not worry
- about the fact that maxfd is computed incorrectly with Winsock (since
+ Note also that WinSock ignores the first argument, so we don't worry
+ about the fact that maxfd is computed incorrectly with WinSock (since
curl_socket_t is unsigned in such cases and thus -1 is the largest
value).
*/
@@ -405,147 +401,3 @@ int Curl_poll(struct pollfd ufds[], unsigned int nfds, timediff_t timeout_ms)
return r;
}
-
-void Curl_pollfds_init(struct curl_pollfds *cpfds,
- struct pollfd *static_pfds,
- unsigned int static_count)
-{
- DEBUGASSERT(cpfds);
- memset(cpfds, 0, sizeof(*cpfds));
- if(static_pfds && static_count) {
- cpfds->pfds = static_pfds;
- cpfds->count = static_count;
- }
-}
-
-void Curl_pollfds_cleanup(struct curl_pollfds *cpfds)
-{
- DEBUGASSERT(cpfds);
- if(cpfds->allocated_pfds) {
- free(cpfds->pfds);
- }
- memset(cpfds, 0, sizeof(*cpfds));
-}
-
-static CURLcode cpfds_increase(struct curl_pollfds *cpfds, unsigned int inc)
-{
- struct pollfd *new_fds;
- unsigned int new_count = cpfds->count + inc;
-
- new_fds = calloc(new_count, sizeof(struct pollfd));
- if(!new_fds)
- return CURLE_OUT_OF_MEMORY;
-
- memcpy(new_fds, cpfds->pfds, cpfds->count * sizeof(struct pollfd));
- if(cpfds->allocated_pfds)
- free(cpfds->pfds);
- cpfds->pfds = new_fds;
- cpfds->count = new_count;
- cpfds->allocated_pfds = TRUE;
- return CURLE_OK;
-}
-
-static CURLcode cpfds_add_sock(struct curl_pollfds *cpfds,
- curl_socket_t sock, short events, bool fold)
-{
- int i;
-
- if(fold && cpfds->n <= INT_MAX) {
- for(i = (int)cpfds->n - 1; i >= 0; --i) {
- if(sock == cpfds->pfds[i].fd) {
- cpfds->pfds[i].events |= events;
- return CURLE_OK;
- }
- }
- }
- /* not folded, add new entry */
- if(cpfds->n >= cpfds->count) {
- if(cpfds_increase(cpfds, 100))
- return CURLE_OUT_OF_MEMORY;
- }
- cpfds->pfds[cpfds->n].fd = sock;
- cpfds->pfds[cpfds->n].events = events;
- ++cpfds->n;
- return CURLE_OK;
-}
-
-CURLcode Curl_pollfds_add_sock(struct curl_pollfds *cpfds,
- curl_socket_t sock, short events)
-{
- return cpfds_add_sock(cpfds, sock, events, FALSE);
-}
-
-CURLcode Curl_pollfds_add_ps(struct curl_pollfds *cpfds,
- struct easy_pollset *ps)
-{
- size_t i;
-
- DEBUGASSERT(cpfds);
- DEBUGASSERT(ps);
- for(i = 0; i < ps->num; i++) {
- short events = 0;
- if(ps->actions[i] & CURL_POLL_IN)
- events |= POLLIN;
- if(ps->actions[i] & CURL_POLL_OUT)
- events |= POLLOUT;
- if(events) {
- if(cpfds_add_sock(cpfds, ps->sockets[i], events, TRUE))
- return CURLE_OUT_OF_MEMORY;
- }
- }
- return CURLE_OK;
-}
-
-void Curl_waitfds_init(struct curl_waitfds *cwfds,
- struct curl_waitfd *static_wfds,
- unsigned int static_count)
-{
- DEBUGASSERT(cwfds);
- DEBUGASSERT(static_wfds);
- memset(cwfds, 0, sizeof(*cwfds));
- cwfds->wfds = static_wfds;
- cwfds->count = static_count;
-}
-
-static CURLcode cwfds_add_sock(struct curl_waitfds *cwfds,
- curl_socket_t sock, short events)
-{
- int i;
-
- if(cwfds->n <= INT_MAX) {
- for(i = (int)cwfds->n - 1; i >= 0; --i) {
- if(sock == cwfds->wfds[i].fd) {
- cwfds->wfds[i].events |= events;
- return CURLE_OK;
- }
- }
- }
- /* not folded, add new entry */
- if(cwfds->n >= cwfds->count)
- return CURLE_OUT_OF_MEMORY;
- cwfds->wfds[cwfds->n].fd = sock;
- cwfds->wfds[cwfds->n].events = events;
- ++cwfds->n;
- return CURLE_OK;
-}
-
-CURLcode Curl_waitfds_add_ps(struct curl_waitfds *cwfds,
- struct easy_pollset *ps)
-{
- size_t i;
-
- DEBUGASSERT(cwfds);
- DEBUGASSERT(ps);
- for(i = 0; i < ps->num; i++) {
- short events = 0;
- if(ps->actions[i] & CURL_POLL_IN)
- events |= CURL_WAIT_POLLIN;
- if(ps->actions[i] & CURL_POLL_OUT)
- events |= CURL_WAIT_POLLOUT;
- if(events) {
- if(cwfds_add_sock(cwfds, ps->sockets[i], events))
- return CURLE_OUT_OF_MEMORY;
- }
- }
- return CURLE_OK;
-}
diff --git a/contrib/libs/curl/lib/select.h b/contrib/libs/curl/lib/select.h
index f01acbdefc..5b1ca23eb1 100644
--- a/contrib/libs/curl/lib/select.h
+++ b/contrib/libs/curl/lib/select.h
@@ -111,37 +111,4 @@ int Curl_wait_ms(timediff_t timeout_ms);
} while(0)
#endif
-struct curl_pollfds {
- struct pollfd *pfds;
- unsigned int n;
- unsigned int count;
- BIT(allocated_pfds);
-};
-
-void Curl_pollfds_init(struct curl_pollfds *cpfds,
- struct pollfd *static_pfds,
- unsigned int static_count);
-
-void Curl_pollfds_cleanup(struct curl_pollfds *cpfds);
-
-CURLcode Curl_pollfds_add_ps(struct curl_pollfds *cpfds,
- struct easy_pollset *ps);
-
-CURLcode Curl_pollfds_add_sock(struct curl_pollfds *cpfds,
- curl_socket_t sock, short events);
-
-struct curl_waitfds {
- struct curl_waitfd *wfds;
- unsigned int n;
- unsigned int count;
-};
-
-void Curl_waitfds_init(struct curl_waitfds *cwfds,
- struct curl_waitfd *static_wfds,
- unsigned int static_count);
-
-CURLcode Curl_waitfds_add_ps(struct curl_waitfds *cwfds,
- struct easy_pollset *ps);
-
-
#endif /* HEADER_CURL_SELECT_H */
diff --git a/contrib/libs/curl/lib/sendf.c b/contrib/libs/curl/lib/sendf.c
index 6f566622fd..a2fac0c4e9 100644
--- a/contrib/libs/curl/lib/sendf.c
+++ b/contrib/libs/curl/lib/sendf.c
@@ -41,7 +41,6 @@
#include "cfilters.h"
#include "connect.h"
#include "content_encoding.h"
-#include "cw-out.h"
#include "vtls/vtls.h"
#include "vssh/ssh.h"
#include "easyif.h"
@@ -50,8 +49,8 @@
#include "select.h"
#include "strdup.h"
#include "http2.h"
+#include "headers.h"
#include "progress.h"
-#include "warnless.h"
#include "ws.h"
/* The last 3 #include files should be in this order */
@@ -60,124 +59,426 @@
#include "memdebug.h"
-static CURLcode do_init_writer_stack(struct Curl_easy *data);
+static CURLcode do_init_stack(struct Curl_easy *data);
+
+#if defined(CURL_DO_LINEEND_CONV) && !defined(CURL_DISABLE_FTP)
+/*
+ * convert_lineends() changes CRLF (\r\n) end-of-line markers to a single LF
+ * (\n), with special processing for CRLF sequences that are split between two
+ * blocks of data. Remaining, bare CRs are changed to LFs. The possibly new
+ * size of the data is returned.
+ */
+static size_t convert_lineends(struct Curl_easy *data,
+ char *startPtr, size_t size)
+{
+ char *inPtr, *outPtr;
+
+ /* sanity check */
+ if(!startPtr || (size < 1)) {
+ return size;
+ }
+
+ if(data->state.prev_block_had_trailing_cr) {
+ /* The previous block of incoming data
+ had a trailing CR, which was turned into a LF. */
+ if(*startPtr == '\n') {
+ /* This block of incoming data starts with the
+ previous block's LF so get rid of it */
+ memmove(startPtr, startPtr + 1, size-1);
+ size--;
+ /* and it wasn't a bare CR but a CRLF conversion instead */
+ data->state.crlf_conversions++;
+ }
+ data->state.prev_block_had_trailing_cr = FALSE; /* reset the flag */
+ }
+
+ /* find 1st CR, if any */
+ inPtr = outPtr = memchr(startPtr, '\r', size);
+ if(inPtr) {
+ /* at least one CR, now look for CRLF */
+ while(inPtr < (startPtr + size-1)) {
+ /* note that it's size-1, so we'll never look past the last byte */
+ if(memcmp(inPtr, "\r\n", 2) == 0) {
+ /* CRLF found, bump past the CR and copy the NL */
+ inPtr++;
+ *outPtr = *inPtr;
+ /* keep track of how many CRLFs we converted */
+ data->state.crlf_conversions++;
+ }
+ else {
+ if(*inPtr == '\r') {
+ /* lone CR, move LF instead */
+ *outPtr = '\n';
+ }
+ else {
+ /* not a CRLF nor a CR, just copy whatever it is */
+ *outPtr = *inPtr;
+ }
+ }
+ outPtr++;
+ inPtr++;
+ } /* end of while loop */
+
+ if(inPtr < startPtr + size) {
+ /* handle last byte */
+ if(*inPtr == '\r') {
+ /* deal with a CR at the end of the buffer */
+ *outPtr = '\n'; /* copy a NL instead */
+ /* note that a CRLF might be split across two blocks */
+ data->state.prev_block_had_trailing_cr = TRUE;
+ }
+ else {
+ /* copy last byte */
+ *outPtr = *inPtr;
+ }
+ outPtr++;
+ }
+ if(outPtr < startPtr + size)
+ /* tidy up by null terminating the now shorter data */
+ *outPtr = '\0';
+
+ return (outPtr - startPtr);
+ }
+ return size;
+}
+#endif /* CURL_DO_LINEEND_CONV && !CURL_DISABLE_FTP */
+
+/*
+ * Curl_nwrite() is an internal write function that sends data to the
+ * server. Works with a socket index for the connection.
+ *
+ * If the write would block (CURLE_AGAIN), it returns CURLE_OK and
+ * (*nwritten == 0). Otherwise we return regular CURLcode value.
+ */
+CURLcode Curl_nwrite(struct Curl_easy *data,
+ int sockindex,
+ const void *buf,
+ size_t blen,
+ ssize_t *pnwritten)
+{
+ ssize_t nwritten;
+ CURLcode result = CURLE_OK;
+ struct connectdata *conn;
+
+ DEBUGASSERT(sockindex >= 0 && sockindex < 2);
+ DEBUGASSERT(pnwritten);
+ DEBUGASSERT(data);
+ DEBUGASSERT(data->conn);
+ conn = data->conn;
+#ifdef CURLDEBUG
+ {
+ /* Allow debug builds to override this logic to force short sends
+ */
+ char *p = getenv("CURL_SMALLSENDS");
+ if(p) {
+ size_t altsize = (size_t)strtoul(p, NULL, 10);
+ if(altsize)
+ blen = CURLMIN(blen, altsize);
+ }
+ }
+#endif
+ nwritten = conn->send[sockindex](data, sockindex, buf, blen, &result);
+ if(result == CURLE_AGAIN) {
+ nwritten = 0;
+ result = CURLE_OK;
+ }
+ else if(result) {
+ nwritten = -1; /* make sure */
+ }
+ else {
+ DEBUGASSERT(nwritten >= 0);
+ }
+
+ *pnwritten = nwritten;
+ return result;
+}
+
+/*
+ * Curl_write() is an internal write function that sends data to the
+ * server. Works with plain sockets, SCP, SSL or kerberos.
+ *
+ * If the write would block (CURLE_AGAIN), we return CURLE_OK and
+ * (*written == 0). Otherwise we return regular CURLcode value.
+ */
+CURLcode Curl_write(struct Curl_easy *data,
+ curl_socket_t sockfd,
+ const void *mem,
+ size_t len,
+ ssize_t *written)
+{
+ struct connectdata *conn;
+ int num;
+
+ DEBUGASSERT(data);
+ DEBUGASSERT(data->conn);
+ conn = data->conn;
+ num = (sockfd != CURL_SOCKET_BAD && sockfd == conn->sock[SECONDARYSOCKET]);
+ return Curl_nwrite(data, num, mem, len, written);
+}
+
+static CURLcode pausewrite(struct Curl_easy *data,
+ int type, /* what type of data */
+ bool paused_body,
+ const char *ptr,
+ size_t len)
+{
+ /* signalled to pause sending on this connection, but since we have data
+ we want to send we need to dup it to save a copy for when the sending
+ is again enabled */
+ struct SingleRequest *k = &data->req;
+ struct UrlState *s = &data->state;
+ unsigned int i;
+ bool newtype = TRUE;
+
+ Curl_conn_ev_data_pause(data, TRUE);
+
+ if(s->tempcount) {
+ for(i = 0; i< s->tempcount; i++) {
+ if(s->tempwrite[i].type == type &&
+ !!s->tempwrite[i].paused_body == !!paused_body) {
+ /* data for this type exists */
+ newtype = FALSE;
+ break;
+ }
+ }
+ DEBUGASSERT(i < 3);
+ if(i >= 3)
+ /* There are more types to store than what fits: very bad */
+ return CURLE_OUT_OF_MEMORY;
+ }
+ else
+ i = 0;
+
+ if(newtype) {
+ /* store this information in the state struct for later use */
+ Curl_dyn_init(&s->tempwrite[i].b, DYN_PAUSE_BUFFER);
+ s->tempwrite[i].type = type;
+ s->tempwrite[i].paused_body = paused_body;
+ s->tempcount++;
+ }
+
+ if(Curl_dyn_addn(&s->tempwrite[i].b, (unsigned char *)ptr, len))
+ return CURLE_OUT_OF_MEMORY;
+
+ /* mark the connection as RECV paused */
+ k->keepon |= KEEP_RECV_PAUSE;
+
+ return CURLE_OK;
+}
+
+
+/* chop_write() writes chunks of data not larger than CURL_MAX_WRITE_SIZE via
+ * client write callback(s) and takes care of pause requests from the
+ * callbacks.
+ */
+static CURLcode chop_write(struct Curl_easy *data,
+ int type,
+ bool skip_body_write,
+ char *optr,
+ size_t olen)
+{
+ struct connectdata *conn = data->conn;
+ curl_write_callback writeheader = NULL;
+ curl_write_callback writebody = NULL;
+ char *ptr = optr;
+ size_t len = olen;
+ void *writebody_ptr = data->set.out;
+
+ if(!len)
+ return CURLE_OK;
+
+ /* If reading is paused, append this data to the already held data for this
+ type. */
+ if(data->req.keepon & KEEP_RECV_PAUSE)
+ return pausewrite(data, type, !skip_body_write, ptr, len);
+
+ /* Determine the callback(s) to use. */
+ if(!skip_body_write &&
+ ((type & CLIENTWRITE_BODY) ||
+ ((type & CLIENTWRITE_HEADER) && data->set.include_header))) {
+#ifdef USE_WEBSOCKETS
+ if(conn->handler->protocol & (CURLPROTO_WS|CURLPROTO_WSS)) {
+ writebody = Curl_ws_writecb;
+ writebody_ptr = data;
+ }
+ else
+#endif
+ writebody = data->set.fwrite_func;
+ }
+ if((type & (CLIENTWRITE_HEADER|CLIENTWRITE_INFO)) &&
+ (data->set.fwrite_header || data->set.writeheader)) {
+ /*
+ * Write headers to the same callback or to the especially setup
+ * header callback function (added after version 7.7.1).
+ */
+ writeheader =
+ data->set.fwrite_header? data->set.fwrite_header: data->set.fwrite_func;
+ }
+
+ /* Chop data, write chunks. */
+ while(len) {
+ size_t chunklen = len <= CURL_MAX_WRITE_SIZE? len: CURL_MAX_WRITE_SIZE;
+
+ if(writebody) {
+ size_t wrote;
+ Curl_set_in_callback(data, true);
+ wrote = writebody(ptr, 1, chunklen, writebody_ptr);
+ Curl_set_in_callback(data, false);
+
+ if(CURL_WRITEFUNC_PAUSE == wrote) {
+ if(conn->handler->flags & PROTOPT_NONETWORK) {
+ /* Protocols that work without network cannot be paused. This is
+ actually only FILE:// just now, and it can't pause since the
+ transfer isn't done using the "normal" procedure. */
+ failf(data, "Write callback asked for PAUSE when not supported");
+ return CURLE_WRITE_ERROR;
+ }
+ return pausewrite(data, type, TRUE, ptr, len);
+ }
+ if(wrote != chunklen) {
+ failf(data, "Failure writing output to destination");
+ return CURLE_WRITE_ERROR;
+ }
+ }
+
+ ptr += chunklen;
+ len -= chunklen;
+ }
+
+#ifndef CURL_DISABLE_HTTP
+ /* HTTP header, but not status-line */
+ if((conn->handler->protocol & PROTO_FAMILY_HTTP) &&
+ (type & CLIENTWRITE_HEADER) && !(type & CLIENTWRITE_STATUS) ) {
+ unsigned char htype = (unsigned char)
+ (type & CLIENTWRITE_CONNECT ? CURLH_CONNECT :
+ (type & CLIENTWRITE_1XX ? CURLH_1XX :
+ (type & CLIENTWRITE_TRAILER ? CURLH_TRAILER :
+ CURLH_HEADER)));
+ CURLcode result = Curl_headers_push(data, optr, htype);
+ if(result)
+ return result;
+ }
+#endif
+
+ if(writeheader) {
+ size_t wrote;
+
+ Curl_set_in_callback(data, true);
+ wrote = writeheader(optr, 1, olen, data->set.writeheader);
+ Curl_set_in_callback(data, false);
+
+ if(CURL_WRITEFUNC_PAUSE == wrote)
+ return pausewrite(data, type, FALSE, optr, olen);
+ if(wrote != olen) {
+ failf(data, "Failed writing header");
+ return CURLE_WRITE_ERROR;
+ }
+ }
+
+ return CURLE_OK;
+}
+
/* Curl_client_write() sends data to the write callback(s)
The bit pattern defines to what "streams" to write to. Body and/or header.
The defines are in sendf.h of course.
+
+ If CURL_DO_LINEEND_CONV is enabled, data is converted IN PLACE to the
+ local character encoding. This is a problem and should be changed in
+ the future to leave the original data alone.
*/
CURLcode Curl_client_write(struct Curl_easy *data,
- int type, const char *buf, size_t blen)
+ int type, char *buf, size_t blen)
{
CURLcode result;
+#if !defined(CURL_DISABLE_FTP) && defined(CURL_DO_LINEEND_CONV)
+ /* FTP data may need conversion. */
+ if((type & CLIENTWRITE_BODY) &&
+ (data->conn->handler->protocol & PROTO_FAMILY_FTP) &&
+ data->conn->proto.ftpc.transfertype == 'A') {
+ /* convert end-of-line markers */
+ blen = convert_lineends(data, buf, blen);
+ }
+#endif
/* it is one of those, at least */
DEBUGASSERT(type & (CLIENTWRITE_BODY|CLIENTWRITE_HEADER|CLIENTWRITE_INFO));
- /* BODY is only BODY (with optional EOS) */
- DEBUGASSERT(!(type & CLIENTWRITE_BODY) ||
- ((type & ~(CLIENTWRITE_BODY|CLIENTWRITE_EOS)) == 0));
- /* INFO is only INFO (with optional EOS) */
- DEBUGASSERT(!(type & CLIENTWRITE_INFO) ||
- ((type & ~(CLIENTWRITE_INFO|CLIENTWRITE_EOS)) == 0));
+ /* BODY is only BODY */
+ DEBUGASSERT(!(type & CLIENTWRITE_BODY) || (type == CLIENTWRITE_BODY));
+ /* INFO is only INFO */
+ DEBUGASSERT(!(type & CLIENTWRITE_INFO) || (type == CLIENTWRITE_INFO));
if(!data->req.writer_stack) {
- result = do_init_writer_stack(data);
+ result = do_init_stack(data);
if(result)
return result;
DEBUGASSERT(data->req.writer_stack);
}
- result = Curl_cwriter_write(data, data->req.writer_stack, type, buf, blen);
- CURL_TRC_WRITE(data, "client_write(type=%x, len=%zu) -> %d",
- type, blen, result);
+ return Curl_cwriter_write(data, data->req.writer_stack, type, buf, blen);
+}
+
+CURLcode Curl_client_unpause(struct Curl_easy *data)
+{
+ CURLcode result = CURLE_OK;
+
+ if(data->state.tempcount) {
+ /* there are buffers for sending that can be delivered as the receive
+ pausing is lifted! */
+ unsigned int i;
+ unsigned int count = data->state.tempcount;
+ struct tempbuf writebuf[3]; /* there can only be three */
+
+ /* copy the structs to allow for immediate re-pausing */
+ for(i = 0; i < data->state.tempcount; i++) {
+ writebuf[i] = data->state.tempwrite[i];
+ Curl_dyn_init(&data->state.tempwrite[i].b, DYN_PAUSE_BUFFER);
+ }
+ data->state.tempcount = 0;
+
+ for(i = 0; i < count; i++) {
+ /* even if one function returns error, this loops through and frees
+ all buffers */
+ if(!result)
+ result = chop_write(data, writebuf[i].type,
+ !writebuf[i].paused_body,
+ Curl_dyn_ptr(&writebuf[i].b),
+ Curl_dyn_len(&writebuf[i].b));
+ Curl_dyn_free(&writebuf[i].b);
+ }
+ }
return result;
}
-static void cl_reset_writer(struct Curl_easy *data)
+void Curl_client_cleanup(struct Curl_easy *data)
{
struct Curl_cwriter *writer = data->req.writer_stack;
+ size_t i;
+
while(writer) {
data->req.writer_stack = writer->next;
writer->cwt->do_close(data, writer);
free(writer);
writer = data->req.writer_stack;
}
-}
-
-static void cl_reset_reader(struct Curl_easy *data)
-{
- struct Curl_creader *reader = data->req.reader_stack;
- while(reader) {
- data->req.reader_stack = reader->next;
- reader->crt->do_close(data, reader);
- free(reader);
- reader = data->req.reader_stack;
- }
-}
-void Curl_client_cleanup(struct Curl_easy *data)
-{
- cl_reset_reader(data);
- cl_reset_writer(data);
-
- data->req.bytecount = 0;
- data->req.headerline = 0;
-}
-
-void Curl_client_reset(struct Curl_easy *data)
-{
- if(data->req.rewind_read) {
- /* already requested */
- CURL_TRC_READ(data, "client_reset, will rewind reader");
+ for(i = 0; i < data->state.tempcount; i++) {
+ Curl_dyn_free(&data->state.tempwrite[i].b);
}
- else {
- CURL_TRC_READ(data, "client_reset, clear readers");
- cl_reset_reader(data);
- }
- cl_reset_writer(data);
-
+ data->state.tempcount = 0;
data->req.bytecount = 0;
data->req.headerline = 0;
}
-CURLcode Curl_client_start(struct Curl_easy *data)
-{
- if(data->req.rewind_read) {
- struct Curl_creader *r = data->req.reader_stack;
- CURLcode result = CURLE_OK;
-
- CURL_TRC_READ(data, "client start, rewind readers");
- while(r) {
- result = r->crt->rewind(data, r);
- if(result) {
- failf(data, "rewind of client reader '%s' failed: %d",
- r->crt->name, result);
- return result;
- }
- r = r->next;
- }
- data->req.rewind_read = FALSE;
- cl_reset_reader(data);
- }
- return CURLE_OK;
-}
-
-bool Curl_creader_will_rewind(struct Curl_easy *data)
-{
- return data->req.rewind_read;
-}
-
-void Curl_creader_set_rewind(struct Curl_easy *data, bool enable)
-{
- data->req.rewind_read = !!enable;
-}
-
-/* Write data using an unencoding writer stack. */
+/* Write data using an unencoding writer stack. "nbytes" is not
+ allowed to be 0. */
CURLcode Curl_cwriter_write(struct Curl_easy *data,
struct Curl_cwriter *writer, int type,
const char *buf, size_t nbytes)
{
+ if(!nbytes)
+ return CURLE_OK;
if(!writer)
return CURLE_WRITE_ERROR;
return writer->cwt->do_write(data, writer, type, buf, nbytes);
@@ -205,6 +506,26 @@ void Curl_cwriter_def_close(struct Curl_easy *data,
(void) writer;
}
+/* Real client writer to installed callbacks. */
+static CURLcode cw_client_write(struct Curl_easy *data,
+ struct Curl_cwriter *writer, int type,
+ const char *buf, size_t nbytes)
+{
+ (void)writer;
+ if(!nbytes)
+ return CURLE_OK;
+ return chop_write(data, type, FALSE, (char *)buf, nbytes);
+}
+
+static const struct Curl_cwtype cw_client = {
+ "client",
+ NULL,
+ Curl_cwriter_def_init,
+ cw_client_write,
+ Curl_cwriter_def_close,
+ sizeof(struct Curl_cwriter)
+};
+
static size_t get_max_body_write_len(struct Curl_easy *data, curl_off_t limit)
{
if(limit != -1) {
@@ -227,79 +548,36 @@ static size_t get_max_body_write_len(struct Curl_easy *data, curl_off_t limit)
return SIZE_T_MAX;
}
-struct cw_download_ctx {
- struct Curl_cwriter super;
- BIT(started_response);
-};
/* Download client writer in phase CURL_CW_PROTOCOL that
* sees the "real" download body data. */
static CURLcode cw_download_write(struct Curl_easy *data,
struct Curl_cwriter *writer, int type,
const char *buf, size_t nbytes)
{
- struct cw_download_ctx *ctx = writer->ctx;
CURLcode result;
size_t nwrite, excess_len = 0;
- bool is_connect = !!(type & CLIENTWRITE_CONNECT);
-
- if(!is_connect && !ctx->started_response) {
- Curl_pgrsTime(data, TIMER_STARTTRANSFER);
- ctx->started_response = TRUE;
- }
+ const char *excess_data = NULL;
if(!(type & CLIENTWRITE_BODY)) {
- if(is_connect && data->set.suppress_connect_headers)
+ if((type & CLIENTWRITE_CONNECT) && data->set.suppress_connect_headers)
return CURLE_OK;
- result = Curl_cwriter_write(data, writer->next, type, buf, nbytes);
- CURL_TRC_WRITE(data, "download_write header(type=%x, blen=%zu) -> %d",
- type, nbytes, result);
- return result;
- }
-
- /* Here, we deal with REAL BODY bytes. All filtering and transfer
- * encodings have been applied and only the true content, e.g. BODY,
- * bytes are passed here.
- * This allows us to check sizes, update stats, etc. independent
- * from the protocol in play. */
-
- if(data->req.no_body && nbytes > 0) {
- /* BODY arrives although we want none, bail out */
- streamclose(data->conn, "ignoring body");
- CURL_TRC_WRITE(data, "download_write body(type=%x, blen=%zu), "
- "did not want a BODY", type, nbytes);
- data->req.download_done = TRUE;
- if(data->info.header_size)
- /* if headers have been received, this is fine */
- return CURLE_OK;
- return CURLE_WEIRD_SERVER_REPLY;
+ return Curl_cwriter_write(data, writer->next, type, buf, nbytes);
}
- /* Determine if we see any bytes in excess to what is allowed.
- * We write the allowed bytes and handle excess further below.
- * This gives deterministic BODY writes on varying buffer receive
- * lengths. */
nwrite = nbytes;
if(-1 != data->req.maxdownload) {
size_t wmax = get_max_body_write_len(data, data->req.maxdownload);
if(nwrite > wmax) {
excess_len = nbytes - wmax;
nwrite = wmax;
+ excess_data = buf + nwrite;
}
if(nwrite == wmax) {
data->req.download_done = TRUE;
}
-
- if((type & CLIENTWRITE_EOS) && !data->req.no_body &&
- (data->req.maxdownload > data->req.bytecount)) {
- failf(data, "end of response with %" FMT_OFF_T " bytes missing",
- data->req.maxdownload - data->req.bytecount);
- return CURLE_PARTIAL_FILE;
- }
}
- /* Error on too large filesize is handled below, after writing
- * the permitted bytes */
if(data->set.max_filesize) {
size_t wmax = get_max_body_write_len(data, data->set.max_filesize);
if(nwrite > wmax) {
@@ -307,38 +585,50 @@ static CURLcode cw_download_write(struct Curl_easy *data,
}
}
- if(!data->req.ignorebody && (nwrite || (type & CLIENTWRITE_EOS))) {
+ data->req.bytecount += nwrite;
+ ++data->req.bodywrites;
+ if(!data->req.ignorebody && nwrite) {
result = Curl_cwriter_write(data, writer->next, type, buf, nwrite);
- CURL_TRC_WRITE(data, "download_write body(type=%x, blen=%zu) -> %d",
- type, nbytes, result);
if(result)
return result;
}
- /* Update stats, write and report progress */
- data->req.bytecount += nwrite;
-#ifdef USE_HYPER
- data->req.bodywritten = TRUE;
-#endif
result = Curl_pgrsSetDownloadCounter(data, data->req.bytecount);
if(result)
return result;
if(excess_len) {
- if(!data->req.ignorebody) {
+ if(data->conn->handler->readwrite) {
+ /* RTSP hack moved from transfer loop to here */
+ bool readmore = FALSE; /* indicates data is incomplete, need more */
+ size_t consumed = 0;
+ result = data->conn->handler->readwrite(data, data->conn,
+ excess_data, excess_len,
+ &consumed, &readmore);
+ if(result)
+ return result;
+ DEBUGASSERT(consumed <= excess_len);
+ excess_len -= consumed;
+ if(readmore) {
+ data->req.download_done = FALSE;
+ data->req.keepon |= KEEP_RECV; /* we're not done reading */
+ }
+ }
+ if(excess_len && !data->req.ignorebody) {
infof(data,
"Excess found writing body:"
" excess = %zu"
- ", size = %" FMT_OFF_T
- ", maxdownload = %" FMT_OFF_T
- ", bytecount = %" FMT_OFF_T,
+ ", size = %" CURL_FORMAT_CURL_OFF_T
+ ", maxdownload = %" CURL_FORMAT_CURL_OFF_T
+ ", bytecount = %" CURL_FORMAT_CURL_OFF_T,
excess_len, data->req.size, data->req.maxdownload,
data->req.bytecount);
connclose(data->conn, "excess found in a read");
}
}
- else if((nwrite < nbytes) && !data->req.ignorebody) {
+ else if(nwrite < nbytes) {
failf(data, "Exceeded the maximum allowed file size "
- "(%" FMT_OFF_T ") with %" FMT_OFF_T " bytes",
+ "(%" CURL_FORMAT_CURL_OFF_T ") with %"
+ CURL_FORMAT_CURL_OFF_T " bytes",
data->set.max_filesize, data->req.bytecount);
return CURLE_FILESIZE_EXCEEDED;
}
@@ -347,12 +637,12 @@ static CURLcode cw_download_write(struct Curl_easy *data,
}
static const struct Curl_cwtype cw_download = {
- "protocol",
+ "download",
NULL,
Curl_cwriter_def_init,
cw_download_write,
Curl_cwriter_def_close,
- sizeof(struct cw_download_ctx)
+ sizeof(struct Curl_cwriter)
};
/* RAW client writer in phase CURL_CW_RAW that
@@ -382,18 +672,15 @@ CURLcode Curl_cwriter_create(struct Curl_cwriter **pwriter,
const struct Curl_cwtype *cwt,
Curl_cwriter_phase phase)
{
- struct Curl_cwriter *writer = NULL;
+ struct Curl_cwriter *writer;
CURLcode result = CURLE_OUT_OF_MEMORY;
- void *p;
DEBUGASSERT(cwt->cwriter_size >= sizeof(struct Curl_cwriter));
- p = calloc(1, cwt->cwriter_size);
- if(!p)
+ writer = (struct Curl_cwriter *) calloc(1, cwt->cwriter_size);
+ if(!writer)
goto out;
- writer = (struct Curl_cwriter *)p;
writer->cwt = cwt;
- writer->ctx = p;
writer->phase = phase;
result = cwt->do_init(data, writer);
@@ -425,14 +712,14 @@ size_t Curl_cwriter_count(struct Curl_easy *data, Curl_cwriter_phase phase)
return n;
}
-static CURLcode do_init_writer_stack(struct Curl_easy *data)
+static CURLcode do_init_stack(struct Curl_easy *data)
{
struct Curl_cwriter *writer;
CURLcode result;
DEBUGASSERT(!data->req.writer_stack);
result = Curl_cwriter_create(&data->req.writer_stack,
- data, &Curl_cwt_out, CURL_CW_CLIENT);
+ data, &cw_client, CURL_CW_CLIENT);
if(result)
return result;
@@ -461,7 +748,7 @@ CURLcode Curl_cwriter_add(struct Curl_easy *data,
struct Curl_cwriter **anchor = &data->req.writer_stack;
if(!*anchor) {
- result = do_init_writer_stack(data);
+ result = do_init_stack(data);
if(result)
return result;
}
@@ -475,969 +762,41 @@ CURLcode Curl_cwriter_add(struct Curl_easy *data,
return CURLE_OK;
}
-struct Curl_cwriter *Curl_cwriter_get_by_name(struct Curl_easy *data,
- const char *name)
-{
- struct Curl_cwriter *writer;
- for(writer = data->req.writer_stack; writer; writer = writer->next) {
- if(!strcmp(name, writer->cwt->name))
- return writer;
- }
- return NULL;
-}
-
-struct Curl_cwriter *Curl_cwriter_get_by_type(struct Curl_easy *data,
- const struct Curl_cwtype *cwt)
-{
- struct Curl_cwriter *writer;
- for(writer = data->req.writer_stack; writer; writer = writer->next) {
- if(writer->cwt == cwt)
- return writer;
- }
- return NULL;
-}
-
-void Curl_cwriter_remove_by_name(struct Curl_easy *data,
- const char *name)
-{
- struct Curl_cwriter **anchor = &data->req.writer_stack;
-
- while(*anchor) {
- if(!strcmp(name, (*anchor)->cwt->name)) {
- struct Curl_cwriter *w = (*anchor);
- *anchor = w->next;
- Curl_cwriter_free(data, w);
- continue;
- }
- anchor = &((*anchor)->next);
- }
-}
-
-bool Curl_cwriter_is_paused(struct Curl_easy *data)
-{
- return Curl_cw_out_is_paused(data);
-}
-
-CURLcode Curl_cwriter_unpause(struct Curl_easy *data)
-{
- return Curl_cw_out_unpause(data);
-}
-
-CURLcode Curl_creader_read(struct Curl_easy *data,
- struct Curl_creader *reader,
- char *buf, size_t blen, size_t *nread, bool *eos)
-{
- *nread = 0;
- *eos = FALSE;
- if(!reader)
- return CURLE_READ_ERROR;
- return reader->crt->do_read(data, reader, buf, blen, nread, eos);
-}
-
-CURLcode Curl_creader_def_init(struct Curl_easy *data,
- struct Curl_creader *reader)
-{
- (void)data;
- (void)reader;
- return CURLE_OK;
-}
-
-void Curl_creader_def_close(struct Curl_easy *data,
- struct Curl_creader *reader)
-{
- (void)data;
- (void)reader;
-}
-
-CURLcode Curl_creader_def_read(struct Curl_easy *data,
- struct Curl_creader *reader,
- char *buf, size_t blen,
- size_t *nread, bool *eos)
-{
- if(reader->next)
- return reader->next->crt->do_read(data, reader->next, buf, blen,
- nread, eos);
- else {
- *nread = 0;
- *eos = FALSE;
- return CURLE_READ_ERROR;
- }
-}
-
-bool Curl_creader_def_needs_rewind(struct Curl_easy *data,
- struct Curl_creader *reader)
-{
- (void)data;
- (void)reader;
- return FALSE;
-}
-
-curl_off_t Curl_creader_def_total_length(struct Curl_easy *data,
- struct Curl_creader *reader)
-{
- return reader->next?
- reader->next->crt->total_length(data, reader->next) : -1;
-}
-
-CURLcode Curl_creader_def_resume_from(struct Curl_easy *data,
- struct Curl_creader *reader,
- curl_off_t offset)
-{
- (void)data;
- (void)reader;
- (void)offset;
- return CURLE_READ_ERROR;
-}
-
-CURLcode Curl_creader_def_rewind(struct Curl_easy *data,
- struct Curl_creader *reader)
-{
- (void)data;
- (void)reader;
- return CURLE_OK;
-}
-
-CURLcode Curl_creader_def_unpause(struct Curl_easy *data,
- struct Curl_creader *reader)
-{
- (void)data;
- (void)reader;
- return CURLE_OK;
-}
-
-bool Curl_creader_def_is_paused(struct Curl_easy *data,
- struct Curl_creader *reader)
-{
- (void)data;
- (void)reader;
- return FALSE;
-}
-
-void Curl_creader_def_done(struct Curl_easy *data,
- struct Curl_creader *reader, int premature)
-{
- (void)data;
- (void)reader;
- (void)premature;
-}
-
-struct cr_in_ctx {
- struct Curl_creader super;
- curl_read_callback read_cb;
- void *cb_user_data;
- curl_off_t total_len;
- curl_off_t read_len;
- CURLcode error_result;
- BIT(seen_eos);
- BIT(errored);
- BIT(has_used_cb);
- BIT(is_paused);
-};
-
-static CURLcode cr_in_init(struct Curl_easy *data, struct Curl_creader *reader)
-{
- struct cr_in_ctx *ctx = reader->ctx;
- (void)data;
- ctx->read_cb = data->state.fread_func;
- ctx->cb_user_data = data->state.in;
- ctx->total_len = -1;
- ctx->read_len = 0;
- return CURLE_OK;
-}
-
-/* Real client reader to installed client callbacks. */
-static CURLcode cr_in_read(struct Curl_easy *data,
- struct Curl_creader *reader,
- char *buf, size_t blen,
- size_t *pnread, bool *peos)
-{
- struct cr_in_ctx *ctx = reader->ctx;
- size_t nread;
-
- ctx->is_paused = FALSE;
-
- /* Once we have errored, we will return the same error forever */
- if(ctx->errored) {
- *pnread = 0;
- *peos = FALSE;
- return ctx->error_result;
- }
- if(ctx->seen_eos) {
- *pnread = 0;
- *peos = TRUE;
- return CURLE_OK;
- }
- /* respect length limitations */
- if(ctx->total_len >= 0) {
- curl_off_t remain = ctx->total_len - ctx->read_len;
- if(remain <= 0)
- blen = 0;
- else if(remain < (curl_off_t)blen)
- blen = (size_t)remain;
- }
- nread = 0;
- if(ctx->read_cb && blen) {
- Curl_set_in_callback(data, true);
- nread = ctx->read_cb(buf, 1, blen, ctx->cb_user_data);
- Curl_set_in_callback(data, false);
- ctx->has_used_cb = TRUE;
- }
-
- switch(nread) {
- case 0:
- if((ctx->total_len >= 0) && (ctx->read_len < ctx->total_len)) {
- failf(data, "client read function EOF fail, "
- "only %"FMT_OFF_T"/%"FMT_OFF_T " of needed bytes read",
- ctx->read_len, ctx->total_len);
- return CURLE_READ_ERROR;
- }
- *pnread = 0;
- *peos = TRUE;
- ctx->seen_eos = TRUE;
- break;
-
- case CURL_READFUNC_ABORT:
- failf(data, "operation aborted by callback");
- *pnread = 0;
- *peos = FALSE;
- ctx->errored = TRUE;
- ctx->error_result = CURLE_ABORTED_BY_CALLBACK;
- return CURLE_ABORTED_BY_CALLBACK;
-
- case CURL_READFUNC_PAUSE:
- if(data->conn->handler->flags & PROTOPT_NONETWORK) {
- /* protocols that work without network cannot be paused. This is
- actually only FILE:// just now, and it cannot pause since the transfer
- is not done using the "normal" procedure. */
- failf(data, "Read callback asked for PAUSE when not supported");
- return CURLE_READ_ERROR;
- }
- /* CURL_READFUNC_PAUSE pauses read callbacks that feed socket writes */
- CURL_TRC_READ(data, "cr_in_read, callback returned CURL_READFUNC_PAUSE");
- ctx->is_paused = TRUE;
- data->req.keepon |= KEEP_SEND_PAUSE; /* mark socket send as paused */
- *pnread = 0;
- *peos = FALSE;
- break; /* nothing was read */
-
- default:
- if(nread > blen) {
- /* the read function returned a too large value */
- failf(data, "read function returned funny value");
- *pnread = 0;
- *peos = FALSE;
- ctx->errored = TRUE;
- ctx->error_result = CURLE_READ_ERROR;
- return CURLE_READ_ERROR;
- }
- ctx->read_len += nread;
- if(ctx->total_len >= 0)
- ctx->seen_eos = (ctx->read_len >= ctx->total_len);
- *pnread = nread;
- *peos = ctx->seen_eos;
- break;
- }
- CURL_TRC_READ(data, "cr_in_read(len=%zu, total=%"FMT_OFF_T
- ", read=%"FMT_OFF_T") -> %d, nread=%zu, eos=%d",
- blen, ctx->total_len, ctx->read_len, CURLE_OK,
- *pnread, *peos);
- return CURLE_OK;
-}
-
-static bool cr_in_needs_rewind(struct Curl_easy *data,
- struct Curl_creader *reader)
-{
- struct cr_in_ctx *ctx = reader->ctx;
- (void)data;
- return ctx->has_used_cb;
-}
-
-static curl_off_t cr_in_total_length(struct Curl_easy *data,
- struct Curl_creader *reader)
-{
- struct cr_in_ctx *ctx = reader->ctx;
- (void)data;
- return ctx->total_len;
-}
-
-static CURLcode cr_in_resume_from(struct Curl_easy *data,
- struct Curl_creader *reader,
- curl_off_t offset)
-{
- struct cr_in_ctx *ctx = reader->ctx;
- int seekerr = CURL_SEEKFUNC_CANTSEEK;
-
- DEBUGASSERT(data->conn);
- /* already started reading? */
- if(ctx->read_len)
- return CURLE_READ_ERROR;
-
- if(data->set.seek_func) {
- Curl_set_in_callback(data, true);
- seekerr = data->set.seek_func(data->set.seek_client, offset, SEEK_SET);
- Curl_set_in_callback(data, false);
- }
-
- if(seekerr != CURL_SEEKFUNC_OK) {
- curl_off_t passed = 0;
-
- if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
- failf(data, "Could not seek stream");
- return CURLE_READ_ERROR;
- }
- /* when seekerr == CURL_SEEKFUNC_CANTSEEK (cannot seek to offset) */
- do {
- char scratch[4*1024];
- size_t readthisamountnow =
- (offset - passed > (curl_off_t)sizeof(scratch)) ?
- sizeof(scratch) :
- curlx_sotouz(offset - passed);
- size_t actuallyread;
-
- Curl_set_in_callback(data, true);
- actuallyread = ctx->read_cb(scratch, 1, readthisamountnow,
- ctx->cb_user_data);
- Curl_set_in_callback(data, false);
-
- passed += actuallyread;
- if((actuallyread == 0) || (actuallyread > readthisamountnow)) {
- /* this checks for greater-than only to make sure that the
- CURL_READFUNC_ABORT return code still aborts */
- failf(data, "Could only read %" FMT_OFF_T " bytes from the input",
- passed);
- return CURLE_READ_ERROR;
- }
- } while(passed < offset);
- }
-
- /* now, decrease the size of the read */
- if(ctx->total_len > 0) {
- ctx->total_len -= offset;
-
- if(ctx->total_len <= 0) {
- failf(data, "File already completely uploaded");
- return CURLE_PARTIAL_FILE;
- }
- }
- /* we have passed, proceed as normal */
- return CURLE_OK;
-}
-
-static CURLcode cr_in_rewind(struct Curl_easy *data,
- struct Curl_creader *reader)
-{
- struct cr_in_ctx *ctx = reader->ctx;
-
- /* If we never invoked the callback, there is noting to rewind */
- if(!ctx->has_used_cb)
- return CURLE_OK;
-
- if(data->set.seek_func) {
- int err;
-
- Curl_set_in_callback(data, true);
- err = (data->set.seek_func)(data->set.seek_client, 0, SEEK_SET);
- Curl_set_in_callback(data, false);
- CURL_TRC_READ(data, "cr_in, rewind via set.seek_func -> %d", err);
- if(err) {
- failf(data, "seek callback returned error %d", (int)err);
- return CURLE_SEND_FAIL_REWIND;
- }
- }
- else if(data->set.ioctl_func) {
- curlioerr err;
-
- Curl_set_in_callback(data, true);
- err = (data->set.ioctl_func)(data, CURLIOCMD_RESTARTREAD,
- data->set.ioctl_client);
- Curl_set_in_callback(data, false);
- CURL_TRC_READ(data, "cr_in, rewind via set.ioctl_func -> %d", (int)err);
- if(err) {
- failf(data, "ioctl callback returned error %d", (int)err);
- return CURLE_SEND_FAIL_REWIND;
- }
- }
- else {
- /* If no CURLOPT_READFUNCTION is used, we know that we operate on a
- given FILE * stream and we can actually attempt to rewind that
- ourselves with fseek() */
- if(data->state.fread_func == (curl_read_callback)fread) {
- int err = fseek(data->state.in, 0, SEEK_SET);
- CURL_TRC_READ(data, "cr_in, rewind via fseek -> %d(%d)",
- (int)err, (int)errno);
- if(-1 != err)
- /* successful rewind */
- return CURLE_OK;
- }
-
- /* no callback set or failure above, makes us fail at once */
- failf(data, "necessary data rewind was not possible");
- return CURLE_SEND_FAIL_REWIND;
- }
- return CURLE_OK;
-}
-
-static CURLcode cr_in_unpause(struct Curl_easy *data,
- struct Curl_creader *reader)
-{
- struct cr_in_ctx *ctx = reader->ctx;
- (void)data;
- ctx->is_paused = FALSE;
- return CURLE_OK;
-}
-
-static bool cr_in_is_paused(struct Curl_easy *data,
- struct Curl_creader *reader)
-{
- struct cr_in_ctx *ctx = reader->ctx;
- (void)data;
- return ctx->is_paused;
-}
-
-static const struct Curl_crtype cr_in = {
- "cr-in",
- cr_in_init,
- cr_in_read,
- Curl_creader_def_close,
- cr_in_needs_rewind,
- cr_in_total_length,
- cr_in_resume_from,
- cr_in_rewind,
- cr_in_unpause,
- cr_in_is_paused,
- Curl_creader_def_done,
- sizeof(struct cr_in_ctx)
-};
-
-CURLcode Curl_creader_create(struct Curl_creader **preader,
- struct Curl_easy *data,
- const struct Curl_crtype *crt,
- Curl_creader_phase phase)
-{
- struct Curl_creader *reader = NULL;
- CURLcode result = CURLE_OUT_OF_MEMORY;
- void *p;
-
- DEBUGASSERT(crt->creader_size >= sizeof(struct Curl_creader));
- p = calloc(1, crt->creader_size);
- if(!p)
- goto out;
-
- reader = (struct Curl_creader *)p;
- reader->crt = crt;
- reader->ctx = p;
- reader->phase = phase;
- result = crt->do_init(data, reader);
-
-out:
- *preader = result? NULL : reader;
- if(result)
- free(reader);
- return result;
-}
-
-void Curl_creader_free(struct Curl_easy *data, struct Curl_creader *reader)
-{
- if(reader) {
- reader->crt->do_close(data, reader);
- free(reader);
- }
-}
-
-struct cr_lc_ctx {
- struct Curl_creader super;
- struct bufq buf;
- BIT(read_eos); /* we read an EOS from the next reader */
- BIT(eos); /* we have returned an EOS */
- BIT(prev_cr); /* the last byte was a CR */
-};
-
-static CURLcode cr_lc_init(struct Curl_easy *data, struct Curl_creader *reader)
-{
- struct cr_lc_ctx *ctx = reader->ctx;
- (void)data;
- Curl_bufq_init2(&ctx->buf, (16 * 1024), 1, BUFQ_OPT_SOFT_LIMIT);
- return CURLE_OK;
-}
-
-static void cr_lc_close(struct Curl_easy *data, struct Curl_creader *reader)
-{
- struct cr_lc_ctx *ctx = reader->ctx;
- (void)data;
- Curl_bufq_free(&ctx->buf);
-}
-
-/* client reader doing line end conversions. */
-static CURLcode cr_lc_read(struct Curl_easy *data,
- struct Curl_creader *reader,
- char *buf, size_t blen,
- size_t *pnread, bool *peos)
-{
- struct cr_lc_ctx *ctx = reader->ctx;
- CURLcode result;
- size_t nread, i, start, n;
- bool eos;
-
- if(ctx->eos) {
- *pnread = 0;
- *peos = TRUE;
- return CURLE_OK;
- }
-
- if(Curl_bufq_is_empty(&ctx->buf)) {
- if(ctx->read_eos) {
- ctx->eos = TRUE;
- *pnread = 0;
- *peos = TRUE;
- return CURLE_OK;
- }
- /* Still getting data form the next reader, ctx->buf is empty */
- result = Curl_creader_read(data, reader->next, buf, blen, &nread, &eos);
- if(result)
- return result;
- ctx->read_eos = eos;
-
- if(!nread || !memchr(buf, '\n', nread)) {
- /* nothing to convert, return this right away */
- if(ctx->read_eos)
- ctx->eos = TRUE;
- *pnread = nread;
- *peos = ctx->eos;
- goto out;
- }
-
- /* at least one \n might need conversion to '\r\n', place into ctx->buf */
- for(i = start = 0; i < nread; ++i) {
- /* if this byte is not an LF character, or if the preceding character is
- a CR (meaning this already is a CRLF pair), go to next */
- if((buf[i] != '\n') || ctx->prev_cr) {
- ctx->prev_cr = (buf[i] == '\r');
- continue;
- }
- ctx->prev_cr = false;
- /* on a soft limit bufq, we do not need to check length */
- result = Curl_bufq_cwrite(&ctx->buf, buf + start, i - start, &n);
- if(!result)
- result = Curl_bufq_cwrite(&ctx->buf, STRCONST("\r\n"), &n);
- if(result)
- return result;
- start = i + 1;
- if(!data->set.crlf && (data->state.infilesize != -1)) {
- /* we are here only because FTP is in ASCII mode...
- bump infilesize for the LF we just added */
- data->state.infilesize++;
- /* comment: this might work for FTP, but in HTTP we could not change
- * the content length after having started the request... */
- }
- }
-
- if(start < i) { /* leftover */
- result = Curl_bufq_cwrite(&ctx->buf, buf + start, i - start, &n);
- if(result)
- return result;
- }
- }
-
- DEBUGASSERT(!Curl_bufq_is_empty(&ctx->buf));
- *peos = FALSE;
- result = Curl_bufq_cread(&ctx->buf, buf, blen, pnread);
- if(!result && ctx->read_eos && Curl_bufq_is_empty(&ctx->buf)) {
- /* no more data, read all, done. */
- ctx->eos = TRUE;
- *peos = TRUE;
- }
-
-out:
- CURL_TRC_READ(data, "cr_lc_read(len=%zu) -> %d, nread=%zu, eos=%d",
- blen, result, *pnread, *peos);
- return result;
-}
-
-static curl_off_t cr_lc_total_length(struct Curl_easy *data,
- struct Curl_creader *reader)
-{
- /* this reader changes length depending on input */
- (void)data;
- (void)reader;
- return -1;
-}
-
-static const struct Curl_crtype cr_lc = {
- "cr-lineconv",
- cr_lc_init,
- cr_lc_read,
- cr_lc_close,
- Curl_creader_def_needs_rewind,
- cr_lc_total_length,
- Curl_creader_def_resume_from,
- Curl_creader_def_rewind,
- Curl_creader_def_unpause,
- Curl_creader_def_is_paused,
- Curl_creader_def_done,
- sizeof(struct cr_lc_ctx)
-};
-
-static CURLcode cr_lc_add(struct Curl_easy *data)
-{
- struct Curl_creader *reader = NULL;
- CURLcode result;
- result = Curl_creader_create(&reader, data, &cr_lc,
- CURL_CR_CONTENT_ENCODE);
- if(!result)
- result = Curl_creader_add(data, reader);
-
- if(result && reader)
- Curl_creader_free(data, reader);
- return result;
-}
-
-static CURLcode do_init_reader_stack(struct Curl_easy *data,
- struct Curl_creader *r)
-{
- CURLcode result = CURLE_OK;
- curl_off_t clen;
-
- DEBUGASSERT(r);
- DEBUGASSERT(r->crt);
- DEBUGASSERT(r->phase == CURL_CR_CLIENT);
- DEBUGASSERT(!data->req.reader_stack);
-
- data->req.reader_stack = r;
- clen = r->crt->total_length(data, r);
- /* if we do not have 0 length init, and crlf conversion is wanted,
- * add the reader for it */
- if(clen && (data->set.crlf
-#ifdef CURL_PREFER_LF_LINEENDS
- || data->state.prefer_ascii
-#endif
- )) {
- result = cr_lc_add(data);
- if(result)
- return result;
- }
-
- return result;
-}
-
-CURLcode Curl_creader_set_fread(struct Curl_easy *data, curl_off_t len)
-{
- CURLcode result;
- struct Curl_creader *r;
- struct cr_in_ctx *ctx;
-
- result = Curl_creader_create(&r, data, &cr_in, CURL_CR_CLIENT);
- if(result)
- goto out;
- ctx = r->ctx;
- ctx->total_len = len;
-
- cl_reset_reader(data);
- result = do_init_reader_stack(data, r);
-out:
- CURL_TRC_READ(data, "add fread reader, len=%"FMT_OFF_T " -> %d",
- len, result);
- return result;
-}
-
-CURLcode Curl_creader_add(struct Curl_easy *data,
- struct Curl_creader *reader)
-{
- CURLcode result;
- struct Curl_creader **anchor = &data->req.reader_stack;
-
- if(!*anchor) {
- result = Curl_creader_set_fread(data, data->state.infilesize);
- if(result)
- return result;
- }
-
- /* Insert the writer as first in its phase.
- * Skip existing readers of lower phases. */
- while(*anchor && (*anchor)->phase < reader->phase)
- anchor = &((*anchor)->next);
- reader->next = *anchor;
- *anchor = reader;
- return CURLE_OK;
-}
-
-CURLcode Curl_creader_set(struct Curl_easy *data, struct Curl_creader *r)
-{
- CURLcode result;
-
- DEBUGASSERT(r);
- DEBUGASSERT(r->crt);
- DEBUGASSERT(r->phase == CURL_CR_CLIENT);
-
- cl_reset_reader(data);
- result = do_init_reader_stack(data, r);
- if(result)
- Curl_creader_free(data, r);
- return result;
-}
-
-CURLcode Curl_client_read(struct Curl_easy *data, char *buf, size_t blen,
- size_t *nread, bool *eos)
-{
- CURLcode result;
-
- DEBUGASSERT(buf);
- DEBUGASSERT(blen);
- DEBUGASSERT(nread);
- DEBUGASSERT(eos);
-
- if(!data->req.reader_stack) {
- result = Curl_creader_set_fread(data, data->state.infilesize);
- if(result)
- return result;
- DEBUGASSERT(data->req.reader_stack);
- }
-
- result = Curl_creader_read(data, data->req.reader_stack, buf, blen,
- nread, eos);
- CURL_TRC_READ(data, "client_read(len=%zu) -> %d, nread=%zu, eos=%d",
- blen, result, *nread, *eos);
- return result;
-}
-
-bool Curl_creader_needs_rewind(struct Curl_easy *data)
-{
- struct Curl_creader *reader = data->req.reader_stack;
- while(reader) {
- if(reader->crt->needs_rewind(data, reader)) {
- CURL_TRC_READ(data, "client reader needs rewind before next request");
- return TRUE;
- }
- reader = reader->next;
- }
- return FALSE;
-}
-
-static CURLcode cr_null_read(struct Curl_easy *data,
- struct Curl_creader *reader,
- char *buf, size_t blen,
- size_t *pnread, bool *peos)
-{
- (void)data;
- (void)reader;
- (void)buf;
- (void)blen;
- *pnread = 0;
- *peos = TRUE;
- return CURLE_OK;
-}
-
-static curl_off_t cr_null_total_length(struct Curl_easy *data,
- struct Curl_creader *reader)
-{
- /* this reader changes length depending on input */
- (void)data;
- (void)reader;
- return 0;
-}
-
-static const struct Curl_crtype cr_null = {
- "cr-null",
- Curl_creader_def_init,
- cr_null_read,
- Curl_creader_def_close,
- Curl_creader_def_needs_rewind,
- cr_null_total_length,
- Curl_creader_def_resume_from,
- Curl_creader_def_rewind,
- Curl_creader_def_unpause,
- Curl_creader_def_is_paused,
- Curl_creader_def_done,
- sizeof(struct Curl_creader)
-};
-
-CURLcode Curl_creader_set_null(struct Curl_easy *data)
-{
- struct Curl_creader *r;
- CURLcode result;
-
- result = Curl_creader_create(&r, data, &cr_null, CURL_CR_CLIENT);
- if(result)
- return result;
-
- cl_reset_reader(data);
- return do_init_reader_stack(data, r);
-}
-
-struct cr_buf_ctx {
- struct Curl_creader super;
- const char *buf;
- size_t blen;
- size_t index;
-};
-
-static CURLcode cr_buf_read(struct Curl_easy *data,
- struct Curl_creader *reader,
- char *buf, size_t blen,
- size_t *pnread, bool *peos)
-{
- struct cr_buf_ctx *ctx = reader->ctx;
- size_t nread = ctx->blen - ctx->index;
-
- (void)data;
- if(!nread || !ctx->buf) {
- *pnread = 0;
- *peos = TRUE;
- }
- else {
- if(nread > blen)
- nread = blen;
- memcpy(buf, ctx->buf + ctx->index, nread);
- *pnread = nread;
- ctx->index += nread;
- *peos = (ctx->index == ctx->blen);
- }
- CURL_TRC_READ(data, "cr_buf_read(len=%zu) -> 0, nread=%zu, eos=%d",
- blen, *pnread, *peos);
- return CURLE_OK;
-}
-
-static bool cr_buf_needs_rewind(struct Curl_easy *data,
- struct Curl_creader *reader)
-{
- struct cr_buf_ctx *ctx = reader->ctx;
- (void)data;
- return ctx->index > 0;
-}
-
-static curl_off_t cr_buf_total_length(struct Curl_easy *data,
- struct Curl_creader *reader)
-{
- struct cr_buf_ctx *ctx = reader->ctx;
- (void)data;
- return (curl_off_t)ctx->blen;
-}
-
-static CURLcode cr_buf_resume_from(struct Curl_easy *data,
- struct Curl_creader *reader,
- curl_off_t offset)
-{
- struct cr_buf_ctx *ctx = reader->ctx;
- size_t boffset;
-
- (void)data;
- DEBUGASSERT(data->conn);
- /* already started reading? */
- if(ctx->index)
- return CURLE_READ_ERROR;
- if(offset <= 0)
- return CURLE_OK;
- boffset = (size_t)offset;
- if(boffset > ctx->blen)
- return CURLE_READ_ERROR;
-
- ctx->buf += boffset;
- ctx->blen -= boffset;
- return CURLE_OK;
-}
-
-static const struct Curl_crtype cr_buf = {
- "cr-buf",
- Curl_creader_def_init,
- cr_buf_read,
- Curl_creader_def_close,
- cr_buf_needs_rewind,
- cr_buf_total_length,
- cr_buf_resume_from,
- Curl_creader_def_rewind,
- Curl_creader_def_unpause,
- Curl_creader_def_is_paused,
- Curl_creader_def_done,
- sizeof(struct cr_buf_ctx)
-};
-
-CURLcode Curl_creader_set_buf(struct Curl_easy *data,
- const char *buf, size_t blen)
-{
- CURLcode result;
- struct Curl_creader *r;
- struct cr_buf_ctx *ctx;
-
- result = Curl_creader_create(&r, data, &cr_buf, CURL_CR_CLIENT);
- if(result)
+/*
+ * Internal read-from-socket function. This is meant to deal with plain
+ * sockets, SSL sockets and kerberos sockets.
+ *
+ * Returns a regular CURLcode value.
+ */
+CURLcode Curl_read(struct Curl_easy *data, /* transfer */
+ curl_socket_t sockfd, /* read from this socket */
+ char *buf, /* store read data here */
+ size_t sizerequested, /* max amount to read */
+ ssize_t *n) /* amount bytes read */
+{
+ CURLcode result = CURLE_RECV_ERROR;
+ ssize_t nread = 0;
+ size_t bytesfromsocket = 0;
+ char *buffertofill = NULL;
+ struct connectdata *conn = data->conn;
+
+ /* Set 'num' to 0 or 1, depending on which socket that has been sent here.
+ If it is the second socket, we set num to 1. Otherwise to 0. This lets
+ us use the correct ssl handle. */
+ int num = (sockfd == conn->sock[SECONDARYSOCKET]);
+
+ *n = 0; /* reset amount to zero */
+
+ bytesfromsocket = CURLMIN(sizerequested, (size_t)data->set.buffer_size);
+ buffertofill = buf;
+
+ nread = conn->recv[num](data, num, buffertofill, bytesfromsocket, &result);
+ if(nread < 0)
goto out;
- ctx = r->ctx;
- ctx->buf = buf;
- ctx->blen = blen;
- ctx->index = 0;
- cl_reset_reader(data);
- result = do_init_reader_stack(data, r);
+ *n += nread;
+ result = CURLE_OK;
out:
- CURL_TRC_READ(data, "add buf reader, len=%zu -> %d", blen, result);
- return result;
-}
-
-curl_off_t Curl_creader_total_length(struct Curl_easy *data)
-{
- struct Curl_creader *r = data->req.reader_stack;
- return r? r->crt->total_length(data, r) : -1;
-}
-
-curl_off_t Curl_creader_client_length(struct Curl_easy *data)
-{
- struct Curl_creader *r = data->req.reader_stack;
- while(r && r->phase != CURL_CR_CLIENT)
- r = r->next;
- return r? r->crt->total_length(data, r) : -1;
-}
-
-CURLcode Curl_creader_resume_from(struct Curl_easy *data, curl_off_t offset)
-{
- struct Curl_creader *r = data->req.reader_stack;
- while(r && r->phase != CURL_CR_CLIENT)
- r = r->next;
- return r? r->crt->resume_from(data, r, offset) : CURLE_READ_ERROR;
-}
-
-CURLcode Curl_creader_unpause(struct Curl_easy *data)
-{
- struct Curl_creader *reader = data->req.reader_stack;
- CURLcode result = CURLE_OK;
-
- while(reader) {
- result = reader->crt->unpause(data, reader);
- if(result)
- break;
- reader = reader->next;
- }
return result;
}
-
-bool Curl_creader_is_paused(struct Curl_easy *data)
-{
- struct Curl_creader *reader = data->req.reader_stack;
-
- while(reader) {
- if(reader->crt->is_paused(data, reader))
- return TRUE;
- reader = reader->next;
- }
- return FALSE;
-}
-
-void Curl_creader_done(struct Curl_easy *data, int premature)
-{
- struct Curl_creader *reader = data->req.reader_stack;
- while(reader) {
- reader->crt->done(data, reader, premature);
- reader = reader->next;
- }
-}
-
-struct Curl_creader *Curl_creader_get_by_type(struct Curl_easy *data,
- const struct Curl_crtype *crt)
-{
- struct Curl_creader *r;
- for(r = data->req.reader_stack; r; r = r->next) {
- if(r->crt == crt)
- return r;
- }
- return NULL;
-
-}
diff --git a/contrib/libs/curl/lib/sendf.h b/contrib/libs/curl/lib/sendf.h
index dc1b82edfe..a70189f2f5 100644
--- a/contrib/libs/curl/lib/sendf.h
+++ b/contrib/libs/curl/lib/sendf.h
@@ -49,31 +49,25 @@
#define CLIENTWRITE_CONNECT (1<<4) /* a CONNECT related HEADER */
#define CLIENTWRITE_1XX (1<<5) /* a 1xx response related HEADER */
#define CLIENTWRITE_TRAILER (1<<6) /* a trailer HEADER */
-#define CLIENTWRITE_EOS (1<<7) /* End Of transfer download Stream */
/**
* Write `len` bytes at `prt` to the client. `type` indicates what
* kind of data is being written.
*/
-CURLcode Curl_client_write(struct Curl_easy *data, int type, const char *ptr,
+CURLcode Curl_client_write(struct Curl_easy *data, int type, char *ptr,
size_t len) WARN_UNUSED_RESULT;
/**
- * Free all resources related to client writing.
- */
-void Curl_client_cleanup(struct Curl_easy *data);
-
-/**
- * Reset readers and writer chains, keep rewind information
- * when necessary.
+ * For a paused transfer, there might be buffered data held back.
+ * Attempt to flush this data to the client. This *may* trigger
+ * another pause of the transfer.
*/
-void Curl_client_reset(struct Curl_easy *data);
+CURLcode Curl_client_unpause(struct Curl_easy *data);
/**
- * A new request is starting, perform any ops like rewinding
- * previous readers when needed.
+ * Free all resources related to client writing.
*/
-CURLcode Curl_client_start(struct Curl_easy *data);
+void Curl_client_cleanup(struct Curl_easy *data);
/**
* Client Writers - a chain passing transfer BODY data to the client.
@@ -117,16 +111,10 @@ struct Curl_cwtype {
size_t cwriter_size; /* sizeof() allocated struct Curl_cwriter */
};
-/* Client writer instance, allocated on creation.
- * `void *ctx` is the pointer from the allocation of
- * the `struct Curl_cwriter` itself. This is suitable for "downcasting"
- * by the writers implementation. See https://github.com/curl/curl/pull/13054
- * for the alignment problems that arise otherwise.
- */
+/* Client writer instance */
struct Curl_cwriter {
const struct Curl_cwtype *cwt; /* type implementation */
struct Curl_cwriter *next; /* Downstream writer. */
- void *ctx; /* allocated instance pointer */
Curl_cwriter_phase phase; /* phase at which it operates */
};
@@ -160,19 +148,6 @@ CURLcode Curl_cwriter_add(struct Curl_easy *data,
struct Curl_cwriter *writer);
/**
- * Look up an installed client writer on `data` by its type.
- * @return first writer with that type or NULL
- */
-struct Curl_cwriter *Curl_cwriter_get_by_type(struct Curl_easy *data,
- const struct Curl_cwtype *cwt);
-
-void Curl_cwriter_remove_by_name(struct Curl_easy *data,
- const char *name);
-
-struct Curl_cwriter *Curl_cwriter_get_by_name(struct Curl_easy *data,
- const char *name);
-
-/**
* Convenience method for calling `writer->do_write()` that
* checks for NULL writer.
*/
@@ -181,16 +156,6 @@ CURLcode Curl_cwriter_write(struct Curl_easy *data,
const char *buf, size_t nbytes);
/**
- * Return TRUE iff client writer is paused.
- */
-bool Curl_cwriter_is_paused(struct Curl_easy *data);
-
-/**
- * Unpause client writer and flush any buffered date to the client.
- */
-CURLcode Curl_cwriter_unpause(struct Curl_easy *data);
-
-/**
* Default implementations for do_init, do_write, do_close that
* do nothing and pass the data through.
*/
@@ -203,213 +168,22 @@ void Curl_cwriter_def_close(struct Curl_easy *data,
struct Curl_cwriter *writer);
+/* internal read-function, does plain socket, SSL and krb4 */
+CURLcode Curl_read(struct Curl_easy *data, curl_socket_t sockfd,
+ char *buf, size_t buffersize,
+ ssize_t *n);
-/* Client Reader Type, provides the implementation */
-struct Curl_crtype {
- const char *name; /* writer name. */
- CURLcode (*do_init)(struct Curl_easy *data, struct Curl_creader *reader);
- CURLcode (*do_read)(struct Curl_easy *data, struct Curl_creader *reader,
- char *buf, size_t blen, size_t *nread, bool *eos);
- void (*do_close)(struct Curl_easy *data, struct Curl_creader *reader);
- bool (*needs_rewind)(struct Curl_easy *data, struct Curl_creader *reader);
- curl_off_t (*total_length)(struct Curl_easy *data,
- struct Curl_creader *reader);
- CURLcode (*resume_from)(struct Curl_easy *data,
- struct Curl_creader *reader, curl_off_t offset);
- CURLcode (*rewind)(struct Curl_easy *data, struct Curl_creader *reader);
- CURLcode (*unpause)(struct Curl_easy *data, struct Curl_creader *reader);
- bool (*is_paused)(struct Curl_easy *data, struct Curl_creader *reader);
- void (*done)(struct Curl_easy *data,
- struct Curl_creader *reader, int premature);
- size_t creader_size; /* sizeof() allocated struct Curl_creader */
-};
-
-/* Phase a reader operates at. */
-typedef enum {
- CURL_CR_NET, /* data send to the network (connection filters) */
- CURL_CR_TRANSFER_ENCODE, /* add transfer-encodings */
- CURL_CR_PROTOCOL, /* before transfer, but after content decoding */
- CURL_CR_CONTENT_ENCODE, /* add content-encodings */
- CURL_CR_CLIENT /* data read from client */
-} Curl_creader_phase;
-
-/* Client reader instance, allocated on creation.
- * `void *ctx` is the pointer from the allocation of
- * the `struct Curl_cwriter` itself. This is suitable for "downcasting"
- * by the writers implementation. See https://github.com/curl/curl/pull/13054
- * for the alignment problems that arise otherwise.
- */
-struct Curl_creader {
- const struct Curl_crtype *crt; /* type implementation */
- struct Curl_creader *next; /* Downstream reader. */
- void *ctx;
- Curl_creader_phase phase; /* phase at which it operates */
-};
-
-/**
- * Default implementations for do_init, do_write, do_close that
- * do nothing and pass the data through.
- */
-CURLcode Curl_creader_def_init(struct Curl_easy *data,
- struct Curl_creader *reader);
-void Curl_creader_def_close(struct Curl_easy *data,
- struct Curl_creader *reader);
-CURLcode Curl_creader_def_read(struct Curl_easy *data,
- struct Curl_creader *reader,
- char *buf, size_t blen,
- size_t *nread, bool *eos);
-bool Curl_creader_def_needs_rewind(struct Curl_easy *data,
- struct Curl_creader *reader);
-curl_off_t Curl_creader_def_total_length(struct Curl_easy *data,
- struct Curl_creader *reader);
-CURLcode Curl_creader_def_resume_from(struct Curl_easy *data,
- struct Curl_creader *reader,
- curl_off_t offset);
-CURLcode Curl_creader_def_rewind(struct Curl_easy *data,
- struct Curl_creader *reader);
-CURLcode Curl_creader_def_unpause(struct Curl_easy *data,
- struct Curl_creader *reader);
-bool Curl_creader_def_is_paused(struct Curl_easy *data,
- struct Curl_creader *reader);
-void Curl_creader_def_done(struct Curl_easy *data,
- struct Curl_creader *reader, int premature);
-
-/**
- * Convenience method for calling `reader->do_read()` that
- * checks for NULL reader.
- */
-CURLcode Curl_creader_read(struct Curl_easy *data,
- struct Curl_creader *reader,
- char *buf, size_t blen, size_t *nread, bool *eos);
-
-/**
- * Create a new creader instance with given type and phase. Is not
- * inserted into the writer chain by this call.
- * Invokes `reader->do_init()`.
- */
-CURLcode Curl_creader_create(struct Curl_creader **preader,
- struct Curl_easy *data,
- const struct Curl_crtype *cr_handler,
- Curl_creader_phase phase);
-
-/**
- * Free a creader instance.
- * Invokes `reader->do_close()`.
- */
-void Curl_creader_free(struct Curl_easy *data, struct Curl_creader *reader);
-
-/**
- * Adds a reader to the transfer's reader chain.
- * The readers `phase` determines where in the chain it is inserted.
- */
-CURLcode Curl_creader_add(struct Curl_easy *data,
- struct Curl_creader *reader);
-
-/**
- * Set the given reader, which needs to be of type CURL_CR_CLIENT,
- * as the new first reader. Discard any installed readers and init
- * the reader chain anew.
- * The function takes ownership of `r`.
- */
-CURLcode Curl_creader_set(struct Curl_easy *data, struct Curl_creader *r);
-
-/**
- * Read at most `blen` bytes at `buf` from the client.
- * @param data the transfer to read client bytes for
- * @param buf the memory location to read to
- * @param blen the amount of memory at `buf`
- * @param nread on return the number of bytes read into `buf`
- * @param eos TRUE iff bytes are the end of data from client
- * @return CURLE_OK on successful read (even 0 length) or error
- */
-CURLcode Curl_client_read(struct Curl_easy *data, char *buf, size_t blen,
- size_t *nread, bool *eos) WARN_UNUSED_RESULT;
-
-/**
- * TRUE iff client reader needs rewing before it can be used for
- * a retry request.
- */
-bool Curl_creader_needs_rewind(struct Curl_easy *data);
-
-/**
- * TRUE iff client reader will rewind at next start
- */
-bool Curl_creader_will_rewind(struct Curl_easy *data);
+/* internal write-function, does plain socket, SSL, SCP, SFTP and krb4 */
+CURLcode Curl_write(struct Curl_easy *data,
+ curl_socket_t sockfd,
+ const void *mem, size_t len,
+ ssize_t *written);
-/**
- * En-/disable rewind of client reader at next start.
- */
-void Curl_creader_set_rewind(struct Curl_easy *data, bool enable);
-
-/**
- * Get the total length of bytes provided by the installed readers.
- * This is independent of the amount already delivered and is calculated
- * by all readers in the stack. If a reader like "chunked" or
- * "crlf conversion" is installed, the returned length will be -1.
- * @return -1 if length is indeterminate
- */
-curl_off_t Curl_creader_total_length(struct Curl_easy *data);
-
-/**
- * Get the total length of bytes provided by the reader at phase
- * CURL_CR_CLIENT. This may not match the amount of bytes read
- * for a request, depending if other, encoding readers are also installed.
- * However it allows for rough estimation of the overall length.
- * @return -1 if length is indeterminate
- */
-curl_off_t Curl_creader_client_length(struct Curl_easy *data);
-
-/**
- * Ask the installed reader at phase CURL_CR_CLIENT to start
- * reading from the given offset. On success, this will reduce
- * the `total_length()` by the amount.
- * @param data the transfer to read client bytes for
- * @param offset the offset where to start reads from, negative
- * values will be ignored.
- * @return CURLE_OK if offset could be set
- * CURLE_READ_ERROR if not supported by reader or seek/read failed
- * of offset larger then total length
- * CURLE_PARTIAL_FILE if offset led to 0 total length
- */
-CURLcode Curl_creader_resume_from(struct Curl_easy *data, curl_off_t offset);
-
-/**
- * Unpause all installed readers.
- */
-CURLcode Curl_creader_unpause(struct Curl_easy *data);
-
-/**
- * Return TRUE iff any of the installed readers is paused.
- */
-bool Curl_creader_is_paused(struct Curl_easy *data);
-
-/**
- * Tell all client readers that they are done.
- */
-void Curl_creader_done(struct Curl_easy *data, int premature);
-
-/**
- * Look up an installed client reader on `data` by its type.
- * @return first reader with that type or NULL
- */
-struct Curl_creader *Curl_creader_get_by_type(struct Curl_easy *data,
- const struct Curl_crtype *crt);
-
-
-/**
- * Set the client reader to provide 0 bytes, immediate EOS.
- */
-CURLcode Curl_creader_set_null(struct Curl_easy *data);
-
-/**
- * Set the client reader the reads from fread callback.
- */
-CURLcode Curl_creader_set_fread(struct Curl_easy *data, curl_off_t len);
-
-/**
- * Set the client reader the reads from the supplied buf (NOT COPIED).
- */
-CURLcode Curl_creader_set_buf(struct Curl_easy *data,
- const char *buf, size_t blen);
+/* internal write-function, using sockindex for connection destination */
+CURLcode Curl_nwrite(struct Curl_easy *data,
+ int sockindex,
+ const void *buf,
+ size_t blen,
+ ssize_t *pnwritten);
#endif /* HEADER_CURL_SENDF_H */
diff --git a/contrib/libs/curl/lib/setopt.c b/contrib/libs/curl/lib/setopt.c
index 5b9a4cbae0..a08140cce8 100644
--- a/contrib/libs/curl/lib/setopt.c
+++ b/contrib/libs/curl/lib/setopt.c
@@ -51,8 +51,6 @@
#include "altsvc.h"
#include "hsts.h"
#include "tftp.h"
-#include "strdup.h"
-#include "escape.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@@ -111,75 +109,52 @@ CURLcode Curl_setblobopt(struct curl_blob **blobp,
static CURLcode setstropt_userpwd(char *option, char **userp, char **passwdp)
{
+ CURLcode result = CURLE_OK;
char *user = NULL;
char *passwd = NULL;
- DEBUGASSERT(userp);
- DEBUGASSERT(passwdp);
-
/* Parse the login details if specified. It not then we treat NULL as a hint
to clear the existing data */
if(option) {
size_t len = strlen(option);
- CURLcode result;
if(len > CURL_MAX_INPUT_LENGTH)
return CURLE_BAD_FUNCTION_ARGUMENT;
- result = Curl_parse_login_details(option, len, &user, &passwd, NULL);
- if(result)
- return result;
+ result = Curl_parse_login_details(option, len,
+ (userp ? &user : NULL),
+ (passwdp ? &passwd : NULL),
+ NULL);
}
- free(*userp);
- *userp = user;
-
- free(*passwdp);
- *passwdp = passwd;
-
- return CURLE_OK;
-}
-
-static CURLcode setstropt_interface(char *option, char **devp,
- char **ifacep, char **hostp)
-{
- char *dev = NULL;
- char *iface = NULL;
- char *host = NULL;
- CURLcode result;
+ if(!result) {
+ /* Store the username part of option if required */
+ if(userp) {
+ if(!user && option && option[0] == ':') {
+ /* Allocate an empty string instead of returning NULL as user name */
+ user = strdup("");
+ if(!user)
+ result = CURLE_OUT_OF_MEMORY;
+ }
- DEBUGASSERT(devp);
- DEBUGASSERT(ifacep);
- DEBUGASSERT(hostp);
+ Curl_safefree(*userp);
+ *userp = user;
+ }
- if(option) {
- /* Parse the interface details if set, otherwise clear them all */
- result = Curl_parse_interface(option, &dev, &iface, &host);
- if(result)
- return result;
+ /* Store the password part of option if required */
+ if(passwdp) {
+ Curl_safefree(*passwdp);
+ *passwdp = passwd;
+ }
}
- free(*devp);
- *devp = dev;
-
- free(*ifacep);
- *ifacep = iface;
- free(*hostp);
- *hostp = host;
-
- return CURLE_OK;
+ return result;
}
#define C_SSLVERSION_VALUE(x) (x & 0xffff)
-#define C_SSLVERSION_MAX_VALUE(x) ((unsigned long)x & 0xffff0000)
+#define C_SSLVERSION_MAX_VALUE(x) (x & 0xffff0000)
static CURLcode protocol2num(const char *str, curl_prot_t *val)
{
- /*
- * We are asked to cherry-pick protocols, so play it safe and disallow all
- * protocols to start with, and re-add the wanted ones back in.
- */
- *val = 0;
-
if(!str)
return CURLE_BAD_FUNCTION_ARGUMENT;
@@ -188,6 +163,8 @@ static CURLcode protocol2num(const char *str, curl_prot_t *val)
return CURLE_OK;
}
+ *val = 0;
+
do {
const char *token = str;
size_t tlen;
@@ -233,39 +210,27 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
data->set.dns_cache_timeout = (int)arg;
break;
case CURLOPT_CA_CACHE_TIMEOUT:
- if(Curl_ssl_supports(data, SSLSUPP_CA_CACHE)) {
- arg = va_arg(param, long);
- if(arg < -1)
- return CURLE_BAD_FUNCTION_ARGUMENT;
- else if(arg > INT_MAX)
- arg = INT_MAX;
+ arg = va_arg(param, long);
+ if(arg < -1)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ else if(arg > INT_MAX)
+ arg = INT_MAX;
- data->set.general_ssl.ca_cache_timeout = (int)arg;
- }
- else
- return CURLE_NOT_BUILT_IN;
+ data->set.general_ssl.ca_cache_timeout = (int)arg;
break;
case CURLOPT_DNS_USE_GLOBAL_CACHE:
/* deprecated */
break;
case CURLOPT_SSL_CIPHER_LIST:
- if(Curl_ssl_supports(data, SSLSUPP_CIPHER_LIST)) {
- /* set a list of cipher we want to use in the SSL connection */
- result = Curl_setstropt(&data->set.str[STRING_SSL_CIPHER_LIST],
- va_arg(param, char *));
- }
- else
- return CURLE_NOT_BUILT_IN;
+ /* set a list of cipher we want to use in the SSL connection */
+ result = Curl_setstropt(&data->set.str[STRING_SSL_CIPHER_LIST],
+ va_arg(param, char *));
break;
#ifndef CURL_DISABLE_PROXY
case CURLOPT_PROXY_SSL_CIPHER_LIST:
- if(Curl_ssl_supports(data, SSLSUPP_CIPHER_LIST)) {
- /* set a list of cipher we want to use in the SSL connection for proxy */
- result = Curl_setstropt(&data->set.str[STRING_SSL_CIPHER_LIST_PROXY],
- va_arg(param, char *));
- }
- else
- return CURLE_NOT_BUILT_IN;
+ /* set a list of cipher we want to use in the SSL connection for proxy */
+ result = Curl_setstropt(&data->set.str[STRING_SSL_CIPHER_LIST_PROXY],
+ va_arg(param, char *));
break;
#endif
case CURLOPT_TLS13_CIPHERS:
@@ -354,7 +319,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
break;
case CURLOPT_FAILONERROR:
/*
- * Do not output the >=400 error code HTML-page, but instead only
+ * Don't output the >=400 error code HTML-page, but instead only
* return error.
*/
data->set.http_fail_on_error = (0 != va_arg(param, long));
@@ -401,17 +366,6 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
else
return CURLE_BAD_FUNCTION_ARGUMENT;
break;
- case CURLOPT_SERVER_RESPONSE_TIMEOUT_MS:
- /*
- * Option that specifies how quickly a server response must be obtained
- * before it is considered failure. For pingpong protocols.
- */
- arg = va_arg(param, long);
- if((arg >= 0) && (arg <= INT_MAX))
- data->set.server_response_timeout = (unsigned int)arg;
- else
- return CURLE_BAD_FUNCTION_ARGUMENT;
- break;
#ifndef CURL_DISABLE_TFTP
case CURLOPT_TFTP_NO_OPTIONS:
/*
@@ -425,10 +379,8 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
* TFTP option that specifies the block size to use for data transmission.
*/
arg = va_arg(param, long);
- if(arg < TFTP_BLKSIZE_MIN)
- arg = 512;
- else if(arg > TFTP_BLKSIZE_MAX)
- arg = TFTP_BLKSIZE_MAX;
+ if(arg > TFTP_BLKSIZE_MAX || arg < TFTP_BLKSIZE_MIN)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
data->set.tftp_blksize = arg;
break;
#endif
@@ -505,7 +457,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
arg = va_arg(param, long);
version = C_SSLVERSION_VALUE(arg);
- version_max = (long)C_SSLVERSION_MAX_VALUE(arg);
+ version_max = C_SSLVERSION_MAX_VALUE(arg);
if(version < CURL_SSLVERSION_DEFAULT ||
version == CURL_SSLVERSION_SSLv2 ||
@@ -545,16 +497,24 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
(data->set.postfieldsize > (curl_off_t)((size_t)-1))))
result = CURLE_OUT_OF_MEMORY;
else {
+ char *p;
+
+ (void) Curl_setstropt(&data->set.str[STRING_COPYPOSTFIELDS], NULL);
+
/* Allocate even when size == 0. This satisfies the need of possible
- later address compare to detect the COPYPOSTFIELDS mode, and to
- mark that postfields is used rather than read function or form
- data.
+ later address compare to detect the COPYPOSTFIELDS mode, and
+ to mark that postfields is used rather than read function or
+ form data.
*/
- char *p = Curl_memdup0(argptr, (size_t)data->set.postfieldsize);
+ p = malloc((size_t)(data->set.postfieldsize?
+ data->set.postfieldsize:1));
+
if(!p)
result = CURLE_OUT_OF_MEMORY;
else {
- free(data->set.str[STRING_COPYPOSTFIELDS]);
+ if(data->set.postfieldsize)
+ memcpy(p, argptr, (size_t)data->set.postfieldsize);
+
data->set.str[STRING_COPYPOSTFIELDS] = p;
}
}
@@ -570,7 +530,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
*/
data->set.postfields = va_arg(param, void *);
/* Release old copied data. */
- Curl_safefree(data->set.str[STRING_COPYPOSTFIELDS]);
+ (void) Curl_setstropt(&data->set.str[STRING_COPYPOSTFIELDS], NULL);
data->set.method = HTTPREQ_POST;
break;
@@ -586,7 +546,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
if(data->set.postfieldsize < bigsize &&
data->set.postfields == data->set.str[STRING_COPYPOSTFIELDS]) {
/* Previous CURLOPT_COPYPOSTFIELDS is no longer valid. */
- Curl_safefree(data->set.str[STRING_COPYPOSTFIELDS]);
+ (void) Curl_setstropt(&data->set.str[STRING_COPYPOSTFIELDS], NULL);
data->set.postfields = NULL;
}
@@ -605,7 +565,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
if(data->set.postfieldsize < bigsize &&
data->set.postfields == data->set.str[STRING_COPYPOSTFIELDS]) {
/* Previous CURLOPT_COPYPOSTFIELDS is no longer valid. */
- Curl_safefree(data->set.str[STRING_COPYPOSTFIELDS]);
+ (void) Curl_setstropt(&data->set.str[STRING_COPYPOSTFIELDS], NULL);
data->set.postfields = NULL;
}
@@ -626,7 +586,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
*
* If the encoding is set to "" we use an Accept-Encoding header that
* encompasses all the encodings we support.
- * If the encoding is set to NULL we do not send an Accept-Encoding header
+ * If the encoding is set to NULL we don't send an Accept-Encoding header
* and ignore an received Content-Encoding header.
*
*/
@@ -690,7 +650,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
case CURLOPT_POST:
/* Does this option serve a purpose anymore? Yes it does, when
- CURLOPT_POSTFIELDS is not used and the POST data is read off the
+ CURLOPT_POSTFIELDS isn't used and the POST data is read off the
callback! */
if(va_arg(param, long)) {
data->set.method = HTTPREQ_POST;
@@ -710,7 +670,6 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
data->set.opt_no_body = FALSE; /* this is implied */
Curl_mime_cleanpart(data->state.formp);
Curl_safefree(data->state.formp);
- data->state.mimepost = NULL;
break;
#endif
@@ -793,7 +752,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
/* general protection against mistakes and abuse */
if(strlen(argptr) > CURL_MAX_INPUT_LENGTH)
return CURLE_BAD_FUNCTION_ARGUMENT;
- /* append the cookie filename to the list of filenames, and deal with
+ /* append the cookie file name to the list of file names, and deal with
them later */
cl = curl_slist_append(data->state.cookielist, argptr);
if(!cl) {
@@ -809,7 +768,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
data->state.cookielist = NULL;
if(!data->share || !data->share->cookies) {
- /* throw away all existing cookies if this is not a shared cookie
+ /* throw away all existing cookies if this isn't a shared cookie
container */
Curl_cookie_clearall(data->cookies);
Curl_cookie_cleanup(data->cookies);
@@ -821,22 +780,24 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
case CURLOPT_COOKIEJAR:
/*
- * Set cookie filename to dump all cookies to when we are done.
+ * Set cookie file name to dump all cookies to when we're done.
*/
+ {
+ struct CookieInfo *newcookies;
result = Curl_setstropt(&data->set.str[STRING_COOKIEJAR],
va_arg(param, char *));
- if(!result) {
- /*
- * Activate the cookie parser. This may or may not already
- * have been made.
- */
- struct CookieInfo *newcookies =
- Curl_cookie_init(data, NULL, data->cookies, data->set.cookiesession);
- if(!newcookies)
- result = CURLE_OUT_OF_MEMORY;
- data->cookies = newcookies;
- }
- break;
+
+ /*
+ * Activate the cookie parser. This may or may not already
+ * have been made.
+ */
+ newcookies = Curl_cookie_init(data, NULL, data->cookies,
+ data->set.cookiesession);
+ if(!newcookies)
+ result = CURLE_OUT_OF_MEMORY;
+ data->cookies = newcookies;
+ }
+ break;
case CURLOPT_COOKIESESSION:
/*
@@ -945,7 +906,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
/* accepted */
break;
#endif
-#ifdef USE_HTTP3
+#ifdef ENABLE_QUIC
case CURL_HTTP_VERSION_3:
case CURL_HTTP_VERSION_3ONLY:
/* accepted */
@@ -972,7 +933,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
break;
case CURLOPT_HTTP09_ALLOWED:
- arg = (long)va_arg(param, unsigned long);
+ arg = va_arg(param, unsigned long);
if(arg > 1L)
return CURLE_BAD_FUNCTION_ARGUMENT;
#ifdef USE_HYPER
@@ -1016,7 +977,6 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
#ifndef CURL_DISABLE_FORM_API
Curl_mime_cleanpart(data->state.formp);
Curl_safefree(data->state.formp);
- data->state.mimepost = NULL;
#endif
}
break;
@@ -1051,9 +1011,12 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
auth &= ~CURLAUTH_DIGEST_IE; /* unset ie digest bit */
}
- /* switch off bits we cannot support */
+ /* switch off bits we can't support */
#ifndef USE_NTLM
auth &= ~CURLAUTH_NTLM; /* no NTLM support */
+ auth &= ~CURLAUTH_NTLM_WB; /* no NTLM_WB support */
+#elif !defined(NTLM_WB_ENABLED)
+ auth &= ~CURLAUTH_NTLM_WB; /* no NTLM_WB support */
#endif
#ifndef USE_SPNEGO
auth &= ~CURLAUTH_NEGOTIATE; /* no Negotiate (SPNEGO) auth without
@@ -1083,7 +1046,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
result = Curl_setstropt(&data->set.str[STRING_CUSTOMREQUEST],
va_arg(param, char *));
- /* we do not set
+ /* we don't set
data->set.method = HTTPREQ_CUSTOM;
here, we continue as if we were using the already set type
and this just changes the actual request keyword */
@@ -1129,9 +1092,12 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
auth |= CURLAUTH_DIGEST; /* set standard digest bit */
auth &= ~CURLAUTH_DIGEST_IE; /* unset ie digest bit */
}
- /* switch off bits we cannot support */
+ /* switch off bits we can't support */
#ifndef USE_NTLM
auth &= ~CURLAUTH_NTLM; /* no NTLM support */
+ auth &= ~CURLAUTH_NTLM_WB; /* no NTLM_WB support */
+#elif !defined(NTLM_WB_ENABLED)
+ auth &= ~CURLAUTH_NTLM_WB; /* no NTLM_WB support */
#endif
#ifndef USE_SPNEGO
auth &= ~CURLAUTH_NEGOTIATE; /* no Negotiate (SPNEGO) auth without
@@ -1159,7 +1125,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
* Set proxy server:port to use as proxy.
*
* If the proxy is set to "" (and CURLOPT_SOCKS_PROXY is set to "" or NULL)
- * we explicitly say that we do not want to use a proxy
+ * we explicitly say that we don't want to use a proxy
* (even though there might be environment variables saying so).
*
* Setting it to NULL, means no proxy but allows the environment variables
@@ -1173,7 +1139,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
/*
* Set proxy server:port to use as SOCKS proxy.
*
- * If the proxy is set to "" or NULL we explicitly say that we do not want
+ * If the proxy is set to "" or NULL we explicitly say that we don't want
* to use the socks proxy.
*/
result = Curl_setstropt(&data->set.str[STRING_PRE_PROXY],
@@ -1344,7 +1310,6 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
return CURLE_BAD_FUNCTION_ARGUMENT;
data->set.ftpsslauth = (unsigned char)(curl_ftpauth)arg;
break;
-#ifdef HAVE_GSSAPI
case CURLOPT_KRBLEVEL:
/*
* A string that defines the kerberos security level.
@@ -1354,7 +1319,6 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
data->set.krb = !!(data->set.str[STRING_KRB_LEVEL]);
break;
#endif
-#endif
#if !defined(CURL_DISABLE_FTP) || defined(USE_SSH)
case CURLOPT_FTP_CREATE_MISSING_DIRS:
/*
@@ -1544,7 +1508,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
case CURLOPT_USERNAME:
/*
- * authentication username to use in the operation
+ * authentication user name to use in the operation
*/
result = Curl_setstropt(&data->set.str[STRING_USERNAME],
va_arg(param, char *));
@@ -1585,7 +1549,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
* Prefix the HOST with dash (-) to _remove_ the entry from the cache.
*
* This API can remove any entry from the DNS cache, but only entries
- * that are not actually in use right now will be pruned immediately.
+ * that aren't actually in use right now will be pruned immediately.
*/
data->set.resolve = va_arg(param, struct curl_slist *);
data->state.resolve = data->set.resolve;
@@ -1621,28 +1585,17 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
break;
#ifndef CURL_DISABLE_PROXY
- case CURLOPT_PROXYUSERPWD: {
+ case CURLOPT_PROXYUSERPWD:
/*
* user:password needed to use the proxy
*/
- char *u = NULL;
- char *p = NULL;
- result = setstropt_userpwd(va_arg(param, char *), &u, &p);
-
- /* URL decode the components */
- if(!result && u)
- result = Curl_urldecode(u, 0, &data->set.str[STRING_PROXYUSERNAME], NULL,
- REJECT_ZERO);
- if(!result && p)
- result = Curl_urldecode(p, 0, &data->set.str[STRING_PROXYPASSWORD], NULL,
- REJECT_ZERO);
- free(u);
- free(p);
- }
+ result = setstropt_userpwd(va_arg(param, char *),
+ &data->set.str[STRING_PROXYUSERNAME],
+ &data->set.str[STRING_PROXYPASSWORD]);
break;
case CURLOPT_PROXYUSERNAME:
/*
- * authentication username to use in the operation
+ * authentication user name to use in the operation
*/
result = Curl_setstropt(&data->set.str[STRING_PROXYUSERNAME],
va_arg(param, char *));
@@ -1694,7 +1647,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
*/
data->set.fdebug = va_arg(param, curl_debug_callback);
/*
- * if the callback provided is NULL, it will use the default callback
+ * if the callback provided is NULL, it'll use the default callback
*/
break;
case CURLOPT_DEBUGDATA:
@@ -1767,7 +1720,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
break;
case CURLOPT_SSLCERT:
/*
- * String that holds filename of the SSL certificate to use
+ * String that holds file name of the SSL certificate to use
*/
result = Curl_setstropt(&data->set.str[STRING_CERT],
va_arg(param, char *));
@@ -1782,7 +1735,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
#ifndef CURL_DISABLE_PROXY
case CURLOPT_PROXY_SSLCERT:
/*
- * String that holds filename of the SSL certificate to use for proxy
+ * String that holds file name of the SSL certificate to use for proxy
*/
result = Curl_setstropt(&data->set.str[STRING_CERT_PROXY],
va_arg(param, char *));
@@ -1813,7 +1766,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
#endif
case CURLOPT_SSLKEY:
/*
- * String that holds filename of the SSL key to use
+ * String that holds file name of the SSL key to use
*/
result = Curl_setstropt(&data->set.str[STRING_KEY],
va_arg(param, char *));
@@ -1828,7 +1781,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
#ifndef CURL_DISABLE_PROXY
case CURLOPT_PROXY_SSLKEY:
/*
- * String that holds filename of the SSL key to use for proxy
+ * String that holds file name of the SSL key to use for proxy
*/
result = Curl_setstropt(&data->set.str[STRING_KEY_PROXY],
va_arg(param, char *));
@@ -1890,7 +1843,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
/*
* flag to set engine as default.
*/
- Curl_safefree(data->set.str[STRING_SSL_ENGINE]);
+ Curl_setstropt(&data->set.str[STRING_SSL_ENGINE], NULL);
result = Curl_ssl_set_engine_default(data);
break;
case CURLOPT_CRLF:
@@ -1921,10 +1874,8 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
* Set what interface or address/hostname to bind the socket to when
* performing an operation and thus what from-IP your connection will use.
*/
- result = setstropt_interface(va_arg(param, char *),
- &data->set.str[STRING_DEVICE],
- &data->set.str[STRING_INTERFACE],
- &data->set.str[STRING_BINDHOST]);
+ result = Curl_setstropt(&data->set.str[STRING_DEVICE],
+ va_arg(param, char *));
break;
#ifndef CURL_DISABLE_BINDLOCAL
case CURLOPT_LOCALPORT:
@@ -1977,7 +1928,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
* Enable peer SSL verifying for proxy.
*/
data->set.proxy_ssl.primary.verifypeer =
- (0 != va_arg(param, long));
+ (0 != va_arg(param, long))?TRUE:FALSE;
/* Update the current connection proxy_ssl_config. */
Curl_ssl_conn_config_update(data, TRUE);
@@ -1985,12 +1936,12 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
#endif
case CURLOPT_SSL_VERIFYHOST:
/*
- * Enable verification of the hostname in the peer certificate
+ * Enable verification of the host name in the peer certificate
*/
arg = va_arg(param, long);
/* Obviously people are not reading documentation and too many thought
- this argument took a boolean when it was not and misused it.
+ this argument took a boolean when it wasn't and misused it.
Treat 1 and 2 the same */
data->set.ssl.primary.verifyhost = !!(arg & 3);
@@ -2000,7 +1951,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
#ifndef CURL_DISABLE_DOH
case CURLOPT_DOH_SSL_VERIFYHOST:
/*
- * Enable verification of the hostname in the peer certificate for DoH
+ * Enable verification of the host name in the peer certificate for DoH
*/
arg = va_arg(param, long);
@@ -2011,12 +1962,12 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
#ifndef CURL_DISABLE_PROXY
case CURLOPT_PROXY_SSL_VERIFYHOST:
/*
- * Enable verification of the hostname in the peer certificate for proxy
+ * Enable verification of the host name in the peer certificate for proxy
*/
arg = va_arg(param, long);
/* Treat both 1 and 2 as TRUE */
- data->set.proxy_ssl.primary.verifyhost = !!(arg & 3);
+ data->set.proxy_ssl.primary.verifyhost = (bool)((arg & 3)?TRUE:FALSE);
/* Update the current connection proxy_ssl_config. */
Curl_ssl_conn_config_update(data, TRUE);
break;
@@ -2092,7 +2043,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
case CURLOPT_PINNEDPUBLICKEY:
/*
* Set pinned public key for SSL connection.
- * Specify filename of the public key in DER format.
+ * Specify file name of the public key in DER format.
*/
#ifdef USE_SSL
if(Curl_ssl_supports(data, SSLSUPP_PINNEDPUBKEY))
@@ -2106,7 +2057,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
case CURLOPT_PROXY_PINNEDPUBLICKEY:
/*
* Set pinned public key for SSL connection.
- * Specify filename of the public key in DER format.
+ * Specify file name of the public key in DER format.
*/
#ifdef USE_SSL
if(Curl_ssl_supports(data, SSLSUPP_PINNEDPUBKEY))
@@ -2119,7 +2070,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
#endif
case CURLOPT_CAINFO:
/*
- * Set CA info for SSL connection. Specify filename of the CA certificate
+ * Set CA info for SSL connection. Specify file name of the CA certificate
*/
result = Curl_setstropt(&data->set.str[STRING_SSL_CAFILE],
va_arg(param, char *));
@@ -2141,7 +2092,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
#ifndef CURL_DISABLE_PROXY
case CURLOPT_PROXY_CAINFO:
/*
- * Set CA info SSL connection for proxy. Specify filename of the
+ * Set CA info SSL connection for proxy. Specify file name of the
* CA certificate
*/
result = Curl_setstropt(&data->set.str[STRING_SSL_CAFILE_PROXY],
@@ -2169,7 +2120,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
*/
#ifdef USE_SSL
if(Curl_ssl_supports(data, SSLSUPP_CA_PATH))
- /* This does not work on Windows. */
+ /* This does not work on windows. */
result = Curl_setstropt(&data->set.str[STRING_SSL_CAPATH],
va_arg(param, char *));
else
@@ -2184,7 +2135,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
*/
#ifdef USE_SSL
if(Curl_ssl_supports(data, SSLSUPP_CA_PATH))
- /* This does not work on Windows. */
+ /* This does not work on windows. */
result = Curl_setstropt(&data->set.str[STRING_SSL_CAPATH_PROXY],
va_arg(param, char *));
else
@@ -2194,7 +2145,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
#endif
case CURLOPT_CRLFILE:
/*
- * Set CRL file info for SSL connection. Specify filename of the CRL
+ * Set CRL file info for SSL connection. Specify file name of the CRL
* to check certificates revocation
*/
result = Curl_setstropt(&data->set.str[STRING_SSL_CRLFILE],
@@ -2203,7 +2154,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
#ifndef CURL_DISABLE_PROXY
case CURLOPT_PROXY_CRLFILE:
/*
- * Set CRL file info for SSL connection for proxy. Specify filename of the
+ * Set CRL file info for SSL connection for proxy. Specify file name of the
* CRL to check certificates revocation
*/
result = Curl_setstropt(&data->set.str[STRING_SSL_CRLFILE_PROXY],
@@ -2253,8 +2204,11 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
case CURLOPT_BUFFERSIZE:
/*
* The application kindly asks for a differently sized receive buffer.
- * If it seems reasonable, we will use it.
+ * If it seems reasonable, we'll use it.
*/
+ if(data->state.buffer)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+
arg = va_arg(param, long);
if(arg > READBUFFER_MAX)
@@ -2280,6 +2234,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
arg = UPLOADBUFFER_MIN;
data->set.upload_buffer_size = (unsigned int)arg;
+ Curl_safefree(data->state.ulbuf); /* force a realloc next opportunity */
break;
case CURLOPT_NOSIGNAL:
@@ -2356,7 +2311,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
Curl_hsts_cleanup(&data->hsts);
data->hsts = data->share->hsts;
}
-#endif
+#endif /* CURL_DISABLE_HTTP */
#ifdef USE_SSL
if(data->share->sslsession) {
data->set.general_ssl.max_ssl_sessions = data->share->max_ssl_sessions;
@@ -2541,17 +2496,16 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
break;
case CURLOPT_SSL_SESSIONID_CACHE:
- data->set.ssl.primary.cache_session = (0 != va_arg(param, long));
+ data->set.ssl.primary.sessionid = (0 != va_arg(param, long));
#ifndef CURL_DISABLE_PROXY
- data->set.proxy_ssl.primary.cache_session =
- data->set.ssl.primary.cache_session;
+ data->set.proxy_ssl.primary.sessionid = data->set.ssl.primary.sessionid;
#endif
break;
#ifdef USE_SSH
/* we only include SSH options if explicitly built to support SSH */
case CURLOPT_SSH_AUTH_TYPES:
- data->set.ssh_auth_types = (int)va_arg(param, long);
+ data->set.ssh_auth_types = (unsigned int)va_arg(param, long);
break;
case CURLOPT_SSH_PUBLIC_KEYFILE:
@@ -2580,7 +2534,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
case CURLOPT_SSH_KNOWNHOSTS:
/*
- * Store the filename to read known hosts from.
+ * Store the file name to read known hosts from.
*/
result = Curl_setstropt(&data->set.str[STRING_SSH_KNOWNHOSTS],
va_arg(param, char *));
@@ -2622,7 +2576,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
break;
case CURLOPT_SSH_COMPRESSION:
- data->set.ssh_compression = (0 != va_arg(param, long));
+ data->set.ssh_compression = (0 != va_arg(param, long))?TRUE:FALSE;
break;
#endif /* USE_SSH */
@@ -2634,7 +2588,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
data->set.http_te_skip = (0 == va_arg(param, long));
break;
#else
- return CURLE_NOT_BUILT_IN; /* hyper does not support */
+ return CURLE_NOT_BUILT_IN; /* hyper doesn't support */
#endif
case CURLOPT_HTTP_CONTENT_DECODING:
@@ -2667,12 +2621,12 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
break;
#endif
-#ifdef USE_IPV6
+#ifdef ENABLE_IPV6
case CURLOPT_ADDRESS_SCOPE:
/*
* Use this scope id when using IPv6
* We always get longs when passed plain numericals so we should check
- * that the value fits into an unsigned 32-bit integer.
+ * that the value fits into an unsigned 32 bit integer.
*/
uarg = va_arg(param, unsigned long);
#if SIZEOF_LONG > 4
@@ -2699,33 +2653,27 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
break;
case CURLOPT_PROTOCOLS_STR: {
+ curl_prot_t prot;
argptr = va_arg(param, char *);
- if(argptr) {
- result = protocol2num(argptr, &data->set.allowed_protocols);
- if(result)
- return result;
- }
- else
- /* make a NULL argument reset to default */
- data->set.allowed_protocols = (curl_prot_t) CURLPROTO_ALL;
+ result = protocol2num(argptr, &prot);
+ if(result)
+ return result;
+ data->set.allowed_protocols = prot;
break;
}
case CURLOPT_REDIR_PROTOCOLS_STR: {
+ curl_prot_t prot;
argptr = va_arg(param, char *);
- if(argptr) {
- result = protocol2num(argptr, &data->set.redir_protocols);
- if(result)
- return result;
- }
- else
- /* make a NULL argument reset to default */
- data->set.redir_protocols = (curl_prot_t) CURLPROTO_REDIR;
+ result = protocol2num(argptr, &prot);
+ if(result)
+ return result;
+ data->set.redir_protocols = prot;
break;
}
case CURLOPT_DEFAULT_PROTOCOL:
- /* Set the protocol to use when the URL does not include any protocol */
+ /* Set the protocol to use when the URL doesn't include any protocol */
result = Curl_setstropt(&data->set.str[STRING_DEFAULT_PROTOCOL],
va_arg(param, char *));
break;
@@ -2915,13 +2863,13 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
#endif
case CURLOPT_TLSAUTH_TYPE:
argptr = va_arg(param, char *);
- if(argptr && !strcasecompare(argptr, "SRP"))
+ if(argptr && !strncasecompare(argptr, "SRP", strlen("SRP")))
return CURLE_BAD_FUNCTION_ARGUMENT;
break;
#ifndef CURL_DISABLE_PROXY
case CURLOPT_PROXY_TLSAUTH_TYPE:
argptr = va_arg(param, char *);
- if(argptr && !strcasecompare(argptr, "SRP"))
+ if(argptr || !strncasecompare(argptr, "SRP", strlen("SRP")))
return CURLE_BAD_FUNCTION_ARGUMENT;
break;
#endif
@@ -2975,18 +2923,10 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
arg = INT_MAX;
data->set.tcp_keepintvl = (int)arg;
break;
- case CURLOPT_TCP_KEEPCNT:
- arg = va_arg(param, long);
- if(arg < 0)
- return CURLE_BAD_FUNCTION_ARGUMENT;
- else if(arg > INT_MAX)
- arg = INT_MAX;
- data->set.tcp_keepcnt = (int)arg;
- break;
case CURLOPT_TCP_FASTOPEN:
#if defined(CONNECT_DATA_IDEMPOTENT) || defined(MSG_FASTOPEN) || \
defined(TCP_FASTOPEN_CONNECT)
- data->set.tcp_fastopen = (0 != va_arg(param, long));
+ data->set.tcp_fastopen = (0 != va_arg(param, long))?TRUE:FALSE;
#else
result = CURLE_NOT_BUILT_IN;
#endif
@@ -3038,7 +2978,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
data->set.connect_to = va_arg(param, struct curl_slist *);
break;
case CURLOPT_SUPPRESS_CONNECT_HEADERS:
- data->set.suppress_connect_headers = (0 != va_arg(param, long));
+ data->set.suppress_connect_headers = (0 != va_arg(param, long))?TRUE:FALSE;
break;
case CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS:
uarg = va_arg(param, unsigned long);
@@ -3058,7 +2998,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
case CURLOPT_DOH_URL:
result = Curl_setstropt(&data->set.str[STRING_DOH],
va_arg(param, char *));
- data->set.doh = !!(data->set.str[STRING_DOH]);
+ data->set.doh = data->set.str[STRING_DOH]?TRUE:FALSE;
break;
#endif
case CURLOPT_UPKEEP_INTERVAL_MS:
@@ -3114,7 +3054,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
result = Curl_setstropt(&data->set.str[STRING_HSTS], argptr);
if(result)
return result;
- /* this needs to build a list of filenames to read from, so that it can
+ /* this needs to build a list of file names to read from, so that it can
read them later, as we might get a shared HSTS handle to load them
into */
h = curl_slist_append(data->state.hstslist, argptr);
@@ -3169,10 +3109,6 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
return CURLE_OUT_OF_MEMORY;
}
arg = va_arg(param, long);
- if(!arg) {
- DEBUGF(infof(data, "bad CURLOPT_ALTSVC_CTRL input"));
- return CURLE_BAD_FUNCTION_ARGUMENT;
- }
result = Curl_altsvc_ctrl(data->asi, arg);
if(result)
return result;
@@ -3193,48 +3129,6 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
break;
}
#endif
-#ifdef USE_ECH
- case CURLOPT_ECH: {
- size_t plen = 0;
-
- argptr = va_arg(param, char *);
- if(!argptr) {
- data->set.tls_ech = CURLECH_DISABLE;
- return CURLE_OK;
- }
- plen = strlen(argptr);
- if(plen > CURL_MAX_INPUT_LENGTH) {
- data->set.tls_ech = CURLECH_DISABLE;
- result = CURLE_BAD_FUNCTION_ARGUMENT;
- return result;
- }
- /* set tls_ech flag value, preserving CLA_CFG bit */
- if(plen == 5 && !strcmp(argptr, "false"))
- data->set.tls_ech = CURLECH_DISABLE
- | (data->set.tls_ech & CURLECH_CLA_CFG);
- else if(plen == 6 && !strcmp(argptr, "grease"))
- data->set.tls_ech = CURLECH_GREASE
- | (data->set.tls_ech & CURLECH_CLA_CFG);
- else if(plen == 4 && !strcmp(argptr, "true"))
- data->set.tls_ech = CURLECH_ENABLE
- | (data->set.tls_ech & CURLECH_CLA_CFG);
- else if(plen == 4 && !strcmp(argptr, "hard"))
- data->set.tls_ech = CURLECH_HARD
- | (data->set.tls_ech & CURLECH_CLA_CFG);
- else if(plen > 5 && !strncmp(argptr, "ecl:", 4)) {
- result = Curl_setstropt(&data->set.str[STRING_ECH_CONFIG], argptr + 4);
- if(result)
- return result;
- data->set.tls_ech |= CURLECH_CLA_CFG;
- }
- else if(plen > 4 && !strncmp(argptr, "pn:", 3)) {
- result = Curl_setstropt(&data->set.str[STRING_ECH_PUBLIC], argptr + 3);
- if(result)
- return result;
- }
- break;
- }
-#endif
case CURLOPT_QUICK_EXIT:
data->set.quick_exit = (0 != va_arg(param, long)) ? 1L:0L;
break;
@@ -3269,9 +3163,5 @@ CURLcode curl_easy_setopt(struct Curl_easy *data, CURLoption tag, ...)
result = Curl_vsetopt(data, tag, arg);
va_end(arg);
-#ifdef DEBUGBUILD
- if(result == CURLE_BAD_FUNCTION_ARGUMENT)
- infof(data, "setopt arg 0x%x returned CURLE_BAD_FUNCTION_ARGUMENT", tag);
-#endif
return result;
}
diff --git a/contrib/libs/curl/lib/setopt.h b/contrib/libs/curl/lib/setopt.h
index b0237467bd..3c14a05e37 100644
--- a/contrib/libs/curl/lib/setopt.h
+++ b/contrib/libs/curl/lib/setopt.h
@@ -24,10 +24,9 @@
*
***************************************************************************/
-CURLcode Curl_setstropt(char **charp, const char *s) WARN_UNUSED_RESULT;
+CURLcode Curl_setstropt(char **charp, const char *s);
CURLcode Curl_setblobopt(struct curl_blob **blobp,
- const struct curl_blob *blob) WARN_UNUSED_RESULT;
-CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list arg)
- WARN_UNUSED_RESULT;
+ const struct curl_blob *blob);
+CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list arg);
#endif /* HEADER_CURL_SETOPT_H */
diff --git a/contrib/libs/curl/lib/setup-win32.h b/contrib/libs/curl/lib/setup-win32.h
index a297bdcff4..4e034d4bb2 100644
--- a/contrib/libs/curl/lib/setup-win32.h
+++ b/contrib/libs/curl/lib/setup-win32.h
@@ -24,53 +24,18 @@
*
***************************************************************************/
-#undef USE_WINSOCK
-/* ---------------------------------------------------------------- */
-/* Watt-32 TCP/IP SPECIFIC */
-/* ---------------------------------------------------------------- */
-#ifdef USE_WATT32
-# include <tcp.h>
-# undef byte
-# undef word
-# define HAVE_SYS_IOCTL_H
-# define HAVE_SYS_SOCKET_H
-# define HAVE_NETINET_IN_H
-# define HAVE_NETDB_H
-# define HAVE_ARPA_INET_H
-# define SOCKET int
-/* ---------------------------------------------------------------- */
-/* BSD-style lwIP TCP/IP stack SPECIFIC */
-/* ---------------------------------------------------------------- */
-#elif defined(USE_LWIPSOCK)
- /* Define to use BSD-style lwIP TCP/IP stack. */
- /* #define USE_LWIPSOCK 1 */
-# undef HAVE_GETHOSTNAME
-# undef LWIP_POSIX_SOCKETS_IO_NAMES
-# undef RECV_TYPE_ARG1
-# undef RECV_TYPE_ARG3
-# undef SEND_TYPE_ARG1
-# undef SEND_TYPE_ARG3
-# define HAVE_GETHOSTBYNAME_R
-# define HAVE_GETHOSTBYNAME_R_6
-# define LWIP_POSIX_SOCKETS_IO_NAMES 0
-# define RECV_TYPE_ARG1 int
-# define RECV_TYPE_ARG3 size_t
-# define SEND_TYPE_ARG1 int
-# define SEND_TYPE_ARG3 size_t
-#elif defined(_WIN32)
-# define USE_WINSOCK 2
-#endif
-
/*
- * Include header files for Windows builds before redefining anything.
+ * Include header files for windows builds before redefining anything.
* Use this preprocessor block only to include or exclude windows.h,
- * winsock2.h or ws2tcpip.h. Any other Windows thing belongs
- * to any other further and independent block. Under Cygwin things work
- * just as under Linux (e.g. <sys/socket.h>) and the Winsock headers should
- * never be included when __CYGWIN__ is defined.
+ * winsock2.h or ws2tcpip.h. Any other windows thing belongs
+ * to any other further and independent block. Under Cygwin things work
+ * just as under linux (e.g. <sys/socket.h>) and the winsock headers should
+ * never be included when __CYGWIN__ is defined. configure script takes
+ * care of this, not defining HAVE_WINDOWS_H, HAVE_WINSOCK2_H,
+ * neither HAVE_WS2TCPIP_H when __CYGWIN__ is defined.
*/
-#ifdef _WIN32
+#ifdef HAVE_WINDOWS_H
# if defined(UNICODE) && !defined(_UNICODE)
# error "UNICODE is defined but _UNICODE is not defined"
# endif
@@ -78,7 +43,7 @@
# error "_UNICODE is defined but UNICODE is not defined"
# endif
/*
- * Do not include unneeded stuff in Windows headers to avoid compiler
+ * Don't include unneeded stuff in Windows headers to avoid compiler
* warnings and macro clashes.
* Make sure to define this macro before including any Windows headers.
*/
@@ -88,8 +53,12 @@
# ifndef NOGDI
# define NOGDI
# endif
-# include <winsock2.h>
-# include <ws2tcpip.h>
+# ifdef HAVE_WINSOCK2_H
+# include <winsock2.h>
+# ifdef HAVE_WS2TCPIP_H
+# include <ws2tcpip.h>
+# endif
+# endif
# include <windows.h>
# include <winerror.h>
# include <tchar.h>
@@ -99,6 +68,17 @@
#endif
/*
+ * Define USE_WINSOCK to 2 if we have and use WINSOCK2 API, else
+ * undefine USE_WINSOCK.
+ */
+
+#undef USE_WINSOCK
+
+#ifdef HAVE_WINSOCK2_H
+# define USE_WINSOCK 2
+#endif
+
+/*
* Define _WIN32_WINNT_[OS] symbols because not all Windows build systems have
* those symbols to compare against, and even those that do may be missing
* newer symbols.
diff --git a/contrib/libs/curl/lib/sha256.c b/contrib/libs/curl/lib/sha256.c
index 22229b968f..7b18f29a11 100644
--- a/contrib/libs/curl/lib/sha256.c
+++ b/contrib/libs/curl/lib/sha256.c
@@ -100,10 +100,10 @@
#if defined(USE_OPENSSL_SHA256)
-struct ossl_sha256_ctx {
+struct sha256_ctx {
EVP_MD_CTX *openssl_ctx;
};
-typedef struct ossl_sha256_ctx my_sha256_ctx;
+typedef struct sha256_ctx my_sha256_ctx;
static CURLcode my_sha256_init(my_sha256_ctx *ctx)
{
@@ -247,7 +247,7 @@ static void my_sha256_final(unsigned char *digest, my_sha256_ctx *ctx)
unsigned long length = 0;
CryptGetHashParam(ctx->hHash, HP_HASHVAL, NULL, &length, 0);
- if(length == CURL_SHA256_DIGEST_LENGTH)
+ if(length == SHA256_DIGEST_LENGTH)
CryptGetHashParam(ctx->hHash, HP_HASHVAL, digest, &length, 0);
if(ctx->hHash)
@@ -334,14 +334,14 @@ static const unsigned long K[64] = {
#define RORc(x, y) \
(((((unsigned long)(x) & 0xFFFFFFFFUL) >> (unsigned long)((y) & 31)) | \
((unsigned long)(x) << (unsigned long)(32 - ((y) & 31)))) & 0xFFFFFFFFUL)
-#define Sha256_Ch(x,y,z) (z ^ (x & (y ^ z)))
-#define Sha256_Maj(x,y,z) (((x | y) & z) | (x & y))
-#define Sha256_S(x, n) RORc((x), (n))
-#define Sha256_R(x, n) (((x)&0xFFFFFFFFUL)>>(n))
-#define Sigma0(x) (Sha256_S(x, 2) ^ Sha256_S(x, 13) ^ Sha256_S(x, 22))
-#define Sigma1(x) (Sha256_S(x, 6) ^ Sha256_S(x, 11) ^ Sha256_S(x, 25))
-#define Gamma0(x) (Sha256_S(x, 7) ^ Sha256_S(x, 18) ^ Sha256_R(x, 3))
-#define Gamma1(x) (Sha256_S(x, 17) ^ Sha256_S(x, 19) ^ Sha256_R(x, 10))
+#define Ch(x,y,z) (z ^ (x & (y ^ z)))
+#define Maj(x,y,z) (((x | y) & z) | (x & y))
+#define S(x, n) RORc((x), (n))
+#define R(x, n) (((x)&0xFFFFFFFFUL)>>(n))
+#define Sigma0(x) (S(x, 2) ^ S(x, 13) ^ S(x, 22))
+#define Sigma1(x) (S(x, 6) ^ S(x, 11) ^ S(x, 25))
+#define Gamma0(x) (S(x, 7) ^ S(x, 18) ^ R(x, 3))
+#define Gamma1(x) (S(x, 17) ^ S(x, 19) ^ R(x, 10))
/* Compress 512-bits */
static int sha256_compress(struct sha256_state *md,
@@ -364,12 +364,12 @@ static int sha256_compress(struct sha256_state *md,
}
/* Compress */
-#define RND(a,b,c,d,e,f,g,h,i) \
- do { \
- unsigned long t0 = h + Sigma1(e) + Sha256_Ch(e, f, g) + K[i] + W[i]; \
- unsigned long t1 = Sigma0(a) + Sha256_Maj(a, b, c); \
- d += t0; \
- h = t0 + t1; \
+#define RND(a,b,c,d,e,f,g,h,i) \
+ do { \
+ unsigned long t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; \
+ unsigned long t1 = Sigma0(a) + Maj(a, b, c); \
+ d += t0; \
+ h = t0 + t1; \
} while(0)
for(i = 0; i < 64; ++i) {
@@ -467,7 +467,7 @@ static int my_sha256_final(unsigned char *out,
md->buf[md->curlen++] = (unsigned char)0x80;
/* If the length is currently above 56 bytes we append zeros
- * then compress. Then we can fall back to padding zeros and length
+ * then compress. Then we can fall back to padding zeros and length
* encoding like normal.
*/
if(md->curlen > 56) {
@@ -542,4 +542,4 @@ const struct HMAC_params Curl_HMAC_SHA256[] = {
};
-#endif /* AWS, DIGEST, or libssh2 */
+#endif /* AWS, DIGEST, or libSSH2 */
diff --git a/contrib/libs/curl/lib/share.c b/contrib/libs/curl/lib/share.c
index 2ddaba6d7e..c0a8d806f3 100644
--- a/contrib/libs/curl/lib/share.c
+++ b/contrib/libs/curl/lib/share.c
@@ -26,12 +26,10 @@
#include <curl/curl.h>
#include "urldata.h"
-#include "connect.h"
#include "share.h"
#include "psl.h"
#include "vtls/vtls.h"
#include "hsts.h"
-#include "url.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@@ -66,7 +64,7 @@ curl_share_setopt(struct Curl_share *share, CURLSHoption option, ...)
return CURLSHE_INVALID;
if(share->dirty)
- /* do not allow setting options while one or more handles are already
+ /* don't allow setting options while one or more handles are already
using this share */
return CURLSHE_IN_USE;
@@ -121,12 +119,8 @@ curl_share_setopt(struct Curl_share *share, CURLSHoption option, ...)
break;
case CURL_LOCK_DATA_CONNECT:
- /* It is safe to set this option several times on a share. */
- if(!share->cpool.idata) {
- if(Curl_cpool_init(&share->cpool, Curl_on_disconnect,
- NULL, share, 103))
- res = CURLSHE_NOMEM;
- }
+ if(Curl_conncache_init(&share->conn_cache, 103))
+ res = CURLSHE_NOMEM;
break;
case CURL_LOCK_DATA_PSL:
@@ -139,13 +133,13 @@ curl_share_setopt(struct Curl_share *share, CURLSHoption option, ...)
res = CURLSHE_BAD_OPTION;
}
if(!res)
- share->specifier |= (unsigned int)(1<<type);
+ share->specifier |= (1<<type);
break;
case CURLSHOPT_UNSHARE:
/* this is a type this share will no longer share */
type = va_arg(param, int);
- share->specifier &= ~(unsigned int)(1<<type);
+ share->specifier &= ~(1<<type);
switch(type) {
case CURL_LOCK_DATA_DNS:
break;
@@ -229,9 +223,8 @@ curl_share_cleanup(struct Curl_share *share)
return CURLSHE_IN_USE;
}
- if(share->specifier & (1 << CURL_LOCK_DATA_CONNECT)) {
- Curl_cpool_destroy(&share->cpool);
- }
+ Curl_conncache_close_all_connections(&share->conn_cache);
+ Curl_conncache_destroy(&share->conn_cache);
Curl_hash_destroy(&share->hostcache);
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
@@ -271,11 +264,11 @@ Curl_share_lock(struct Curl_easy *data, curl_lock_data type,
if(!share)
return CURLSHE_INVALID;
- if(share->specifier & (unsigned int)(1<<type)) {
+ if(share->specifier & (1<<type)) {
if(share->lockfunc) /* only call this if set! */
share->lockfunc(data, type, accesstype, share->clientdata);
}
- /* else if we do not share this, pretend successful lock */
+ /* else if we don't share this, pretend successful lock */
return CURLSHE_OK;
}
@@ -288,7 +281,7 @@ Curl_share_unlock(struct Curl_easy *data, curl_lock_data type)
if(!share)
return CURLSHE_INVALID;
- if(share->specifier & (unsigned int)(1<<type)) {
+ if(share->specifier & (1<<type)) {
if(share->unlockfunc) /* only call this if set! */
share->unlockfunc (data, type, share->clientdata);
}
diff --git a/contrib/libs/curl/lib/share.h b/contrib/libs/curl/lib/share.h
index 124f7049f1..632d9198f9 100644
--- a/contrib/libs/curl/lib/share.h
+++ b/contrib/libs/curl/lib/share.h
@@ -34,10 +34,7 @@
#define CURL_GOOD_SHARE 0x7e117a1e
#define GOOD_SHARE_HANDLE(x) ((x) && (x)->magic == CURL_GOOD_SHARE)
-#define CURL_SHARE_KEEP_CONNECT(s) \
- ((s) && ((s)->specifier & (1<< CURL_LOCK_DATA_CONNECT)))
-
-/* this struct is libcurl-private, do not export details */
+/* this struct is libcurl-private, don't export details */
struct Curl_share {
unsigned int magic; /* CURL_GOOD_SHARE */
unsigned int specifier;
@@ -46,7 +43,7 @@ struct Curl_share {
curl_lock_function lockfunc;
curl_unlock_function unlockfunc;
void *clientdata;
- struct cpool cpool;
+ struct conncache conn_cache;
struct Curl_hash hostcache;
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
struct CookieInfo *cookies;
diff --git a/contrib/libs/curl/lib/sigpipe.h b/contrib/libs/curl/lib/sigpipe.h
index c57580f434..9b29403c28 100644
--- a/contrib/libs/curl/lib/sigpipe.h
+++ b/contrib/libs/curl/lib/sigpipe.h
@@ -35,13 +35,6 @@ struct sigpipe_ignore {
};
#define SIGPIPE_VARIABLE(x) struct sigpipe_ignore x
-#define SIGPIPE_MEMBER(x) struct sigpipe_ignore x
-
-static void sigpipe_init(struct sigpipe_ignore *ig)
-{
- memset(ig, 0, sizeof(*ig));
- ig->no_signal = TRUE;
-}
/*
* sigpipe_ignore() makes sure we ignore SIGPIPE while running libcurl
@@ -77,23 +70,11 @@ static void sigpipe_restore(struct sigpipe_ignore *ig)
sigaction(SIGPIPE, &ig->old_pipe_act, NULL);
}
-static void sigpipe_apply(struct Curl_easy *data,
- struct sigpipe_ignore *ig)
-{
- if(data->set.no_signal != ig->no_signal) {
- sigpipe_restore(ig);
- sigpipe_ignore(data, ig);
- }
-}
-
#else
/* for systems without sigaction */
#define sigpipe_ignore(x,y) Curl_nop_stmt
-#define sigpipe_apply(x,y) Curl_nop_stmt
-#define sigpipe_init(x) Curl_nop_stmt
#define sigpipe_restore(x) Curl_nop_stmt
#define SIGPIPE_VARIABLE(x)
-#define SIGPIPE_MEMBER(x) bool x
#endif
#endif /* HEADER_CURL_SIGPIPE_H */
diff --git a/contrib/libs/curl/lib/smb.c b/contrib/libs/curl/lib/smb.c
index f4fff9e615..6c8a47c7fd 100644
--- a/contrib/libs/curl/lib/smb.c
+++ b/contrib/libs/curl/lib/smb.c
@@ -259,7 +259,7 @@ static CURLcode smb_parse_url_path(struct Curl_easy *data,
* SMB handler interface
*/
const struct Curl_handler Curl_handler_smb = {
- "smb", /* scheme */
+ "SMB", /* scheme */
smb_setup_connection, /* setup_connection */
smb_do, /* do_it */
ZERO_NULL, /* done */
@@ -272,8 +272,7 @@ const struct Curl_handler Curl_handler_smb = {
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
smb_disconnect, /* disconnect */
- ZERO_NULL, /* write_resp */
- ZERO_NULL, /* write_resp_hd */
+ ZERO_NULL, /* readwrite */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_SMB, /* defport */
@@ -287,7 +286,7 @@ const struct Curl_handler Curl_handler_smb = {
* SMBS handler interface
*/
const struct Curl_handler Curl_handler_smbs = {
- "smbs", /* scheme */
+ "SMBS", /* scheme */
smb_setup_connection, /* setup_connection */
smb_do, /* do_it */
ZERO_NULL, /* done */
@@ -300,8 +299,7 @@ const struct Curl_handler Curl_handler_smbs = {
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
smb_disconnect, /* disconnect */
- ZERO_NULL, /* write_resp */
- ZERO_NULL, /* write_resp_hd */
+ ZERO_NULL, /* readwrite */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_SMBS, /* defport */
@@ -458,9 +456,6 @@ static CURLcode smb_connect(struct Curl_easy *data, bool *done)
smbc->recv_buf = malloc(MAX_MESSAGE_SIZE);
if(!smbc->recv_buf)
return CURLE_OUT_OF_MEMORY;
- smbc->send_buf = malloc(MAX_MESSAGE_SIZE);
- if(!smbc->send_buf)
- return CURLE_OUT_OF_MEMORY;
/* Multiple requests are allowed with this connection */
connkeep(conn, "SMB default");
@@ -490,6 +485,7 @@ static CURLcode smb_connect(struct Curl_easy *data, bool *done)
static CURLcode smb_recv_message(struct Curl_easy *data, void **msg)
{
struct connectdata *conn = data->conn;
+ curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
struct smb_conn *smbc = &conn->proto.smbc;
char *buf = smbc->recv_buf;
ssize_t bytes_read;
@@ -498,7 +494,7 @@ static CURLcode smb_recv_message(struct Curl_easy *data, void **msg)
size_t len = MAX_MESSAGE_SIZE - smbc->got;
CURLcode result;
- result = Curl_xfer_recv(data, buf + smbc->got, len, &bytes_read);
+ result = Curl_read(data, sockfd, buf + smbc->got, len, &bytes_read);
if(result)
return result;
@@ -559,20 +555,21 @@ static void smb_format_message(struct Curl_easy *data, struct smb_header *h,
h->flags2 = smb_swap16(SMB_FLAGS2_IS_LONG_NAME | SMB_FLAGS2_KNOWS_LONG_NAME);
h->uid = smb_swap16(smbc->uid);
h->tid = smb_swap16(req->tid);
- pid = (unsigned int)getpid();
+ pid = getpid();
h->pid_high = smb_swap16((unsigned short)(pid >> 16));
h->pid = smb_swap16((unsigned short) pid);
}
-static CURLcode smb_send(struct Curl_easy *data, size_t len,
+static CURLcode smb_send(struct Curl_easy *data, ssize_t len,
size_t upload_size)
{
struct connectdata *conn = data->conn;
struct smb_conn *smbc = &conn->proto.smbc;
- size_t bytes_written;
+ ssize_t bytes_written;
CURLcode result;
- result = Curl_xfer_send(data, smbc->send_buf, len, FALSE, &bytes_written);
+ result = Curl_nwrite(data, FIRSTSOCKET, data->state.ulbuf,
+ len, &bytes_written);
if(result)
return result;
@@ -590,15 +587,16 @@ static CURLcode smb_flush(struct Curl_easy *data)
{
struct connectdata *conn = data->conn;
struct smb_conn *smbc = &conn->proto.smbc;
- size_t bytes_written;
- size_t len = smbc->send_size - smbc->sent;
+ ssize_t bytes_written;
+ ssize_t len = smbc->send_size - smbc->sent;
CURLcode result;
if(!smbc->send_size)
return CURLE_OK;
- result = Curl_xfer_send(data, smbc->send_buf + smbc->sent, len, FALSE,
- &bytes_written);
+ result = Curl_nwrite(data, FIRSTSOCKET,
+ data->state.ulbuf + smbc->sent,
+ len, &bytes_written);
if(result)
return result;
@@ -613,13 +611,13 @@ static CURLcode smb_flush(struct Curl_easy *data)
static CURLcode smb_send_message(struct Curl_easy *data, unsigned char cmd,
const void *msg, size_t msg_len)
{
- struct connectdata *conn = data->conn;
- struct smb_conn *smbc = &conn->proto.smbc;
-
- smb_format_message(data, (struct smb_header *)smbc->send_buf,
+ CURLcode result = Curl_get_upload_buffer(data);
+ if(result)
+ return result;
+ smb_format_message(data, (struct smb_header *)data->state.ulbuf,
cmd, msg_len);
- DEBUGASSERT((sizeof(struct smb_header) + msg_len) <= MAX_MESSAGE_SIZE);
- memcpy(smbc->send_buf + sizeof(struct smb_header), msg, msg_len);
+ memcpy(data->state.ulbuf + sizeof(struct smb_header),
+ msg, msg_len);
return smb_send(data, sizeof(struct smb_header) + msg_len, 0);
}
@@ -642,9 +640,9 @@ static CURLcode smb_send_setup(struct Curl_easy *data)
unsigned char nt_hash[21];
unsigned char nt[24];
- const size_t byte_count = sizeof(lm) + sizeof(nt) +
- strlen(smbc->user) + strlen(smbc->domain) +
- strlen(OS) + strlen(CLIENTNAME) + 4; /* 4 null chars */
+ size_t byte_count = sizeof(lm) + sizeof(nt);
+ byte_count += strlen(smbc->user) + strlen(smbc->domain);
+ byte_count += strlen(OS) + strlen(CLIENTNAME) + 4; /* 4 null chars */
if(byte_count > sizeof(msg.bytes))
return CURLE_FILESIZE_EXCEEDED;
@@ -653,7 +651,7 @@ static CURLcode smb_send_setup(struct Curl_easy *data)
Curl_ntlm_core_mk_nt_hash(conn->passwd, nt_hash);
Curl_ntlm_core_lm_resp(nt_hash, smbc->challenge, nt);
- memset(&msg, 0, sizeof(msg) - sizeof(msg.bytes));
+ memset(&msg, 0, sizeof(msg));
msg.word_count = SMB_WC_SETUP_ANDX;
msg.andx.command = SMB_COM_NO_ANDX_COMMAND;
msg.max_buffer_size = smb_swap16(MAX_MESSAGE_SIZE);
@@ -671,7 +669,7 @@ static CURLcode smb_send_setup(struct Curl_easy *data)
MSGCATNULL(smbc->domain);
MSGCATNULL(OS);
MSGCATNULL(CLIENTNAME);
- DEBUGASSERT(byte_count == (size_t)(p - msg.bytes));
+ byte_count = p - msg.bytes;
msg.byte_count = smb_swap16((unsigned short)byte_count);
return smb_send_message(data, SMB_COM_SETUP_ANDX, &msg,
@@ -685,12 +683,12 @@ static CURLcode smb_send_tree_connect(struct Curl_easy *data)
struct smb_conn *smbc = &conn->proto.smbc;
char *p = msg.bytes;
- const size_t byte_count = strlen(conn->host.name) + strlen(smbc->share) +
- strlen(SERVICENAME) + 5; /* 2 nulls and 3 backslashes */
+ size_t byte_count = strlen(conn->host.name) + strlen(smbc->share);
+ byte_count += strlen(SERVICENAME) + 5; /* 2 nulls and 3 backslashes */
if(byte_count > sizeof(msg.bytes))
return CURLE_FILESIZE_EXCEEDED;
- memset(&msg, 0, sizeof(msg) - sizeof(msg.bytes));
+ memset(&msg, 0, sizeof(msg));
msg.word_count = SMB_WC_TREE_CONNECT_ANDX;
msg.andx.command = SMB_COM_NO_ANDX_COMMAND;
msg.pw_len = 0;
@@ -699,7 +697,7 @@ static CURLcode smb_send_tree_connect(struct Curl_easy *data)
MSGCAT("\\");
MSGCATNULL(smbc->share);
MSGCATNULL(SERVICENAME); /* Match any type of service */
- DEBUGASSERT(byte_count == (size_t)(p - msg.bytes));
+ byte_count = p - msg.bytes;
msg.byte_count = smb_swap16((unsigned short)byte_count);
return smb_send_message(data, SMB_COM_TREE_CONNECT_ANDX, &msg,
@@ -710,15 +708,16 @@ static CURLcode smb_send_open(struct Curl_easy *data)
{
struct smb_request *req = data->req.p.smb;
struct smb_nt_create msg;
- const size_t byte_count = strlen(req->path) + 1;
+ size_t byte_count;
- if(byte_count > sizeof(msg.bytes))
+ if((strlen(req->path) + 1) > sizeof(msg.bytes))
return CURLE_FILESIZE_EXCEEDED;
- memset(&msg, 0, sizeof(msg) - sizeof(msg.bytes));
+ memset(&msg, 0, sizeof(msg));
msg.word_count = SMB_WC_NT_CREATE_ANDX;
msg.andx.command = SMB_COM_NO_ANDX_COMMAND;
- msg.name_length = smb_swap16((unsigned short)(byte_count - 1));
+ byte_count = strlen(req->path);
+ msg.name_length = smb_swap16((unsigned short)byte_count);
msg.share_access = smb_swap32(SMB_FILE_SHARE_ALL);
if(data->state.upload) {
msg.access = smb_swap32(SMB_GENERIC_READ | SMB_GENERIC_WRITE);
@@ -728,7 +727,7 @@ static CURLcode smb_send_open(struct Curl_easy *data)
msg.access = smb_swap32(SMB_GENERIC_READ);
msg.create_disposition = smb_swap32(SMB_FILE_OPEN);
}
- msg.byte_count = smb_swap16((unsigned short) byte_count);
+ msg.byte_count = smb_swap16((unsigned short) ++byte_count);
strcpy(msg.bytes, req->path);
return smb_send_message(data, SMB_COM_NT_CREATE_ANDX, &msg,
@@ -776,14 +775,15 @@ static CURLcode smb_send_read(struct Curl_easy *data)
static CURLcode smb_send_write(struct Curl_easy *data)
{
- struct connectdata *conn = data->conn;
- struct smb_conn *smbc = &conn->proto.smbc;
struct smb_write *msg;
struct smb_request *req = data->req.p.smb;
curl_off_t offset = data->req.offset;
curl_off_t upload_size = data->req.size - data->req.bytecount;
+ CURLcode result = Curl_get_upload_buffer(data);
+ if(result)
+ return result;
+ msg = (struct smb_write *)data->state.ulbuf;
- msg = (struct smb_write *)smbc->send_buf;
if(upload_size >= MAX_PAYLOAD_SIZE - 1) /* There is one byte of padding */
upload_size = MAX_PAYLOAD_SIZE - 1;
@@ -812,11 +812,10 @@ static CURLcode smb_send_and_recv(struct Curl_easy *data, void **msg)
/* Check if there is data in the transfer buffer */
if(!smbc->send_size && smbc->upload_size) {
- size_t nread = smbc->upload_size > (size_t)MAX_MESSAGE_SIZE ?
- (size_t)MAX_MESSAGE_SIZE : smbc->upload_size;
- bool eos;
-
- result = Curl_client_read(data, smbc->send_buf, nread, &nread, &eos);
+ size_t nread = smbc->upload_size > (size_t)data->set.upload_buffer_size ?
+ (size_t)data->set.upload_buffer_size : smbc->upload_size;
+ data->req.upload_fromhere = data->state.ulbuf;
+ result = Curl_fillreadbuffer(data, nread, &nread);
if(result && result != CURLE_AGAIN)
return result;
if(!nread)
@@ -923,7 +922,7 @@ static CURLcode smb_connection_state(struct Curl_easy *data, bool *done)
/*
* Convert a timestamp from the Windows world (100 nsec units from 1 Jan 1601)
- * to POSIX time. Cap the output to fit within a time_t.
+ * to Posix time. Cap the output to fit within a time_t.
*/
static void get_posix_time(time_t *out, curl_off_t timestamp)
{
@@ -1070,7 +1069,7 @@ static CURLcode smb_request_state(struct Curl_easy *data, bool *done)
break;
case SMB_CLOSE:
- /* We do not care if the close failed, proceed to tree disconnect anyway */
+ /* We don't care if the close failed, proceed to tree disconnect anyway */
next_state = SMB_TREE_DISCONNECT;
break;
@@ -1134,7 +1133,6 @@ static CURLcode smb_disconnect(struct Curl_easy *data,
Curl_safefree(smbc->share);
Curl_safefree(smbc->domain);
Curl_safefree(smbc->recv_buf);
- Curl_safefree(smbc->send_buf);
return CURLE_OK;
}
diff --git a/contrib/libs/curl/lib/smb.h b/contrib/libs/curl/lib/smb.h
index 9ea2a8cc31..437f4a58a8 100644
--- a/contrib/libs/curl/lib/smb.h
+++ b/contrib/libs/curl/lib/smb.h
@@ -42,7 +42,6 @@ struct smb_conn {
unsigned int session_key;
unsigned short uid;
char *recv_buf;
- char *send_buf;
size_t upload_size;
size_t send_size;
size_t sent;
diff --git a/contrib/libs/curl/lib/smtp.c b/contrib/libs/curl/lib/smtp.c
index 3c5893284b..65fbc5b6c5 100644
--- a/contrib/libs/curl/lib/smtp.c
+++ b/contrib/libs/curl/lib/smtp.c
@@ -111,14 +111,13 @@ static CURLcode smtp_continue_auth(struct Curl_easy *data, const char *mech,
const struct bufref *resp);
static CURLcode smtp_cancel_auth(struct Curl_easy *data, const char *mech);
static CURLcode smtp_get_message(struct Curl_easy *data, struct bufref *out);
-static CURLcode cr_eob_add(struct Curl_easy *data);
/*
* SMTP protocol handler.
*/
const struct Curl_handler Curl_handler_smtp = {
- "smtp", /* scheme */
+ "SMTP", /* scheme */
smtp_setup_connection, /* setup_connection */
smtp_do, /* do_it */
smtp_done, /* done */
@@ -131,8 +130,7 @@ const struct Curl_handler Curl_handler_smtp = {
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
smtp_disconnect, /* disconnect */
- ZERO_NULL, /* write_resp */
- ZERO_NULL, /* write_resp_hd */
+ ZERO_NULL, /* readwrite */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_SMTP, /* defport */
@@ -148,7 +146,7 @@ const struct Curl_handler Curl_handler_smtp = {
*/
const struct Curl_handler Curl_handler_smtps = {
- "smtps", /* scheme */
+ "SMTPS", /* scheme */
smtp_setup_connection, /* setup_connection */
smtp_do, /* do_it */
smtp_done, /* done */
@@ -161,8 +159,7 @@ const struct Curl_handler Curl_handler_smtps = {
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
smtp_disconnect, /* disconnect */
- ZERO_NULL, /* write_resp */
- ZERO_NULL, /* write_resp_hd */
+ ZERO_NULL, /* readwrite */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_SMTPS, /* defport */
@@ -253,8 +250,8 @@ static bool smtp_endofresp(struct Curl_easy *data, struct connectdata *conn,
*/
static CURLcode smtp_get_message(struct Curl_easy *data, struct bufref *out)
{
- char *message = Curl_dyn_ptr(&data->conn->proto.smtpc.pp.recvbuf);
- size_t len = data->conn->proto.smtpc.pp.nfinal;
+ char *message = data->state.buffer;
+ size_t len = strlen(message);
if(len > 4) {
/* Find the start of the message */
@@ -288,7 +285,7 @@ static CURLcode smtp_get_message(struct Curl_easy *data, struct bufref *out)
static void smtp_state(struct Curl_easy *data, smtpstate newstate)
{
struct smtp_conn *smtpc = &data->conn->proto.smtpc;
-#if !defined(CURL_DISABLE_VERBOSE_STRINGS)
+#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
/* for debug purposes */
static const char * const names[] = {
"STOP",
@@ -308,8 +305,8 @@ static void smtp_state(struct Curl_easy *data, smtpstate newstate)
};
if(smtpc->state != newstate)
- CURL_TRC_SMTP(data, "state change from %s to %s",
- names[smtpc->state], names[newstate]);
+ infof(data, "SMTP %p state change from %s to %s",
+ (void *)smtpc, names[smtpc->state], names[newstate]);
#endif
smtpc->state = newstate;
@@ -534,16 +531,16 @@ static CURLcode smtp_perform_command(struct Curl_easy *data)
if(smtp->rcpt) {
/* We notify the server we are sending UTF-8 data if a) it supports the
SMTPUTF8 extension and b) The mailbox contains UTF-8 characters, in
- either the local address or hostname parts. This is regardless of
- whether the hostname is encoded using IDN ACE */
+ either the local address or host name parts. This is regardless of
+ whether the host name is encoded using IDN ACE */
bool utf8 = FALSE;
if((!smtp->custom) || (!smtp->custom[0])) {
char *address = NULL;
struct hostname host = { NULL, NULL, NULL, NULL };
- /* Parse the mailbox to verify into the local address and hostname
- parts, converting the hostname to an IDN A-label if necessary */
+ /* Parse the mailbox to verify into the local address and host name
+ parts, converting the host name to an IDN A-label if necessary */
result = smtp_parse_address(smtp->rcpt->data,
&address, &host);
if(result)
@@ -555,7 +552,7 @@ static CURLcode smtp_perform_command(struct Curl_easy *data)
((host.encalloc) || (!Curl_is_ASCII_name(address)) ||
(!Curl_is_ASCII_name(host.name)));
- /* Send the VRFY command (Note: The hostname part may be absent when the
+ /* Send the VRFY command (Note: The host name part may be absent when the
host is a local system) */
result = Curl_pp_sendf(data, &conn->proto.smtpc.pp, "VRFY %s%s%s%s",
address,
@@ -607,8 +604,8 @@ static CURLcode smtp_perform_mail(struct Curl_easy *data)
/* We notify the server we are sending UTF-8 data if a) it supports the
SMTPUTF8 extension and b) The mailbox contains UTF-8 characters, in
- either the local address or hostname parts. This is regardless of
- whether the hostname is encoded using IDN ACE */
+ either the local address or host name parts. This is regardless of
+ whether the host name is encoded using IDN ACE */
bool utf8 = FALSE;
/* Calculate the FROM parameter */
@@ -616,12 +613,12 @@ static CURLcode smtp_perform_mail(struct Curl_easy *data)
char *address = NULL;
struct hostname host = { NULL, NULL, NULL, NULL };
- /* Parse the FROM mailbox into the local address and hostname parts,
- converting the hostname to an IDN A-label if necessary */
+ /* Parse the FROM mailbox into the local address and host name parts,
+ converting the host name to an IDN A-label if necessary */
result = smtp_parse_address(data->set.str[STRING_MAIL_FROM],
&address, &host);
if(result)
- goto out;
+ return result;
/* Establish whether we should report SMTPUTF8 to the server for this
mailbox as per RFC-6531 sect. 3.1 point 4 and sect. 3.4 */
@@ -635,8 +632,8 @@ static CURLcode smtp_perform_mail(struct Curl_easy *data)
Curl_free_idnconverted_hostname(&host);
}
else
- /* An invalid mailbox was provided but we will simply let the server
- worry about that and reply with a 501 error */
+ /* An invalid mailbox was provided but we'll simply let the server worry
+ about that and reply with a 501 error */
from = aprintf("<%s>", address);
free(address);
@@ -645,10 +642,8 @@ static CURLcode smtp_perform_mail(struct Curl_easy *data)
/* Null reverse-path, RFC-5321, sect. 3.6.3 */
from = strdup("<>");
- if(!from) {
- result = CURLE_OUT_OF_MEMORY;
- goto out;
- }
+ if(!from)
+ return CURLE_OUT_OF_MEMORY;
/* Calculate the optional AUTH parameter */
if(data->set.str[STRING_MAIL_AUTH] && conn->proto.smtpc.sasl.authused) {
@@ -656,12 +651,14 @@ static CURLcode smtp_perform_mail(struct Curl_easy *data)
char *address = NULL;
struct hostname host = { NULL, NULL, NULL, NULL };
- /* Parse the AUTH mailbox into the local address and hostname parts,
- converting the hostname to an IDN A-label if necessary */
+ /* Parse the AUTH mailbox into the local address and host name parts,
+ converting the host name to an IDN A-label if necessary */
result = smtp_parse_address(data->set.str[STRING_MAIL_AUTH],
&address, &host);
- if(result)
- goto out;
+ if(result) {
+ free(from);
+ return result;
+ }
/* Establish whether we should report SMTPUTF8 to the server for this
mailbox as per RFC-6531 sect. 3.1 point 4 and sect. 3.4 */
@@ -676,9 +673,10 @@ static CURLcode smtp_perform_mail(struct Curl_easy *data)
Curl_free_idnconverted_hostname(&host);
}
else
- /* An invalid mailbox was provided but we will simply let the server
+ /* An invalid mailbox was provided but we'll simply let the server
worry about it */
auth = aprintf("<%s>", address);
+
free(address);
}
else
@@ -686,16 +684,16 @@ static CURLcode smtp_perform_mail(struct Curl_easy *data)
auth = strdup("<>");
if(!auth) {
- result = CURLE_OUT_OF_MEMORY;
- goto out;
+ free(from);
+
+ return CURLE_OUT_OF_MEMORY;
}
}
-#ifndef CURL_DISABLE_MIME
/* Prepare the mime data if some. */
if(data->set.mimepost.kind != MIMEKIND_NONE) {
/* Use the whole structure as data. */
- data->set.mimepost.flags &= ~(unsigned int)MIME_BODY_ONLY;
+ data->set.mimepost.flags &= ~MIME_BODY_ONLY;
/* Add external headers and mime version. */
curl_mime_headers(&data->set.mimepost, data->set.headers, 0);
@@ -707,31 +705,37 @@ static CURLcode smtp_perform_mail(struct Curl_easy *data)
result = Curl_mime_add_header(&data->set.mimepost.curlheaders,
"Mime-Version: 1.0");
+ /* Make sure we will read the entire mime structure. */
if(!result)
- result = Curl_creader_set_mime(data, &data->set.mimepost);
- if(result)
- goto out;
- data->state.infilesize = Curl_creader_total_length(data);
- }
- else
-#endif
- {
- result = Curl_creader_set_fread(data, data->state.infilesize);
- if(result)
- goto out;
+ result = Curl_mime_rewind(&data->set.mimepost);
+
+ if(result) {
+ free(from);
+ free(auth);
+
+ return result;
+ }
+
+ data->state.infilesize = Curl_mime_size(&data->set.mimepost);
+
+ /* Read from mime structure. */
+ data->state.fread_func = (curl_read_callback) Curl_mime_read;
+ data->state.in = (void *) &data->set.mimepost;
}
/* Calculate the optional SIZE parameter */
if(conn->proto.smtpc.size_supported && data->state.infilesize > 0) {
- size = aprintf("%" FMT_OFF_T, data->state.infilesize);
+ size = aprintf("%" CURL_FORMAT_CURL_OFF_T, data->state.infilesize);
if(!size) {
- result = CURLE_OUT_OF_MEMORY;
- goto out;
+ free(from);
+ free(auth);
+
+ return CURLE_OUT_OF_MEMORY;
}
}
- /* If the mailboxes in the FROM and AUTH parameters do not include a UTF-8
+ /* If the mailboxes in the FROM and AUTH parameters don't include a UTF-8
based address then quickly scan through the recipient list and check if
any there do, as we need to correctly identify our support for SMTPUTF8
in the envelope, as per RFC-6531 sect. 3.4 */
@@ -740,7 +744,7 @@ static CURLcode smtp_perform_mail(struct Curl_easy *data)
struct curl_slist *rcpt = smtp->rcpt;
while(rcpt && !utf8) {
- /* Does the hostname contain non-ASCII characters? */
+ /* Does the host name contain non-ASCII characters? */
if(!Curl_is_ASCII_name(rcpt->data))
utf8 = TRUE;
@@ -748,11 +752,6 @@ static CURLcode smtp_perform_mail(struct Curl_easy *data)
}
}
- /* Add the client reader doing STMP EOB escaping */
- result = cr_eob_add(data);
- if(result)
- goto out;
-
/* Send the MAIL command */
result = Curl_pp_sendf(data, &conn->proto.smtpc.pp,
"MAIL FROM:%s%s%s%s%s%s",
@@ -764,7 +763,6 @@ static CURLcode smtp_perform_mail(struct Curl_easy *data)
utf8 ? " SMTPUTF8" /* Internationalised mailbox */
: ""); /* included in our envelope */
-out:
free(from);
free(auth);
free(size);
@@ -790,8 +788,8 @@ static CURLcode smtp_perform_rcpt_to(struct Curl_easy *data)
char *address = NULL;
struct hostname host = { NULL, NULL, NULL, NULL };
- /* Parse the recipient mailbox into the local address and hostname parts,
- converting the hostname to an IDN A-label if necessary */
+ /* Parse the recipient mailbox into the local address and host name parts,
+ converting the host name to an IDN A-label if necessary */
result = smtp_parse_address(smtp->rcpt->data,
&address, &host);
if(result)
@@ -802,7 +800,7 @@ static CURLcode smtp_perform_rcpt_to(struct Curl_easy *data)
result = Curl_pp_sendf(data, &conn->proto.smtpc.pp, "RCPT TO:<%s@%s>",
address, host.name);
else
- /* An invalid mailbox was provided but we will simply let the server worry
+ /* An invalid mailbox was provided but we'll simply let the server worry
about that and reply with a 501 error */
result = Curl_pp_sendf(data, &conn->proto.smtpc.pp, "RCPT TO:<%s>",
address);
@@ -861,7 +859,7 @@ static CURLcode smtp_state_starttls_resp(struct Curl_easy *data,
(void)instate; /* no use for this yet */
/* Pipelining in response is forbidden. */
- if(data->conn->proto.smtpc.pp.overflow)
+ if(data->conn->proto.smtpc.pp.cache_size)
return CURLE_WEIRD_SERVER_REPLY;
if(smtpcode != 220) {
@@ -885,8 +883,8 @@ static CURLcode smtp_state_ehlo_resp(struct Curl_easy *data,
{
CURLcode result = CURLE_OK;
struct smtp_conn *smtpc = &conn->proto.smtpc;
- const char *line = Curl_dyn_ptr(&smtpc->pp.recvbuf);
- size_t len = smtpc->pp.nfinal;
+ const char *line = data->state.buffer;
+ size_t len = strlen(line);
(void)instate; /* no use for this yet */
@@ -958,7 +956,7 @@ static CURLcode smtp_state_ehlo_resp(struct Curl_easy *data,
if(smtpcode != 1) {
if(data->set.use_ssl && !Curl_conn_is_ssl(conn, FIRSTSOCKET)) {
- /* We do not have a SSL/TLS connection yet, but SSL is requested */
+ /* We don't have a SSL/TLS connection yet, but SSL is requested */
if(smtpc->tls_supported)
/* Switch to TLS connection now */
result = smtp_perform_starttls(data, conn);
@@ -1035,8 +1033,8 @@ static CURLcode smtp_state_command_resp(struct Curl_easy *data, int smtpcode,
{
CURLcode result = CURLE_OK;
struct SMTP *smtp = data->req.p.smtp;
- char *line = Curl_dyn_ptr(&data->conn->proto.smtpc.pp.recvbuf);
- size_t len = data->conn->proto.smtpc.pp.nfinal;
+ char *line = data->state.buffer;
+ size_t len = strlen(line);
(void)instate; /* no use for this yet */
@@ -1046,8 +1044,12 @@ static CURLcode smtp_state_command_resp(struct Curl_easy *data, int smtpcode,
result = CURLE_WEIRD_SERVER_REPLY;
}
else {
- if(!data->req.no_body)
- result = Curl_client_write(data, CLIENTWRITE_BODY, line, len);
+ /* Temporarily add the LF character back and send as body to the client */
+ if(!data->req.no_body) {
+ line[len] = '\n';
+ result = Curl_client_write(data, CLIENTWRITE_BODY, line, len + 1);
+ line[len] = '\0';
+ }
if(smtpcode != 1) {
if(smtp->rcpt) {
@@ -1102,7 +1104,7 @@ static CURLcode smtp_state_rcpt_resp(struct Curl_easy *data,
is_smtp_err = (smtpcode/100 != 2) ? TRUE : FALSE;
- /* If there is multiple RCPT TO to be issued, it is possible to ignore errors
+ /* If there's multiple RCPT TO to be issued, it's possible to ignore errors
and proceed with only the valid addresses. */
is_smtp_blocking_err =
(is_smtp_err && !data->set.mail_rcpt_allowfails) ? TRUE : FALSE;
@@ -1129,7 +1131,7 @@ static CURLcode smtp_state_rcpt_resp(struct Curl_easy *data,
/* Send the next RCPT TO command */
result = smtp_perform_rcpt_to(data);
else {
- /* We were not able to issue a successful RCPT TO command while going
+ /* We weren't able to issue a successful RCPT TO command while going
over recipients (potentially multiple). Sending back last error. */
if(!smtp->rcpt_had_ok) {
failf(data, "RCPT failed: %d (last error)", smtp->rcpt_last_error);
@@ -1164,7 +1166,7 @@ static CURLcode smtp_state_data_resp(struct Curl_easy *data, int smtpcode,
Curl_pgrsSetUploadSize(data, data->state.infilesize);
/* SMTP upload */
- Curl_xfer_setup1(data, CURL_XFER_SEND, -1, FALSE);
+ Curl_setup_transfer(data, -1, -1, FALSE, FIRSTSOCKET);
/* End of DO phase */
smtp_state(data, SMTP_STOP);
@@ -1196,13 +1198,13 @@ static CURLcode smtp_statemachine(struct Curl_easy *data,
struct connectdata *conn)
{
CURLcode result = CURLE_OK;
+ curl_socket_t sock = conn->sock[FIRSTSOCKET];
int smtpcode;
struct smtp_conn *smtpc = &conn->proto.smtpc;
struct pingpong *pp = &smtpc->pp;
size_t nread = 0;
/* Busy upgrading the connection; right now all I/O is SSL/TLS, not SMTP */
-upgrade_tls:
if(smtpc->state == SMTP_UPGRADETLS)
return smtp_perform_upgrade_tls(data);
@@ -1212,7 +1214,7 @@ upgrade_tls:
do {
/* Read the response from the server */
- result = Curl_pp_readresp(data, FIRSTSOCKET, pp, &smtpcode, &nread);
+ result = Curl_pp_readresp(data, sock, pp, &smtpcode, &nread);
if(result)
return result;
@@ -1239,10 +1241,6 @@ upgrade_tls:
case SMTP_STARTTLS:
result = smtp_state_starttls_resp(data, smtpcode, smtpc->state);
- /* During UPGRADETLS, leave the read loop as we need to connect
- * (e.g. TLS handshake) before we continue sending/receiving. */
- if(!result && (smtpc->state == SMTP_UPGRADETLS))
- goto upgrade_tls;
break;
case SMTP_AUTH:
@@ -1270,6 +1268,7 @@ upgrade_tls:
break;
case SMTP_QUIT:
+ /* fallthrough, just stop! */
default:
/* internal error */
smtp_state(data, SMTP_STOP);
@@ -1363,7 +1362,8 @@ static CURLcode smtp_connect(struct Curl_easy *data, bool *done)
Curl_sasl_init(&smtpc->sasl, data, &saslsmtp);
/* Initialise the pingpong layer */
- Curl_pp_init(pp);
+ Curl_pp_setup(pp);
+ Curl_pp_init(data, pp);
/* Parse the URL options */
result = smtp_parse_url_options(conn);
@@ -1398,6 +1398,10 @@ static CURLcode smtp_done(struct Curl_easy *data, CURLcode status,
CURLcode result = CURLE_OK;
struct connectdata *conn = data->conn;
struct SMTP *smtp = data->req.p.smtp;
+ struct pingpong *pp = &conn->proto.smtpc.pp;
+ char *eob;
+ ssize_t len;
+ ssize_t bytes_written;
(void)premature;
@@ -1412,7 +1416,47 @@ static CURLcode smtp_done(struct Curl_easy *data, CURLcode status,
result = status; /* use the already set error code */
}
else if(!data->set.connect_only && data->set.mail_rcpt &&
- (data->state.upload || IS_MIME_POST(data))) {
+ (data->state.upload || data->set.mimepost.kind)) {
+ /* Calculate the EOB taking into account any terminating CRLF from the
+ previous line of the email or the CRLF of the DATA command when there
+ is "no mail data". RFC-5321, sect. 4.1.1.4.
+
+ Note: As some SSL backends, such as OpenSSL, will cause Curl_write() to
+ fail when using a different pointer following a previous write, that
+ returned CURLE_AGAIN, we duplicate the EOB now rather than when the
+ bytes written doesn't equal len. */
+ if(smtp->trailing_crlf || !data->state.infilesize) {
+ eob = strdup(&SMTP_EOB[2]);
+ len = SMTP_EOB_LEN - 2;
+ }
+ else {
+ eob = strdup(SMTP_EOB);
+ len = SMTP_EOB_LEN;
+ }
+
+ if(!eob)
+ return CURLE_OUT_OF_MEMORY;
+
+ /* Send the end of block data */
+ result = Curl_write(data, conn->writesockfd, eob, len, &bytes_written);
+ if(result) {
+ free(eob);
+ return result;
+ }
+
+ if(bytes_written != len) {
+ /* The whole chunk was not sent so keep it around and adjust the
+ pingpong structure accordingly */
+ pp->sendthis = eob;
+ pp->sendsize = len;
+ pp->sendleft = len - bytes_written;
+ }
+ else {
+ /* Successfully sent so adjust the response timeout relative to now */
+ pp->response = Curl_now();
+
+ free(eob);
+ }
smtp_state(data, SMTP_POSTDATA);
@@ -1422,8 +1466,7 @@ static CURLcode smtp_done(struct Curl_easy *data, CURLcode status,
/* Clear the transfer mode for the next request */
smtp->transfer = PPTRANSFER_BODY;
- CURL_TRC_SMTP(data, "smtp_done(status=%d, premature=%d) -> %d",
- status, premature, result);
+
return result;
}
@@ -1441,7 +1484,7 @@ static CURLcode smtp_perform(struct Curl_easy *data, bool *connected,
CURLcode result = CURLE_OK;
struct SMTP *smtp = data->req.p.smtp;
- CURL_TRC_SMTP(data, "smtp_perform(), start");
+ DEBUGF(infof(data, "DO phase starts"));
if(data->req.no_body) {
/* Requested no body means no transfer */
@@ -1453,10 +1496,10 @@ static CURLcode smtp_perform(struct Curl_easy *data, bool *connected,
/* Store the first recipient (or NULL if not specified) */
smtp->rcpt = data->set.mail_rcpt;
- /* Track of whether we have successfully sent at least one RCPT TO command */
+ /* Track of whether we've successfully sent at least one RCPT TO command */
smtp->rcpt_had_ok = FALSE;
- /* Track of the last error we have received by sending RCPT TO command */
+ /* Track of the last error we've received by sending RCPT TO command */
smtp->rcpt_last_error = 0;
/* Initial data character is the first character in line: it is implicitly
@@ -1465,7 +1508,7 @@ static CURLcode smtp_perform(struct Curl_easy *data, bool *connected,
smtp->eob = 2;
/* Start the first command in the DO phase */
- if((data->state.upload || IS_MIME_POST(data)) && data->set.mail_rcpt)
+ if((data->state.upload || data->set.mimepost.kind) && data->set.mail_rcpt)
/* MAIL transfer */
result = smtp_perform_mail(data);
else
@@ -1473,16 +1516,16 @@ static CURLcode smtp_perform(struct Curl_easy *data, bool *connected,
result = smtp_perform_command(data);
if(result)
- goto out;
+ return result;
/* Run the state-machine */
result = smtp_multi_statemach(data, dophase_done);
*connected = Curl_conn_is_connected(data->conn, FIRSTSOCKET);
-out:
- CURL_TRC_SMTP(data, "smtp_perform() -> %d, connected=%d, done=%d",
- result, *connected, *dophase_done);
+ if(*dophase_done)
+ DEBUGF(infof(data, "DO phase is complete"));
+
return result;
}
@@ -1498,8 +1541,6 @@ out:
static CURLcode smtp_do(struct Curl_easy *data, bool *done)
{
CURLcode result = CURLE_OK;
- DEBUGASSERT(data);
- DEBUGASSERT(data->conn);
*done = FALSE; /* default to false */
/* Parse the custom request */
@@ -1508,7 +1549,7 @@ static CURLcode smtp_do(struct Curl_easy *data, bool *done)
return result;
result = smtp_regular_transfer(data, done);
- CURL_TRC_SMTP(data, "smtp_do() -> %d, done=%d", result, *done);
+
return result;
}
@@ -1543,7 +1584,6 @@ static CURLcode smtp_disconnect(struct Curl_easy *data,
/* Cleanup our connection based variables */
Curl_safefree(smtpc->domain);
- CURL_TRC_SMTP(data, "smtp_disconnect(), finished");
return CURLE_OK;
}
@@ -1557,7 +1597,7 @@ static CURLcode smtp_dophase_done(struct Curl_easy *data, bool connected)
if(smtp->transfer != PPTRANSFER_BODY)
/* no data to transfer */
- Curl_xfer_setup_nop(data);
+ Curl_setup_transfer(data, -1, -1, FALSE, -1);
return CURLE_OK;
}
@@ -1575,7 +1615,6 @@ static CURLcode smtp_doing(struct Curl_easy *data, bool *dophase_done)
DEBUGF(infof(data, "DO phase is complete"));
}
- CURL_TRC_SMTP(data, "smtp_doing() -> %d, done=%d", result, *dophase_done);
return result;
}
@@ -1610,8 +1649,6 @@ static CURLcode smtp_regular_transfer(struct Curl_easy *data,
if(!result && *dophase_done)
result = smtp_dophase_done(data, connected);
- CURL_TRC_SMTP(data, "smtp_regular_transfer() -> %d, done=%d",
- result, *dophase_done);
return result;
}
@@ -1625,8 +1662,10 @@ static CURLcode smtp_setup_connection(struct Curl_easy *data,
/* Initialise the SMTP layer */
result = smtp_init(data);
- CURL_TRC_SMTP(data, "smtp_setup_connection() -> %d", result);
- return result;
+ if(result)
+ return result;
+
+ return CURLE_OK;
}
/***********************************************************************
@@ -1716,7 +1755,7 @@ static CURLcode smtp_parse_custom_request(struct Curl_easy *data)
* smtp_parse_address()
*
* Parse the fully qualified mailbox address into a local address part and the
- * hostname, converting the hostname to an IDN A-label, as per RFC-5890, if
+ * host name, converting the host name to an IDN A-label, as per RFC-5890, if
* necessary.
*
* Parameters:
@@ -1727,8 +1766,8 @@ static CURLcode smtp_parse_custom_request(struct Curl_easy *data)
* address [in/out] - A new allocated buffer which holds the local
* address part of the mailbox. This buffer must be
* free'ed by the caller.
- * host [in/out] - The hostname structure that holds the original,
- * and optionally encoded, hostname.
+ * host [in/out] - The host name structure that holds the original,
+ * and optionally encoded, host name.
* Curl_free_idnconverted_hostname() must be called
* once the caller has finished with the structure.
*
@@ -1736,14 +1775,14 @@ static CURLcode smtp_parse_custom_request(struct Curl_easy *data)
*
* Notes:
*
- * Should a UTF-8 hostname require conversion to IDN ACE and we cannot honor
+ * Should a UTF-8 host name require conversion to IDN ACE and we cannot honor
* that conversion then we shall return success. This allow the caller to send
* the data to the server as a U-label (as per RFC-6531 sect. 3.2).
*
* If an mailbox '@' separator cannot be located then the mailbox is considered
* to be either a local mailbox or an invalid mailbox (depending on what the
* calling function deems it to be) then the input will simply be returned in
- * the address part with the hostname being NULL.
+ * the address part with the host name being NULL.
*/
static CURLcode smtp_parse_address(const char *fqma, char **address,
struct hostname *host)
@@ -1752,7 +1791,7 @@ static CURLcode smtp_parse_address(const char *fqma, char **address,
size_t length;
/* Duplicate the fully qualified email address so we can manipulate it,
- ensuring it does not contain the delimiters if specified */
+ ensuring it doesn't contain the delimiters if specified */
char *dup = strdup(fqma[0] == '<' ? fqma + 1 : fqma);
if(!dup)
return CURLE_OUT_OF_MEMORY;
@@ -1763,17 +1802,17 @@ static CURLcode smtp_parse_address(const char *fqma, char **address,
dup[length - 1] = '\0';
}
- /* Extract the hostname from the address (if we can) */
+ /* Extract the host name from the address (if we can) */
host->name = strpbrk(dup, "@");
if(host->name) {
*host->name = '\0';
host->name = host->name + 1;
- /* Attempt to convert the hostname to IDN ACE */
+ /* Attempt to convert the host name to IDN ACE */
(void) Curl_idnconvert_hostname(host);
/* If Curl_idnconvert_hostname() fails then we shall attempt to continue
- and send the hostname using UTF-8 rather than as 7-bit ACE (which is
+ and send the host name using UTF-8 rather than as 7-bit ACE (which is
our preference) */
}
@@ -1783,174 +1822,108 @@ static CURLcode smtp_parse_address(const char *fqma, char **address,
return result;
}
-struct cr_eob_ctx {
- struct Curl_creader super;
- struct bufq buf;
- size_t n_eob; /* how many EOB bytes we matched so far */
- size_t eob; /* Number of bytes of the EOB (End Of Body) that
- have been received so far */
- BIT(read_eos); /* we read an EOS from the next reader */
- BIT(eos); /* we have returned an EOS */
-};
-
-static CURLcode cr_eob_init(struct Curl_easy *data,
- struct Curl_creader *reader)
+CURLcode Curl_smtp_escape_eob(struct Curl_easy *data,
+ const ssize_t nread,
+ const ssize_t offset)
{
- struct cr_eob_ctx *ctx = reader->ctx;
- (void)data;
- /* The first char we read is the first on a line, as if we had
- * read CRLF just before */
- ctx->n_eob = 2;
- Curl_bufq_init2(&ctx->buf, (16 * 1024), 1, BUFQ_OPT_SOFT_LIMIT);
- return CURLE_OK;
-}
-
-static void cr_eob_close(struct Curl_easy *data, struct Curl_creader *reader)
-{
- struct cr_eob_ctx *ctx = reader->ctx;
- (void)data;
- Curl_bufq_free(&ctx->buf);
-}
-
-/* this is the 5-bytes End-Of-Body marker for SMTP */
-#define SMTP_EOB "\r\n.\r\n"
-#define SMTP_EOB_FIND_LEN 3
-
-/* client reader doing SMTP End-Of-Body escaping. */
-static CURLcode cr_eob_read(struct Curl_easy *data,
- struct Curl_creader *reader,
- char *buf, size_t blen,
- size_t *pnread, bool *peos)
-{
- struct cr_eob_ctx *ctx = reader->ctx;
- CURLcode result = CURLE_OK;
- size_t nread, i, start, n;
- bool eos;
+ /* When sending a SMTP payload we must detect CRLF. sequences making sure
+ they are sent as CRLF.. instead, as a . on the beginning of a line will
+ be deleted by the server when not part of an EOB terminator and a
+ genuine CRLF.CRLF which isn't escaped will wrongly be detected as end of
+ data by the server
+ */
+ ssize_t i;
+ ssize_t si;
+ struct SMTP *smtp = data->req.p.smtp;
+ char *scratch = data->state.scratch;
+ char *newscratch = NULL;
+ char *oldscratch = NULL;
+ size_t eob_sent;
- if(!ctx->read_eos && Curl_bufq_is_empty(&ctx->buf)) {
- /* Get more and convert it when needed */
- result = Curl_creader_read(data, reader->next, buf, blen, &nread, &eos);
- if(result)
- return result;
+ /* Do we need to allocate a scratch buffer? */
+ if(!scratch || data->set.crlf) {
+ oldscratch = scratch;
- ctx->read_eos = eos;
- if(nread) {
- if(!ctx->n_eob && !memchr(buf, SMTP_EOB[0], nread)) {
- /* not in the middle of a match, no EOB start found, just pass */
- *pnread = nread;
- *peos = FALSE;
- return CURLE_OK;
- }
- /* scan for EOB (continuation) and convert */
- for(i = start = 0; i < nread; ++i) {
- if(ctx->n_eob >= SMTP_EOB_FIND_LEN) {
- /* matched the EOB prefix and seeing additional char, add '.' */
- result = Curl_bufq_cwrite(&ctx->buf, buf + start, i - start, &n);
- if(result)
- return result;
- result = Curl_bufq_cwrite(&ctx->buf, ".", 1, &n);
- if(result)
- return result;
- ctx->n_eob = 0;
- start = i;
- if(data->state.infilesize > 0)
- data->state.infilesize++;
- }
+ scratch = newscratch = malloc(2 * data->set.upload_buffer_size);
+ if(!newscratch) {
+ failf(data, "Failed to alloc scratch buffer");
- if(buf[i] != SMTP_EOB[ctx->n_eob])
- ctx->n_eob = 0;
+ return CURLE_OUT_OF_MEMORY;
+ }
+ }
+ DEBUGASSERT((size_t)data->set.upload_buffer_size >= (size_t)nread);
+
+ /* Have we already sent part of the EOB? */
+ eob_sent = smtp->eob;
+
+ /* This loop can be improved by some kind of Boyer-Moore style of
+ approach but that is saved for later... */
+ if(offset)
+ memcpy(scratch, data->req.upload_fromhere, offset);
+ for(i = offset, si = offset; i < nread; i++) {
+ if(SMTP_EOB[smtp->eob] == data->req.upload_fromhere[i]) {
+ smtp->eob++;
+
+ /* Is the EOB potentially the terminating CRLF? */
+ if(2 == smtp->eob || SMTP_EOB_LEN == smtp->eob)
+ smtp->trailing_crlf = TRUE;
+ else
+ smtp->trailing_crlf = FALSE;
+ }
+ else if(smtp->eob) {
+ /* A previous substring matched so output that first */
+ memcpy(&scratch[si], &SMTP_EOB[eob_sent], smtp->eob - eob_sent);
+ si += smtp->eob - eob_sent;
+
+ /* Then compare the first byte */
+ if(SMTP_EOB[0] == data->req.upload_fromhere[i])
+ smtp->eob = 1;
+ else
+ smtp->eob = 0;
- if(buf[i] == SMTP_EOB[ctx->n_eob]) {
- /* matching another char of the EOB */
- ++ctx->n_eob;
- }
- }
+ eob_sent = 0;
- /* add any remainder to buf */
- if(start < nread) {
- result = Curl_bufq_cwrite(&ctx->buf, buf + start, nread - start, &n);
- if(result)
- return result;
- }
+ /* Reset the trailing CRLF flag as there was more data */
+ smtp->trailing_crlf = FALSE;
}
- if(ctx->read_eos) {
- /* if we last matched a CRLF or if the data was empty, add ".\r\n"
- * to end the body. If we sent something and it did not end with "\r\n",
- * add "\r\n.\r\n" to end the body */
- const char *eob = SMTP_EOB;
- switch(ctx->n_eob) {
- case 2:
- /* seen a CRLF at the end, just add the remainder */
- eob = &SMTP_EOB[2];
- break;
- case 3:
- /* ended with '\r\n.', we should escpe the last '.' */
- eob = "." SMTP_EOB;
- break;
- default:
- break;
- }
- result = Curl_bufq_cwrite(&ctx->buf, eob, strlen(eob), &n);
- if(result)
- return result;
+ /* Do we have a match for CRLF. as per RFC-5321, sect. 4.5.2 */
+ if(SMTP_EOB_FIND_LEN == smtp->eob) {
+ /* Copy the replacement data to the target buffer */
+ memcpy(&scratch[si], &SMTP_EOB_REPL[eob_sent],
+ SMTP_EOB_REPL_LEN - eob_sent);
+ si += SMTP_EOB_REPL_LEN - eob_sent;
+ smtp->eob = 0;
+ eob_sent = 0;
}
+ else if(!smtp->eob)
+ scratch[si++] = data->req.upload_fromhere[i];
}
- *peos = FALSE;
- if(!Curl_bufq_is_empty(&ctx->buf)) {
- result = Curl_bufq_cread(&ctx->buf, buf, blen, pnread);
+ if(smtp->eob - eob_sent) {
+ /* A substring matched before processing ended so output that now */
+ memcpy(&scratch[si], &SMTP_EOB[eob_sent], smtp->eob - eob_sent);
+ si += smtp->eob - eob_sent;
}
- else
- *pnread = 0;
- if(ctx->read_eos && Curl_bufq_is_empty(&ctx->buf)) {
- /* no more data, read all, done. */
- ctx->eos = TRUE;
- }
- *peos = ctx->eos;
- DEBUGF(infof(data, "cr_eob_read(%zu) -> %d, %zd, %d",
- blen, result, *pnread, *peos));
- return result;
-}
+ /* Only use the new buffer if we replaced something */
+ if(si != nread) {
+ /* Upload from the new (replaced) buffer instead */
+ data->req.upload_fromhere = scratch;
-static curl_off_t cr_eob_total_length(struct Curl_easy *data,
- struct Curl_creader *reader)
-{
- /* this reader changes length depending on input */
- (void)data;
- (void)reader;
- return -1;
-}
+ /* Save the buffer so it can be freed later */
+ data->state.scratch = scratch;
-static const struct Curl_crtype cr_eob = {
- "cr-smtp-eob",
- cr_eob_init,
- cr_eob_read,
- cr_eob_close,
- Curl_creader_def_needs_rewind,
- cr_eob_total_length,
- Curl_creader_def_resume_from,
- Curl_creader_def_rewind,
- Curl_creader_def_unpause,
- Curl_creader_def_is_paused,
- Curl_creader_def_done,
- sizeof(struct cr_eob_ctx)
-};
-
-static CURLcode cr_eob_add(struct Curl_easy *data)
-{
- struct Curl_creader *reader = NULL;
- CURLcode result;
+ /* Free the old scratch buffer */
+ free(oldscratch);
- result = Curl_creader_create(&reader, data, &cr_eob,
- CURL_CR_CONTENT_ENCODE);
- if(!result)
- result = Curl_creader_add(data, reader);
+ /* Set the new amount too */
+ data->req.upload_present = si;
+ }
+ else
+ free(newscratch);
- if(result && reader)
- Curl_creader_free(data, reader);
- return result;
+ return CURLE_OK;
}
#endif /* CURL_DISABLE_SMTP */
diff --git a/contrib/libs/curl/lib/smtp.h b/contrib/libs/curl/lib/smtp.h
index 7c2af68073..7a04c21549 100644
--- a/contrib/libs/curl/lib/smtp.h
+++ b/contrib/libs/curl/lib/smtp.h
@@ -84,4 +84,17 @@ struct smtp_conn {
extern const struct Curl_handler Curl_handler_smtp;
extern const struct Curl_handler Curl_handler_smtps;
+/* this is the 5-bytes End-Of-Body marker for SMTP */
+#define SMTP_EOB "\x0d\x0a\x2e\x0d\x0a"
+#define SMTP_EOB_LEN 5
+#define SMTP_EOB_FIND_LEN 3
+
+/* if found in data, replace it with this string instead */
+#define SMTP_EOB_REPL "\x0d\x0a\x2e\x2e"
+#define SMTP_EOB_REPL_LEN 4
+
+CURLcode Curl_smtp_escape_eob(struct Curl_easy *data,
+ const ssize_t nread,
+ const ssize_t offset);
+
#endif /* HEADER_CURL_SMTP_H */
diff --git a/contrib/libs/curl/lib/sockaddr.h b/contrib/libs/curl/lib/sockaddr.h
index 2e2d375e06..5a6bb207dc 100644
--- a/contrib/libs/curl/lib/sockaddr.h
+++ b/contrib/libs/curl/lib/sockaddr.h
@@ -30,7 +30,7 @@ struct Curl_sockaddr_storage {
union {
struct sockaddr sa;
struct sockaddr_in sa_in;
-#ifdef USE_IPV6
+#ifdef ENABLE_IPV6
struct sockaddr_in6 sa_in6;
#endif
#ifdef HAVE_STRUCT_SOCKADDR_STORAGE
diff --git a/contrib/libs/curl/lib/socketpair.c b/contrib/libs/curl/lib/socketpair.c
index b14f5a5f14..e3d40ff94e 100644
--- a/contrib/libs/curl/lib/socketpair.c
+++ b/contrib/libs/curl/lib/socketpair.c
@@ -27,82 +27,15 @@
#include "urldata.h"
#include "rand.h"
-#if defined(USE_EVENTFD)
-#ifdef HAVE_SYS_EVENTFD_H
-#include <sys/eventfd.h>
-#endif
-
-int Curl_eventfd(curl_socket_t socks[2], bool nonblocking)
-{
- int efd = eventfd(0, nonblocking ? EFD_CLOEXEC | EFD_NONBLOCK : EFD_CLOEXEC);
- if(efd == -1) {
- socks[0] = socks[1] = CURL_SOCKET_BAD;
- return -1;
- }
- socks[0] = socks[1] = efd;
- return 0;
-}
-#elif defined(HAVE_PIPE)
-#ifdef HAVE_FCNTL
-#include <fcntl.h>
-#endif
-
-int Curl_pipe(curl_socket_t socks[2], bool nonblocking)
-{
- if(pipe(socks))
- return -1;
-#ifdef HAVE_FCNTL
- if(fcntl(socks[0], F_SETFD, FD_CLOEXEC) ||
- fcntl(socks[1], F_SETFD, FD_CLOEXEC) ) {
- close(socks[0]);
- close(socks[1]);
- socks[0] = socks[1] = CURL_SOCKET_BAD;
- return -1;
- }
-#endif
- if(nonblocking) {
- if(curlx_nonblock(socks[0], TRUE) < 0 ||
- curlx_nonblock(socks[1], TRUE) < 0) {
- close(socks[0]);
- close(socks[1]);
- socks[0] = socks[1] = CURL_SOCKET_BAD;
- return -1;
- }
- }
-
- return 0;
-}
-#endif
-
-
-#ifndef CURL_DISABLE_SOCKETPAIR
-#ifdef HAVE_SOCKETPAIR
-int Curl_socketpair(int domain, int type, int protocol,
- curl_socket_t socks[2], bool nonblocking)
-{
-#ifdef SOCK_NONBLOCK
- type = nonblocking ? type | SOCK_NONBLOCK : type;
-#endif
- if(socketpair(domain, type, protocol, socks))
- return -1;
-#ifndef SOCK_NONBLOCK
- if(nonblocking) {
- if(curlx_nonblock(socks[0], TRUE) < 0 ||
- curlx_nonblock(socks[1], TRUE) < 0) {
- close(socks[0]);
- close(socks[1]);
- return -1;
- }
- }
-#endif
- return 0;
-}
-#else /* !HAVE_SOCKETPAIR */
+#if !defined(HAVE_SOCKETPAIR) && !defined(CURL_DISABLE_SOCKETPAIR)
#ifdef _WIN32
/*
* This is a socketpair() implementation for Windows.
*/
#include <string.h>
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#include <windows.h>
#include <io.h>
#else
#ifdef HAVE_NETDB_H
@@ -129,7 +62,7 @@ int Curl_socketpair(int domain, int type, int protocol,
#include "memdebug.h"
int Curl_socketpair(int domain, int type, int protocol,
- curl_socket_t socks[2], bool nonblocking)
+ curl_socket_t socks[2])
{
union {
struct sockaddr_in inaddr;
@@ -155,7 +88,7 @@ int Curl_socketpair(int domain, int type, int protocol,
socks[0] = socks[1] = CURL_SOCKET_BAD;
#if defined(_WIN32) || defined(__CYGWIN__)
- /* do not set SO_REUSEADDR on Windows */
+ /* don't set SO_REUSEADDR on Windows */
(void)reuse;
#ifdef SO_EXCLUSIVEADDRUSE
{
@@ -183,7 +116,7 @@ int Curl_socketpair(int domain, int type, int protocol,
if(connect(socks[0], &a.addr, sizeof(a.inaddr)) == -1)
goto error;
- /* use non-blocking accept to make sure we do not block forever */
+ /* use non-blocking accept to make sure we don't block forever */
if(curlx_nonblock(listener, TRUE) < 0)
goto error;
pfd[0].fd = listener;
@@ -217,7 +150,7 @@ int Curl_socketpair(int domain, int type, int protocol,
nread = sread(socks[1], p, s);
if(nread == -1) {
int sockerr = SOCKERRNO;
- /* Do not block forever */
+ /* Don't block forever */
if(Curl_timediff(Curl_now(), start) > (60 * 1000))
goto error;
if(
@@ -247,10 +180,6 @@ int Curl_socketpair(int domain, int type, int protocol,
} while(1);
}
- if(nonblocking)
- if(curlx_nonblock(socks[0], TRUE) < 0 ||
- curlx_nonblock(socks[1], TRUE) < 0)
- goto error;
sclose(listener);
return 0;
@@ -260,5 +189,5 @@ error:
sclose(socks[1]);
return -1;
}
-#endif
-#endif /* !CURL_DISABLE_SOCKETPAIR */
+
+#endif /* ! HAVE_SOCKETPAIR */
diff --git a/contrib/libs/curl/lib/socketpair.h b/contrib/libs/curl/lib/socketpair.h
index 3044f1122e..bd499abbef 100644
--- a/contrib/libs/curl/lib/socketpair.h
+++ b/contrib/libs/curl/lib/socketpair.h
@@ -26,73 +26,29 @@
#include "curl_setup.h"
-#if defined(HAVE_EVENTFD) && \
- defined(__x86_64__) && \
- defined(__aarch64__) && \
- defined(__ia64__) && \
- defined(__ppc64__) && \
- defined(__mips64) && \
- defined(__sparc64__) && \
- defined(__riscv_64e) && \
- defined(__s390x__)
-
-/* Use eventfd only with 64-bit CPU architectures because eventfd has a
- * stringent rule of requiring the 8-byte buffer when calling read(2) and
- * write(2) on it. In some rare cases, the C standard library implementation
- * on a 32-bit system might choose to define uint64_t as a 32-bit type for
- * various reasons (memory limitations, compatibility with older code),
- * which makes eventfd broken.
- */
-#define USE_EVENTFD 1
+#ifdef HAVE_PIPE
#define wakeup_write write
#define wakeup_read read
#define wakeup_close close
-#define wakeup_create(p,nb) Curl_eventfd(p,nb)
-
-#include <curl/curl.h>
-int Curl_eventfd(curl_socket_t socks[2], bool nonblocking);
-
-#elif defined(HAVE_PIPE)
-
-#define wakeup_write write
-#define wakeup_read read
-#define wakeup_close close
-#define wakeup_create(p,nb) Curl_pipe(p,nb)
-
-#include <curl/curl.h>
-int Curl_pipe(curl_socket_t socks[2], bool nonblocking);
+#define wakeup_create pipe
-#else /* !USE_EVENTFD && !HAVE_PIPE */
+#else /* HAVE_PIPE */
#define wakeup_write swrite
#define wakeup_read sread
#define wakeup_close sclose
+#define wakeup_create(p) Curl_socketpair(AF_UNIX, SOCK_STREAM, 0, p)
-#if defined(USE_UNIX_SOCKETS) && defined(HAVE_SOCKETPAIR)
-#define SOCKETPAIR_FAMILY AF_UNIX
-#elif !defined(HAVE_SOCKETPAIR)
-#define SOCKETPAIR_FAMILY 0 /* not used */
-#else
-#error "unsupported Unix domain and socketpair build combo"
-#endif
+#endif /* HAVE_PIPE */
-#ifdef SOCK_CLOEXEC
-#define SOCKETPAIR_TYPE (SOCK_STREAM | SOCK_CLOEXEC)
-#else
-#define SOCKETPAIR_TYPE SOCK_STREAM
-#endif
-
-#define wakeup_create(p,nb)\
-Curl_socketpair(SOCKETPAIR_FAMILY, SOCKETPAIR_TYPE, 0, p, nb)
-
-#endif /* USE_EVENTFD */
-
-#ifndef CURL_DISABLE_SOCKETPAIR
+#ifndef HAVE_SOCKETPAIR
#include <curl/curl.h>
int Curl_socketpair(int domain, int type, int protocol,
- curl_socket_t socks[2], bool nonblocking);
+ curl_socket_t socks[2]);
+#else
+#define Curl_socketpair(a,b,c,d) socketpair(a,b,c,d)
#endif
#endif /* HEADER_CURL_SOCKETPAIR_H */
diff --git a/contrib/libs/curl/lib/socks.c b/contrib/libs/curl/lib/socks.c
index 1f2b7b6099..3a396de620 100644
--- a/contrib/libs/curl/lib/socks.c
+++ b/contrib/libs/curl/lib/socks.c
@@ -71,18 +71,9 @@ enum connect_t {
CONNECT_DONE /* 17 connected fine to the remote or the SOCKS proxy */
};
-#define CURL_SOCKS_BUF_SIZE 600
-
-/* make sure we configure it not too low */
-#if CURL_SOCKS_BUF_SIZE < 600
-#error CURL_SOCKS_BUF_SIZE must be at least 600
-#endif
-
-
struct socks_state {
enum connect_t state;
ssize_t outstanding; /* send this many bytes more */
- unsigned char buffer[CURL_SOCKS_BUF_SIZE];
unsigned char *outp; /* send from this pointer */
const char *hostname;
@@ -125,7 +116,7 @@ int Curl_blockread_all(struct Curl_cfilter *cf,
}
nread = Curl_conn_cf_recv(cf->next, data, buf, buffersize, &err);
if(nread <= 0) {
- result = (int)err;
+ result = err;
if(CURLE_AGAIN == err)
continue;
if(err) {
@@ -194,7 +185,7 @@ static void socksstate(struct socks_state *sx, struct Curl_easy *data,
(void)data;
if(oldstate == state)
- /* do not bother when the new state is the same as the old state */
+ /* don't bother when the new state is the same as the old state */
return;
sx->state = state;
@@ -217,7 +208,7 @@ static CURLproxycode socks_state_send(struct Curl_cfilter *cf,
CURLcode result;
nwritten = Curl_conn_cf_send(cf->next, data, (char *)sx->outp,
- sx->outstanding, FALSE, &result);
+ sx->outstanding, &result);
if(nwritten <= 0) {
if(CURLE_AGAIN == result) {
return CURLPX_OK;
@@ -258,7 +249,7 @@ static CURLproxycode socks_state_recv(struct Curl_cfilter *cf,
failf(data, "connection to proxy closed");
return CURLPX_CLOSED;
}
- failf(data, "SOCKS: Failed receiving %s: %s", description,
+ failf(data, "SOCKS4: Failed receiving %s: %s", description,
curl_easy_strerror(result));
return failcode;
}
@@ -287,11 +278,14 @@ static CURLproxycode do_SOCKS4(struct Curl_cfilter *cf,
struct connectdata *conn = cf->conn;
const bool protocol4a =
(conn->socks_proxy.proxytype == CURLPROXY_SOCKS4A) ? TRUE : FALSE;
- unsigned char *socksreq = sx->buffer;
+ unsigned char *socksreq = (unsigned char *)data->state.buffer;
CURLcode result;
CURLproxycode presult;
struct Curl_dns_entry *dns = NULL;
+ /* make sure that the buffer is at least 600 bytes */
+ DEBUGASSERT(READBUFFER_MIN >= 600);
+
switch(sx->state) {
case CONNECT_SOCKS_INIT:
/* SOCKS4 can only do IPv4, insist! */
@@ -335,18 +329,18 @@ static CURLproxycode do_SOCKS4(struct Curl_cfilter *cf,
goto CONNECT_RESOLVED;
}
- /* socks4a does not resolve anything locally */
+ /* socks4a doesn't resolve anything locally */
sxstate(sx, data, CONNECT_REQ_INIT);
goto CONNECT_REQ_INIT;
case CONNECT_RESOLVING:
/* check if we have the name resolved by now */
- dns = Curl_fetch_addr(data, sx->hostname, conn->primary.remote_port);
+ dns = Curl_fetch_addr(data, sx->hostname, (int)conn->port);
if(dns) {
#ifdef CURLRES_ASYNCH
- data->state.async.dns = dns;
- data->state.async.done = TRUE;
+ conn->resolve_async.dns = dns;
+ conn->resolve_async.done = TRUE;
#endif
infof(data, "Hostname '%s' was found", sx->hostname);
sxstate(sx, data, CONNECT_RESOLVED);
@@ -359,13 +353,12 @@ static CURLproxycode do_SOCKS4(struct Curl_cfilter *cf,
return CURLPX_OK;
}
}
- FALLTHROUGH();
- case CONNECT_RESOLVED:
+ /* FALLTHROUGH */
CONNECT_RESOLVED:
- {
+ case CONNECT_RESOLVED: {
struct Curl_addrinfo *hp = NULL;
/*
- * We cannot use 'hostent' as a struct that Curl_resolv() returns. It
+ * We cannot use 'hostent' as a struct that Curl_resolv() returns. It
* returns a Curl_addrinfo pointer that may not always look the same.
*/
if(dns) {
@@ -388,7 +381,7 @@ CONNECT_RESOLVED:
infof(data, "SOCKS4 connect to IPv4 %s (locally resolved)", buf);
- Curl_resolv_unlink(data, &dns); /* not used anymore from now on */
+ Curl_resolv_unlock(data, dns); /* not used anymore from now on */
}
else
failf(data, "SOCKS4 connection to %s not supported", sx->hostname);
@@ -400,9 +393,9 @@ CONNECT_RESOLVED:
if(!hp)
return CURLPX_RESOLVE_HOST;
}
- FALLTHROUGH();
- case CONNECT_REQ_INIT:
+ /* FALLTHROUGH */
CONNECT_REQ_INIT:
+ case CONNECT_REQ_INIT:
/*
* This is currently not supporting "Identification Protocol (RFC1413)".
*/
@@ -413,7 +406,7 @@ CONNECT_REQ_INIT:
/* there is no real size limit to this field in the protocol, but
SOCKS5 limits the proxy user field to 255 bytes and it seems likely
that a longer field is either a mistake or malicious input */
- failf(data, "Too long SOCKS proxy username");
+ failf(data, "Too long SOCKS proxy user name");
return CURLPX_LONG_USER;
}
/* copy the proxy name WITH trailing zero */
@@ -437,20 +430,19 @@ CONNECT_REQ_INIT:
/* append hostname */
hostnamelen = strlen(sx->hostname) + 1; /* length including NUL */
if((hostnamelen <= 255) &&
- (packetsize + hostnamelen < sizeof(sx->buffer)))
+ (packetsize + hostnamelen < data->set.buffer_size))
strcpy((char *)socksreq + packetsize, sx->hostname);
else {
- failf(data, "SOCKS4: too long hostname");
+ failf(data, "SOCKS4: too long host name");
return CURLPX_LONG_HOSTNAME;
}
packetsize += hostnamelen;
}
sx->outp = socksreq;
- DEBUGASSERT(packetsize <= sizeof(sx->buffer));
sx->outstanding = packetsize;
sxstate(sx, data, CONNECT_REQ_SENDING);
}
- FALLTHROUGH();
+ /* FALLTHROUGH */
case CONNECT_REQ_SENDING:
/* Send request */
presult = socks_state_send(cf, sx, data, CURLPX_SEND_CONNECT,
@@ -466,7 +458,7 @@ CONNECT_REQ_INIT:
sx->outp = socksreq;
sxstate(sx, data, CONNECT_SOCKS_READ);
- FALLTHROUGH();
+ /* FALLTHROUGH */
case CONNECT_SOCKS_READ:
/* Receive response */
presult = socks_state_recv(cf, sx, data, CURLPX_RECV_CONNECT,
@@ -516,7 +508,7 @@ CONNECT_REQ_INIT:
break;
case 91:
failf(data,
- "cannot complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
+ "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
", request rejected or failed.",
socksreq[4], socksreq[5], socksreq[6], socksreq[7],
(((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]),
@@ -524,7 +516,7 @@ CONNECT_REQ_INIT:
return CURLPX_REQUEST_FAILED;
case 92:
failf(data,
- "cannot complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
+ "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
", request rejected because SOCKS server cannot connect to "
"identd on the client.",
socksreq[4], socksreq[5], socksreq[6], socksreq[7],
@@ -533,7 +525,7 @@ CONNECT_REQ_INIT:
return CURLPX_IDENTD;
case 93:
failf(data,
- "cannot complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
+ "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
", request rejected because the client program and identd "
"report different user-ids.",
socksreq[4], socksreq[5], socksreq[6], socksreq[7],
@@ -542,7 +534,7 @@ CONNECT_REQ_INIT:
return CURLPX_IDENTD_DIFFER;
default:
failf(data,
- "cannot complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
+ "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
", Unknown.",
socksreq[4], socksreq[5], socksreq[6], socksreq[7],
(((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]),
@@ -562,7 +554,7 @@ static CURLproxycode do_SOCKS5(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
/*
- According to the RFC1928, section "6. Replies". This is what a SOCK5
+ According to the RFC1928, section "6. Replies". This is what a SOCK5
replies:
+----+-----+-------+------+----------+----------+
@@ -578,14 +570,14 @@ static CURLproxycode do_SOCKS5(struct Curl_cfilter *cf,
o X'00' succeeded
*/
struct connectdata *conn = cf->conn;
- unsigned char *socksreq = sx->buffer;
- size_t idx;
+ unsigned char *socksreq = (unsigned char *)data->state.buffer;
+ int idx;
CURLcode result;
CURLproxycode presult;
bool socks5_resolve_local =
(conn->socks_proxy.proxytype == CURLPROXY_SOCKS5) ? TRUE : FALSE;
const size_t hostname_len = strlen(sx->hostname);
- size_t len = 0;
+ ssize_t len = 0;
const unsigned char auth = data->set.socks5auth;
bool allow_gssapi = FALSE;
struct Curl_dns_entry *dns = NULL;
@@ -628,7 +620,6 @@ static CURLproxycode do_SOCKS5(struct Curl_cfilter *cf,
socksreq[1] = (unsigned char) (idx - 2);
sx->outp = socksreq;
- DEBUGASSERT(idx <= sizeof(sx->buffer));
sx->outstanding = idx;
presult = socks_state_send(cf, sx, data, CURLPX_SEND_CONNECT,
"initial SOCKS5 request");
@@ -649,12 +640,12 @@ static CURLproxycode do_SOCKS5(struct Curl_cfilter *cf,
/* remain in sending state */
return CURLPX_OK;
}
- FALLTHROUGH();
- case CONNECT_SOCKS_READ_INIT:
+ /* FALLTHROUGH */
CONNECT_SOCKS_READ_INIT:
+ case CONNECT_SOCKS_READ_INIT:
sx->outstanding = 2; /* expect two bytes */
sx->outp = socksreq; /* store it here */
- FALLTHROUGH();
+ /* FALLTHROUGH */
case CONNECT_SOCKS_READ:
presult = socks_state_recv(cf, sx, data, CURLPX_RECV_CONNECT,
"initial SOCKS5 response");
@@ -714,7 +705,7 @@ CONNECT_SOCKS_READ_INIT:
CONNECT_AUTH_INIT:
case CONNECT_AUTH_INIT: {
- /* Needs username and password */
+ /* Needs user name and password */
size_t proxy_user_len, proxy_password_len;
if(sx->proxy_user && sx->proxy_password) {
proxy_user_len = strlen(sx->proxy_user);
@@ -738,7 +729,7 @@ CONNECT_AUTH_INIT:
if(sx->proxy_user && proxy_user_len) {
/* the length must fit in a single byte */
if(proxy_user_len > 255) {
- failf(data, "Excessive username length for proxy auth");
+ failf(data, "Excessive user name length for proxy auth");
return CURLPX_LONG_USER;
}
memcpy(socksreq + len, sx->proxy_user, proxy_user_len);
@@ -755,11 +746,10 @@ CONNECT_AUTH_INIT:
}
len += proxy_password_len;
sxstate(sx, data, CONNECT_AUTH_SEND);
- DEBUGASSERT(len <= sizeof(sx->buffer));
sx->outstanding = len;
sx->outp = socksreq;
}
- FALLTHROUGH();
+ /* FALLTHROUGH */
case CONNECT_AUTH_SEND:
presult = socks_state_send(cf, sx, data, CURLPX_SEND_AUTH,
"SOCKS5 sub-negotiation request");
@@ -772,7 +762,7 @@ CONNECT_AUTH_INIT:
sx->outp = socksreq;
sx->outstanding = 2;
sxstate(sx, data, CONNECT_AUTH_READ);
- FALLTHROUGH();
+ /* FALLTHROUGH */
case CONNECT_AUTH_READ:
presult = socks_state_recv(cf, sx, data, CURLPX_RECV_AUTH,
"SOCKS5 sub-negotiation response");
@@ -791,9 +781,9 @@ CONNECT_AUTH_INIT:
/* Everything is good so far, user was authenticated! */
sxstate(sx, data, CONNECT_REQ_INIT);
- FALLTHROUGH();
- case CONNECT_REQ_INIT:
+ /* FALLTHROUGH */
CONNECT_REQ_INIT:
+ case CONNECT_REQ_INIT:
if(socks5_resolve_local) {
enum resolve_t rc = Curl_resolv(data, sx->hostname, sx->remote_port,
TRUE, &dns);
@@ -816,8 +806,8 @@ CONNECT_REQ_INIT:
if(dns) {
#ifdef CURLRES_ASYNCH
- data->state.async.dns = dns;
- data->state.async.done = TRUE;
+ conn->resolve_async.dns = dns;
+ conn->resolve_async.done = TRUE;
#endif
infof(data, "SOCKS5: hostname '%s' found", sx->hostname);
}
@@ -830,15 +820,14 @@ CONNECT_REQ_INIT:
return CURLPX_OK;
}
}
- FALLTHROUGH();
- case CONNECT_RESOLVED:
+ /* FALLTHROUGH */
CONNECT_RESOLVED:
- {
+ case CONNECT_RESOLVED: {
char dest[MAX_IPADR_LEN]; /* printable address */
struct Curl_addrinfo *hp = NULL;
if(dns)
hp = dns->addr;
-#ifdef USE_IPV6
+#ifdef ENABLE_IPV6
if(data->set.ipver != CURL_IPRESOLVE_WHATEVER) {
int wanted_family = data->set.ipver == CURL_IPRESOLVE_V4 ?
AF_INET : AF_INET6;
@@ -872,7 +861,7 @@ CONNECT_RESOLVED:
infof(data, "SOCKS5 connect to %s:%d (locally resolved)", dest,
sx->remote_port);
}
-#ifdef USE_IPV6
+#ifdef ENABLE_IPV6
else if(hp->ai_family == AF_INET6) {
int i;
struct sockaddr_in6 *saddr_in6;
@@ -893,7 +882,7 @@ CONNECT_RESOLVED:
failf(data, "SOCKS5 connection to %s not supported", dest);
}
- Curl_resolv_unlink(data, &dns); /* not used anymore from now on */
+ Curl_resolv_unlock(data, dns); /* not used anymore from now on */
goto CONNECT_REQ_SEND;
}
CONNECT_RESOLVE_REMOTE:
@@ -909,7 +898,7 @@ CONNECT_RESOLVE_REMOTE:
IPv6 == 4,
IPv4 == 1 */
unsigned char ip4[4];
-#ifdef USE_IPV6
+#ifdef ENABLE_IPV6
if(conn->bits.ipv6_ip) {
char ip6[16];
if(1 != Curl_inet_pton(AF_INET6, sx->hostname, ip6))
@@ -934,10 +923,10 @@ CONNECT_RESOLVE_REMOTE:
infof(data, "SOCKS5 connect to %s:%d (remotely resolved)",
sx->hostname, sx->remote_port);
}
- FALLTHROUGH();
+ /* FALLTHROUGH */
- case CONNECT_REQ_SEND:
CONNECT_REQ_SEND:
+ case CONNECT_REQ_SEND:
/* PORT MSB */
socksreq[len++] = (unsigned char)((sx->remote_port >> 8) & 0xff);
/* PORT LSB */
@@ -950,10 +939,9 @@ CONNECT_REQ_SEND:
}
#endif
sx->outp = socksreq;
- DEBUGASSERT(len <= sizeof(sx->buffer));
sx->outstanding = len;
sxstate(sx, data, CONNECT_REQ_SENDING);
- FALLTHROUGH();
+ /* FALLTHROUGH */
case CONNECT_REQ_SENDING:
presult = socks_state_send(cf, sx, data, CURLPX_SEND_REQUEST,
"SOCKS5 connect request");
@@ -972,7 +960,7 @@ CONNECT_REQ_SEND:
sx->outstanding = 10; /* minimum packet size is 10 */
sx->outp = socksreq;
sxstate(sx, data, CONNECT_REQ_READ);
- FALLTHROUGH();
+ /* FALLTHROUGH */
case CONNECT_REQ_READ:
presult = socks_state_recv(cf, sx, data, CURLPX_RECV_REQACK,
"SOCKS5 connect request ack");
@@ -990,7 +978,7 @@ CONNECT_REQ_SEND:
else if(socksreq[1]) { /* Anything besides 0 is an error */
CURLproxycode rc = CURLPX_REPLY_UNASSIGNED;
int code = socksreq[1];
- failf(data, "cannot complete SOCKS5 connection to %s. (%d)",
+ failf(data, "Can't complete SOCKS5 connection to %s. (%d)",
sx->hostname, (unsigned char)socksreq[1]);
if(code < 9) {
/* RFC 1928 section 6 lists: */
@@ -1050,7 +1038,6 @@ CONNECT_REQ_SEND:
/* decrypt_gssapi_blockread already read the whole packet */
#endif
if(len > 10) {
- DEBUGASSERT(len <= sizeof(sx->buffer));
sx->outstanding = len - 10; /* get the rest */
sx->outp = &socksreq[10];
sxstate(sx, data, CONNECT_REQ_READ_MORE);
@@ -1062,7 +1049,7 @@ CONNECT_REQ_SEND:
#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
}
#endif
- FALLTHROUGH();
+ /* FALLTHROUGH */
case CONNECT_REQ_READ_MORE:
presult = socks_state_recv(cf, sx, data, CURLPX_RECV_ADDRESS,
"SOCKS5 connect request address");
@@ -1120,7 +1107,7 @@ static void socks_proxy_cf_free(struct Curl_cfilter *cf)
}
/* After a TCP connection to the proxy has been verified, this function does
- the next magic steps. If 'done' is not set TRUE, it is not done yet and
+ the next magic steps. If 'done' isn't set TRUE, it is not done yet and
must be called again.
Note: this function's sub-functions call failf()
@@ -1175,7 +1162,7 @@ static CURLcode socks_proxy_cf_connect(struct Curl_cfilter *cf,
result = connect_SOCKS(cf, sx, data);
if(!result && sx->state == CONNECT_DONE) {
cf->connected = TRUE;
- Curl_verboseconnect(data, conn, cf->sockindex);
+ Curl_verboseconnect(data, conn);
socks_proxy_cf_free(cf);
}
@@ -1244,12 +1231,11 @@ static void socks_cf_get_host(struct Curl_cfilter *cf,
struct Curl_cftype Curl_cft_socks_proxy = {
"SOCKS-PROXYY",
- CF_TYPE_IP_CONNECT|CF_TYPE_PROXY,
+ CF_TYPE_IP_CONNECT,
0,
socks_proxy_cf_destroy,
socks_proxy_cf_connect,
socks_proxy_cf_close,
- Curl_cf_def_shutdown,
socks_cf_get_host,
socks_cf_adjust_pollset,
Curl_cf_def_data_pending,
diff --git a/contrib/libs/curl/lib/socks_gssapi.c b/contrib/libs/curl/lib/socks_gssapi.c
index 30fae9f8ff..8a8d1ce28e 100644
--- a/contrib/libs/curl/lib/socks_gssapi.c
+++ b/contrib/libs/curl/lib/socks_gssapi.c
@@ -35,7 +35,6 @@
#include "timeval.h"
#include "socks.h"
#include "warnless.h"
-#include "strdup.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@@ -140,9 +139,10 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf,
/* prepare service name */
if(strchr(serviceptr, '/')) {
service.length = serviceptr_length;
- service.value = Curl_memdup(serviceptr, service.length);
+ service.value = malloc(service.length);
if(!service.value)
return CURLE_OUT_OF_MEMORY;
+ memcpy(service.value, serviceptr, service.length);
gss_major_status = gss_import_name(&gss_minor_status, &service,
(gss_OID) GSS_C_NULL_OID, &server);
@@ -172,7 +172,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf,
(void)curlx_nonblock(sock, FALSE);
- /* As long as we need to keep sending some context info, and there is no */
+ /* As long as we need to keep sending some context info, and there's no */
/* errors, keep sending it... */
for(;;) {
gss_major_status = Curl_gss_init_sec_context(data,
@@ -201,11 +201,10 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf,
if(gss_send_token.length) {
socksreq[0] = 1; /* GSS-API subnegotiation version */
socksreq[1] = 1; /* authentication message type */
- us_length = htons((unsigned short)gss_send_token.length);
+ us_length = htons((short)gss_send_token.length);
memcpy(socksreq + 2, &us_length, sizeof(short));
- nwritten = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 4,
- FALSE, &code);
+ nwritten = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 4, &code);
if(code || (4 != nwritten)) {
failf(data, "Failed to send GSS-API authentication request.");
gss_release_name(&gss_status, &server);
@@ -217,7 +216,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf,
nwritten = Curl_conn_cf_send(cf->next, data,
(char *)gss_send_token.value,
- gss_send_token.length, FALSE, &code);
+ gss_send_token.length, &code);
if(code || ((ssize_t)gss_send_token.length != nwritten)) {
failf(data, "Failed to send GSS-API authentication token.");
gss_release_name(&gss_status, &server);
@@ -307,7 +306,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf,
gss_minor_status, "gss_inquire_context")) {
gss_delete_sec_context(&gss_status, &gss_context, NULL);
gss_release_name(&gss_status, &gss_client_name);
- failf(data, "Failed to determine username.");
+ failf(data, "Failed to determine user name.");
return CURLE_COULDNT_CONNECT;
}
gss_major_status = gss_display_name(&gss_minor_status, gss_client_name,
@@ -317,7 +316,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf,
gss_delete_sec_context(&gss_status, &gss_context, NULL);
gss_release_name(&gss_status, &gss_client_name);
gss_release_buffer(&gss_status, &gss_send_token);
- failf(data, "Failed to determine username.");
+ failf(data, "Failed to determine user name.");
return CURLE_COULDNT_CONNECT;
}
user = malloc(gss_send_token.length + 1);
@@ -378,7 +377,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf,
*
* The token is produced by encapsulating an octet containing the
* required protection level using gss_seal()/gss_wrap() with conf_req
- * set to FALSE. The token is verified using gss_unseal()/
+ * set to FALSE. The token is verified using gss_unseal()/
* gss_unwrap().
*
*/
@@ -388,11 +387,12 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf,
}
else {
gss_send_token.length = 1;
- gss_send_token.value = Curl_memdup(&gss_enc, 1);
+ gss_send_token.value = malloc(1);
if(!gss_send_token.value) {
gss_delete_sec_context(&gss_status, &gss_context, NULL);
return CURLE_OUT_OF_MEMORY;
}
+ memcpy(gss_send_token.value, &gss_enc, 1);
gss_major_status = gss_wrap(&gss_minor_status, gss_context, 0,
GSS_C_QOP_DEFAULT, &gss_send_token,
@@ -407,12 +407,11 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf,
}
gss_release_buffer(&gss_status, &gss_send_token);
- us_length = htons((unsigned short)gss_w_token.length);
+ us_length = htons((short)gss_w_token.length);
memcpy(socksreq + 2, &us_length, sizeof(short));
}
- nwritten = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 4, FALSE,
- &code);
+ nwritten = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 4, &code);
if(code || (4 != nwritten)) {
failf(data, "Failed to send GSS-API encryption request.");
gss_release_buffer(&gss_status, &gss_w_token);
@@ -422,8 +421,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf,
if(data->set.socks5_gssapi_nec) {
memcpy(socksreq, &gss_enc, 1);
- nwritten = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 1, FALSE,
- &code);
+ nwritten = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 1, &code);
if(code || ( 1 != nwritten)) {
failf(data, "Failed to send GSS-API encryption type.");
gss_delete_sec_context(&gss_status, &gss_context, NULL);
@@ -433,7 +431,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf,
else {
nwritten = Curl_conn_cf_send(cf->next, data,
(char *)gss_w_token.value,
- gss_w_token.length, FALSE, &code);
+ gss_w_token.length, &code);
if(code || ((ssize_t)gss_w_token.length != nwritten)) {
failf(data, "Failed to send GSS-API encryption type.");
gss_release_buffer(&gss_status, &gss_w_token);
@@ -478,7 +476,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf,
gss_recv_token.length, &actualread);
if(result || (actualread != us_length)) {
- failf(data, "Failed to receive GSS-API encryption type.");
+ failf(data, "Failed to receive GSS-API encryptrion type.");
gss_release_buffer(&gss_status, &gss_recv_token);
gss_delete_sec_context(&gss_status, &gss_context, NULL);
return CURLE_COULDNT_CONNECT;
diff --git a/contrib/libs/curl/lib/socks_sspi.c b/contrib/libs/curl/lib/socks_sspi.c
index a76d261804..d1200ea037 100644
--- a/contrib/libs/curl/lib/socks_sspi.c
+++ b/contrib/libs/curl/lib/socks_sspi.c
@@ -139,7 +139,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf,
cred_handle.dwLower = 0;
cred_handle.dwUpper = 0;
- status = Curl_pSecFn->AcquireCredentialsHandle(NULL,
+ status = s_pSecFn->AcquireCredentialsHandle(NULL,
(TCHAR *) TEXT("Kerberos"),
SECPKG_CRED_OUTBOUND,
NULL,
@@ -152,13 +152,13 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf,
if(check_sspi_err(data, status, "AcquireCredentialsHandle")) {
failf(data, "Failed to acquire credentials.");
free(service_name);
- Curl_pSecFn->FreeCredentialsHandle(&cred_handle);
+ s_pSecFn->FreeCredentialsHandle(&cred_handle);
return CURLE_COULDNT_CONNECT;
}
(void)curlx_nonblock(sock, FALSE);
- /* As long as we need to keep sending some context info, and there is no */
+ /* As long as we need to keep sending some context info, and there's no */
/* errors, keep sending it... */
for(;;) {
TCHAR *sname;
@@ -167,7 +167,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf,
if(!sname)
return CURLE_OUT_OF_MEMORY;
- status = Curl_pSecFn->InitializeSecurityContext(&cred_handle,
+ status = s_pSecFn->InitializeSecurityContext(&cred_handle,
context_handle,
sname,
ISC_REQ_MUTUAL_AUTH |
@@ -186,17 +186,17 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf,
curlx_unicodefree(sname);
if(sspi_recv_token.pvBuffer) {
- Curl_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer);
+ s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer);
sspi_recv_token.pvBuffer = NULL;
sspi_recv_token.cbBuffer = 0;
}
if(check_sspi_err(data, status, "InitializeSecurityContext")) {
free(service_name);
- Curl_pSecFn->FreeCredentialsHandle(&cred_handle);
- Curl_pSecFn->DeleteSecurityContext(&sspi_context);
+ s_pSecFn->FreeCredentialsHandle(&cred_handle);
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
if(sspi_recv_token.pvBuffer)
- Curl_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer);
+ s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer);
failf(data, "Failed to initialise security context.");
return CURLE_COULDNT_CONNECT;
}
@@ -204,48 +204,47 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf,
if(sspi_send_token.cbBuffer) {
socksreq[0] = 1; /* GSS-API subnegotiation version */
socksreq[1] = 1; /* authentication message type */
- us_length = htons((unsigned short)sspi_send_token.cbBuffer);
+ us_length = htons((short)sspi_send_token.cbBuffer);
memcpy(socksreq + 2, &us_length, sizeof(short));
- written = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 4, FALSE,
- &code);
+ written = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 4, &code);
if(code || (4 != written)) {
failf(data, "Failed to send SSPI authentication request.");
free(service_name);
if(sspi_send_token.pvBuffer)
- Curl_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer);
+ s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer);
if(sspi_recv_token.pvBuffer)
- Curl_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer);
- Curl_pSecFn->FreeCredentialsHandle(&cred_handle);
- Curl_pSecFn->DeleteSecurityContext(&sspi_context);
+ s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer);
+ s_pSecFn->FreeCredentialsHandle(&cred_handle);
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
return CURLE_COULDNT_CONNECT;
}
written = Curl_conn_cf_send(cf->next, data,
(char *)sspi_send_token.pvBuffer,
- sspi_send_token.cbBuffer, FALSE, &code);
+ sspi_send_token.cbBuffer, &code);
if(code || (sspi_send_token.cbBuffer != (size_t)written)) {
failf(data, "Failed to send SSPI authentication token.");
free(service_name);
if(sspi_send_token.pvBuffer)
- Curl_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer);
+ s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer);
if(sspi_recv_token.pvBuffer)
- Curl_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer);
- Curl_pSecFn->FreeCredentialsHandle(&cred_handle);
- Curl_pSecFn->DeleteSecurityContext(&sspi_context);
+ s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer);
+ s_pSecFn->FreeCredentialsHandle(&cred_handle);
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
return CURLE_COULDNT_CONNECT;
}
}
if(sspi_send_token.pvBuffer) {
- Curl_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer);
+ s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer);
sspi_send_token.pvBuffer = NULL;
}
sspi_send_token.cbBuffer = 0;
if(sspi_recv_token.pvBuffer) {
- Curl_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer);
+ s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer);
sspi_recv_token.pvBuffer = NULL;
}
sspi_recv_token.cbBuffer = 0;
@@ -267,8 +266,8 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf,
if(result || (actualread != 4)) {
failf(data, "Failed to receive SSPI authentication response.");
free(service_name);
- Curl_pSecFn->FreeCredentialsHandle(&cred_handle);
- Curl_pSecFn->DeleteSecurityContext(&sspi_context);
+ s_pSecFn->FreeCredentialsHandle(&cred_handle);
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
return CURLE_COULDNT_CONNECT;
}
@@ -277,8 +276,8 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf,
failf(data, "User was rejected by the SOCKS5 server (%u %u).",
(unsigned int)socksreq[0], (unsigned int)socksreq[1]);
free(service_name);
- Curl_pSecFn->FreeCredentialsHandle(&cred_handle);
- Curl_pSecFn->DeleteSecurityContext(&sspi_context);
+ s_pSecFn->FreeCredentialsHandle(&cred_handle);
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
return CURLE_COULDNT_CONNECT;
}
@@ -286,8 +285,8 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf,
failf(data, "Invalid SSPI authentication response type (%u %u).",
(unsigned int)socksreq[0], (unsigned int)socksreq[1]);
free(service_name);
- Curl_pSecFn->FreeCredentialsHandle(&cred_handle);
- Curl_pSecFn->DeleteSecurityContext(&sspi_context);
+ s_pSecFn->FreeCredentialsHandle(&cred_handle);
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
return CURLE_COULDNT_CONNECT;
}
@@ -299,8 +298,8 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf,
if(!sspi_recv_token.pvBuffer) {
free(service_name);
- Curl_pSecFn->FreeCredentialsHandle(&cred_handle);
- Curl_pSecFn->DeleteSecurityContext(&sspi_context);
+ s_pSecFn->FreeCredentialsHandle(&cred_handle);
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
return CURLE_OUT_OF_MEMORY;
}
result = Curl_blockread_all(cf, data, (char *)sspi_recv_token.pvBuffer,
@@ -310,9 +309,9 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf,
failf(data, "Failed to receive SSPI authentication token.");
free(service_name);
if(sspi_recv_token.pvBuffer)
- Curl_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer);
- Curl_pSecFn->FreeCredentialsHandle(&cred_handle);
- Curl_pSecFn->DeleteSecurityContext(&sspi_context);
+ s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer);
+ s_pSecFn->FreeCredentialsHandle(&cred_handle);
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
return CURLE_COULDNT_CONNECT;
}
@@ -322,25 +321,19 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf,
free(service_name);
/* Everything is good so far, user was authenticated! */
- status = Curl_pSecFn->QueryCredentialsAttributes(&cred_handle,
+ status = s_pSecFn->QueryCredentialsAttributes(&cred_handle,
SECPKG_CRED_ATTR_NAMES,
&names);
- Curl_pSecFn->FreeCredentialsHandle(&cred_handle);
+ s_pSecFn->FreeCredentialsHandle(&cred_handle);
if(check_sspi_err(data, status, "QueryCredentialAttributes")) {
- Curl_pSecFn->DeleteSecurityContext(&sspi_context);
- Curl_pSecFn->FreeContextBuffer(names.sUserName);
- failf(data, "Failed to determine username.");
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
+ s_pSecFn->FreeContextBuffer(names.sUserName);
+ failf(data, "Failed to determine user name.");
return CURLE_COULDNT_CONNECT;
}
- else {
-#ifndef CURL_DISABLE_VERBOSE_STRINGS
- char *user_utf8 = curlx_convert_tchar_to_UTF8(names.sUserName);
- infof(data, "SOCKS5 server authenticated user %s with GSS-API.",
- (user_utf8 ? user_utf8 : "(unknown)"));
- curlx_unicodefree(user_utf8);
-#endif
- Curl_pSecFn->FreeContextBuffer(names.sUserName);
- }
+ infof(data, "SOCKS5 server authenticated user %s with GSS-API.",
+ names.sUserName);
+ s_pSecFn->FreeContextBuffer(names.sUserName);
/* Do encryption */
socksreq[0] = 1; /* GSS-API subnegotiation version */
@@ -384,21 +377,21 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf,
*
* The token is produced by encapsulating an octet containing the
* required protection level using gss_seal()/gss_wrap() with conf_req
- * set to FALSE. The token is verified using gss_unseal()/
+ * set to FALSE. The token is verified using gss_unseal()/
* gss_unwrap().
*
*/
if(data->set.socks5_gssapi_nec) {
- us_length = htons((unsigned short)1);
+ us_length = htons((short)1);
memcpy(socksreq + 2, &us_length, sizeof(short));
}
else {
- status = Curl_pSecFn->QueryContextAttributes(&sspi_context,
+ status = s_pSecFn->QueryContextAttributes(&sspi_context,
SECPKG_ATTR_SIZES,
&sspi_sizes);
if(check_sspi_err(data, status, "QueryContextAttributes")) {
- Curl_pSecFn->DeleteSecurityContext(&sspi_context);
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
failf(data, "Failed to query security context attributes.");
return CURLE_COULDNT_CONNECT;
}
@@ -408,15 +401,15 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf,
sspi_w_token[0].pvBuffer = malloc(sspi_sizes.cbSecurityTrailer);
if(!sspi_w_token[0].pvBuffer) {
- Curl_pSecFn->DeleteSecurityContext(&sspi_context);
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
return CURLE_OUT_OF_MEMORY;
}
sspi_w_token[1].cbBuffer = 1;
sspi_w_token[1].pvBuffer = malloc(1);
if(!sspi_w_token[1].pvBuffer) {
- Curl_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
- Curl_pSecFn->DeleteSecurityContext(&sspi_context);
+ s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
return CURLE_OUT_OF_MEMORY;
}
@@ -425,20 +418,20 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf,
sspi_w_token[2].cbBuffer = sspi_sizes.cbBlockSize;
sspi_w_token[2].pvBuffer = malloc(sspi_sizes.cbBlockSize);
if(!sspi_w_token[2].pvBuffer) {
- Curl_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
- Curl_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer);
- Curl_pSecFn->DeleteSecurityContext(&sspi_context);
+ s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
+ s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer);
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
return CURLE_OUT_OF_MEMORY;
}
- status = Curl_pSecFn->EncryptMessage(&sspi_context,
+ status = s_pSecFn->EncryptMessage(&sspi_context,
KERB_WRAP_NO_ENCRYPT,
&wrap_desc,
0);
if(check_sspi_err(data, status, "EncryptMessage")) {
- Curl_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
- Curl_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer);
- Curl_pSecFn->FreeContextBuffer(sspi_w_token[2].pvBuffer);
- Curl_pSecFn->DeleteSecurityContext(&sspi_context);
+ s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
+ s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer);
+ s_pSecFn->FreeContextBuffer(sspi_w_token[2].pvBuffer);
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
failf(data, "Failed to query security context attributes.");
return CURLE_COULDNT_CONNECT;
}
@@ -447,10 +440,10 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf,
+ sspi_w_token[2].cbBuffer;
sspi_send_token.pvBuffer = malloc(sspi_send_token.cbBuffer);
if(!sspi_send_token.pvBuffer) {
- Curl_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
- Curl_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer);
- Curl_pSecFn->FreeContextBuffer(sspi_w_token[2].pvBuffer);
- Curl_pSecFn->DeleteSecurityContext(&sspi_context);
+ s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
+ s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer);
+ s_pSecFn->FreeContextBuffer(sspi_w_token[2].pvBuffer);
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
return CURLE_OUT_OF_MEMORY;
}
@@ -463,59 +456,57 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf,
+ sspi_w_token[1].cbBuffer,
sspi_w_token[2].pvBuffer, sspi_w_token[2].cbBuffer);
- Curl_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
+ s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
sspi_w_token[0].pvBuffer = NULL;
sspi_w_token[0].cbBuffer = 0;
- Curl_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer);
+ s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer);
sspi_w_token[1].pvBuffer = NULL;
sspi_w_token[1].cbBuffer = 0;
- Curl_pSecFn->FreeContextBuffer(sspi_w_token[2].pvBuffer);
+ s_pSecFn->FreeContextBuffer(sspi_w_token[2].pvBuffer);
sspi_w_token[2].pvBuffer = NULL;
sspi_w_token[2].cbBuffer = 0;
- us_length = htons((unsigned short)sspi_send_token.cbBuffer);
+ us_length = htons((short)sspi_send_token.cbBuffer);
memcpy(socksreq + 2, &us_length, sizeof(short));
}
- written = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 4, FALSE,
- &code);
+ written = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 4, &code);
if(code || (4 != written)) {
failf(data, "Failed to send SSPI encryption request.");
if(sspi_send_token.pvBuffer)
- Curl_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer);
- Curl_pSecFn->DeleteSecurityContext(&sspi_context);
+ s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer);
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
return CURLE_COULDNT_CONNECT;
}
if(data->set.socks5_gssapi_nec) {
memcpy(socksreq, &gss_enc, 1);
- written = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 1, FALSE,
- &code);
+ written = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 1, &code);
if(code || (1 != written)) {
failf(data, "Failed to send SSPI encryption type.");
- Curl_pSecFn->DeleteSecurityContext(&sspi_context);
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
return CURLE_COULDNT_CONNECT;
}
}
else {
written = Curl_conn_cf_send(cf->next, data,
(char *)sspi_send_token.pvBuffer,
- sspi_send_token.cbBuffer, FALSE, &code);
+ sspi_send_token.cbBuffer, &code);
if(code || (sspi_send_token.cbBuffer != (size_t)written)) {
failf(data, "Failed to send SSPI encryption type.");
if(sspi_send_token.pvBuffer)
- Curl_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer);
- Curl_pSecFn->DeleteSecurityContext(&sspi_context);
+ s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer);
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
return CURLE_COULDNT_CONNECT;
}
if(sspi_send_token.pvBuffer)
- Curl_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer);
+ s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer);
}
result = Curl_blockread_all(cf, data, (char *)socksreq, 4, &actualread);
if(result || (actualread != 4)) {
failf(data, "Failed to receive SSPI encryption response.");
- Curl_pSecFn->DeleteSecurityContext(&sspi_context);
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
return CURLE_COULDNT_CONNECT;
}
@@ -523,14 +514,14 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf,
if(socksreq[1] == 255) { /* status / message type */
failf(data, "User was rejected by the SOCKS5 server (%u %u).",
(unsigned int)socksreq[0], (unsigned int)socksreq[1]);
- Curl_pSecFn->DeleteSecurityContext(&sspi_context);
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
return CURLE_COULDNT_CONNECT;
}
if(socksreq[1] != 2) { /* status / message type */
failf(data, "Invalid SSPI encryption response type (%u %u).",
(unsigned int)socksreq[0], (unsigned int)socksreq[1]);
- Curl_pSecFn->DeleteSecurityContext(&sspi_context);
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
return CURLE_COULDNT_CONNECT;
}
@@ -540,7 +531,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf,
sspi_w_token[0].cbBuffer = us_length;
sspi_w_token[0].pvBuffer = malloc(us_length);
if(!sspi_w_token[0].pvBuffer) {
- Curl_pSecFn->DeleteSecurityContext(&sspi_context);
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
return CURLE_OUT_OF_MEMORY;
}
@@ -549,8 +540,8 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf,
if(result || (actualread != us_length)) {
failf(data, "Failed to receive SSPI encryption type.");
- Curl_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
- Curl_pSecFn->DeleteSecurityContext(&sspi_context);
+ s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
return CURLE_COULDNT_CONNECT;
}
@@ -562,17 +553,17 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf,
sspi_w_token[1].cbBuffer = 0;
sspi_w_token[1].pvBuffer = NULL;
- status = Curl_pSecFn->DecryptMessage(&sspi_context,
+ status = s_pSecFn->DecryptMessage(&sspi_context,
&wrap_desc,
0,
&qop);
if(check_sspi_err(data, status, "DecryptMessage")) {
if(sspi_w_token[0].pvBuffer)
- Curl_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
+ s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
if(sspi_w_token[1].pvBuffer)
- Curl_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer);
- Curl_pSecFn->DeleteSecurityContext(&sspi_context);
+ s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer);
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
failf(data, "Failed to query security context attributes.");
return CURLE_COULDNT_CONNECT;
}
@@ -581,27 +572,27 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf,
failf(data, "Invalid SSPI encryption response length (%lu).",
(unsigned long)sspi_w_token[1].cbBuffer);
if(sspi_w_token[0].pvBuffer)
- Curl_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
+ s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
if(sspi_w_token[1].pvBuffer)
- Curl_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer);
- Curl_pSecFn->DeleteSecurityContext(&sspi_context);
+ s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer);
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
return CURLE_COULDNT_CONNECT;
}
memcpy(socksreq, sspi_w_token[1].pvBuffer, sspi_w_token[1].cbBuffer);
- Curl_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
- Curl_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer);
+ s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
+ s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer);
}
else {
if(sspi_w_token[0].cbBuffer != 1) {
failf(data, "Invalid SSPI encryption response length (%lu).",
(unsigned long)sspi_w_token[0].cbBuffer);
- Curl_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
- Curl_pSecFn->DeleteSecurityContext(&sspi_context);
+ s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
return CURLE_COULDNT_CONNECT;
}
memcpy(socksreq, sspi_w_token[0].pvBuffer, sspi_w_token[0].cbBuffer);
- Curl_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
+ s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
}
(void)curlx_nonblock(sock, TRUE);
@@ -614,7 +605,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf,
if(socksreq[0] != 0)
conn->socks5_sspi_context = sspi_context;
else {
- Curl_pSecFn->DeleteSecurityContext(&sspi_context);
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
conn->socks5_sspi_context = sspi_context;
}
*/
diff --git a/contrib/libs/curl/lib/splay.c b/contrib/libs/curl/lib/splay.c
index 5e27b08a6c..48e079b32a 100644
--- a/contrib/libs/curl/lib/splay.c
+++ b/contrib/libs/curl/lib/splay.c
@@ -24,7 +24,6 @@
#include "curl_setup.h"
-#include "timeval.h"
#include "splay.h"
/*
@@ -34,7 +33,7 @@
* zero : when i is equal to j
* positive when : when i is larger than j
*/
-#define compare(i,j) Curl_timediff_us(i,j)
+#define compare(i,j) Curl_splaycomparekeys((i),(j))
/*
* Splay using the key i (which may or may not be in the tree.) The starting
@@ -46,12 +45,12 @@ struct Curl_tree *Curl_splay(struct curltime i,
struct Curl_tree N, *l, *r, *y;
if(!t)
- return NULL;
+ return t;
N.smaller = N.larger = NULL;
l = r = &N;
for(;;) {
- timediff_t comp = compare(i, t->key);
+ long comp = compare(i, t->key);
if(comp < 0) {
if(!t->smaller)
break;
@@ -94,7 +93,7 @@ struct Curl_tree *Curl_splay(struct curltime i,
return t;
}
-/* Insert key i into the tree t. Return a pointer to the resulting tree or
+/* Insert key i into the tree t. Return a pointer to the resulting tree or
* NULL if something went wrong.
*
* @unittest: 1309
@@ -107,11 +106,11 @@ struct Curl_tree *Curl_splayinsert(struct curltime i,
~0, -1
}; /* will *NEVER* appear */
- DEBUGASSERT(node);
+ if(!node)
+ return t;
if(t) {
t = Curl_splay(i, t);
- DEBUGASSERT(t);
if(compare(i, t->key) == 0) {
/* There already exists a node in the tree with the very same key. Build
a doubly-linked circular list of nodes. We add the new 'node' struct
@@ -151,7 +150,7 @@ struct Curl_tree *Curl_splayinsert(struct curltime i,
}
/* Finds and deletes the best-fit node from the tree. Return a pointer to the
- resulting tree. best-fit means the smallest node if it is not larger than
+ resulting tree. best-fit means the smallest node if it is not larger than
the key */
struct Curl_tree *Curl_splaygetbest(struct curltime i,
struct Curl_tree *t,
@@ -167,7 +166,6 @@ struct Curl_tree *Curl_splaygetbest(struct curltime i,
/* find smallest */
t = Curl_splay(tv_zero, t);
- DEBUGASSERT(t);
if(compare(i, t->key) < 0) {
/* even the smallest is too big */
*removed = NULL;
@@ -199,13 +197,13 @@ struct Curl_tree *Curl_splaygetbest(struct curltime i,
}
-/* Deletes the very node we point out from the tree if it is there. Stores a
+/* Deletes the very node we point out from the tree if it's there. Stores a
* pointer to the new resulting tree in 'newroot'.
*
* Returns zero on success and non-zero on errors!
* When returning error, it does not touch the 'newroot' pointer.
*
- * NOTE: when the last node of the tree is removed, there is no tree left so
+ * NOTE: when the last node of the tree is removed, there's no tree left so
* 'newroot' will be made to point to NULL.
*
* @unittest: 1309
@@ -219,11 +217,9 @@ int Curl_splayremove(struct Curl_tree *t,
}; /* will *NEVER* appear */
struct Curl_tree *x;
- if(!t)
+ if(!t || !removenode)
return 1;
- DEBUGASSERT(removenode);
-
if(compare(KEY_NOTUSED, removenode->key) == 0) {
/* Key set to NOTUSED means it is a subnode within a 'same' linked list
and thus we can unlink it easily. */
@@ -242,11 +238,10 @@ int Curl_splayremove(struct Curl_tree *t,
}
t = Curl_splay(removenode->key, t);
- DEBUGASSERT(t);
/* First make sure that we got the same root node as the one we want
to remove, as otherwise we might be trying to remove a node that
- is not actually in the tree.
+ isn't actually in the tree.
We cannot just compare the keys here as a double remove in quick
succession of a node with key != KEY_NOTUSED && same != NULL
@@ -254,7 +249,7 @@ int Curl_splayremove(struct Curl_tree *t,
if(t != removenode)
return 2;
- /* Check if there is a list with identical sizes, as then we are trying to
+ /* Check if there is a list with identical sizes, as then we're trying to
remove the root node of a list of nodes with identical keys. */
x = t->samen;
if(x != t) {
@@ -273,7 +268,6 @@ int Curl_splayremove(struct Curl_tree *t,
x = t->larger;
else {
x = Curl_splay(removenode->key, t->smaller);
- DEBUGASSERT(x);
x->larger = t->larger;
}
}
@@ -282,16 +276,3 @@ int Curl_splayremove(struct Curl_tree *t,
return 0;
}
-
-/* set and get the custom payload for this tree node */
-void Curl_splayset(struct Curl_tree *node, void *payload)
-{
- DEBUGASSERT(node);
- node->ptr = payload;
-}
-
-void *Curl_splayget(struct Curl_tree *node)
-{
- DEBUGASSERT(node);
- return node->ptr;
-}
diff --git a/contrib/libs/curl/lib/splay.h b/contrib/libs/curl/lib/splay.h
index b8c9360e57..dd1d07ac2e 100644
--- a/contrib/libs/curl/lib/splay.h
+++ b/contrib/libs/curl/lib/splay.h
@@ -26,14 +26,13 @@
#include "curl_setup.h"
#include "timeval.h"
-/* only use function calls to access this struct */
struct Curl_tree {
struct Curl_tree *smaller; /* smaller node */
struct Curl_tree *larger; /* larger node */
struct Curl_tree *samen; /* points to the next node with identical key */
struct Curl_tree *samep; /* points to the prev node with identical key */
- struct curltime key; /* this node's "sort" key */
- void *ptr; /* data the splay code does not care about */
+ struct curltime key; /* this node's "sort" key */
+ void *payload; /* data the splay code doesn't care about */
};
struct Curl_tree *Curl_splay(struct curltime i,
@@ -51,8 +50,9 @@ int Curl_splayremove(struct Curl_tree *t,
struct Curl_tree *removenode,
struct Curl_tree **newroot);
-/* set and get the custom payload for this tree node */
-void Curl_splayset(struct Curl_tree *node, void *payload);
-void *Curl_splayget(struct Curl_tree *node);
+#define Curl_splaycomparekeys(i,j) ( ((i.tv_sec) < (j.tv_sec)) ? -1 : \
+ ( ((i.tv_sec) > (j.tv_sec)) ? 1 : \
+ ( ((i.tv_usec) < (j.tv_usec)) ? -1 : \
+ ( ((i.tv_usec) > (j.tv_usec)) ? 1 : 0))))
#endif /* HEADER_CURL_SPLAY_H */
diff --git a/contrib/libs/curl/lib/strcase.c b/contrib/libs/curl/lib/strcase.c
index b22dd31fc8..7c0b4ef909 100644
--- a/contrib/libs/curl/lib/strcase.c
+++ b/contrib/libs/curl/lib/strcase.c
@@ -71,7 +71,7 @@ static const unsigned char tolowermap[256] = {
altered by the current locale. */
char Curl_raw_toupper(char in)
{
- return (char)touppermap[(unsigned char) in];
+ return touppermap[(unsigned char) in];
}
@@ -79,7 +79,7 @@ char Curl_raw_toupper(char in)
altered by the current locale. */
char Curl_raw_tolower(char in)
{
- return (char)tolowermap[(unsigned char) in];
+ return tolowermap[(unsigned char) in];
}
/*
@@ -93,12 +93,12 @@ static int casecompare(const char *first, const char *second)
{
while(*first && *second) {
if(Curl_raw_toupper(*first) != Curl_raw_toupper(*second))
- /* get out of the loop as soon as they do not match */
+ /* get out of the loop as soon as they don't match */
return 0;
first++;
second++;
}
- /* If we are here either the strings are the same or the length is different.
+ /* If we're here either the strings are the same or the length is different.
We can just test if the "current" character is non-zero for one and zero
for the other. Note that the characters may not be exactly the same even
if they match, we only want to compare zero-ness. */
@@ -141,8 +141,8 @@ int curl_strnequal(const char *first, const char *second, size_t max)
/* if both pointers are NULL then treat them as equal if max is non-zero */
return (NULL == first && NULL == second && max);
}
-/* Copy an upper case version of the string from src to dest. The
- * strings may overlap. No more than n characters of the string are copied
+/* Copy an upper case version of the string from src to dest. The
+ * strings may overlap. No more than n characters of the string are copied
* (including any NUL) and the destination string will NOT be
* NUL-terminated if that limit is reached.
*/
@@ -156,8 +156,8 @@ void Curl_strntoupper(char *dest, const char *src, size_t n)
} while(*src++ && --n);
}
-/* Copy a lower case version of the string from src to dest. The
- * strings may overlap. No more than n characters of the string are copied
+/* Copy a lower case version of the string from src to dest. The
+ * strings may overlap. No more than n characters of the string are copied
* (including any NUL) and the destination string will NOT be
* NUL-terminated if that limit is reached.
*/
diff --git a/contrib/libs/curl/lib/strdup.c b/contrib/libs/curl/lib/strdup.c
index 299c9cc36b..2578441c31 100644
--- a/contrib/libs/curl/lib/strdup.c
+++ b/contrib/libs/curl/lib/strdup.c
@@ -101,17 +101,21 @@ void *Curl_memdup(const void *src, size_t length)
/***************************************************************************
*
- * Curl_memdup0(source, length)
+ * Curl_strndup(source, length)
*
* Copies the 'source' string to a newly allocated buffer (that is returned).
- * Copies 'length' bytes then adds a null terminator.
+ * Copies not more than 'length' bytes (up to a null terminator) then adds a
+ * null terminator.
*
* Returns the new pointer or NULL on failure.
*
***************************************************************************/
-void *Curl_memdup0(const char *src, size_t length)
+void *Curl_strndup(const char *src, size_t length)
{
- char *buf = malloc(length + 1);
+ char *buf = memchr(src, '\0', length);
+ if(buf)
+ length = buf - src;
+ buf = malloc(length + 1);
if(!buf)
return NULL;
memcpy(buf, src, length);
diff --git a/contrib/libs/curl/lib/strdup.h b/contrib/libs/curl/lib/strdup.h
index 238a2611f6..9f12b25482 100644
--- a/contrib/libs/curl/lib/strdup.h
+++ b/contrib/libs/curl/lib/strdup.h
@@ -33,6 +33,6 @@ wchar_t* Curl_wcsdup(const wchar_t* src);
#endif
void *Curl_memdup(const void *src, size_t buffer_length);
void *Curl_saferealloc(void *ptr, size_t size);
-void *Curl_memdup0(const char *src, size_t length);
+void *Curl_strndup(const char *src, size_t length);
#endif /* HEADER_CURL_STRDUP_H */
diff --git a/contrib/libs/curl/lib/strerror.c b/contrib/libs/curl/lib/strerror.c
index 96b41a8cde..bdc1bcc729 100644
--- a/contrib/libs/curl/lib/strerror.c
+++ b/contrib/libs/curl/lib/strerror.c
@@ -74,13 +74,13 @@ curl_easy_strerror(CURLcode error)
" this libcurl due to a build-time decision.";
case CURLE_COULDNT_RESOLVE_PROXY:
- return "Could not resolve proxy name";
+ return "Couldn't resolve proxy name";
case CURLE_COULDNT_RESOLVE_HOST:
- return "Could not resolve hostname";
+ return "Couldn't resolve host name";
case CURLE_COULDNT_CONNECT:
- return "Could not connect to server";
+ return "Couldn't connect to server";
case CURLE_WEIRD_SERVER_REPLY:
return "Weird server reply";
@@ -107,19 +107,19 @@ curl_easy_strerror(CURLcode error)
return "FTP: unknown 227 response format";
case CURLE_FTP_CANT_GET_HOST:
- return "FTP: cannot figure out the host in the PASV response";
+ return "FTP: can't figure out the host in the PASV response";
case CURLE_HTTP2:
return "Error in the HTTP2 framing layer";
case CURLE_FTP_COULDNT_SET_TYPE:
- return "FTP: could not set file type";
+ return "FTP: couldn't set file type";
case CURLE_PARTIAL_FILE:
return "Transferred a partial file";
case CURLE_FTP_COULDNT_RETR_FILE:
- return "FTP: could not retrieve (RETR failed) the specified file";
+ return "FTP: couldn't retrieve (RETR failed) the specified file";
case CURLE_QUOTE_ERROR:
return "Quote command returned error";
@@ -158,10 +158,10 @@ curl_easy_strerror(CURLcode error)
return "SSL connect error";
case CURLE_BAD_DOWNLOAD_RESUME:
- return "Could not resume download";
+ return "Couldn't resume download";
case CURLE_FILE_COULDNT_READ_FILE:
- return "Could not read a file:// file";
+ return "Couldn't read a file:// file";
case CURLE_LDAP_CANNOT_BIND:
return "LDAP: cannot bind";
@@ -212,7 +212,7 @@ curl_easy_strerror(CURLcode error)
return "Problem with the local SSL certificate";
case CURLE_SSL_CIPHER:
- return "Could not use specified SSL cipher";
+ return "Couldn't use specified SSL cipher";
case CURLE_PEER_FAILED_VERIFICATION:
return "SSL peer certificate or SSH remote key was not OK";
@@ -319,12 +319,6 @@ curl_easy_strerror(CURLcode error)
case CURLE_UNRECOVERABLE_POLL:
return "Unrecoverable error in select/poll";
- case CURLE_TOO_LARGE:
- return "A value or data field grew larger than allowed";
-
- case CURLE_ECH_REQUIRED:
- return "ECH attempted but failed";
-
/* error codes not used by current libcurl */
case CURLE_OBSOLETE20:
case CURLE_OBSOLETE24:
@@ -345,15 +339,16 @@ curl_easy_strerror(CURLcode error)
/*
* By using a switch, gcc -Wall will complain about enum values
* which do not appear, helping keep this function up-to-date.
- * By using gcc -Wall -Werror, you cannot forget.
+ * By using gcc -Wall -Werror, you can't forget.
*
- * A table would not have the same benefit. Most compilers will generate
- * code very similar to a table in any case, so there is little performance
- * gain from a table. Something is broken for the user's application,
- * anyways, so does it matter how fast it _does not_ work?
+ * A table would not have the same benefit. Most compilers will
+ * generate code very similar to a table in any case, so there
+ * is little performance gain from a table. And something is broken
+ * for the user's application, anyways, so does it matter how fast
+ * it _doesn't_ work?
*
- * The line number for the error will be near this comment, which is why it
- * is here, and not at the start of the switch.
+ * The line number for the error will be near this comment, which
+ * is why it is here, and not at the start of the switch.
*/
return "Unknown error";
#else
@@ -558,9 +553,6 @@ curl_url_strerror(CURLUcode error)
case CURLUE_LACKS_IDN:
return "libcurl lacks IDN support";
- case CURLUE_TOO_LARGE:
- return "A value or data field is larger than allowed";
-
case CURLUE_LAST:
break;
}
@@ -580,11 +572,10 @@ curl_url_strerror(CURLUcode error)
* Returns NULL if no error message was found for error code.
*/
static const char *
-get_winsock_error(int err, char *buf, size_t len)
+get_winsock_error (int err, char *buf, size_t len)
{
#ifndef CURL_DISABLE_VERBOSE_STRINGS
const char *p;
- size_t alen;
#endif
if(!len)
@@ -764,9 +755,8 @@ get_winsock_error(int err, char *buf, size_t len)
default:
return NULL;
}
- alen = strlen(p);
- if(alen < len)
- strcpy(buf, p);
+ strncpy(buf, p, len);
+ buf [len-1] = '\0';
return buf;
#endif
}
@@ -794,7 +784,7 @@ get_winapi_error(int err, char *buf, size_t buflen)
expect the local codepage (eg fprintf, failf, infof).
FormatMessageW -> wcstombs is used for Windows CE compatibility. */
if(FormatMessageW((FORMAT_MESSAGE_FROM_SYSTEM |
- FORMAT_MESSAGE_IGNORE_INSERTS), NULL, (DWORD)err,
+ FORMAT_MESSAGE_IGNORE_INSERTS), NULL, err,
LANG_NEUTRAL, wbuf, sizeof(wbuf)/sizeof(wchar_t), NULL)) {
size_t written = wcstombs(buf, wbuf, buflen - 1);
if(written != (size_t)-1)
@@ -822,9 +812,9 @@ get_winapi_error(int err, char *buf, size_t buflen)
* The 'err' argument passed in to this function MUST be a true errno number
* as reported on this system. We do no range checking on the number before
* we pass it to the "number-to-message" conversion function and there might
- * be systems that do not do proper range checking in there themselves.
+ * be systems that don't do proper range checking in there themselves.
*
- * We do not do range checking (on systems other than Windows) since there is
+ * We don't do range checking (on systems other than Windows) since there is
* no good reliable and portable way to do it.
*
* On Windows different types of error codes overlap. This function has an
@@ -842,6 +832,7 @@ const char *Curl_strerror(int err, char *buf, size_t buflen)
#endif
int old_errno = errno;
char *p;
+ size_t max;
if(!buflen)
return NULL;
@@ -850,22 +841,23 @@ const char *Curl_strerror(int err, char *buf, size_t buflen)
DEBUGASSERT(err >= 0);
#endif
+ max = buflen - 1;
*buf = '\0';
#if defined(_WIN32) || defined(_WIN32_WCE)
#if defined(_WIN32)
/* 'sys_nerr' is the maximum errno number, it is not widely portable */
if(err >= 0 && err < sys_nerr)
- msnprintf(buf, buflen, "%s", sys_errlist[err]);
+ strncpy(buf, sys_errlist[err], max);
else
#endif
{
if(
#ifdef USE_WINSOCK
- !get_winsock_error(err, buf, buflen) &&
+ !get_winsock_error(err, buf, max) &&
#endif
- !get_winapi_error(err, buf, buflen))
- msnprintf(buf, buflen, "Unknown error %d (%#x)", err, err);
+ !get_winapi_error((DWORD)err, buf, max))
+ msnprintf(buf, max, "Unknown error %d (%#x)", err, err);
}
#else /* not Windows coming up */
@@ -875,9 +867,9 @@ const char *Curl_strerror(int err, char *buf, size_t buflen)
* storage is supplied via 'strerrbuf' and 'buflen' to hold the generated
* message string, or EINVAL if 'errnum' is not a valid error number.
*/
- if(0 != strerror_r(err, buf, buflen)) {
+ if(0 != strerror_r(err, buf, max)) {
if('\0' == buf[0])
- msnprintf(buf, buflen, "Unknown error %d", err);
+ msnprintf(buf, max, "Unknown error %d", err);
}
#elif defined(HAVE_STRERROR_R) && defined(HAVE_GLIBC_STRERROR_R)
/*
@@ -889,23 +881,25 @@ const char *Curl_strerror(int err, char *buf, size_t buflen)
char buffer[256];
char *msg = strerror_r(err, buffer, sizeof(buffer));
if(msg)
- msnprintf(buf, buflen, "%s", msg);
+ strncpy(buf, msg, max);
else
- msnprintf(buf, buflen, "Unknown error %d", err);
+ msnprintf(buf, max, "Unknown error %d", err);
}
#else
{
/* !checksrc! disable STRERROR 1 */
const char *msg = strerror(err);
if(msg)
- msnprintf(buf, buflen, "%s", msg);
+ strncpy(buf, msg, max);
else
- msnprintf(buf, buflen, "Unknown error %d", err);
+ msnprintf(buf, max, "Unknown error %d", err);
}
#endif
#endif /* end of not Windows */
+ buf[max] = '\0'; /* make sure the string is null-terminated */
+
/* strip trailing '\r\n' or '\n'. */
p = strrchr(buf, '\n');
if(p && (p - buf) >= 2)
@@ -943,14 +937,14 @@ const char *Curl_winapi_strerror(DWORD err, char *buf, size_t buflen)
*buf = '\0';
#ifndef CURL_DISABLE_VERBOSE_STRINGS
- if(!get_winapi_error((int)err, buf, buflen)) {
+ if(!get_winapi_error(err, buf, buflen)) {
msnprintf(buf, buflen, "Unknown error %lu (0x%08lX)", err, err);
}
#else
{
const char *txt = (err == ERROR_SUCCESS) ? "No error" : "Error";
- if(strlen(txt) < buflen)
- strcpy(buf, txt);
+ strncpy(buf, txt, buflen);
+ buf[buflen - 1] = '\0';
}
#endif
@@ -1087,11 +1081,17 @@ const char *Curl_sspi_strerror(int err, char *buf, size_t buflen)
err);
}
else {
+ char txtbuf[80];
char msgbuf[256];
+
+ msnprintf(txtbuf, sizeof(txtbuf), "%s (0x%08X)", txt, err);
+
if(get_winapi_error(err, msgbuf, sizeof(msgbuf)))
- msnprintf(buf, buflen, "%s (0x%08X) - %s", txt, err, msgbuf);
- else
- msnprintf(buf, buflen, "%s (0x%08X)", txt, err);
+ msnprintf(buf, buflen, "%s - %s", txtbuf, msgbuf);
+ else {
+ strncpy(buf, txtbuf, buflen);
+ buf[buflen - 1] = '\0';
+ }
}
#else
@@ -1099,8 +1099,8 @@ const char *Curl_sspi_strerror(int err, char *buf, size_t buflen)
txt = "No error";
else
txt = "Error";
- if(buflen > strlen(txt))
- strcpy(buf, txt);
+ strncpy(buf, txt, buflen);
+ buf[buflen - 1] = '\0';
#endif
if(errno != old_errno)
diff --git a/contrib/libs/curl/lib/strtok.c b/contrib/libs/curl/lib/strtok.c
index d2cc71c47d..d8e1e8183f 100644
--- a/contrib/libs/curl/lib/strtok.c
+++ b/contrib/libs/curl/lib/strtok.c
@@ -65,4 +65,4 @@ Curl_strtok_r(char *ptr, const char *sep, char **end)
return NULL;
}
-#endif /* this was only compiled if strtok_r was not present */
+#endif /* this was only compiled if strtok_r wasn't present */
diff --git a/contrib/libs/curl/lib/strtoofft.c b/contrib/libs/curl/lib/strtoofft.c
index f1c7ba2711..077b25792e 100644
--- a/contrib/libs/curl/lib/strtoofft.c
+++ b/contrib/libs/curl/lib/strtoofft.c
@@ -31,7 +31,7 @@
* NOTE:
*
* In the ISO C standard (IEEE Std 1003.1), there is a strtoimax() function we
- * could use in case strtoll() does not exist... See
+ * could use in case strtoll() doesn't exist... See
* https://www.opengroup.org/onlinepubs/009695399/functions/strtoimax.html
*/
@@ -73,16 +73,17 @@ static const char valchars[] =
static int get_char(char c, int base);
/**
- * Custom version of the strtooff function. This extracts a curl_off_t
+ * Custom version of the strtooff function. This extracts a curl_off_t
* value from the given input string and returns it.
*/
static curl_off_t strtooff(const char *nptr, char **endptr, int base)
{
char *end;
- bool is_negative = FALSE;
- bool overflow = FALSE;
+ int is_negative = 0;
+ int overflow;
int i;
curl_off_t value = 0;
+ curl_off_t newval;
/* Skip leading whitespace. */
end = (char *)nptr;
@@ -92,7 +93,7 @@ static curl_off_t strtooff(const char *nptr, char **endptr, int base)
/* Handle the sign, if any. */
if(end[0] == '-') {
- is_negative = TRUE;
+ is_negative = 1;
end++;
}
else if(end[0] == '+') {
@@ -120,23 +121,27 @@ static curl_off_t strtooff(const char *nptr, char **endptr, int base)
}
}
- /* Matching strtol, if the base is 0 and it does not look like
- * the number is octal or hex, we assume it is base 10.
+ /* Matching strtol, if the base is 0 and it doesn't look like
+ * the number is octal or hex, we assume it's base 10.
*/
if(base == 0) {
base = 10;
}
/* Loop handling digits. */
+ value = 0;
+ overflow = 0;
for(i = get_char(end[0], base);
i != -1;
end++, i = get_char(end[0], base)) {
-
- if(value > (CURL_OFF_T_MAX - i) / base) {
- overflow = TRUE;
+ newval = base * value + i;
+ if(newval < value) {
+ /* We've overflowed. */
+ overflow = 1;
break;
}
- value = base * value + i;
+ else
+ value = newval;
}
if(!overflow) {
@@ -168,7 +173,7 @@ static curl_off_t strtooff(const char *nptr, char **endptr, int base)
* @param c the character to interpret according to base
* @param base the base in which to interpret c
*
- * @return the value of c in base, or -1 if c is not in range
+ * @return the value of c in base, or -1 if c isn't in range
*/
static int get_char(char c, int base)
{
@@ -204,15 +209,15 @@ static int get_char(char c, int base)
return value;
}
-#endif /* Only present if we need strtoll, but do not have it. */
+#endif /* Only present if we need strtoll, but don't have it. */
/*
- * Parse a *positive* up to 64-bit number written in ASCII.
+ * Parse a *positive* up to 64 bit number written in ascii.
*/
CURLofft curlx_strtoofft(const char *str, char **endp, int base,
curl_off_t *num)
{
- char *end = NULL;
+ char *end;
curl_off_t number;
errno = 0;
*num = 0; /* clear by default */
@@ -222,7 +227,7 @@ CURLofft curlx_strtoofft(const char *str, char **endp, int base,
str++;
if(('-' == *str) || (ISSPACE(*str))) {
if(endp)
- *endp = (char *)str; /* did not actually move */
+ *endp = (char *)str; /* didn't actually move */
return CURL_OFFT_INVAL; /* nothing parsed */
}
number = strtooff(str, &end, base);
diff --git a/contrib/libs/curl/lib/strtoofft.h b/contrib/libs/curl/lib/strtoofft.h
index 71808b719c..34d293ba38 100644
--- a/contrib/libs/curl/lib/strtoofft.h
+++ b/contrib/libs/curl/lib/strtoofft.h
@@ -30,7 +30,7 @@
* Determine which string to integral data type conversion function we use
* to implement string conversion to our curl_off_t integral data type.
*
- * Notice that curl_off_t might be 64 or 32 bits wide, and that it might use
+ * Notice that curl_off_t might be 64 or 32 bit wide, and that it might use
* an underlying data type which might be 'long', 'int64_t', 'long long' or
* '__int64' and more remotely other data types.
*
diff --git a/contrib/libs/curl/lib/system_win32.c b/contrib/libs/curl/lib/system_win32.c
index f4dbe0310a..9408d026b1 100644
--- a/contrib/libs/curl/lib/system_win32.c
+++ b/contrib/libs/curl/lib/system_win32.c
@@ -45,11 +45,11 @@ static HMODULE s_hIpHlpApiDll = NULL;
/* Pointer to the if_nametoindex function */
IF_NAMETOINDEX_FN Curl_if_nametoindex = NULL;
-/* Curl_win32_init() performs Win32 global initialization */
+/* Curl_win32_init() performs win32 global initialization */
CURLcode Curl_win32_init(long flags)
{
/* CURL_GLOBAL_WIN32 controls the *optional* part of the initialization which
- is just for Winsock at the moment. Any required Win32 initialization
+ is just for Winsock at the moment. Any required win32 initialization
should take place after this block. */
if(flags & CURL_GLOBAL_WIN32) {
#ifdef USE_WINSOCK
@@ -61,7 +61,7 @@ CURLcode Curl_win32_init(long flags)
res = WSAStartup(wVersionRequested, &wsaData);
if(res)
- /* Tell the user that we could not find a usable */
+ /* Tell the user that we couldn't find a usable */
/* winsock.dll. */
return CURLE_FAILED_INIT;
@@ -73,7 +73,7 @@ CURLcode Curl_win32_init(long flags)
if(LOBYTE(wsaData.wVersion) != LOBYTE(wVersionRequested) ||
HIBYTE(wsaData.wVersion) != HIBYTE(wVersionRequested) ) {
- /* Tell the user that we could not find a usable */
+ /* Tell the user that we couldn't find a usable */
/* winsock.dll. */
WSACleanup();
@@ -179,7 +179,7 @@ HMODULE Curl_load_library(LPCTSTR filename)
HMODULE hModule = NULL;
LOADLIBRARYEX_FN pLoadLibraryEx = NULL;
- /* Get a handle to kernel32 so we can access its functions at runtime */
+ /* Get a handle to kernel32 so we can access it's functions at runtime */
HMODULE hKernel32 = GetModuleHandle(TEXT("kernel32"));
if(!hKernel32)
return NULL;
@@ -190,7 +190,7 @@ HMODULE Curl_load_library(LPCTSTR filename)
CURLX_FUNCTION_CAST(LOADLIBRARYEX_FN,
(GetProcAddress(hKernel32, LOADLIBARYEX)));
- /* Detect if there is already a path in the filename and load the library if
+ /* Detect if there's already a path in the filename and load the library if
there is. Note: Both back slashes and forward slashes have been supported
since the earlier days of DOS at an API level although they are not
supported by command prompt */
@@ -232,7 +232,7 @@ HMODULE Curl_load_library(LPCTSTR filename)
}
return hModule;
#else
- /* the Universal Windows Platform (UWP) cannot do this */
+ /* the Universal Windows Platform (UWP) can't do this */
(void)filename;
return NULL;
#endif
diff --git a/contrib/libs/curl/lib/system_win32.h b/contrib/libs/curl/lib/system_win32.h
index 024d959f32..2566766681 100644
--- a/contrib/libs/curl/lib/system_win32.h
+++ b/contrib/libs/curl/lib/system_win32.h
@@ -28,8 +28,6 @@
#if defined(_WIN32)
-#include <curl/curl.h>
-
extern LARGE_INTEGER Curl_freq;
extern bool Curl_isVistaOrGreater;
diff --git a/contrib/libs/curl/lib/telnet.c b/contrib/libs/curl/lib/telnet.c
index 8cd19b1b09..836e255c9d 100644
--- a/contrib/libs/curl/lib/telnet.c
+++ b/contrib/libs/curl/lib/telnet.c
@@ -160,7 +160,6 @@ struct TELNET {
unsigned short subopt_wsy; /* Set with suboption NAWS */
TelnetReceive telrcv_state;
struct curl_slist *telnet_vars; /* Environment variables */
- struct dynbuf out; /* output buffer */
/* suboptions */
unsigned char subbuffer[SUBBUFSIZE];
@@ -173,7 +172,7 @@ struct TELNET {
*/
const struct Curl_handler Curl_handler_telnet = {
- "telnet", /* scheme */
+ "TELNET", /* scheme */
ZERO_NULL, /* setup_connection */
telnet_do, /* do_it */
telnet_done, /* done */
@@ -186,8 +185,7 @@ const struct Curl_handler Curl_handler_telnet = {
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
ZERO_NULL, /* disconnect */
- ZERO_NULL, /* write_resp */
- ZERO_NULL, /* write_resp_hd */
+ ZERO_NULL, /* readwrite */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_TELNET, /* defport */
@@ -206,7 +204,6 @@ CURLcode init_telnet(struct Curl_easy *data)
if(!tn)
return CURLE_OUT_OF_MEMORY;
- Curl_dyn_init(&tn->out, 0xffff);
data->req.p.telnet = tn; /* make us known */
tn->telrcv_state = CURL_TS_DATA;
@@ -798,14 +795,12 @@ static CURLcode check_telnet_options(struct Curl_easy *data)
struct TELNET *tn = data->req.p.telnet;
CURLcode result = CURLE_OK;
- /* Add the username as an environment variable if it
+ /* Add the user name as an environment variable if it
was given on the command line */
if(data->state.aptr.user) {
char buffer[256];
- if(str_is_nonascii(data->conn->user)) {
- DEBUGF(infof(data, "set a non ASCII username in telnet"));
+ if(str_is_nonascii(data->conn->user))
return CURLE_BAD_FUNCTION_ARGUMENT;
- }
msnprintf(buffer, sizeof(buffer), "USER,%s", data->conn->user);
beg = curl_slist_append(tn->telnet_vars, buffer);
if(!beg) {
@@ -831,27 +826,23 @@ static CURLcode check_telnet_options(struct Curl_easy *data)
case 5:
/* Terminal type */
if(strncasecompare(option, "TTYPE", 5)) {
- size_t l = strlen(arg);
- if(l < sizeof(tn->subopt_ttype)) {
- strcpy(tn->subopt_ttype, arg);
- tn->us_preferred[CURL_TELOPT_TTYPE] = CURL_YES;
- break;
- }
+ strncpy(tn->subopt_ttype, arg, 31);
+ tn->subopt_ttype[31] = 0; /* String termination */
+ tn->us_preferred[CURL_TELOPT_TTYPE] = CURL_YES;
}
- result = CURLE_UNKNOWN_OPTION;
+ else
+ result = CURLE_UNKNOWN_OPTION;
break;
case 8:
/* Display variable */
if(strncasecompare(option, "XDISPLOC", 8)) {
- size_t l = strlen(arg);
- if(l < sizeof(tn->subopt_xdisploc)) {
- strcpy(tn->subopt_xdisploc, arg);
- tn->us_preferred[CURL_TELOPT_XDISPLOC] = CURL_YES;
- break;
- }
+ strncpy(tn->subopt_xdisploc, arg, 127);
+ tn->subopt_xdisploc[127] = 0; /* String termination */
+ tn->us_preferred[CURL_TELOPT_XDISPLOC] = CURL_YES;
}
- result = CURLE_UNKNOWN_OPTION;
+ else
+ result = CURLE_UNKNOWN_OPTION;
break;
case 7:
@@ -1191,12 +1182,12 @@ process_iac:
if(c != CURL_SE) {
if(c != CURL_IAC) {
/*
- * This is an error. We only expect to get "IAC IAC" or "IAC SE".
- * Several things may have happened. An IAC was not doubled, the
+ * This is an error. We only expect to get "IAC IAC" or "IAC SE".
+ * Several things may have happened. An IAC was not doubled, the
* IAC SE was left off, or another option got inserted into the
- * suboption are all possibilities. If we assume that the IAC was
+ * suboption are all possibilities. If we assume that the IAC was
* not doubled, and really the IAC SE was left off, we could get
- * into an infinite loop here. So, instead, we terminate the
+ * into an infinite loop here. So, instead, we terminate the
* suboption, and process the partial suboption if we can.
*/
CURL_SB_ACCUM(tn, CURL_IAC);
@@ -1232,37 +1223,37 @@ process_iac:
static CURLcode send_telnet_data(struct Curl_easy *data,
char *buffer, ssize_t nread)
{
- size_t i, outlen;
- unsigned char *outbuf;
+ ssize_t escapes, i, outlen;
+ unsigned char *outbuf = NULL;
CURLcode result = CURLE_OK;
- size_t bytes_written;
- size_t total_written = 0;
+ ssize_t bytes_written, total_written;
struct connectdata *conn = data->conn;
- struct TELNET *tn = data->req.p.telnet;
- DEBUGASSERT(tn);
- DEBUGASSERT(nread > 0);
- if(nread < 0)
- return CURLE_TOO_LARGE;
+ /* Determine size of new buffer after escaping */
+ escapes = 0;
+ for(i = 0; i < nread; i++)
+ if((unsigned char)buffer[i] == CURL_IAC)
+ escapes++;
+ outlen = nread + escapes;
- if(memchr(buffer, CURL_IAC, nread)) {
- /* only use the escape buffer when necessary */
- Curl_dyn_reset(&tn->out);
+ if(outlen == nread)
+ outbuf = (unsigned char *)buffer;
+ else {
+ ssize_t j;
+ outbuf = malloc(nread + escapes + 1);
+ if(!outbuf)
+ return CURLE_OUT_OF_MEMORY;
- for(i = 0; i < (size_t)nread && !result; i++) {
- result = Curl_dyn_addn(&tn->out, &buffer[i], 1);
- if(!result && ((unsigned char)buffer[i] == CURL_IAC))
- /* IAC is FF in hex */
- result = Curl_dyn_addn(&tn->out, "\xff", 1);
+ j = 0;
+ for(i = 0; i < nread; i++) {
+ outbuf[j++] = (unsigned char)buffer[i];
+ if((unsigned char)buffer[i] == CURL_IAC)
+ outbuf[j++] = CURL_IAC;
}
-
- outlen = Curl_dyn_len(&tn->out);
- outbuf = Curl_dyn_uptr(&tn->out);
- }
- else {
- outlen = (size_t)nread;
- outbuf = (unsigned char *)buffer;
+ outbuf[j] = '\0';
}
+
+ total_written = 0;
while(!result && total_written < outlen) {
/* Make sure socket is writable to avoid EWOULDBLOCK condition */
struct pollfd pfd[1];
@@ -1275,13 +1266,19 @@ static CURLcode send_telnet_data(struct Curl_easy *data,
break;
default: /* write! */
bytes_written = 0;
- result = Curl_xfer_send(data, outbuf + total_written,
- outlen - total_written, FALSE, &bytes_written);
+ result = Curl_nwrite(data, FIRSTSOCKET,
+ outbuf + total_written,
+ outlen - total_written,
+ &bytes_written);
total_written += bytes_written;
break;
}
}
+ /* Free malloc copy if escaped */
+ if(outbuf != (unsigned char *)buffer)
+ free(outbuf);
+
return result;
}
@@ -1297,7 +1294,6 @@ static CURLcode telnet_done(struct Curl_easy *data,
curl_slist_free_all(tn->telnet_vars);
tn->telnet_vars = NULL;
- Curl_dyn_free(&tn->out);
return CURLE_OK;
}
@@ -1325,7 +1321,7 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done)
ssize_t nread;
struct curltime now;
bool keepon = TRUE;
- char buffer[4*1024];
+ char *buf = data->state.buffer;
struct TELNET *tn;
*done = TRUE; /* unconditionally */
@@ -1342,7 +1338,7 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done)
#ifdef USE_WINSOCK
/* We want to wait for both stdin and the socket. Since
- ** the select() function in Winsock only works on sockets
+ ** the select() function in winsock only works on sockets
** we have to use the WaitForMultipleObjects() call.
*/
@@ -1353,7 +1349,7 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done)
return CURLE_FAILED_INIT;
}
- /* Tell Winsock what events we want to listen to */
+ /* Tell winsock what events we want to listen to */
if(WSAEventSelect(sockfd, event_handle, FD_READ|FD_CLOSE) == SOCKET_ERROR) {
WSACloseEvent(event_handle);
return CURLE_OK;
@@ -1370,7 +1366,7 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done)
else use the old WaitForMultipleObjects() way */
if(GetFileType(stdin_handle) == FILE_TYPE_PIPE ||
data->set.is_fread_set) {
- /* Do not wait for stdin_handle, just wait for event_handle */
+ /* Don't wait for stdin_handle, just wait for event_handle */
obj_count = 1;
/* Check stdin_handle per 100 milliseconds */
wait_timeout = 100;
@@ -1382,7 +1378,7 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done)
/* Keep on listening and act on events */
while(keepon) {
- const DWORD buf_size = (DWORD)sizeof(buffer);
+ const DWORD buf_size = (DWORD)data->set.buffer_size;
DWORD waitret = WaitForMultipleObjects(obj_count, objs,
FALSE, wait_timeout);
switch(waitret) {
@@ -1393,7 +1389,7 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done)
if(data->set.is_fread_set) {
size_t n;
/* read from user-supplied method */
- n = data->state.fread_func(buffer, 1, buf_size, data->state.in);
+ n = data->state.fread_func(buf, 1, buf_size, data->state.in);
if(n == CURL_READFUNC_ABORT) {
keepon = FALSE;
result = CURLE_READ_ERROR;
@@ -1421,7 +1417,7 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done)
if(!readfile_read)
break;
- if(!ReadFile(stdin_handle, buffer, buf_size,
+ if(!ReadFile(stdin_handle, buf, buf_size,
&readfile_read, NULL)) {
keepon = FALSE;
result = CURLE_READ_ERROR;
@@ -1429,7 +1425,7 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done)
}
}
- result = send_telnet_data(data, buffer, readfile_read);
+ result = send_telnet_data(data, buf, readfile_read);
if(result) {
keepon = FALSE;
break;
@@ -1440,14 +1436,14 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done)
case WAIT_OBJECT_0 + 1:
{
- if(!ReadFile(stdin_handle, buffer, buf_size,
+ if(!ReadFile(stdin_handle, buf, buf_size,
&readfile_read, NULL)) {
keepon = FALSE;
result = CURLE_READ_ERROR;
break;
}
- result = send_telnet_data(data, buffer, readfile_read);
+ result = send_telnet_data(data, buf, readfile_read);
if(result) {
keepon = FALSE;
break;
@@ -1469,8 +1465,8 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done)
}
if(events.lNetworkEvents & FD_READ) {
/* read data from network */
- result = Curl_xfer_recv(data, buffer, sizeof(buffer), &nread);
- /* read would have blocked. Loop again */
+ result = Curl_read(data, sockfd, buf, data->set.buffer_size, &nread);
+ /* read would've blocked. Loop again */
if(result == CURLE_AGAIN)
break;
/* returned not-zero, this an error */
@@ -1485,14 +1481,14 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done)
break;
}
- result = telrcv(data, (unsigned char *) buffer, nread);
+ result = telrcv(data, (unsigned char *) buf, nread);
if(result) {
keepon = FALSE;
break;
}
/* Negotiate if the peer has started negotiating,
- otherwise do not. We do not want to speak telnet with
+ otherwise don't. We don't want to speak telnet with
non-telnet servers, like POP or SMTP. */
if(tn->please_negotiate && !tn->already_negotiated) {
negotiate(data);
@@ -1535,28 +1531,23 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done)
pfd[1].events = POLLIN;
poll_cnt = 2;
interval_ms = 1 * 1000;
- if(pfd[1].fd < 0) {
- failf(data, "cannot read input");
- result = CURLE_RECV_ERROR;
- keepon = FALSE;
- }
}
while(keepon) {
DEBUGF(infof(data, "telnet_do, poll %d fds", poll_cnt));
- switch(Curl_poll(pfd, (unsigned int)poll_cnt, interval_ms)) {
+ switch(Curl_poll(pfd, poll_cnt, interval_ms)) {
case -1: /* error, stop reading */
keepon = FALSE;
continue;
case 0: /* timeout */
pfd[0].revents = 0;
pfd[1].revents = 0;
- FALLTHROUGH();
+ /* FALLTHROUGH */
default: /* read! */
if(pfd[0].revents & POLLIN) {
/* read data from network */
- result = Curl_xfer_recv(data, buffer, sizeof(buffer), &nread);
- /* read would have blocked. Loop again */
+ result = Curl_read(data, sockfd, buf, data->set.buffer_size, &nread);
+ /* read would've blocked. Loop again */
if(result == CURLE_AGAIN)
break;
/* returned not-zero, this an error */
@@ -1581,14 +1572,14 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done)
total_dl += nread;
result = Curl_pgrsSetDownloadCounter(data, total_dl);
if(!result)
- result = telrcv(data, (unsigned char *)buffer, nread);
+ result = telrcv(data, (unsigned char *)buf, nread);
if(result) {
keepon = FALSE;
break;
}
/* Negotiate if the peer has started negotiating,
- otherwise do not. We do not want to speak telnet with
+ otherwise don't. We don't want to speak telnet with
non-telnet servers, like POP or SMTP. */
if(tn->please_negotiate && !tn->already_negotiated) {
negotiate(data);
@@ -1599,12 +1590,12 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done)
nread = 0;
if(poll_cnt == 2) {
if(pfd[1].revents & POLLIN) { /* read from in file */
- nread = read(pfd[1].fd, buffer, sizeof(buffer));
+ nread = read(pfd[1].fd, buf, data->set.buffer_size);
}
}
else {
/* read from user-supplied method */
- nread = (int)data->state.fread_func(buffer, 1, sizeof(buffer),
+ nread = (int)data->state.fread_func(buf, 1, data->set.buffer_size,
data->state.in);
if(nread == CURL_READFUNC_ABORT) {
keepon = FALSE;
@@ -1615,7 +1606,7 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done)
}
if(nread > 0) {
- result = send_telnet_data(data, buffer, nread);
+ result = send_telnet_data(data, buf, nread);
if(result) {
keepon = FALSE;
break;
@@ -1645,7 +1636,7 @@ static CURLcode telnet_do(struct Curl_easy *data, bool *done)
}
#endif
/* mark this as "no further transfer wanted" */
- Curl_xfer_setup_nop(data);
+ Curl_setup_transfer(data, -1, -1, FALSE, -1);
return result;
}
diff --git a/contrib/libs/curl/lib/tftp.c b/contrib/libs/curl/lib/tftp.c
index dbae202d52..663015502d 100644
--- a/contrib/libs/curl/lib/tftp.c
+++ b/contrib/libs/curl/lib/tftp.c
@@ -168,7 +168,7 @@ static CURLcode tftp_translate_code(tftp_error_t error);
*/
const struct Curl_handler Curl_handler_tftp = {
- "tftp", /* scheme */
+ "TFTP", /* scheme */
tftp_setup_connection, /* setup_connection */
tftp_do, /* do_it */
tftp_done, /* done */
@@ -181,8 +181,7 @@ const struct Curl_handler Curl_handler_tftp = {
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
tftp_disconnect, /* disconnect */
- ZERO_NULL, /* write_resp */
- ZERO_NULL, /* write_resp_hd */
+ ZERO_NULL, /* readwrite */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_TFTP, /* defport */
@@ -240,11 +239,12 @@ static CURLcode tftp_set_timeouts(struct tftp_state_data *state)
state->retry_time = 1;
infof(state->data,
- "set timeouts for state %d; Total % " FMT_OFF_T ", retry %d maxtry %d",
+ "set timeouts for state %d; Total % " CURL_FORMAT_CURL_OFF_T
+ ", retry %d maxtry %d",
(int)state->state, timeout_ms, state->retry_time, state->retry_max);
/* init RX time */
- state->rx_time = time(NULL);
+ time(&state->rx_time);
return CURLE_OK;
}
@@ -314,7 +314,7 @@ static CURLcode tftp_parse_option_ack(struct tftp_state_data *state,
const char *tmp = ptr;
struct Curl_easy *data = state->data;
- /* if OACK does not contain blksize option, the default (512) must be used */
+ /* if OACK doesn't contain blksize option, the default (512) must be used */
state->blksize = TFTP_BLKSIZE_DEFAULT;
while(tmp < ptr + len) {
@@ -348,7 +348,7 @@ static CURLcode tftp_parse_option_ack(struct tftp_state_data *state,
return CURLE_TFTP_ILLEGAL;
}
else if(blksize > state->requested_blksize) {
- /* could realloc pkt buffers here, but the spec does not call out
+ /* could realloc pkt buffers here, but the spec doesn't call out
* support for the server requesting a bigger blksize than the client
* requests */
failf(data, "%s (%ld)",
@@ -433,7 +433,7 @@ static CURLcode tftp_send_first(struct tftp_state_data *state,
struct Curl_easy *data = state->data;
CURLcode result = CURLE_OK;
- /* Set ASCII mode if -B flag was used */
+ /* Set ascii mode if -B flag was used */
if(data->state.prefer_ascii)
mode = "netascii";
@@ -452,6 +452,8 @@ static CURLcode tftp_send_first(struct tftp_state_data *state,
if(data->state.upload) {
/* If we are uploading, send an WRQ */
setpacketevent(&state->spacket, TFTP_EVENT_WRQ);
+ state->data->req.upload_fromhere =
+ (char *)state->spacket.data + 4;
if(data->state.infilesize != -1)
Curl_pgrsSetUploadSize(data, data->state.infilesize);
}
@@ -460,7 +462,7 @@ static CURLcode tftp_send_first(struct tftp_state_data *state,
setpacketevent(&state->spacket, TFTP_EVENT_RRQ);
}
/* As RFC3617 describes the separator slash is not actually part of the
- filename so we skip the always-present first letter of the path
+ file name so we skip the always-present first letter of the path
string. */
result = Curl_urldecode(&state->data->state.up.path[1], 0,
&filename, NULL, REJECT_ZERO);
@@ -468,9 +470,9 @@ static CURLcode tftp_send_first(struct tftp_state_data *state,
return result;
if(strlen(filename) > (state->blksize - strlen(mode) - 4)) {
- failf(data, "TFTP filename too long");
+ failf(data, "TFTP file name too long");
free(filename);
- return CURLE_TFTP_ILLEGAL; /* too long filename field */
+ return CURLE_TFTP_ILLEGAL; /* too long file name field */
}
msnprintf((char *)state->spacket.data + 2,
@@ -483,7 +485,7 @@ static CURLcode tftp_send_first(struct tftp_state_data *state,
char buf[64];
/* add tsize option */
if(data->state.upload && (data->state.infilesize != -1))
- msnprintf(buf, sizeof(buf), "%" FMT_OFF_T,
+ msnprintf(buf, sizeof(buf), "%" CURL_FORMAT_CURL_OFF_T,
data->state.infilesize);
else
strcpy(buf, "0"); /* the destination is large enough */
@@ -527,7 +529,7 @@ static CURLcode tftp_send_first(struct tftp_state_data *state,
senddata = sendto(state->sockfd, (void *)state->spacket.data,
(SEND_TYPE_ARG3)sbytes, 0,
&data->conn->remote_addr->sa_addr,
- (curl_socklen_t)data->conn->remote_addr->addrlen);
+ data->conn->remote_addr->addrlen);
if(senddata != (ssize_t)sbytes) {
char buffer[STRERROR_LEN];
failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
@@ -589,7 +591,7 @@ static CURLcode tftp_rx(struct tftp_state_data *state,
/* Is this the block we expect? */
rblock = getrpacketblock(&state->rpacket);
if(NEXT_BLOCKNUM(state->block) == rblock) {
- /* This is the expected block. Reset counters and ACK it. */
+ /* This is the expected block. Reset counters and ACK it. */
state->retries = 0;
}
else if(state->block == rblock) {
@@ -625,7 +627,7 @@ static CURLcode tftp_rx(struct tftp_state_data *state,
else {
state->state = TFTP_STATE_RX;
}
- state->rx_time = time(NULL);
+ time(&state->rx_time);
break;
case TFTP_EVENT_OACK:
@@ -643,16 +645,16 @@ static CURLcode tftp_rx(struct tftp_state_data *state,
return CURLE_SEND_ERROR;
}
- /* we are ready to RX data */
+ /* we're ready to RX data */
state->state = TFTP_STATE_RX;
- state->rx_time = time(NULL);
+ time(&state->rx_time);
break;
case TFTP_EVENT_TIMEOUT:
/* Increment the retry count and fail if over the limit */
state->retries++;
infof(data,
- "Timeout waiting for block %d ACK. Retries = %d",
+ "Timeout waiting for block %d ACK. Retries = %d",
NEXT_BLOCKNUM(state->block), state->retries);
if(state->retries > state->retry_max) {
state->error = TFTP_ERR_TIMEOUT;
@@ -678,8 +680,8 @@ static CURLcode tftp_rx(struct tftp_state_data *state,
4, SEND_4TH_ARG,
(struct sockaddr *)&state->remote_addr,
state->remote_addrlen);
- /* do not bother with the return code, but if the socket is still up we
- * should be a good TFTP client and let the server know we are done */
+ /* don't bother with the return code, but if the socket is still up we
+ * should be a good TFTP client and let the server know we're done */
state->state = TFTP_STATE_FIN;
break;
@@ -706,8 +708,6 @@ static CURLcode tftp_tx(struct tftp_state_data *state, tftp_event_t event)
struct SingleRequest *k = &data->req;
size_t cb; /* Bytes currently read */
char buffer[STRERROR_LEN];
- char *bufptr;
- bool eos;
switch(event) {
@@ -718,13 +718,13 @@ static CURLcode tftp_tx(struct tftp_state_data *state, tftp_event_t event)
int rblock = getrpacketblock(&state->rpacket);
if(rblock != state->block &&
- /* There is a bug in tftpd-hpa that causes it to send us an ack for
- * 65535 when the block number wraps to 0. So when we are expecting
+ /* There's a bug in tftpd-hpa that causes it to send us an ack for
+ * 65535 when the block number wraps to 0. So when we're expecting
* 0, also accept 65535. See
* https://www.syslinux.org/archives/2010-September/015612.html
* */
!(state->block == 0 && rblock == 65535)) {
- /* This is not the expected block. Log it and up the retry counter */
+ /* This isn't the expected block. Log it and up the retry counter */
infof(data, "Received ACK for block %d, expecting %d",
rblock, state->block);
state->retries++;
@@ -737,7 +737,7 @@ static CURLcode tftp_tx(struct tftp_state_data *state, tftp_event_t event)
else {
/* Re-send the data packet */
sbytes = sendto(state->sockfd, (void *)state->spacket.data,
- 4 + (SEND_TYPE_ARG3)state->sbytes, SEND_4TH_ARG,
+ 4 + state->sbytes, SEND_4TH_ARG,
(struct sockaddr *)&state->remote_addr,
state->remote_addrlen);
/* Check all sbytes were sent */
@@ -750,9 +750,9 @@ static CURLcode tftp_tx(struct tftp_state_data *state, tftp_event_t event)
return result;
}
- /* This is the expected packet. Reset the counters and send the next
+ /* This is the expected packet. Reset the counters and send the next
block */
- state->rx_time = time(NULL);
+ time(&state->rx_time);
state->block++;
}
else
@@ -771,18 +771,17 @@ static CURLcode tftp_tx(struct tftp_state_data *state, tftp_event_t event)
* data block.
* */
state->sbytes = 0;
- bufptr = (char *)state->spacket.data + 4;
+ state->data->req.upload_fromhere = (char *)state->spacket.data + 4;
do {
- result = Curl_client_read(data, bufptr, state->blksize - state->sbytes,
- &cb, &eos);
+ result = Curl_fillreadbuffer(data, state->blksize - state->sbytes, &cb);
if(result)
return result;
state->sbytes += (int)cb;
- bufptr += cb;
+ state->data->req.upload_fromhere += cb;
} while(state->sbytes < state->blksize && cb);
sbytes = sendto(state->sockfd, (void *) state->spacket.data,
- 4 + (SEND_TYPE_ARG3)state->sbytes, SEND_4TH_ARG,
+ 4 + state->sbytes, SEND_4TH_ARG,
(struct sockaddr *)&state->remote_addr,
state->remote_addrlen);
/* Check all sbytes were sent */
@@ -800,7 +799,7 @@ static CURLcode tftp_tx(struct tftp_state_data *state, tftp_event_t event)
state->retries++;
infof(data, "Timeout waiting for block %d ACK. "
" Retries = %d", NEXT_BLOCKNUM(state->block), state->retries);
- /* Decide if we have had enough */
+ /* Decide if we've had enough */
if(state->retries > state->retry_max) {
state->error = TFTP_ERR_TIMEOUT;
state->state = TFTP_STATE_FIN;
@@ -808,7 +807,7 @@ static CURLcode tftp_tx(struct tftp_state_data *state, tftp_event_t event)
else {
/* Re-send the data packet */
sbytes = sendto(state->sockfd, (void *)state->spacket.data,
- 4 + (SEND_TYPE_ARG3)state->sbytes, SEND_4TH_ARG,
+ 4 + state->sbytes, SEND_4TH_ARG,
(struct sockaddr *)&state->remote_addr,
state->remote_addrlen);
/* Check all sbytes were sent */
@@ -828,8 +827,8 @@ static CURLcode tftp_tx(struct tftp_state_data *state, tftp_event_t event)
(void)sendto(state->sockfd, (void *)state->spacket.data, 4, SEND_4TH_ARG,
(struct sockaddr *)&state->remote_addr,
state->remote_addrlen);
- /* do not bother with the return code, but if the socket is still up we
- * should be a good TFTP client and let the server know we are done */
+ /* don't bother with the return code, but if the socket is still up we
+ * should be a good TFTP client and let the server know we're done */
state->state = TFTP_STATE_FIN;
break;
@@ -1000,7 +999,7 @@ static CURLcode tftp_connect(struct Curl_easy *data, bool *done)
return CURLE_OUT_OF_MEMORY;
}
- /* we do not keep TFTP connections up basically because there is none or very
+ /* we don't keep TFTP connections up basically because there's none or very
* little gain for UDP */
connclose(conn, "TFTP");
@@ -1031,7 +1030,7 @@ static CURLcode tftp_connect(struct Curl_easy *data, bool *done)
* IPv4 and IPv6...
*/
int rc = bind(state->sockfd, (struct sockaddr *)&state->local_addr,
- (curl_socklen_t)conn->remote_addr->addrlen);
+ conn->remote_addr->addrlen);
if(rc) {
char buffer[STRERROR_LEN];
failf(data, "bind() failed; %s",
@@ -1109,7 +1108,7 @@ static CURLcode tftp_receive_packet(struct Curl_easy *data)
fromlen = sizeof(fromaddr);
state->rbytes = (int)recvfrom(state->sockfd,
(void *)state->rpacket.data,
- (RECV_TYPE_ARG3)state->blksize + 4,
+ state->blksize + 4,
0,
(struct sockaddr *)&fromaddr,
&fromlen);
@@ -1131,7 +1130,7 @@ static CURLcode tftp_receive_packet(struct Curl_easy *data)
switch(state->event) {
case TFTP_EVENT_DATA:
- /* Do not pass to the client empty or retransmitted packets */
+ /* Don't pass to the client empty or retransmitted packets */
if(state->rbytes > 4 &&
(NEXT_BLOCKNUM(state->block) == getrpacketblock(&state->rpacket))) {
result = Curl_client_write(data, CLIENTWRITE_BODY,
@@ -1203,11 +1202,11 @@ static timediff_t tftp_state_timeout(struct Curl_easy *data,
state->state = TFTP_STATE_FIN;
return 0;
}
- current = time(NULL);
+ time(&current);
if(current > state->rx_time + state->retry_time) {
if(event)
*event = TFTP_EVENT_TIMEOUT;
- state->rx_time = time(NULL); /* update even though we received nothing */
+ time(&state->rx_time); /* update even though we received nothing */
}
return timeout_ms;
@@ -1240,8 +1239,8 @@ static CURLcode tftp_multi_statemach(struct Curl_easy *data, bool *done)
return result;
*done = (state->state == TFTP_STATE_FIN) ? TRUE : FALSE;
if(*done)
- /* Tell curl we are done */
- Curl_xfer_setup_nop(data);
+ /* Tell curl we're done */
+ Curl_setup_transfer(data, -1, -1, FALSE, -1);
}
else {
/* no timeouts to handle, check our socket */
@@ -1263,8 +1262,8 @@ static CURLcode tftp_multi_statemach(struct Curl_easy *data, bool *done)
return result;
*done = (state->state == TFTP_STATE_FIN) ? TRUE : FALSE;
if(*done)
- /* Tell curl we are done */
- Curl_xfer_setup_nop(data);
+ /* Tell curl we're done */
+ Curl_setup_transfer(data, -1, -1, FALSE, -1);
}
/* if rc == 0, then select() timed out */
}
@@ -1288,7 +1287,7 @@ static CURLcode tftp_doing(struct Curl_easy *data, bool *dophase_done)
DEBUGF(infof(data, "DO phase is complete"));
}
else if(!result) {
- /* The multi code does not have this logic for the DOING state so we
+ /* The multi code doesn't have this logic for the DOING state so we
provide it for TFTP since it may do the entire transfer in this
state. */
if(Curl_pgrsUpdate(data))
@@ -1375,7 +1374,7 @@ static CURLcode tftp_setup_connection(struct Curl_easy *data,
conn->transport = TRNSPRT_UDP;
/* TFTP URLs support an extension like ";mode=<typecode>" that
- * we will try to get now! */
+ * we'll try to get now! */
type = strstr(data->state.up.path, ";mode=");
if(!type)
diff --git a/contrib/libs/curl/lib/timediff.h b/contrib/libs/curl/lib/timediff.h
index 75f996c55c..fb318d4f2b 100644
--- a/contrib/libs/curl/lib/timediff.h
+++ b/contrib/libs/curl/lib/timediff.h
@@ -26,10 +26,10 @@
#include "curl_setup.h"
-/* Use a larger type even for 32-bit time_t systems so that we can keep
+/* Use a larger type even for 32 bit time_t systems so that we can keep
microsecond accuracy in it */
typedef curl_off_t timediff_t;
-#define FMT_TIMEDIFF_T FMT_OFF_T
+#define CURL_FORMAT_TIMEDIFF_T CURL_FORMAT_CURL_OFF_T
#define TIMEDIFF_T_MAX CURL_OFF_T_MAX
#define TIMEDIFF_T_MIN CURL_OFF_T_MIN
diff --git a/contrib/libs/curl/lib/timeval.c b/contrib/libs/curl/lib/timeval.c
index bb29bfdfee..5a6727cbc4 100644
--- a/contrib/libs/curl/lib/timeval.c
+++ b/contrib/libs/curl/lib/timeval.c
@@ -51,8 +51,8 @@ struct curltime Curl_now(void)
#pragma warning(pop)
#endif
- now.tv_sec = (time_t)(milliseconds / 1000);
- now.tv_usec = (int)((milliseconds % 1000) * 1000);
+ now.tv_sec = milliseconds / 1000;
+ now.tv_usec = (milliseconds % 1000) * 1000;
}
return now;
}
@@ -77,7 +77,7 @@ struct curltime Curl_now(void)
/*
** clock_gettime() may be defined by Apple's SDK as weak symbol thus
- ** code compiles but fails during runtime if clock_gettime() is
+ ** code compiles but fails during run-time if clock_gettime() is
** called on unsupported OS version.
*/
#if defined(__APPLE__) && defined(HAVE_BUILTIN_AVAILABLE) && \
@@ -95,7 +95,7 @@ struct curltime Curl_now(void)
#endif
(0 == clock_gettime(CLOCK_MONOTONIC_RAW, &tsnow))) {
cnow.tv_sec = tsnow.tv_sec;
- cnow.tv_usec = (int)(tsnow.tv_nsec / 1000);
+ cnow.tv_usec = (unsigned int)(tsnow.tv_nsec / 1000);
}
else
#endif
@@ -107,18 +107,18 @@ struct curltime Curl_now(void)
#endif
(0 == clock_gettime(CLOCK_MONOTONIC, &tsnow))) {
cnow.tv_sec = tsnow.tv_sec;
- cnow.tv_usec = (int)(tsnow.tv_nsec / 1000);
+ cnow.tv_usec = (unsigned int)(tsnow.tv_nsec / 1000);
}
/*
** Even when the configure process has truly detected monotonic clock
** availability, it might happen that it is not actually available at
- ** runtime. When this occurs simply fallback to other time source.
+ ** run-time. When this occurs simply fallback to other time source.
*/
#ifdef HAVE_GETTIMEOFDAY
else {
(void)gettimeofday(&now, NULL);
cnow.tv_sec = now.tv_sec;
- cnow.tv_usec = (int)now.tv_usec;
+ cnow.tv_usec = (unsigned int)now.tv_usec;
}
#else
else {
@@ -137,7 +137,7 @@ struct curltime Curl_now(void)
struct curltime Curl_now(void)
{
/*
- ** Monotonic timer on macOS is provided by mach_absolute_time(), which
+ ** Monotonic timer on Mac OS is provided by mach_absolute_time(), which
** returns time in Mach "absolute time units," which are platform-dependent.
** To convert to nanoseconds, one must use conversion factors specified by
** mach_timebase_info().
diff --git a/contrib/libs/curl/lib/transfer.c b/contrib/libs/curl/lib/transfer.c
index b660054437..96f1fde755 100644
--- a/contrib/libs/curl/lib/transfer.c
+++ b/contrib/libs/curl/lib/transfer.c
@@ -53,7 +53,7 @@
#endif
#ifndef HAVE_SOCKET
-#error "We cannot compile without socket() support!"
+#error "We can't compile without socket() support!"
#endif
#include "urldata.h"
@@ -63,7 +63,6 @@
#include "content_encoding.h"
#include "hostip.h"
#include "cfilters.h"
-#include "cw-out.h"
#include "transfer.h"
#include "sendf.h"
#include "speedcheck.h"
@@ -115,6 +114,260 @@ char *Curl_checkheaders(const struct Curl_easy *data,
}
#endif
+CURLcode Curl_get_upload_buffer(struct Curl_easy *data)
+{
+ if(!data->state.ulbuf) {
+ data->state.ulbuf = malloc(data->set.upload_buffer_size);
+ if(!data->state.ulbuf)
+ return CURLE_OUT_OF_MEMORY;
+ }
+ return CURLE_OK;
+}
+
+#ifndef CURL_DISABLE_HTTP
+/*
+ * This function will be called to loop through the trailers buffer
+ * until no more data is available for sending.
+ */
+static size_t trailers_read(char *buffer, size_t size, size_t nitems,
+ void *raw)
+{
+ struct Curl_easy *data = (struct Curl_easy *)raw;
+ struct dynbuf *trailers_buf = &data->state.trailers_buf;
+ size_t bytes_left = Curl_dyn_len(trailers_buf) -
+ data->state.trailers_bytes_sent;
+ size_t to_copy = (size*nitems < bytes_left) ? size*nitems : bytes_left;
+ if(to_copy) {
+ memcpy(buffer,
+ Curl_dyn_ptr(trailers_buf) + data->state.trailers_bytes_sent,
+ to_copy);
+ data->state.trailers_bytes_sent += to_copy;
+ }
+ return to_copy;
+}
+
+static size_t trailers_left(void *raw)
+{
+ struct Curl_easy *data = (struct Curl_easy *)raw;
+ struct dynbuf *trailers_buf = &data->state.trailers_buf;
+ return Curl_dyn_len(trailers_buf) - data->state.trailers_bytes_sent;
+}
+#endif
+
+/*
+ * This function will call the read callback to fill our buffer with data
+ * to upload.
+ */
+CURLcode Curl_fillreadbuffer(struct Curl_easy *data, size_t bytes,
+ size_t *nreadp)
+{
+ size_t buffersize = bytes;
+ size_t nread;
+ curl_read_callback readfunc = NULL;
+ void *extra_data = NULL;
+ int eof_index = 0;
+
+#ifndef CURL_DISABLE_HTTP
+ if(data->state.trailers_state == TRAILERS_INITIALIZED) {
+ struct curl_slist *trailers = NULL;
+ CURLcode result;
+ int trailers_ret_code;
+
+ /* at this point we already verified that the callback exists
+ so we compile and store the trailers buffer, then proceed */
+ infof(data,
+ "Moving trailers state machine from initialized to sending.");
+ data->state.trailers_state = TRAILERS_SENDING;
+ Curl_dyn_init(&data->state.trailers_buf, DYN_TRAILERS);
+
+ data->state.trailers_bytes_sent = 0;
+ Curl_set_in_callback(data, true);
+ trailers_ret_code = data->set.trailer_callback(&trailers,
+ data->set.trailer_data);
+ Curl_set_in_callback(data, false);
+ if(trailers_ret_code == CURL_TRAILERFUNC_OK) {
+ result = Curl_http_compile_trailers(trailers, &data->state.trailers_buf,
+ data);
+ }
+ else {
+ failf(data, "operation aborted by trailing headers callback");
+ *nreadp = 0;
+ result = CURLE_ABORTED_BY_CALLBACK;
+ }
+ if(result) {
+ Curl_dyn_free(&data->state.trailers_buf);
+ curl_slist_free_all(trailers);
+ return result;
+ }
+ infof(data, "Successfully compiled trailers.");
+ curl_slist_free_all(trailers);
+ }
+#endif
+
+#ifndef CURL_DISABLE_HTTP
+ /* if we are transmitting trailing data, we don't need to write
+ a chunk size so we skip this */
+ if(data->req.upload_chunky &&
+ data->state.trailers_state == TRAILERS_NONE) {
+ /* if chunked Transfer-Encoding */
+ buffersize -= (8 + 2 + 2); /* 32bit hex + CRLF + CRLF */
+ data->req.upload_fromhere += (8 + 2); /* 32bit hex + CRLF */
+ }
+
+ if(data->state.trailers_state == TRAILERS_SENDING) {
+ /* if we're here then that means that we already sent the last empty chunk
+ but we didn't send a final CR LF, so we sent 0 CR LF. We then start
+ pulling trailing data until we have no more at which point we
+ simply return to the previous point in the state machine as if
+ nothing happened.
+ */
+ readfunc = trailers_read;
+ extra_data = (void *)data;
+ eof_index = 1;
+ }
+ else
+#endif
+ {
+ readfunc = data->state.fread_func;
+ extra_data = data->state.in;
+ }
+
+ if(!data->req.fread_eof[eof_index]) {
+ Curl_set_in_callback(data, true);
+ nread = readfunc(data->req.upload_fromhere, 1, buffersize, extra_data);
+ Curl_set_in_callback(data, false);
+ /* make sure the callback is not called again after EOF */
+ data->req.fread_eof[eof_index] = !nread;
+ }
+ else
+ nread = 0;
+
+ if(nread == CURL_READFUNC_ABORT) {
+ failf(data, "operation aborted by callback");
+ *nreadp = 0;
+ return CURLE_ABORTED_BY_CALLBACK;
+ }
+ if(nread == CURL_READFUNC_PAUSE) {
+ struct SingleRequest *k = &data->req;
+
+ if(data->conn->handler->flags & PROTOPT_NONETWORK) {
+ /* protocols that work without network cannot be paused. This is
+ actually only FILE:// just now, and it can't pause since the transfer
+ isn't done using the "normal" procedure. */
+ failf(data, "Read callback asked for PAUSE when not supported");
+ return CURLE_READ_ERROR;
+ }
+
+ /* CURL_READFUNC_PAUSE pauses read callbacks that feed socket writes */
+ k->keepon |= KEEP_SEND_PAUSE; /* mark socket send as paused */
+ if(data->req.upload_chunky) {
+ /* Back out the preallocation done above */
+ data->req.upload_fromhere -= (8 + 2);
+ }
+ *nreadp = 0;
+
+ return CURLE_OK; /* nothing was read */
+ }
+ else if(nread > buffersize) {
+ /* the read function returned a too large value */
+ *nreadp = 0;
+ failf(data, "read function returned funny value");
+ return CURLE_READ_ERROR;
+ }
+
+#ifndef CURL_DISABLE_HTTP
+ if(!data->req.forbidchunk && data->req.upload_chunky) {
+ /* if chunked Transfer-Encoding
+ * build chunk:
+ *
+ * <HEX SIZE> CRLF
+ * <DATA> CRLF
+ */
+ /* On non-ASCII platforms the <DATA> may or may not be
+ translated based on state.prefer_ascii while the protocol
+ portion must always be translated to the network encoding.
+ To further complicate matters, line end conversion might be
+ done later on, so we need to prevent CRLFs from becoming
+ CRCRLFs if that's the case. To do this we use bare LFs
+ here, knowing they'll become CRLFs later on.
+ */
+
+ bool added_crlf = FALSE;
+ int hexlen = 0;
+ const char *endofline_native;
+ const char *endofline_network;
+
+ if(
+#ifdef CURL_DO_LINEEND_CONV
+ (data->state.prefer_ascii) ||
+#endif
+ (data->set.crlf)) {
+ /* \n will become \r\n later on */
+ endofline_native = "\n";
+ endofline_network = "\x0a";
+ }
+ else {
+ endofline_native = "\r\n";
+ endofline_network = "\x0d\x0a";
+ }
+
+ /* if we're not handling trailing data, proceed as usual */
+ if(data->state.trailers_state != TRAILERS_SENDING) {
+ char hexbuffer[11] = "";
+ hexlen = msnprintf(hexbuffer, sizeof(hexbuffer),
+ "%zx%s", nread, endofline_native);
+
+ /* move buffer pointer */
+ data->req.upload_fromhere -= hexlen;
+ nread += hexlen;
+
+ /* copy the prefix to the buffer, leaving out the NUL */
+ memcpy(data->req.upload_fromhere, hexbuffer, hexlen);
+
+ /* always append ASCII CRLF to the data unless
+ we have a valid trailer callback */
+ if((nread-hexlen) == 0 &&
+ data->set.trailer_callback != NULL &&
+ data->state.trailers_state == TRAILERS_NONE) {
+ data->state.trailers_state = TRAILERS_INITIALIZED;
+ }
+ else {
+ memcpy(data->req.upload_fromhere + nread,
+ endofline_network,
+ strlen(endofline_network));
+ added_crlf = TRUE;
+ }
+ }
+
+ if(data->state.trailers_state == TRAILERS_SENDING &&
+ !trailers_left(data)) {
+ Curl_dyn_free(&data->state.trailers_buf);
+ data->state.trailers_state = TRAILERS_DONE;
+ data->set.trailer_data = NULL;
+ data->set.trailer_callback = NULL;
+ /* mark the transfer as done */
+ data->req.upload_done = TRUE;
+ infof(data, "Signaling end of chunked upload after trailers.");
+ }
+ else
+ if((nread - hexlen) == 0 &&
+ data->state.trailers_state != TRAILERS_INITIALIZED) {
+ /* mark this as done once this chunk is transferred */
+ data->req.upload_done = TRUE;
+ infof(data,
+ "Signaling end of chunked upload via terminating chunk.");
+ }
+
+ if(added_crlf)
+ nread += strlen(endofline_network); /* for the added end of line */
+ }
+#endif
+
+ *nreadp = nread;
+
+ return CURLE_OK;
+}
+
static int data_pending(struct Curl_easy *data)
{
struct connectdata *conn = data->conn;
@@ -160,240 +413,606 @@ bool Curl_meets_timecondition(struct Curl_easy *data, time_t timeofdoc)
return TRUE;
}
-static CURLcode xfer_recv_shutdown(struct Curl_easy *data, bool *done)
-{
- int sockindex;
-
- if(!data || !data->conn)
- return CURLE_FAILED_INIT;
- if(data->conn->sockfd == CURL_SOCKET_BAD)
- return CURLE_FAILED_INIT;
- sockindex = (data->conn->sockfd == data->conn->sock[SECONDARYSOCKET]);
- return Curl_conn_shutdown(data, sockindex, done);
-}
-
-static bool xfer_recv_shutdown_started(struct Curl_easy *data)
-{
- int sockindex;
-
- if(!data || !data->conn)
- return CURLE_FAILED_INIT;
- if(data->conn->sockfd == CURL_SOCKET_BAD)
- return CURLE_FAILED_INIT;
- sockindex = (data->conn->sockfd == data->conn->sock[SECONDARYSOCKET]);
- return Curl_shutdown_started(data, sockindex);
-}
-
-CURLcode Curl_xfer_send_shutdown(struct Curl_easy *data, bool *done)
-{
- int sockindex;
-
- if(!data || !data->conn)
- return CURLE_FAILED_INIT;
- if(data->conn->writesockfd == CURL_SOCKET_BAD)
- return CURLE_FAILED_INIT;
- sockindex = (data->conn->writesockfd == data->conn->sock[SECONDARYSOCKET]);
- return Curl_conn_shutdown(data, sockindex, done);
-}
-
-/**
- * Receive raw response data for the transfer.
- * @param data the transfer
- * @param buf buffer to keep response data received
- * @param blen length of `buf`
- * @param eos_reliable if EOS detection in underlying connection is reliable
- * @param err error code in case of -1 return
- * @return number of bytes read or -1 for error
- */
-static ssize_t Curl_xfer_recv_resp(struct Curl_easy *data,
- char *buf, size_t blen,
- bool eos_reliable,
- CURLcode *err)
-{
- ssize_t nread;
-
- DEBUGASSERT(blen > 0);
- /* If we are reading BODY data and the connection does NOT handle EOF
- * and we know the size of the BODY data, limit the read amount */
- if(!eos_reliable && !data->req.header && data->req.size != -1) {
- curl_off_t totalleft = data->req.size - data->req.bytecount;
- if(totalleft <= 0)
- blen = 0;
- else if(totalleft < (curl_off_t)blen)
- blen = (size_t)totalleft;
- }
- else if(xfer_recv_shutdown_started(data)) {
- /* we already reveived everything. Do not try more. */
- blen = 0;
- }
-
- if(!blen) {
- /* want nothing more */
- *err = CURLE_OK;
- nread = 0;
- }
- else {
- *err = Curl_xfer_recv(data, buf, blen, &nread);
- }
-
- if(*err)
- return -1;
- if(nread == 0) {
- if(data->req.shutdown) {
- bool done;
- *err = xfer_recv_shutdown(data, &done);
- if(*err)
- return -1;
- if(!done) {
- *err = CURLE_AGAIN;
- return -1;
- }
- }
- DEBUGF(infof(data, "sendrecv_dl: we are done"));
- }
- DEBUGASSERT(nread >= 0);
- return nread;
-}
-
/*
* Go ahead and do a read if we have a readable socket or if
* the stream was rewound (in which case we have data in a
* buffer)
+ *
+ * return '*comeback' TRUE if we didn't properly drain the socket so this
+ * function should get called again without select() or similar in between!
*/
-static CURLcode sendrecv_dl(struct Curl_easy *data,
- struct SingleRequest *k,
- int *didwhat)
+static CURLcode readwrite_data(struct Curl_easy *data,
+ struct connectdata *conn,
+ struct SingleRequest *k,
+ int *didwhat, bool *done,
+ bool *comeback)
{
- struct connectdata *conn = data->conn;
CURLcode result = CURLE_OK;
- char *buf, *xfer_buf;
- size_t blen, xfer_blen;
- int maxloops = 10;
- curl_off_t total_received = 0;
- bool is_multiplex = FALSE;
-
- result = Curl_multi_xfer_buf_borrow(data, &xfer_buf, &xfer_blen);
- if(result)
- goto out;
+ char *buf;
+ size_t blen;
+ size_t consumed;
+ int maxloops = 100;
+ curl_off_t max_recv = data->set.max_recv_speed?
+ data->set.max_recv_speed : CURL_OFF_T_MAX;
+ bool data_eof_handled = FALSE;
+
+ DEBUGASSERT(data->state.buffer);
+ *done = FALSE;
+ *comeback = FALSE;
/* This is where we loop until we have read everything there is to
read or we get a CURLE_AGAIN */
do {
- bool is_eos = FALSE;
- size_t bytestoread;
- ssize_t nread;
-
- if(!is_multiplex) {
- /* Multiplexed connection have inherent handling of EOF and we do not
- * have to carefully restrict the amount we try to read.
- * Multiplexed changes only in one direction. */
- is_multiplex = Curl_conn_is_multiplex(conn, FIRSTSOCKET);
- }
-
- buf = xfer_buf;
- bytestoread = xfer_blen;
+ bool is_empty_data = FALSE;
+ size_t bytestoread = data->set.buffer_size;
+ /* For HTTP/2 and HTTP/3, read data without caring about the content
+ length. This is safe because body in HTTP/2 is always segmented
+ thanks to its framing layer. Meanwhile, we have to call Curl_read
+ to ensure that http2_handle_stream_close is called when we read all
+ incoming bytes for a particular stream. */
+ bool is_http3 = Curl_conn_is_http3(data, conn, FIRSTSOCKET);
+ data_eof_handled = is_http3 || Curl_conn_is_http2(data, conn, FIRSTSOCKET);
+
+ /* Each loop iteration starts with a fresh buffer and handles
+ * all data read into it. */
+ buf = data->state.buffer;
+ blen = 0;
- if(bytestoread && data->set.max_recv_speed > 0) {
- /* In case of speed limit on receiving: if this loop already got
- * data, break out. If not, limit the amount of bytes to receive.
- * The overall, timed, speed limiting is done in multi.c */
- if(total_received)
- break;
- if(data->set.max_recv_speed < (curl_off_t)bytestoread)
- bytestoread = (size_t)data->set.max_recv_speed;
+ /* If we are reading BODY data and the connection does NOT handle EOF
+ * and we know the size of the BODY data, limit the read amount */
+ if(!k->header && !data_eof_handled && k->size != -1) {
+ curl_off_t totalleft = k->size - k->bytecount;
+ if(totalleft <= 0)
+ bytestoread = 0;
+ else if(totalleft < (curl_off_t)bytestoread)
+ bytestoread = (size_t)totalleft;
}
- nread = Curl_xfer_recv_resp(data, buf, bytestoread,
- is_multiplex, &result);
- if(nread < 0) {
- if(CURLE_AGAIN != result)
- goto out; /* real error */
- result = CURLE_OK;
- if(data->req.download_done && data->req.no_body &&
- !data->req.resp_trailer) {
- DEBUGF(infof(data, "EAGAIN, download done, no trailer announced, "
- "not waiting for EOS"));
- nread = 0;
- /* continue as if we read the EOS */
- }
- else
+ if(bytestoread) {
+ /* receive data from the network! */
+ ssize_t nread; /* number of bytes read */
+ result = Curl_read(data, conn->sockfd, buf, bytestoread, &nread);
+ if(CURLE_AGAIN == result) {
+ result = CURLE_OK;
break; /* get out of loop */
+ }
+ else if(result)
+ goto out;
+ DEBUGASSERT(nread >= 0);
+ blen = (size_t)nread;
+ }
+ else {
+ /* read nothing but since we wanted nothing we consider this an OK
+ situation to proceed from */
+ DEBUGF(infof(data, "readwrite_data: we're done"));
+ }
+
+ if(!k->bytecount) {
+ Curl_pgrsTime(data, TIMER_STARTTRANSFER);
+ if(k->exp100 > EXP100_SEND_DATA)
+ /* set time stamp to compare with when waiting for the 100 */
+ k->start100 = Curl_now();
}
- /* We only get a 0-length read on EndOfStream */
- blen = (size_t)nread;
- is_eos = (blen == 0);
*didwhat |= KEEP_RECV;
+ /* indicates data of zero size, i.e. empty file */
+ is_empty_data = ((blen == 0) && (k->bodywrites == 0)) ? TRUE : FALSE;
+
+ if(0 < blen || is_empty_data) {
+ /* data->state.buffer is allocated 1 byte larger than
+ * data->set.buffer_size admits. *wink* */
+ /* TODO: we should really not rely on this being 0-terminated, since
+ * the actual data read might contain 0s. */
+ buf[blen] = 0;
+ }
if(!blen) {
/* if we receive 0 or less here, either the data transfer is done or the
server closed the connection and we bail out from this! */
- if(is_multiplex)
+ if(data_eof_handled)
DEBUGF(infof(data, "nread == 0, stream closed, bailing"));
else
DEBUGF(infof(data, "nread <= 0, server closed connection, bailing"));
- result = Curl_req_stop_send_recv(data);
+ k->keepon = 0; /* stop sending as well */
+ if(!is_empty_data)
+ break;
+ }
+
+ if(conn->handler->readwrite) {
+ bool readmore = FALSE; /* indicates data is incomplete, need more */
+ consumed = 0;
+ result = conn->handler->readwrite(data, conn, buf, blen,
+ &consumed, &readmore);
if(result)
goto out;
- if(k->eos_written) /* already did write this to client, leave */
+ if(readmore)
break;
+ buf += consumed;
+ blen -= consumed;
+ if(k->download_done) {
+ /* We've stopped dealing with input, get out of the do-while loop */
+ if(blen > 0) {
+ infof(data,
+ "Excess found:"
+ " excess = %zu"
+ " url = %s (zero-length body)",
+ blen, data->state.up.path);
+ }
+
+ /* we make sure that this socket isn't read more now */
+ k->keepon &= ~KEEP_RECV;
+ break;
+ }
}
- total_received += blen;
- result = Curl_xfer_write_resp(data, buf, blen, is_eos);
- if(result || data->req.done)
- goto out;
+#ifndef CURL_DISABLE_HTTP
+ /* Since this is a two-state thing, we check if we are parsing
+ headers at the moment or not. */
+ if(k->header) {
+ consumed = 0;
+ result = Curl_http_readwrite_headers(data, conn, buf, blen, &consumed);
+ if(result)
+ goto out;
+ buf += consumed;
+ blen -= consumed;
+
+ if(conn->handler->readwrite &&
+ (k->maxdownload <= 0 && blen > 0)) {
+ bool readmore = FALSE; /* indicates data is incomplete, need more */
+ consumed = 0;
+ result = conn->handler->readwrite(data, conn, buf, blen,
+ &consumed, &readmore);
+ if(result)
+ goto out;
+ if(readmore)
+ break;
+ buf += consumed;
+ blen -= consumed;
+ }
+
+ if(k->download_done) {
+ /* We've stopped dealing with input, get out of the do-while loop */
+ if(blen > 0) {
+ infof(data,
+ "Excess found:"
+ " excess = %zu"
+ " url = %s (zero-length body)",
+ blen, data->state.up.path);
+ }
+
+ /* we make sure that this socket isn't read more now */
+ k->keepon &= ~KEEP_RECV;
+ break;
+ }
+ }
+#endif /* CURL_DISABLE_HTTP */
+
+
+ /* This is not an 'else if' since it may be a rest from the header
+ parsing, where the beginning of the buffer is headers and the end
+ is non-headers. */
+ if(!k->header && (blen > 0 || is_empty_data)) {
- /* if we are done, we stop receiving. On multiplexed connections,
- * we should read the EOS. Which may arrive as meta data after
- * the bytes. Not taking it in might lead to RST of streams. */
- if((!is_multiplex && data->req.download_done) || is_eos) {
- data->req.keepon &= ~KEEP_RECV;
+ if(data->req.no_body && blen > 0) {
+ /* data arrives although we want none, bail out */
+ streamclose(conn, "ignoring body");
+ DEBUGF(infof(data, "did not want a BODY, but seeing %zu bytes",
+ blen));
+ *done = TRUE;
+ result = CURLE_WEIRD_SERVER_REPLY;
+ goto out;
+ }
+
+#ifndef CURL_DISABLE_HTTP
+ if(0 == k->bodywrites && !is_empty_data) {
+ /* These checks are only made the first time we are about to
+ write a piece of the body */
+ if(conn->handler->protocol&(PROTO_FAMILY_HTTP|CURLPROTO_RTSP)) {
+ /* HTTP-only checks */
+ result = Curl_http_firstwrite(data, conn, done);
+ if(result || *done)
+ goto out;
+ }
+ } /* this is the first time we write a body part */
+#endif /* CURL_DISABLE_HTTP */
+
+#ifndef CURL_DISABLE_HTTP
+ if(k->chunk) {
+ /*
+ * Here comes a chunked transfer flying and we need to decode this
+ * properly. While the name says read, this function both reads
+ * and writes away the data.
+ */
+ CURLcode extra;
+ CHUNKcode res;
+
+ consumed = 0;
+ res = Curl_httpchunk_read(data, buf, blen, &consumed, &extra);
+
+ if(CHUNKE_OK < res) {
+ if(CHUNKE_PASSTHRU_ERROR == res) {
+ failf(data, "Failed reading the chunked-encoded stream");
+ result = extra;
+ goto out;
+ }
+ failf(data, "%s in chunked-encoding", Curl_chunked_strerror(res));
+ result = CURLE_RECV_ERROR;
+ goto out;
+ }
+
+ buf += consumed;
+ blen -= consumed;
+ if(CHUNKE_STOP == res) {
+ /* we're done reading chunks! */
+ k->keepon &= ~KEEP_RECV; /* read no more */
+ /* chunks read successfully, download is complete */
+ k->download_done = TRUE;
+
+ /* N number of bytes at the end of the str buffer that weren't
+ written to the client. */
+ if(conn->chunk.datasize) {
+ infof(data, "Leftovers after chunking: % "
+ CURL_FORMAT_CURL_OFF_T "u bytes",
+ conn->chunk.datasize);
+ }
+ }
+ /* If it returned OK, we just keep going */
+ }
+#endif /* CURL_DISABLE_HTTP */
+
+ max_recv -= blen;
+
+ if(!k->chunk && (blen || k->badheader || is_empty_data)) {
+ /* If this is chunky transfer, it was already written */
+
+ if(k->badheader) {
+ /* we parsed a piece of data wrongly assuming it was a header
+ and now we output it as body instead */
+ size_t headlen = Curl_dyn_len(&data->state.headerb);
+
+ /* Don't let excess data pollute body writes */
+ if(k->maxdownload != -1 && (curl_off_t)headlen > k->maxdownload)
+ headlen = (size_t)k->maxdownload;
+
+ result = Curl_client_write(data, CLIENTWRITE_BODY,
+ Curl_dyn_ptr(&data->state.headerb),
+ headlen);
+ if(result)
+ goto out;
+ }
+
+ if(blen) {
+#ifndef CURL_DISABLE_POP3
+ if(conn->handler->protocol & PROTO_FAMILY_POP3) {
+ result = k->ignorebody? CURLE_OK :
+ Curl_pop3_write(data, buf, blen);
+ }
+ else
+#endif /* CURL_DISABLE_POP3 */
+ result = Curl_client_write(data, CLIENTWRITE_BODY, buf, blen);
+ }
+ k->badheader = FALSE; /* taken care of now */
+
+ if(result)
+ goto out;
+ }
+
+ if(k->download_done && !is_http3) {
+ /* HTTP/3 over QUIC should keep reading until QUIC connection
+ is closed. In contrast to HTTP/2 which can stop reading
+ from TCP connection, HTTP/3 over QUIC needs ACK from server
+ to ensure stream closure. It should keep reading. */
+ k->keepon &= ~KEEP_RECV; /* we're done reading */
+ }
+ } /* if(!header and data to read) */
+
+ if(is_empty_data) {
+ /* if we received nothing, the server closed the connection and we
+ are done */
+ k->keepon &= ~KEEP_RECV;
+ k->download_done = TRUE;
}
- /* if we are PAUSEd or stopped receiving, leave the loop */
- if((k->keepon & KEEP_RECV_PAUSE) || !(k->keepon & KEEP_RECV))
+
+ if((k->keepon & KEEP_RECV_PAUSE) || !(k->keepon & KEEP_RECV)) {
+ /* this is a paused or stopped transfer */
break;
+ }
- } while(maxloops--);
+ } while((max_recv > 0) && data_pending(data) && maxloops--);
- if((maxloops <= 0) || data_pending(data)) {
- /* did not read until EAGAIN or there is still pending data, mark as
- read-again-please */
- data->state.select_bits = CURL_CSELECT_IN;
- if((k->keepon & KEEP_SENDBITS) == KEEP_SEND)
- data->state.select_bits |= CURL_CSELECT_OUT;
+ if(maxloops <= 0 || max_recv <= 0) {
+ /* we mark it as read-again-please */
+ data->state.dselect_bits = CURL_CSELECT_IN;
+ *comeback = TRUE;
}
if(((k->keepon & (KEEP_RECV|KEEP_SEND)) == KEEP_SEND) &&
- (conn->bits.close || is_multiplex)) {
- /* When we have read the entire thing and the close bit is set, the server
- may now close the connection. If there is now any kind of sending going
+ (conn->bits.close || data_eof_handled)) {
+ /* When we've read the entire thing and the close bit is set, the server
+ may now close the connection. If there's now any kind of sending going
on from our side, we need to stop that immediately. */
infof(data, "we are done reading and this is set to close, stop send");
- Curl_req_abort_sending(data);
+ k->keepon &= ~KEEP_SEND; /* no writing anymore either */
+ k->keepon &= ~KEEP_SEND_PAUSE; /* no pausing anymore either */
}
out:
- Curl_multi_xfer_buf_release(data, xfer_buf);
if(result)
- DEBUGF(infof(data, "sendrecv_dl() -> %d", result));
+ DEBUGF(infof(data, "readwrite_data() -> %d", result));
return result;
}
+CURLcode Curl_done_sending(struct Curl_easy *data,
+ struct SingleRequest *k)
+{
+ k->keepon &= ~KEEP_SEND; /* we're done writing */
+
+ /* These functions should be moved into the handler struct! */
+ Curl_conn_ev_data_done_send(data);
+
+ return CURLE_OK;
+}
+
+#if defined(_WIN32) && defined(USE_WINSOCK)
+#ifndef SIO_IDEAL_SEND_BACKLOG_QUERY
+#define SIO_IDEAL_SEND_BACKLOG_QUERY 0x4004747B
+#endif
+
+static void win_update_buffer_size(curl_socket_t sockfd)
+{
+ int result;
+ ULONG ideal;
+ DWORD ideallen;
+ result = WSAIoctl(sockfd, SIO_IDEAL_SEND_BACKLOG_QUERY, 0, 0,
+ &ideal, sizeof(ideal), &ideallen, 0, 0);
+ if(result == 0) {
+ setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF,
+ (const char *)&ideal, sizeof(ideal));
+ }
+}
+#else
+#define win_update_buffer_size(x)
+#endif
+
+#define curl_upload_refill_watermark(data) \
+ ((ssize_t)((data)->set.upload_buffer_size >> 5))
+
/*
* Send data to upload to the server, when the socket is writable.
*/
-static CURLcode sendrecv_ul(struct Curl_easy *data, int *didwhat)
+static CURLcode readwrite_upload(struct Curl_easy *data,
+ struct connectdata *conn,
+ int *didwhat)
{
- /* We should not get here when the sending is already done. It
- * probably means that someone set `data-req.keepon |= KEEP_SEND`
- * when it should not. */
- DEBUGASSERT(!Curl_req_done_sending(data));
-
- if(!Curl_req_done_sending(data)) {
- *didwhat |= KEEP_SEND;
- return Curl_req_send_more(data);
- }
+ ssize_t i, si;
+ ssize_t bytes_written;
+ CURLcode result;
+ ssize_t nread; /* number of bytes read */
+ bool sending_http_headers = FALSE;
+ struct SingleRequest *k = &data->req;
+
+ *didwhat |= KEEP_SEND;
+
+ do {
+ curl_off_t nbody;
+ ssize_t offset = 0;
+
+ if(0 != k->upload_present &&
+ k->upload_present < curl_upload_refill_watermark(data) &&
+ !k->upload_chunky &&/*(variable sized chunked header; append not safe)*/
+ !k->upload_done && /*!(k->upload_done once k->upload_present sent)*/
+ !(k->writebytecount + k->upload_present - k->pendingheader ==
+ data->state.infilesize)) {
+ offset = k->upload_present;
+ }
+
+ /* only read more data if there's no upload data already
+ present in the upload buffer, or if appending to upload buffer */
+ if(0 == k->upload_present || offset) {
+ result = Curl_get_upload_buffer(data);
+ if(result)
+ return result;
+ if(offset && k->upload_fromhere != data->state.ulbuf)
+ memmove(data->state.ulbuf, k->upload_fromhere, offset);
+ /* init the "upload from here" pointer */
+ k->upload_fromhere = data->state.ulbuf;
+
+ if(!k->upload_done) {
+ /* HTTP pollution, this should be written nicer to become more
+ protocol agnostic. */
+ size_t fillcount;
+ struct HTTP *http = k->p.http;
+
+ if((k->exp100 == EXP100_SENDING_REQUEST) &&
+ (http->sending == HTTPSEND_BODY)) {
+ /* If this call is to send body data, we must take some action:
+ We have sent off the full HTTP 1.1 request, and we shall now
+ go into the Expect: 100 state and await such a header */
+ k->exp100 = EXP100_AWAITING_CONTINUE; /* wait for the header */
+ k->keepon &= ~KEEP_SEND; /* disable writing */
+ k->start100 = Curl_now(); /* timeout count starts now */
+ *didwhat &= ~KEEP_SEND; /* we didn't write anything actually */
+ /* set a timeout for the multi interface */
+ Curl_expire(data, data->set.expect_100_timeout, EXPIRE_100_TIMEOUT);
+ break;
+ }
+
+ if(conn->handler->protocol&(PROTO_FAMILY_HTTP|CURLPROTO_RTSP)) {
+ if(http->sending == HTTPSEND_REQUEST)
+ /* We're sending the HTTP request headers, not the data.
+ Remember that so we don't change the line endings. */
+ sending_http_headers = TRUE;
+ else
+ sending_http_headers = FALSE;
+ }
+
+ k->upload_fromhere += offset;
+ result = Curl_fillreadbuffer(data, data->set.upload_buffer_size-offset,
+ &fillcount);
+ k->upload_fromhere -= offset;
+ if(result)
+ return result;
+
+ nread = offset + fillcount;
+ }
+ else
+ nread = 0; /* we're done uploading/reading */
+
+ if(!nread && (k->keepon & KEEP_SEND_PAUSE)) {
+ /* this is a paused transfer */
+ break;
+ }
+ if(nread <= 0) {
+ result = Curl_done_sending(data, k);
+ if(result)
+ return result;
+ break;
+ }
+
+ /* store number of bytes available for upload */
+ k->upload_present = nread;
+
+ /* convert LF to CRLF if so asked */
+ if((!sending_http_headers) && (
+#ifdef CURL_DO_LINEEND_CONV
+ /* always convert if we're FTPing in ASCII mode */
+ (data->state.prefer_ascii) ||
+#endif
+ (data->set.crlf))) {
+ /* Do we need to allocate a scratch buffer? */
+ if(!data->state.scratch) {
+ data->state.scratch = malloc(2 * data->set.upload_buffer_size);
+ if(!data->state.scratch) {
+ failf(data, "Failed to alloc scratch buffer");
+
+ return CURLE_OUT_OF_MEMORY;
+ }
+ }
+
+ /*
+ * ASCII/EBCDIC Note: This is presumably a text (not binary)
+ * transfer so the data should already be in ASCII.
+ * That means the hex values for ASCII CR (0x0d) & LF (0x0a)
+ * must be used instead of the escape sequences \r & \n.
+ */
+ if(offset)
+ memcpy(data->state.scratch, k->upload_fromhere, offset);
+ for(i = offset, si = offset; i < nread; i++, si++) {
+ if(k->upload_fromhere[i] == 0x0a) {
+ data->state.scratch[si++] = 0x0d;
+ data->state.scratch[si] = 0x0a;
+ if(!data->set.crlf) {
+ /* we're here only because FTP is in ASCII mode...
+ bump infilesize for the LF we just added */
+ if(data->state.infilesize != -1)
+ data->state.infilesize++;
+ }
+ }
+ else
+ data->state.scratch[si] = k->upload_fromhere[i];
+ }
+
+ if(si != nread) {
+ /* only perform the special operation if we really did replace
+ anything */
+ nread = si;
+
+ /* upload from the new (replaced) buffer instead */
+ k->upload_fromhere = data->state.scratch;
+
+ /* set the new amount too */
+ k->upload_present = nread;
+ }
+ }
+
+#ifndef CURL_DISABLE_SMTP
+ if(conn->handler->protocol & PROTO_FAMILY_SMTP) {
+ result = Curl_smtp_escape_eob(data, nread, offset);
+ if(result)
+ return result;
+ }
+#endif /* CURL_DISABLE_SMTP */
+ } /* if 0 == k->upload_present or appended to upload buffer */
+ else {
+ /* We have a partial buffer left from a previous "round". Use
+ that instead of reading more data */
+ }
+
+ /* write to socket (send away data) */
+ result = Curl_write(data,
+ conn->writesockfd, /* socket to send to */
+ k->upload_fromhere, /* buffer pointer */
+ k->upload_present, /* buffer size */
+ &bytes_written); /* actually sent */
+ if(result)
+ return result;
+
+#if defined(_WIN32) && defined(USE_WINSOCK)
+ {
+ struct curltime n = Curl_now();
+ if(Curl_timediff(n, k->last_sndbuf_update) > 1000) {
+ win_update_buffer_size(conn->writesockfd);
+ k->last_sndbuf_update = n;
+ }
+ }
+#endif
+
+ if(k->pendingheader) {
+ /* parts of what was sent was header */
+ curl_off_t n = CURLMIN(k->pendingheader, bytes_written);
+ /* show the data before we change the pointer upload_fromhere */
+ Curl_debug(data, CURLINFO_HEADER_OUT, k->upload_fromhere, (size_t)n);
+ k->pendingheader -= n;
+ nbody = bytes_written - n; /* size of the written body part */
+ }
+ else
+ nbody = bytes_written;
+
+ if(nbody) {
+ /* show the data before we change the pointer upload_fromhere */
+ Curl_debug(data, CURLINFO_DATA_OUT,
+ &k->upload_fromhere[bytes_written - nbody],
+ (size_t)nbody);
+
+ k->writebytecount += nbody;
+ Curl_pgrsSetUploadCounter(data, k->writebytecount);
+ }
+
+ if((!k->upload_chunky || k->forbidchunk) &&
+ (k->writebytecount == data->state.infilesize)) {
+ /* we have sent all data we were supposed to */
+ k->upload_done = TRUE;
+ infof(data, "We are completely uploaded and fine");
+ }
+
+ if(k->upload_present != bytes_written) {
+ /* we only wrote a part of the buffer (if anything), deal with it! */
+
+ /* store the amount of bytes left in the buffer to write */
+ k->upload_present -= bytes_written;
+
+ /* advance the pointer where to find the buffer when the next send
+ is to happen */
+ k->upload_fromhere += bytes_written;
+ }
+ else {
+ /* we've uploaded that buffer now */
+ result = Curl_get_upload_buffer(data);
+ if(result)
+ return result;
+ k->upload_fromhere = data->state.ulbuf;
+ k->upload_present = 0; /* no more bytes left */
+
+ if(k->upload_done) {
+ result = Curl_done_sending(data, k);
+ if(result)
+ return result;
+ }
+ }
+
+
+ } while(0); /* just to break out from! */
+
return CURLE_OK;
}
@@ -404,58 +1023,93 @@ static int select_bits_paused(struct Curl_easy *data, int select_bits)
* of our state machine are handling PAUSED transfers correctly. So, we
* do not want to go there.
* NOTE: we are only interested in PAUSE, not HOLD. */
-
- /* if there is data in a direction not paused, return false */
- if(((select_bits & CURL_CSELECT_IN) &&
- !(data->req.keepon & KEEP_RECV_PAUSE)) ||
- ((select_bits & CURL_CSELECT_OUT) &&
- !(data->req.keepon & KEEP_SEND_PAUSE)))
- return FALSE;
-
- return (data->req.keepon & (KEEP_RECV_PAUSE|KEEP_SEND_PAUSE));
+ return (((select_bits & CURL_CSELECT_IN) &&
+ (data->req.keepon & KEEP_RECV_PAUSE)) ||
+ ((select_bits & CURL_CSELECT_OUT) &&
+ (data->req.keepon & KEEP_SEND_PAUSE)));
}
/*
- * Curl_sendrecv() is the low-level function to be called when data is to
+ * Curl_readwrite() is the low-level function to be called when data is to
* be read and written to/from the connection.
+ *
+ * return '*comeback' TRUE if we didn't properly drain the socket so this
+ * function should get called again without select() or similar in between!
*/
-CURLcode Curl_sendrecv(struct Curl_easy *data, struct curltime *nowp)
+CURLcode Curl_readwrite(struct connectdata *conn,
+ struct Curl_easy *data,
+ bool *done,
+ bool *comeback)
{
struct SingleRequest *k = &data->req;
- CURLcode result = CURLE_OK;
+ CURLcode result;
+ struct curltime now;
int didwhat = 0;
+ int select_bits;
- DEBUGASSERT(nowp);
- if(data->state.select_bits) {
- if(select_bits_paused(data, data->state.select_bits)) {
+ if(data->state.dselect_bits) {
+ if(select_bits_paused(data, data->state.dselect_bits)) {
/* leave the bits unchanged, so they'll tell us what to do when
* this transfer gets unpaused. */
+ DEBUGF(infof(data, "readwrite, dselect_bits, early return on PAUSED"));
result = CURLE_OK;
goto out;
}
- data->state.select_bits = 0;
+ select_bits = data->state.dselect_bits;
+ data->state.dselect_bits = 0;
+ }
+ else if(conn->cselect_bits) {
+ /* CAVEAT: adding `select_bits_paused()` check here makes test640 hang
+ * (among others). Which hints at strange state handling in FTP land... */
+ select_bits = conn->cselect_bits;
+ conn->cselect_bits = 0;
+ }
+ else {
+ curl_socket_t fd_read;
+ curl_socket_t fd_write;
+ /* only use the proper socket if the *_HOLD bit is not set simultaneously
+ as then we are in rate limiting state in that transfer direction */
+ if((k->keepon & KEEP_RECVBITS) == KEEP_RECV)
+ fd_read = conn->sockfd;
+ else
+ fd_read = CURL_SOCKET_BAD;
+
+ if((k->keepon & KEEP_SENDBITS) == KEEP_SEND)
+ fd_write = conn->writesockfd;
+ else
+ fd_write = CURL_SOCKET_BAD;
+
+ select_bits = Curl_socket_check(fd_read, CURL_SOCKET_BAD, fd_write, 0);
+ }
+
+ if(select_bits == CURL_CSELECT_ERR) {
+ failf(data, "select/poll returned error");
+ result = CURLE_SEND_ERROR;
+ goto out;
}
#ifdef USE_HYPER
- if(data->conn->datastream) {
- result = data->conn->datastream(data, data->conn, &didwhat,
- CURL_CSELECT_OUT|CURL_CSELECT_IN);
- if(result || data->req.done)
+ if(conn->datastream) {
+ result = conn->datastream(data, conn, &didwhat, done, select_bits);
+ if(result || *done)
goto out;
}
else {
#endif
- /* We go ahead and do a read if we have a readable socket or if the stream
- was rewound (in which case we have data in a buffer) */
- if(k->keepon & KEEP_RECV) {
- result = sendrecv_dl(data, k, &didwhat);
- if(result || data->req.done)
+ /* We go ahead and do a read if we have a readable socket or if
+ the stream was rewound (in which case we have data in a
+ buffer) */
+ if((k->keepon & KEEP_RECV) && (select_bits & CURL_CSELECT_IN)) {
+ result = readwrite_data(data, conn, k, &didwhat, done, comeback);
+ if(result || *done)
goto out;
}
/* If we still have writing to do, we check if we have a writable socket. */
- if(Curl_req_want_send(data) || (data->req.keepon & KEEP_SEND_TIMED)) {
- result = sendrecv_ul(data, &didwhat);
+ if((k->keepon & KEEP_SEND) && (select_bits & CURL_CSELECT_OUT)) {
+ /* write */
+
+ result = readwrite_upload(data, conn, &didwhat);
if(result)
goto out;
}
@@ -463,8 +1117,33 @@ CURLcode Curl_sendrecv(struct Curl_easy *data, struct curltime *nowp)
}
#endif
+ now = Curl_now();
if(!didwhat) {
- /* Transfer wanted to send/recv, but nothing was possible. */
+ /* no read no write, this is a timeout? */
+ if(k->exp100 == EXP100_AWAITING_CONTINUE) {
+ /* This should allow some time for the header to arrive, but only a
+ very short time as otherwise it'll be too much wasted time too
+ often. */
+
+ /* Quoting RFC2616, section "8.2.3 Use of the 100 (Continue) Status":
+
+ Therefore, when a client sends this header field to an origin server
+ (possibly via a proxy) from which it has never seen a 100 (Continue)
+ status, the client SHOULD NOT wait for an indefinite period before
+ sending the request body.
+
+ */
+
+ timediff_t ms = Curl_timediff(now, k->start100);
+ if(ms >= data->set.expect_100_timeout) {
+ /* we've waited long enough, continue anyway */
+ k->exp100 = EXP100_SEND_DATA;
+ k->keepon |= KEEP_SEND;
+ Curl_expire_done(data, EXPIRE_100_TIMEOUT);
+ infof(data, "Done waiting for 100-continue");
+ }
+ }
+
result = Curl_conn_ev_data_idle(data);
if(result)
goto out;
@@ -473,23 +1152,23 @@ CURLcode Curl_sendrecv(struct Curl_easy *data, struct curltime *nowp)
if(Curl_pgrsUpdate(data))
result = CURLE_ABORTED_BY_CALLBACK;
else
- result = Curl_speedcheck(data, *nowp);
+ result = Curl_speedcheck(data, now);
if(result)
goto out;
if(k->keepon) {
- if(0 > Curl_timeleft(data, nowp, FALSE)) {
+ if(0 > Curl_timeleft(data, &now, FALSE)) {
if(k->size != -1) {
- failf(data, "Operation timed out after %" FMT_TIMEDIFF_T
- " milliseconds with %" FMT_OFF_T " out of %"
- FMT_OFF_T " bytes received",
- Curl_timediff(*nowp, data->progress.t_startsingle),
+ failf(data, "Operation timed out after %" CURL_FORMAT_TIMEDIFF_T
+ " milliseconds with %" CURL_FORMAT_CURL_OFF_T " out of %"
+ CURL_FORMAT_CURL_OFF_T " bytes received",
+ Curl_timediff(now, data->progress.t_startsingle),
k->bytecount, k->size);
}
else {
- failf(data, "Operation timed out after %" FMT_TIMEDIFF_T
- " milliseconds with %" FMT_OFF_T " bytes received",
- Curl_timediff(*nowp, data->progress.t_startsingle),
+ failf(data, "Operation timed out after %" CURL_FORMAT_TIMEDIFF_T
+ " milliseconds with %" CURL_FORMAT_CURL_OFF_T " bytes received",
+ Curl_timediff(now, data->progress.t_startsingle),
k->bytecount);
}
result = CURLE_OPERATION_TIMEDOUT;
@@ -501,29 +1180,97 @@ CURLcode Curl_sendrecv(struct Curl_easy *data, struct curltime *nowp)
* The transfer has been performed. Just make some general checks before
* returning.
*/
+
if(!(data->req.no_body) && (k->size != -1) &&
- (k->bytecount != k->size) && !k->newurl) {
- failf(data, "transfer closed with %" FMT_OFF_T
+ (k->bytecount != k->size) &&
+#ifdef CURL_DO_LINEEND_CONV
+ /* Most FTP servers don't adjust their file SIZE response for CRLFs,
+ so we'll check to see if the discrepancy can be explained
+ by the number of CRLFs we've changed to LFs.
+ */
+ (k->bytecount != (k->size + data->state.crlf_conversions)) &&
+#endif /* CURL_DO_LINEEND_CONV */
+ !k->newurl) {
+ failf(data, "transfer closed with %" CURL_FORMAT_CURL_OFF_T
" bytes remaining to read", k->size - k->bytecount);
result = CURLE_PARTIAL_FILE;
goto out;
}
+ if(!(data->req.no_body) && k->chunk &&
+ (conn->chunk.state != CHUNK_STOP)) {
+ /*
+ * In chunked mode, return an error if the connection is closed prior to
+ * the empty (terminating) chunk is read.
+ *
+ * The condition above used to check for
+ * conn->proto.http->chunk.datasize != 0 which is true after reading
+ * *any* chunk, not just the empty chunk.
+ *
+ */
+ failf(data, "transfer closed with outstanding read data remaining");
+ result = CURLE_PARTIAL_FILE;
+ goto out;
+ }
if(Curl_pgrsUpdate(data)) {
result = CURLE_ABORTED_BY_CALLBACK;
goto out;
}
}
- /* If there is nothing more to send/recv, the request is done */
- if(0 == (k->keepon&(KEEP_RECVBITS|KEEP_SENDBITS)))
- data->req.done = TRUE;
-
+ /* Now update the "done" boolean we return */
+ *done = (0 == (k->keepon&(KEEP_RECVBITS|KEEP_SENDBITS))) ? TRUE : FALSE;
out:
if(result)
- DEBUGF(infof(data, "Curl_sendrecv() -> %d", result));
+ DEBUGF(infof(data, "Curl_readwrite() -> %d", result));
return result;
}
+/*
+ * Curl_single_getsock() gets called by the multi interface code when the app
+ * has requested to get the sockets for the current connection. This function
+ * will then be called once for every connection that the multi interface
+ * keeps track of. This function will only be called for connections that are
+ * in the proper state to have this information available.
+ */
+int Curl_single_getsock(struct Curl_easy *data,
+ struct connectdata *conn,
+ curl_socket_t *sock)
+{
+ int bitmap = GETSOCK_BLANK;
+ unsigned sockindex = 0;
+
+ if(conn->handler->perform_getsock)
+ return conn->handler->perform_getsock(data, conn, sock);
+
+ /* don't include HOLD and PAUSE connections */
+ if((data->req.keepon & KEEP_RECVBITS) == KEEP_RECV) {
+
+ DEBUGASSERT(conn->sockfd != CURL_SOCKET_BAD);
+
+ bitmap |= GETSOCK_READSOCK(sockindex);
+ sock[sockindex] = conn->sockfd;
+ }
+
+ /* don't include HOLD and PAUSE connections */
+ if((data->req.keepon & KEEP_SENDBITS) == KEEP_SEND) {
+ if((conn->sockfd != conn->writesockfd) ||
+ bitmap == GETSOCK_BLANK) {
+ /* only if they are not the same socket and we have a readable
+ one, we increase index */
+ if(bitmap != GETSOCK_BLANK)
+ sockindex++; /* increase index if we need two entries */
+
+ DEBUGASSERT(conn->writesockfd != CURL_SOCKET_BAD);
+
+ sock[sockindex] = conn->writesockfd;
+ }
+
+ bitmap |= GETSOCK_WRITESOCK(sockindex);
+ }
+
+ return bitmap;
+}
+
/* Curl_init_CONNECT() gets called each time the handle switches to CONNECT
which means this gets called once for each subsequent redirect etc */
void Curl_init_CONNECT(struct Curl_easy *data)
@@ -543,7 +1290,7 @@ CURLcode Curl_pretransfer(struct Curl_easy *data)
CURLcode result;
if(!data->state.url && !data->set.uh) {
- /* we cannot do anything without URL */
+ /* we can't do anything without URL */
failf(data, "No URL set");
return CURLE_URL_MALFORMAT;
}
@@ -567,7 +1314,7 @@ CURLcode Curl_pretransfer(struct Curl_easy *data)
}
if(data->set.postfields && data->set.set_resume_from) {
- /* we cannot */
+ /* we can't */
failf(data, "cannot mix POSTFIELDS with RESUME_FROM");
return CURLE_BAD_FUNCTION_ARGUMENT;
}
@@ -669,7 +1416,7 @@ CURLcode Curl_pretransfer(struct Curl_easy *data)
/*
* Set user-agent. Used for HTTP, but since we can attempt to tunnel
- * basically anything through an HTTP proxy we cannot limit this based on
+ * basically anything through an HTTP proxy we can't limit this based on
* protocol.
*/
if(data->set.str[STRING_USERAGENT]) {
@@ -686,14 +1433,12 @@ CURLcode Curl_pretransfer(struct Curl_easy *data)
if(!result)
result = Curl_setstropt(&data->state.aptr.passwd,
data->set.str[STRING_PASSWORD]);
-#ifndef CURL_DISABLE_PROXY
if(!result)
result = Curl_setstropt(&data->state.aptr.proxyuser,
data->set.str[STRING_PROXYUSERNAME]);
if(!result)
result = Curl_setstropt(&data->state.aptr.proxypasswd,
data->set.str[STRING_PROXYPASSWORD]);
-#endif
data->req.headerbytecount = 0;
Curl_headers_cleanup(data);
@@ -701,6 +1446,22 @@ CURLcode Curl_pretransfer(struct Curl_easy *data)
}
/*
+ * Curl_posttransfer() is called immediately after a transfer ends
+ */
+CURLcode Curl_posttransfer(struct Curl_easy *data)
+{
+#if defined(HAVE_SIGNAL) && defined(SIGPIPE) && !defined(HAVE_MSG_NOSIGNAL)
+ /* restore the signal handler for SIGPIPE before we get back */
+ if(!data->set.no_signal)
+ signal(SIGPIPE, data->state.prev_signal);
+#else
+ (void)data; /* unused parameter */
+#endif
+
+ return CURLE_OK;
+}
+
+/*
* Curl_follow() handles the URL redirect magic. Pass in the 'newurl' string
* as given by the remote server and set up the new URL to request.
*
@@ -781,16 +1542,16 @@ CURLcode Curl_follow(struct Curl_easy *data,
(data->req.httpcode != 401) && (data->req.httpcode != 407) &&
Curl_is_absolute_url(newurl, NULL, 0, FALSE)) {
/* If this is not redirect due to a 401 or 407 response and an absolute
- URL: do not allow a custom port number */
+ URL: don't allow a custom port number */
disallowport = TRUE;
}
DEBUGASSERT(data->state.uh);
- uc = curl_url_set(data->state.uh, CURLUPART_URL, newurl, (unsigned int)
- ((type == FOLLOW_FAKE) ? CURLU_NON_SUPPORT_SCHEME :
- ((type == FOLLOW_REDIR) ? CURLU_URLENCODE : 0) |
- CURLU_ALLOW_SPACE |
- (data->set.path_as_is ? CURLU_PATH_AS_IS : 0)));
+ uc = curl_url_set(data->state.uh, CURLUPART_URL, newurl,
+ (type == FOLLOW_FAKE) ? CURLU_NON_SUPPORT_SCHEME :
+ ((type == FOLLOW_REDIR) ? CURLU_URLENCODE : 0) |
+ CURLU_ALLOW_SPACE |
+ (data->set.path_as_is ? CURLU_PATH_AS_IS : 0));
if(uc) {
if(type != FOLLOW_FAKE) {
failf(data, "The redirect target URL could not be parsed: %s",
@@ -859,8 +1620,8 @@ CURLcode Curl_follow(struct Curl_easy *data,
}
if(type == FOLLOW_FAKE) {
- /* we are only figuring out the new URL if we would have followed locations
- but now we are done so we can get out! */
+ /* we're only figuring out the new url if we would've followed locations
+ but now we're done so we can get out! */
data->info.wouldredirect = newurl;
if(reachedmax) {
@@ -878,7 +1639,7 @@ CURLcode Curl_follow(struct Curl_easy *data,
data->state.url = newurl;
data->state.url_alloc = TRUE;
- Curl_req_soft_reset(&data->req, data);
+
infof(data, "Issue another request to this URL: '%s'", data->state.url);
/*
@@ -897,15 +1658,15 @@ CURLcode Curl_follow(struct Curl_easy *data,
/* 306 - Not used */
/* 307 - Temporary Redirect */
default: /* for all above (and the unknown ones) */
- /* Some codes are explicitly mentioned since I have checked RFC2616 and
- * they seem to be OK to POST to.
+ /* Some codes are explicitly mentioned since I've checked RFC2616 and they
+ * seem to be OK to POST to.
*/
break;
case 301: /* Moved Permanently */
/* (quote from RFC7231, section 6.4.2)
*
* Note: For historical reasons, a user agent MAY change the request
- * method from POST to GET for the subsequent request. If this
+ * method from POST to GET for the subsequent request. If this
* behavior is undesired, the 307 (Temporary Redirect) status code
* can be used instead.
*
@@ -924,14 +1685,13 @@ CURLcode Curl_follow(struct Curl_easy *data,
&& !(data->set.keep_post & CURL_REDIR_POST_301)) {
infof(data, "Switch from POST to GET");
data->state.httpreq = HTTPREQ_GET;
- Curl_creader_set_rewind(data, FALSE);
}
break;
case 302: /* Found */
/* (quote from RFC7231, section 6.4.3)
*
* Note: For historical reasons, a user agent MAY change the request
- * method from POST to GET for the subsequent request. If this
+ * method from POST to GET for the subsequent request. If this
* behavior is undesired, the 307 (Temporary Redirect) status code
* can be used instead.
*
@@ -950,7 +1710,6 @@ CURLcode Curl_follow(struct Curl_easy *data,
&& !(data->set.keep_post & CURL_REDIR_POST_302)) {
infof(data, "Switch from POST to GET");
data->state.httpreq = HTTPREQ_GET;
- Curl_creader_set_rewind(data, FALSE);
}
break;
@@ -972,14 +1731,14 @@ CURLcode Curl_follow(struct Curl_easy *data,
break;
case 304: /* Not Modified */
/* 304 means we did a conditional request and it was "Not modified".
- * We should not get any Location: header in this response!
+ * We shouldn't get any Location: header in this response!
*/
break;
case 305: /* Use Proxy */
/* (quote from RFC2616, section 10.3.6):
* "The requested resource MUST be accessed through the proxy given
* by the Location field. The Location field gives the URI of the
- * proxy. The recipient is expected to repeat this single request
+ * proxy. The recipient is expected to repeat this single request
* via the proxy. 305 responses MUST only be generated by origin
* servers."
*/
@@ -1001,9 +1760,8 @@ CURLcode Curl_retry_request(struct Curl_easy *data, char **url)
bool retry = FALSE;
*url = NULL;
- /* if we are talking upload, we cannot do the checks below, unless the
- protocol is HTTP as when uploading over HTTP we will still get a
- response */
+ /* if we're talking upload, we can't do the checks below, unless the protocol
+ is HTTP as when uploading over HTTP we will still get a response */
if(data->state.upload &&
!(conn->handler->protocol&(PROTO_FAMILY_HTTP|CURLPROTO_RTSP)))
return CURLE_OK;
@@ -1049,46 +1807,54 @@ CURLcode Curl_retry_request(struct Curl_easy *data, char **url)
return CURLE_OUT_OF_MEMORY;
connclose(conn, "retry"); /* close this connection */
- conn->bits.retry = TRUE; /* mark this as a connection we are about
+ conn->bits.retry = TRUE; /* mark this as a connection we're about
to retry. Marking it this way should
prevent i.e HTTP transfers to return
error just because nothing has been
transferred! */
- Curl_creader_set_rewind(data, TRUE);
+
+
+ if((conn->handler->protocol&PROTO_FAMILY_HTTP) &&
+ data->req.writebytecount) {
+ data->state.rewindbeforesend = TRUE;
+ infof(data, "state.rewindbeforesend = TRUE");
+ }
}
return CURLE_OK;
}
/*
- * xfer_setup() is called to setup basic properties for the transfer.
+ * Curl_setup_transfer() is called to setup some basic properties for the
+ * upcoming transfer.
*/
-static void xfer_setup(
+void
+Curl_setup_transfer(
struct Curl_easy *data, /* transfer */
int sockindex, /* socket index to read from or -1 */
curl_off_t size, /* -1 if unknown at this point */
bool getheader, /* TRUE if header parsing is wanted */
- int writesockindex, /* socket index to write to, it may very well be
+ int writesockindex /* socket index to write to, it may very well be
the same we read from. -1 disables */
- bool shutdown /* shutdown connection at transfer end. Only
- * supported when sending OR receiving. */
)
{
struct SingleRequest *k = &data->req;
struct connectdata *conn = data->conn;
- bool want_send = Curl_req_want_send(data);
+ struct HTTP *http = data->req.p.http;
+ bool httpsending;
DEBUGASSERT(conn != NULL);
DEBUGASSERT((sockindex <= 1) && (sockindex >= -1));
- DEBUGASSERT((writesockindex <= 1) && (writesockindex >= -1));
- DEBUGASSERT(!shutdown || (sockindex == -1) || (writesockindex == -1));
- if(conn->bits.multiplex || conn->httpversion >= 20 || want_send) {
+ httpsending = ((conn->handler->protocol&PROTO_FAMILY_HTTP) &&
+ (http->sending == HTTPSEND_REQUEST));
+
+ if(conn->bits.multiplex || conn->httpversion >= 20 || httpsending) {
/* when multiplexing, the read/write sockets need to be the same! */
conn->sockfd = sockindex == -1 ?
((writesockindex == -1 ? CURL_SOCKET_BAD : conn->sock[writesockindex])) :
conn->sock[sockindex];
conn->writesockfd = conn->sockfd;
- if(want_send)
+ if(httpsending)
/* special and very HTTP-specific */
writesockindex = FIRSTSOCKET;
}
@@ -1098,10 +1864,9 @@ static void xfer_setup(
conn->writesockfd = writesockindex == -1 ?
CURL_SOCKET_BAD:conn->sock[writesockindex];
}
-
k->getheader = getheader;
+
k->size = size;
- k->shutdown = shutdown;
/* The code sequence below is placed in this function just because all
necessary input is not always known in do_complete() as this function may
@@ -1112,167 +1877,43 @@ static void xfer_setup(
if(size > 0)
Curl_pgrsSetDownloadSize(data, size);
}
- /* we want header and/or body, if neither then do not do this! */
+ /* we want header and/or body, if neither then don't do this! */
if(k->getheader || !data->req.no_body) {
if(sockindex != -1)
k->keepon |= KEEP_RECV;
- if(writesockindex != -1)
- k->keepon |= KEEP_SEND;
- } /* if(k->getheader || !data->req.no_body) */
-
-}
-
-void Curl_xfer_setup_nop(struct Curl_easy *data)
-{
- xfer_setup(data, -1, -1, FALSE, -1, FALSE);
-}
-
-void Curl_xfer_setup1(struct Curl_easy *data,
- int send_recv,
- curl_off_t recv_size,
- bool getheader)
-{
- int recv_index = (send_recv & CURL_XFER_RECV)? FIRSTSOCKET : -1;
- int send_index = (send_recv & CURL_XFER_SEND)? FIRSTSOCKET : -1;
- DEBUGASSERT((recv_index >= 0) || (recv_size == -1));
- xfer_setup(data, recv_index, recv_size, getheader, send_index, FALSE);
-}
-
-void Curl_xfer_setup2(struct Curl_easy *data,
- int send_recv,
- curl_off_t recv_size,
- bool shutdown)
-{
- int recv_index = (send_recv & CURL_XFER_RECV)? SECONDARYSOCKET : -1;
- int send_index = (send_recv & CURL_XFER_SEND)? SECONDARYSOCKET : -1;
- DEBUGASSERT((recv_index >= 0) || (recv_size == -1));
- xfer_setup(data, recv_index, recv_size, FALSE, send_index, shutdown);
-}
-
-CURLcode Curl_xfer_write_resp(struct Curl_easy *data,
- const char *buf, size_t blen,
- bool is_eos)
-{
- CURLcode result = CURLE_OK;
-
- if(data->conn->handler->write_resp) {
- /* protocol handlers offering this function take full responsibility
- * for writing all received download data to the client. */
- result = data->conn->handler->write_resp(data, buf, blen, is_eos);
- }
- else {
- /* No special handling by protocol handler, write all received data
- * as BODY to the client. */
- if(blen || is_eos) {
- int cwtype = CLIENTWRITE_BODY;
- if(is_eos)
- cwtype |= CLIENTWRITE_EOS;
- result = Curl_client_write(data, cwtype, buf, blen);
- }
- }
-
- if(!result && is_eos) {
- /* If we wrote the EOS, we are definitely done */
- data->req.eos_written = TRUE;
- data->req.download_done = TRUE;
- }
- CURL_TRC_WRITE(data, "xfer_write_resp(len=%zu, eos=%d) -> %d",
- blen, is_eos, result);
- return result;
-}
-
-CURLcode Curl_xfer_write_resp_hd(struct Curl_easy *data,
- const char *hd0, size_t hdlen, bool is_eos)
-{
- if(data->conn->handler->write_resp_hd) {
- /* protocol handlers offering this function take full responsibility
- * for writing all received download data to the client. */
- return data->conn->handler->write_resp_hd(data, hd0, hdlen, is_eos);
- }
- /* No special handling by protocol handler, write as response bytes */
- return Curl_xfer_write_resp(data, hd0, hdlen, is_eos);
-}
-
-CURLcode Curl_xfer_write_done(struct Curl_easy *data, bool premature)
-{
- (void)premature;
- return Curl_cw_out_done(data);
-}
-
-bool Curl_xfer_needs_flush(struct Curl_easy *data)
-{
- int sockindex;
- sockindex = ((data->conn->writesockfd != CURL_SOCKET_BAD) &&
- (data->conn->writesockfd == data->conn->sock[SECONDARYSOCKET]));
- return Curl_conn_needs_flush(data, sockindex);
-}
-
-CURLcode Curl_xfer_flush(struct Curl_easy *data)
-{
- int sockindex;
- sockindex = ((data->conn->writesockfd != CURL_SOCKET_BAD) &&
- (data->conn->writesockfd == data->conn->sock[SECONDARYSOCKET]));
- return Curl_conn_flush(data, sockindex);
-}
-
-CURLcode Curl_xfer_send(struct Curl_easy *data,
- const void *buf, size_t blen, bool eos,
- size_t *pnwritten)
-{
- CURLcode result;
- int sockindex;
-
- DEBUGASSERT(data);
- DEBUGASSERT(data->conn);
-
- sockindex = ((data->conn->writesockfd != CURL_SOCKET_BAD) &&
- (data->conn->writesockfd == data->conn->sock[SECONDARYSOCKET]));
- result = Curl_conn_send(data, sockindex, buf, blen, eos, pnwritten);
- if(result == CURLE_AGAIN) {
- result = CURLE_OK;
- *pnwritten = 0;
- }
- else if(!result && *pnwritten)
- data->info.request_size += *pnwritten;
-
- DEBUGF(infof(data, "Curl_xfer_send(len=%zu, eos=%d) -> %d, %zu",
- blen, eos, result, *pnwritten));
- return result;
-}
-
-CURLcode Curl_xfer_recv(struct Curl_easy *data,
- char *buf, size_t blen,
- ssize_t *pnrcvd)
-{
- int sockindex;
-
- DEBUGASSERT(data);
- DEBUGASSERT(data->conn);
- DEBUGASSERT(data->set.buffer_size > 0);
-
- sockindex = ((data->conn->sockfd != CURL_SOCKET_BAD) &&
- (data->conn->sockfd == data->conn->sock[SECONDARYSOCKET]));
- if((size_t)data->set.buffer_size < blen)
- blen = (size_t)data->set.buffer_size;
- return Curl_conn_recv(data, sockindex, buf, blen, pnrcvd);
-}
+ if(writesockindex != -1) {
+ /* HTTP 1.1 magic:
+
+ Even if we require a 100-return code before uploading data, we might
+ need to write data before that since the REQUEST may not have been
+ finished sent off just yet.
+
+ Thus, we must check if the request has been sent before we set the
+ state info where we wait for the 100-return code
+ */
+ if((data->state.expect100header) &&
+ (conn->handler->protocol&PROTO_FAMILY_HTTP) &&
+ (http->sending == HTTPSEND_BODY)) {
+ /* wait with write until we either got 100-continue or a timeout */
+ k->exp100 = EXP100_AWAITING_CONTINUE;
+ k->start100 = Curl_now();
+
+ /* Set a timeout for the multi interface. Add the inaccuracy margin so
+ that we don't fire slightly too early and get denied to run. */
+ Curl_expire(data, data->set.expect_100_timeout, EXPIRE_100_TIMEOUT);
+ }
+ else {
+ if(data->state.expect100header)
+ /* when we've sent off the rest of the headers, we must await a
+ 100-continue but first finish sending the request */
+ k->exp100 = EXP100_SENDING_REQUEST;
-CURLcode Curl_xfer_send_close(struct Curl_easy *data)
-{
- Curl_conn_ev_data_done_send(data);
- return CURLE_OK;
-}
+ /* enable the write bit when we're not waiting for continue */
+ k->keepon |= KEEP_SEND;
+ }
+ } /* if(writesockindex != -1) */
+ } /* if(k->getheader || !data->req.no_body) */
-bool Curl_xfer_is_blocked(struct Curl_easy *data)
-{
- bool want_send = ((data)->req.keepon & KEEP_SEND);
- bool want_recv = ((data)->req.keepon & KEEP_RECV);
- if(!want_send)
- return (want_recv && Curl_cwriter_is_paused(data));
- else if(!want_recv)
- return (want_send && Curl_creader_is_paused(data));
- else
- return Curl_creader_is_paused(data) && Curl_cwriter_is_paused(data);
}
diff --git a/contrib/libs/curl/lib/transfer.h b/contrib/libs/curl/lib/transfer.h
index 8d6f98d750..536ac249b7 100644
--- a/contrib/libs/curl/lib/transfer.h
+++ b/contrib/libs/curl/lib/transfer.h
@@ -32,6 +32,7 @@ char *Curl_checkheaders(const struct Curl_easy *data,
void Curl_init_CONNECT(struct Curl_easy *data);
CURLcode Curl_pretransfer(struct Curl_easy *data);
+CURLcode Curl_posttransfer(struct Curl_easy *data);
typedef enum {
FOLLOW_NONE, /* not used within the function, just a placeholder to
@@ -44,112 +45,29 @@ typedef enum {
CURLcode Curl_follow(struct Curl_easy *data, char *newurl,
followtype type);
-CURLcode Curl_sendrecv(struct Curl_easy *data, struct curltime *nowp);
+CURLcode Curl_readwrite(struct connectdata *conn,
+ struct Curl_easy *data, bool *done,
+ bool *comeback);
int Curl_single_getsock(struct Curl_easy *data,
struct connectdata *conn, curl_socket_t *socks);
+CURLcode Curl_fillreadbuffer(struct Curl_easy *data, size_t bytes,
+ size_t *nreadp);
CURLcode Curl_retry_request(struct Curl_easy *data, char **url);
bool Curl_meets_timecondition(struct Curl_easy *data, time_t timeofdoc);
-
-/**
- * Write the transfer raw response bytes, as received from the connection.
- * Will handle all passed bytes or return an error. By default, this will
- * write the bytes as BODY to the client. Protocols may provide a
- * "write_resp" callback in their handler to add specific treatment. E.g.
- * HTTP parses response headers and passes them differently to the client.
- * @param data the transfer
- * @param buf the raw response bytes
- * @param blen the amount of bytes in `buf`
- * @param is_eos TRUE iff the connection indicates this to be the last
- * bytes of the response
- */
-CURLcode Curl_xfer_write_resp(struct Curl_easy *data,
- const char *buf, size_t blen,
- bool is_eos);
-
-/**
- * Write a single "header" line from a server response.
- * @param hd0 the 0-terminated, single header line
- * @param hdlen the length of the header line
- * @param is_eos TRUE iff this is the end of the response
- */
-CURLcode Curl_xfer_write_resp_hd(struct Curl_easy *data,
- const char *hd0, size_t hdlen, bool is_eos);
-
-#define CURL_XFER_NOP (0)
-#define CURL_XFER_RECV (1<<(0))
-#define CURL_XFER_SEND (1<<(1))
-#define CURL_XFER_SENDRECV (CURL_XFER_RECV|CURL_XFER_SEND)
-
-/**
- * The transfer is neither receiving nor sending now.
- */
-void Curl_xfer_setup_nop(struct Curl_easy *data);
-
-/**
- * The transfer will use socket 1 to send/recv. `recv_size` is
- * the amount to receive or -1 if unknown. `getheader` indicates
- * response header processing is expected.
- */
-void Curl_xfer_setup1(struct Curl_easy *data,
- int send_recv,
- curl_off_t recv_size,
- bool getheader);
-
-/**
- * The transfer will use socket 2 to send/recv. `recv_size` is
- * the amount to receive or -1 if unknown. With `shutdown` being
- * set, the transfer is only allowed to either send OR receive
- * and the socket 2 connection will be shutdown at the end of
- * the transfer. An unclean shutdown will fail the transfer.
- */
-void Curl_xfer_setup2(struct Curl_easy *data,
- int send_recv,
- curl_off_t recv_size,
- bool shutdown);
-
-/**
- * Multi has set transfer to DONE. Last chance to trigger
- * missing response things like writing an EOS to the client.
- */
-CURLcode Curl_xfer_write_done(struct Curl_easy *data, bool premature);
-
-/**
- * Return TRUE iff transfer has pending data to send. Checks involved
- * connection filters.
- */
-bool Curl_xfer_needs_flush(struct Curl_easy *data);
-
-/**
- * Flush any pending send data on the transfer connection.
- */
-CURLcode Curl_xfer_flush(struct Curl_easy *data);
-
-/**
- * Send data on the socket/connection filter designated
- * for transfer's outgoing data.
- * Will return CURLE_OK on blocking with (*pnwritten == 0).
- */
-CURLcode Curl_xfer_send(struct Curl_easy *data,
- const void *buf, size_t blen, bool eos,
- size_t *pnwritten);
-
-/**
- * Receive data on the socket/connection filter designated
- * for transfer's incoming data.
- * Will return CURLE_AGAIN on blocking with (*pnrcvd == 0).
- */
-CURLcode Curl_xfer_recv(struct Curl_easy *data,
- char *buf, size_t blen,
- ssize_t *pnrcvd);
-
-CURLcode Curl_xfer_send_close(struct Curl_easy *data);
-CURLcode Curl_xfer_send_shutdown(struct Curl_easy *data, bool *done);
-
-/**
- * Return TRUE iff the transfer is not done, but further progress
- * is blocked. For example when it is only receiving and its writer
- * is PAUSED.
- */
-bool Curl_xfer_is_blocked(struct Curl_easy *data);
+CURLcode Curl_get_upload_buffer(struct Curl_easy *data);
+
+CURLcode Curl_done_sending(struct Curl_easy *data,
+ struct SingleRequest *k);
+
+/* This sets up a forthcoming transfer */
+void
+Curl_setup_transfer (struct Curl_easy *data,
+ int sockindex, /* socket index to read from or -1 */
+ curl_off_t size, /* -1 if unknown at this point */
+ bool getheader, /* TRUE if header parsing is wanted */
+ int writesockindex /* socket index to write to. May be
+ the same we read from. -1
+ disables */
+ );
#endif /* HEADER_CURL_TRANSFER_H */
diff --git a/contrib/libs/curl/lib/url.c b/contrib/libs/curl/lib/url.c
index 3bf0c05985..b81785fe2e 100644
--- a/contrib/libs/curl/lib/url.c
+++ b/contrib/libs/curl/lib/url.c
@@ -56,7 +56,7 @@
#endif
#ifndef HAVE_SOCKET
-#error "We cannot compile without socket() support!"
+#error "We can't compile without socket() support!"
#endif
#include <limits.h>
@@ -136,7 +136,7 @@ static void data_priority_cleanup(struct Curl_easy *data);
#endif
/* Some parts of the code (e.g. chunked encoding) assume this buffer has at
- * more than just a few bytes to play with. Do not let it become too small or
+ * more than just a few bytes to play with. Don't let it become too small or
* bad things will happen.
*/
#if READBUFFER_SIZE < READBUFFER_MIN
@@ -234,6 +234,8 @@ CURLcode Curl_close(struct Curl_easy **datap)
data = *datap;
*datap = NULL;
+ Curl_expire_clear(data); /* shut off timers */
+
/* Detach connection if any is left. This should not be normal, but can be
the case for example with CONNECT_ONLY + recv/send (test 556) */
Curl_detach_connection(data);
@@ -251,8 +253,6 @@ CURLcode Curl_close(struct Curl_easy **datap)
}
}
- Curl_expire_clear(data); /* shut off any timers left */
-
data->magic = 0; /* force a clear AFTER the possibly enforced removal from
the multi handle, since that function uses the magic
field! */
@@ -260,14 +260,19 @@ CURLcode Curl_close(struct Curl_easy **datap)
if(data->state.rangestringalloc)
free(data->state.range);
- /* freed here just in case DONE was not called */
- Curl_req_free(&data->req, data);
+ /* freed here just in case DONE wasn't called */
+ Curl_free_request_state(data);
/* Close down all open SSL info and sessions */
Curl_ssl_close_all(data);
Curl_safefree(data->state.first_host);
+ Curl_safefree(data->state.scratch);
Curl_ssl_free_certinfo(data);
+ /* Cleanup possible redirect junk */
+ free(data->req.newurl);
+ data->req.newurl = NULL;
+
if(data->state.referer_alloc) {
Curl_safefree(data->state.referer);
data->state.referer_alloc = FALSE;
@@ -275,14 +280,14 @@ CURLcode Curl_close(struct Curl_easy **datap)
data->state.referer = NULL;
up_free(data);
+ Curl_safefree(data->state.buffer);
Curl_dyn_free(&data->state.headerb);
+ Curl_safefree(data->state.ulbuf);
Curl_flush_cookies(data, TRUE);
-#ifndef CURL_DISABLE_ALTSVC
Curl_altsvc_save(data, data->asi, data->set.str[STRING_ALTSVC]);
Curl_altsvc_cleanup(&data->asi);
-#endif
-#ifndef CURL_DISABLE_HSTS
Curl_hsts_save(data, data->hsts, data->set.str[STRING_HSTS]);
+#ifndef CURL_DISABLE_HSTS
if(!data->share || !data->share->hsts)
Curl_hsts_cleanup(&data->hsts);
curl_slist_free_all(data->state.hstslist); /* clean up list */
@@ -293,10 +298,6 @@ CURLcode Curl_close(struct Curl_easy **datap)
Curl_safefree(data->info.contenttype);
Curl_safefree(data->info.wouldredirect);
- /* this destroys the channel and we cannot use it anymore after this */
- Curl_resolver_cancel(data);
- Curl_resolver_cleanup(data->state.async.resolver);
-
data_priority_cleanup(data);
/* No longer a dirty share, if it exists */
@@ -306,9 +307,7 @@ CURLcode Curl_close(struct Curl_easy **datap)
Curl_share_unlock(data, CURL_LOCK_DATA_SHARE);
}
-#ifndef CURL_DISABLE_PROXY
Curl_safefree(data->state.aptr.proxyuserpwd);
-#endif
Curl_safefree(data->state.aptr.uagent);
Curl_safefree(data->state.aptr.userpwd);
Curl_safefree(data->state.aptr.accept_encoding);
@@ -316,20 +315,23 @@ CURLcode Curl_close(struct Curl_easy **datap)
Curl_safefree(data->state.aptr.rangeline);
Curl_safefree(data->state.aptr.ref);
Curl_safefree(data->state.aptr.host);
-#ifndef CURL_DISABLE_COOKIES
Curl_safefree(data->state.aptr.cookiehost);
-#endif
-#ifndef CURL_DISABLE_RTSP
Curl_safefree(data->state.aptr.rtsp_transport);
-#endif
Curl_safefree(data->state.aptr.user);
Curl_safefree(data->state.aptr.passwd);
-#ifndef CURL_DISABLE_PROXY
Curl_safefree(data->state.aptr.proxyuser);
Curl_safefree(data->state.aptr.proxypasswd);
+
+#ifndef CURL_DISABLE_DOH
+ if(data->req.doh) {
+ Curl_dyn_free(&data->req.doh->probe[0].serverdoh);
+ Curl_dyn_free(&data->req.doh->probe[1].serverdoh);
+ curl_slist_free_all(data->req.doh->headers);
+ Curl_safefree(data->req.doh);
+ }
#endif
-#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_FORM_API)
+#ifndef CURL_DISABLE_HTTP
Curl_mime_cleanpart(data->state.formp);
Curl_safefree(data->state.formp);
#endif
@@ -362,9 +364,10 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data)
set->fread_func_set = (curl_read_callback)fread;
set->is_fread_set = 0;
+ set->seek_func = ZERO_NULL;
set->seek_client = ZERO_NULL;
- set->filesize = -1; /* we do not know the size */
+ set->filesize = -1; /* we don't know the size */
set->postfieldsize = -1; /* unknown size */
set->maxredirs = 30; /* sensible default */
@@ -414,7 +417,8 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data)
set->new_file_perms = 0644; /* Default permissions */
set->allowed_protocols = (curl_prot_t) CURLPROTO_ALL;
- set->redir_protocols = CURLPROTO_REDIR;
+ set->redir_protocols = CURLPROTO_HTTP | CURLPROTO_HTTPS | CURLPROTO_FTP |
+ CURLPROTO_FTPS;
#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
/*
@@ -426,34 +430,30 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data)
/* Set the default CA cert bundle/path detected/specified at build time.
*
- * If Schannel or SecureTransport is the selected SSL backend then these
- * locations are ignored. We allow setting CA location for schannel and
- * securetransport when explicitly specified by the user via
- * CURLOPT_CAINFO / --cacert.
+ * If Schannel is the selected SSL backend then these locations are
+ * ignored. We allow setting CA location for schannel only when explicitly
+ * specified by the user via CURLOPT_CAINFO / --cacert.
*/
- if(Curl_ssl_backend() != CURLSSLBACKEND_SCHANNEL &&
- Curl_ssl_backend() != CURLSSLBACKEND_SECURETRANSPORT) {
+ if(Curl_ssl_backend() != CURLSSLBACKEND_SCHANNEL) {
#if defined(CURL_CA_BUNDLE)
result = Curl_setstropt(&set->str[STRING_SSL_CAFILE], CURL_CA_BUNDLE);
if(result)
return result;
-#ifndef CURL_DISABLE_PROXY
+
result = Curl_setstropt(&set->str[STRING_SSL_CAFILE_PROXY],
CURL_CA_BUNDLE);
if(result)
return result;
#endif
-#endif
#if defined(CURL_CA_PATH)
result = Curl_setstropt(&set->str[STRING_SSL_CAPATH], CURL_CA_PATH);
if(result)
return result;
-#ifndef CURL_DISABLE_PROXY
+
result = Curl_setstropt(&set->str[STRING_SSL_CAPATH_PROXY], CURL_CA_PATH);
if(result)
return result;
#endif
-#endif
}
#ifndef CURL_DISABLE_FTP
@@ -465,7 +465,6 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data)
set->tcp_keepalive = FALSE;
set->tcp_keepintvl = 60;
set->tcp_keepidle = 60;
- set->tcp_keepcnt = 9;
set->tcp_fastopen = FALSE;
set->tcp_nodelay = TRUE;
set->ssl_enable_alpn = TRUE;
@@ -515,16 +514,6 @@ CURLcode Curl_open(struct Curl_easy **curl)
data->magic = CURLEASY_MAGIC_NUMBER;
- Curl_req_init(&data->req);
-
- result = Curl_resolver_init(data, &data->state.async.resolver);
- if(result) {
- DEBUGF(fprintf(stderr, "Error: resolver_init failed\n"));
- Curl_req_free(&data->req, data);
- free(data);
- return result;
- }
-
result = Curl_init_userdefined(data);
if(!result) {
Curl_dyn_init(&data->state.headerb, CURL_MAX_HTTP_HEADER);
@@ -535,32 +524,36 @@ CURLcode Curl_open(struct Curl_easy **curl)
data->state.recent_conn_id = -1;
/* and not assigned an id yet */
data->id = -1;
- data->mid = -1;
-#ifndef CURL_DISABLE_DOH
- data->set.dohfor_mid = -1;
-#endif
data->progress.flags |= PGRS_HIDE;
data->state.current_speed = -1; /* init to negative == impossible */
-#ifndef CURL_DISABLE_HTTP
- Curl_llist_init(&data->state.httphdrs, NULL);
-#endif
}
if(result) {
- Curl_resolver_cleanup(data->state.async.resolver);
Curl_dyn_free(&data->state.headerb);
Curl_freeset(data);
- Curl_req_free(&data->req, data);
free(data);
data = NULL;
}
else
*curl = data;
+
return result;
}
-void Curl_conn_free(struct Curl_easy *data, struct connectdata *conn)
+static void conn_shutdown(struct Curl_easy *data)
+{
+ DEBUGASSERT(data);
+ infof(data, "Closing connection");
+
+ /* possible left-overs from the async name resolvers */
+ Curl_resolver_cancel(data);
+
+ Curl_conn_close(data, SECONDARYSOCKET);
+ Curl_conn_close(data, FIRSTSOCKET);
+}
+
+static void conn_free(struct Curl_easy *data, struct connectdata *conn)
{
size_t i;
@@ -570,6 +563,7 @@ void Curl_conn_free(struct Curl_easy *data, struct connectdata *conn)
Curl_conn_cf_discard_all(data, conn, (int)i);
}
+ Curl_resolver_cleanup(conn->resolve_async.resolver);
Curl_free_idnconverted_hostname(&conn->host);
Curl_free_idnconverted_hostname(&conn->conn_to_host);
#ifndef CURL_DISABLE_PROXY
@@ -587,8 +581,11 @@ void Curl_conn_free(struct Curl_easy *data, struct connectdata *conn)
Curl_safefree(conn->sasl_authzid);
Curl_safefree(conn->options);
Curl_safefree(conn->oauth_bearer);
- Curl_safefree(conn->host.rawalloc); /* hostname buffer */
- Curl_safefree(conn->conn_to_host.rawalloc); /* hostname buffer */
+#ifndef CURL_DISABLE_HTTP
+ Curl_dyn_free(&conn->trailer);
+#endif
+ Curl_safefree(conn->host.rawalloc); /* host name buffer */
+ Curl_safefree(conn->conn_to_host.rawalloc); /* host name buffer */
Curl_safefree(conn->hostname_resolve);
Curl_safefree(conn->secondaryhostname);
Curl_safefree(conn->localdev);
@@ -597,14 +594,13 @@ void Curl_conn_free(struct Curl_easy *data, struct connectdata *conn)
#ifdef USE_UNIX_SOCKETS
Curl_safefree(conn->unix_domain_socket);
#endif
- Curl_safefree(conn->destination);
free(conn); /* free all the connection oriented data */
}
/*
* Disconnects the given connection. Note the connection may not be the
- * primary connection, like when freeing room in the connection pool or
+ * primary connection, like when freeing room in the connection cache or
* killing of a dead old connection.
*
* A connection needs an easy handle when closing down. We support this passed
@@ -612,16 +608,18 @@ void Curl_conn_free(struct Curl_easy *data, struct connectdata *conn)
* disassociated from an easy handle.
*
* This function MUST NOT reset state in the Curl_easy struct if that
- * is not strictly bound to the life-time of *this* particular connection.
+ * isn't strictly bound to the life-time of *this* particular connection.
+ *
*/
-bool Curl_on_disconnect(struct Curl_easy *data,
- struct connectdata *conn, bool aborted)
+
+void Curl_disconnect(struct Curl_easy *data,
+ struct connectdata *conn, bool dead_connection)
{
/* there must be a connection to close */
DEBUGASSERT(conn);
- /* it must be removed from the connection pool */
- DEBUGASSERT(!conn->bits.in_cpool);
+ /* it must be removed from the connection cache */
+ DEBUGASSERT(!conn->bundle);
/* there must be an associated transfer */
DEBUGASSERT(data);
@@ -629,11 +627,22 @@ bool Curl_on_disconnect(struct Curl_easy *data,
/* the transfer must be detached from the connection */
DEBUGASSERT(!data->conn);
- DEBUGF(infof(data, "Curl_disconnect(conn #%" FMT_OFF_T ", aborted=%d)",
- conn->connection_id, aborted));
+ DEBUGF(infof(data, "Curl_disconnect(conn #%"
+ CURL_FORMAT_CURL_OFF_T ", dead=%d)",
+ conn->connection_id, dead_connection));
+ /*
+ * If this connection isn't marked to force-close, leave it open if there
+ * are other users of it
+ */
+ if(CONN_INUSE(conn) && !dead_connection) {
+ DEBUGF(infof(data, "Curl_disconnect when inuse: %zu", CONN_INUSE(conn)));
+ return;
+ }
- if(conn->dns_entry)
- Curl_resolv_unlink(data, &conn->dns_entry);
+ if(conn->dns_entry) {
+ Curl_resolv_unlock(data, conn->dns_entry);
+ conn->dns_entry = NULL;
+ }
/* Cleanup NTLM connection-related data */
Curl_http_auth_cleanup_ntlm(conn);
@@ -642,31 +651,47 @@ bool Curl_on_disconnect(struct Curl_easy *data,
Curl_http_auth_cleanup_negotiate(conn);
if(conn->connect_only)
- /* treat the connection as aborted in CONNECT_ONLY situations */
- aborted = TRUE;
+ /* treat the connection as dead in CONNECT_ONLY situations */
+ dead_connection = TRUE;
+
+ /* temporarily attach the connection to this transfer handle for the
+ disconnect and shutdown */
+ Curl_attach_connection(data, conn);
- return aborted;
+ if(conn->handler && conn->handler->disconnect)
+ /* This is set if protocol-specific cleanups should be made */
+ conn->handler->disconnect(data, conn, dead_connection);
+
+ conn_shutdown(data);
+ Curl_resolver_cancel(data);
+
+ /* detach it again */
+ Curl_detach_connection(data);
+
+ conn_free(data, conn);
}
/*
- * Curl_xfer_may_multiplex()
+ * IsMultiplexingPossible()
*
- * Return a TRUE, iff the transfer can be done over an (appropriate)
- * multiplexed connection.
+ * Return a bitmask with the available multiplexing options for the given
+ * requested connection.
*/
-static bool Curl_xfer_may_multiplex(const struct Curl_easy *data,
- const struct connectdata *conn)
+static int IsMultiplexingPossible(const struct Curl_easy *handle,
+ const struct connectdata *conn)
{
+ int avail = 0;
+
/* If an HTTP protocol and multiplexing is enabled */
if((conn->handler->protocol & PROTO_FAMILY_HTTP) &&
(!conn->bits.protoconnstart || !conn->bits.close)) {
- if(Curl_multiplex_wanted(data->multi) &&
- (data->state.httpwant >= CURL_HTTP_VERSION_2))
- /* allows HTTP/2 or newer */
- return TRUE;
+ if(Curl_multiplex_wanted(handle->multi) &&
+ (handle->state.httpwant >= CURL_HTTP_VERSION_2))
+ /* allows HTTP/2 */
+ avail |= CURLPIPE_MULTIPLEX;
}
- return FALSE;
+ return avail;
}
#ifndef CURL_DISABLE_PROXY
@@ -701,7 +726,7 @@ socks_proxy_info_matches(const struct proxy_info *data,
return TRUE;
}
#else
-/* disabled, will not get called */
+/* disabled, won't get called */
#define proxy_info_matches(x,y) FALSE
#define socks_proxy_info_matches(x,y) FALSE
#endif
@@ -720,7 +745,7 @@ static bool conn_maxage(struct Curl_easy *data,
idletime /= 1000; /* integer seconds is fine */
if(idletime > data->set.maxage_conn) {
- infof(data, "Too old connection (%" FMT_TIMEDIFF_T
+ infof(data, "Too old connection (%" CURL_FORMAT_TIMEDIFF_T
" seconds idle), disconnect it", idletime);
return TRUE;
}
@@ -730,7 +755,7 @@ static bool conn_maxage(struct Curl_easy *data,
if(data->set.maxlifetime_conn && lifetime > data->set.maxlifetime_conn) {
infof(data,
- "Too old connection (%" FMT_TIMEDIFF_T
+ "Too old connection (%" CURL_FORMAT_TIMEDIFF_T
" seconds since creation), disconnect it", lifetime);
return TRUE;
}
@@ -740,24 +765,23 @@ static bool conn_maxage(struct Curl_easy *data,
}
/*
- * Return TRUE iff the given connection is considered dead.
+ * This function checks if the given connection is dead and extracts it from
+ * the connection cache if so.
+ *
+ * When this is called as a Curl_conncache_foreach() callback, the connection
+ * cache lock is held!
+ *
+ * Returns TRUE if the connection was dead and extracted.
*/
-bool Curl_conn_seems_dead(struct connectdata *conn,
- struct Curl_easy *data,
- struct curltime *pnow)
+static bool extract_if_dead(struct connectdata *conn,
+ struct Curl_easy *data)
{
- DEBUGASSERT(!data->conn);
if(!CONN_INUSE(conn)) {
- /* The check for a dead socket makes sense only if the connection is not in
+ /* The check for a dead socket makes sense only if the connection isn't in
use */
bool dead;
- struct curltime now;
- if(!pnow) {
- now = Curl_now();
- pnow = &now;
- }
-
- if(conn_maxage(data, conn, *pnow)) {
+ struct curltime now = Curl_now();
+ if(conn_maxage(data, conn, now)) {
/* avoid check if already too old */
dead = TRUE;
}
@@ -777,7 +801,7 @@ bool Curl_conn_seems_dead(struct connectdata *conn,
}
else {
- bool input_pending = FALSE;
+ bool input_pending;
Curl_attach_connection(data, conn);
dead = !Curl_conn_is_alive(data, conn, &input_pending);
@@ -790,47 +814,77 @@ bool Curl_conn_seems_dead(struct connectdata *conn,
* any time (HTTP/2 PING for example), the protocol handler needs
* to install its own `connection_check` callback.
*/
- DEBUGF(infof(data, "connection has input pending, not reusable"));
dead = TRUE;
}
Curl_detach_connection(data);
}
if(dead) {
- /* remove connection from cpool */
- infof(data, "Connection %" FMT_OFF_T " seems to be dead",
+ infof(data, "Connection %" CURL_FORMAT_CURL_OFF_T " seems to be dead",
conn->connection_id);
+ Curl_conncache_remove_conn(data, conn, FALSE);
return TRUE;
}
}
return FALSE;
}
-CURLcode Curl_conn_upkeep(struct Curl_easy *data,
- struct connectdata *conn,
- struct curltime *now)
-{
- CURLcode result = CURLE_OK;
- if(Curl_timediff(*now, conn->keepalive) <= data->set.upkeep_interval_ms)
- return result;
+struct prunedead {
+ struct Curl_easy *data;
+ struct connectdata *extracted;
+};
- /* briefly attach for action */
- Curl_attach_connection(data, conn);
- if(conn->handler->connection_check) {
- /* Do a protocol-specific keepalive check on the connection. */
- unsigned int rc;
- rc = conn->handler->connection_check(data, conn, CONNCHECK_KEEPALIVE);
- if(rc & CONNRESULT_DEAD)
- result = CURLE_RECV_ERROR;
- }
- else {
- /* Do the generic action on the FIRSTSOCKET filter chain */
- result = Curl_conn_keep_alive(data, conn, FIRSTSOCKET);
+/*
+ * Wrapper to use extract_if_dead() function in Curl_conncache_foreach()
+ *
+ */
+static int call_extract_if_dead(struct Curl_easy *data,
+ struct connectdata *conn, void *param)
+{
+ struct prunedead *p = (struct prunedead *)param;
+ if(extract_if_dead(conn, data)) {
+ /* stop the iteration here, pass back the connection that was extracted */
+ p->extracted = conn;
+ return 1;
}
- Curl_detach_connection(data);
+ return 0; /* continue iteration */
+}
- conn->keepalive = *now;
- return result;
+/*
+ * This function scans the connection cache for half-open/dead connections,
+ * closes and removes them. The cleanup is done at most once per second.
+ *
+ * When called, this transfer has no connection attached.
+ */
+static void prune_dead_connections(struct Curl_easy *data)
+{
+ struct curltime now = Curl_now();
+ timediff_t elapsed;
+
+ DEBUGASSERT(!data->conn); /* no connection */
+ CONNCACHE_LOCK(data);
+ elapsed =
+ Curl_timediff(now, data->state.conn_cache->last_cleanup);
+ CONNCACHE_UNLOCK(data);
+
+ if(elapsed >= 1000L) {
+ struct prunedead prune;
+ prune.data = data;
+ prune.extracted = NULL;
+ while(Curl_conncache_foreach(data, data->state.conn_cache, &prune,
+ call_extract_if_dead)) {
+ /* unlocked */
+
+ /* remove connection from cache */
+ Curl_conncache_remove_conn(data, prune.extracted, TRUE);
+
+ /* disconnect it */
+ Curl_disconnect(data, prune.extracted, TRUE);
+ }
+ CONNCACHE_LOCK(data);
+ data->state.conn_cache->last_cleanup = now;
+ CONNCACHE_UNLOCK(data);
+ }
}
#ifdef USE_SSH
@@ -844,420 +898,426 @@ static bool ssh_config_matches(struct connectdata *one,
#define ssh_config_matches(x,y) FALSE
#endif
-struct url_conn_match {
- struct connectdata *found;
- struct Curl_easy *data;
- struct connectdata *needle;
- BIT(may_multiplex);
- BIT(want_ntlm_http);
- BIT(want_proxy_ntlm_http);
-
- BIT(wait_pipe);
- BIT(force_reuse);
- BIT(seen_pending_conn);
- BIT(seen_single_use_conn);
- BIT(seen_multiplex_conn);
-};
-
-static bool url_match_conn(struct connectdata *conn, void *userdata)
+/*
+ * Given one filled in connection struct (named needle), this function should
+ * detect if there already is one that has all the significant details
+ * exactly the same and thus should be used instead.
+ *
+ * If there is a match, this function returns TRUE - and has marked the
+ * connection as 'in-use'. It must later be called with ConnectionDone() to
+ * return back to 'idle' (unused) state.
+ *
+ * The force_reuse flag is set if the connection must be used.
+ */
+static bool
+ConnectionExists(struct Curl_easy *data,
+ struct connectdata *needle,
+ struct connectdata **usethis,
+ bool *force_reuse,
+ bool *waitpipe)
{
- struct url_conn_match *match = userdata;
- struct Curl_easy *data = match->data;
- struct connectdata *needle = match->needle;
-
- /* Check if `conn` can be used for transfer `data` */
-
- if(conn->connect_only || conn->bits.close)
- /* connect-only or to-be-closed connections will not be reused */
- return FALSE;
-
- if(data->set.ipver != CURL_IPRESOLVE_WHATEVER
- && data->set.ipver != conn->ip_version) {
- /* skip because the connection is not via the requested IP version */
- return FALSE;
- }
+ struct connectdata *chosen = NULL;
+ bool foundPendingCandidate = FALSE;
+ bool canmultiplex = FALSE;
+ struct connectbundle *bundle;
+ struct Curl_llist_element *curr;
- if(needle->localdev || needle->localport) {
- /* If we are bound to a specific local end (IP+port), we must not
- reuse a random other one, although if we did not ask for a
- particular one we can reuse one that was bound.
-
- This comparison is a bit rough and too strict. Since the input
- parameters can be specified in numerous ways and still end up the
- same it would take a lot of processing to make it really accurate.
- Instead, this matching will assume that reuses of bound connections
- will most likely also reuse the exact same binding parameters and
- missing out a few edge cases should not hurt anyone very much.
- */
- if((conn->localport != needle->localport) ||
- (conn->localportrange != needle->localportrange) ||
- (needle->localdev &&
- (!conn->localdev || strcmp(conn->localdev, needle->localdev))))
- return FALSE;
- }
-
- if(needle->bits.conn_to_host != conn->bits.conn_to_host)
- /* do not mix connections that use the "connect to host" feature and
- * connections that do not use this feature */
- return FALSE;
+#ifdef USE_NTLM
+ bool wantNTLMhttp = ((data->state.authhost.want &
+ (CURLAUTH_NTLM | CURLAUTH_NTLM_WB)) &&
+ (needle->handler->protocol & PROTO_FAMILY_HTTP));
+#ifndef CURL_DISABLE_PROXY
+ bool wantProxyNTLMhttp = (needle->bits.proxy_user_passwd &&
+ ((data->state.authproxy.want &
+ (CURLAUTH_NTLM | CURLAUTH_NTLM_WB)) &&
+ (needle->handler->protocol & PROTO_FAMILY_HTTP)));
+#else
+ bool wantProxyNTLMhttp = FALSE;
+#endif
+#endif
+ /* plain HTTP with upgrade */
+ bool h2upgrade = (data->state.httpwant == CURL_HTTP_VERSION_2_0) &&
+ (needle->handler->protocol & CURLPROTO_HTTP);
- if(needle->bits.conn_to_port != conn->bits.conn_to_port)
- /* do not mix connections that use the "connect to port" feature and
- * connections that do not use this feature */
- return FALSE;
+ *usethis = NULL;
+ *force_reuse = FALSE;
+ *waitpipe = FALSE;
- if(!Curl_conn_is_connected(conn, FIRSTSOCKET) ||
- conn->bits.asks_multiplex) {
- /* Not yet connected, or not yet decided if it multiplexes. The later
- * happens for HTTP/2 Upgrade: requests that need a response. */
- if(match->may_multiplex) {
- match->seen_pending_conn = TRUE;
- /* Do not pick a connection that has not connected yet */
- infof(data, "Connection #%" FMT_OFF_T
- " is not open enough, cannot reuse", conn->connection_id);
- }
- /* Do not pick a connection that has not connected yet */
+ /* Look up the bundle with all the connections to this particular host.
+ Locks the connection cache, beware of early returns! */
+ bundle = Curl_conncache_find_bundle(data, needle, data->state.conn_cache);
+ if(!bundle) {
+ CONNCACHE_UNLOCK(data);
return FALSE;
}
- /* `conn` is connected. If it has transfers, can we add ours to it? */
-
- if(CONN_INUSE(conn)) {
- if(!conn->bits.multiplex) {
- /* conn busy and conn cannot take more transfers */
- match->seen_single_use_conn = TRUE;
- return FALSE;
+ infof(data, "Found bundle for host: %p [%s]",
+ (void *)bundle, (bundle->multiuse == BUNDLE_MULTIPLEX ?
+ "can multiplex" : "serially"));
+
+ /* We can only multiplex iff the transfer allows it AND we know
+ * that the server we want to talk to supports it as well. */
+ canmultiplex = FALSE;
+ if(IsMultiplexingPossible(data, needle)) {
+ if(bundle->multiuse == BUNDLE_UNKNOWN) {
+ if(data->set.pipewait) {
+ infof(data, "Server doesn't support multiplex yet, wait");
+ *waitpipe = TRUE;
+ CONNCACHE_UNLOCK(data);
+ return FALSE; /* no reuse */
+ }
+ infof(data, "Server doesn't support multiplex (yet)");
}
- match->seen_multiplex_conn = TRUE;
- if(!match->may_multiplex)
- /* conn busy and transfer cannot be multiplexed */
- return FALSE;
- else {
- /* transfer and conn multiplex. Are they on the same multi? */
- struct Curl_llist_node *e = Curl_llist_head(&conn->easyq);
- struct Curl_easy *entry = Curl_node_elem(e);
- if(entry->multi != data->multi)
- return FALSE;
+ else if(bundle->multiuse == BUNDLE_MULTIPLEX) {
+ if(Curl_multiplex_wanted(data->multi))
+ canmultiplex = TRUE;
+ else
+ infof(data, "Could multiplex, but not asked to");
+ }
+ else if(bundle->multiuse == BUNDLE_NO_MULTIUSE) {
+ infof(data, "Can not multiplex, even if we wanted to");
}
}
- /* `conn` is connected and we could add the transfer to it, if
- * all the other criteria do match. */
- /* Does `conn` use the correct protocol? */
-#ifdef USE_UNIX_SOCKETS
- if(needle->unix_domain_socket) {
- if(!conn->unix_domain_socket)
- return FALSE;
- if(strcmp(needle->unix_domain_socket, conn->unix_domain_socket))
- return FALSE;
- if(needle->bits.abstract_unix_socket != conn->bits.abstract_unix_socket)
- return FALSE;
- }
- else if(conn->unix_domain_socket)
- return FALSE;
-#endif
+ curr = bundle->conn_list.head;
+ while(curr) {
+ struct connectdata *check = curr->ptr;
+ /* Get next node now. We might remove a dead `check` connection which
+ * would invalidate `curr` as well. */
+ curr = curr->next;
- if((needle->handler->flags&PROTOPT_SSL) !=
- (conn->handler->flags&PROTOPT_SSL))
- /* do not do mixed SSL and non-SSL connections */
- if(get_protocol_family(conn->handler) !=
- needle->handler->protocol || !conn->bits.tls_upgraded)
- /* except protocols that have been upgraded via TLS */
- return FALSE;
+ /* Note that if we use an HTTP proxy in normal mode (no tunneling), we
+ * check connections to that proxy and not to the actual remote server.
+ */
+ if(check->connect_only || check->bits.close)
+ /* connect-only or to-be-closed connections will not be reused */
+ continue;
-#ifndef CURL_DISABLE_PROXY
- if(needle->bits.httpproxy != conn->bits.httpproxy ||
- needle->bits.socksproxy != conn->bits.socksproxy)
- return FALSE;
+ if(data->set.ipver != CURL_IPRESOLVE_WHATEVER
+ && data->set.ipver != check->ip_version) {
+ /* skip because the connection is not via the requested IP version */
+ continue;
+ }
- if(needle->bits.socksproxy &&
- !socks_proxy_info_matches(&needle->socks_proxy,
- &conn->socks_proxy))
- return FALSE;
+ if(!canmultiplex) {
+ if(Curl_resolver_asynch() &&
+ /* primary_ip[0] is NUL only if the resolving of the name hasn't
+ completed yet and until then we don't reuse this connection */
+ !check->primary_ip[0])
+ continue;
+ }
- if(needle->bits.httpproxy) {
- if(needle->bits.tunnel_proxy != conn->bits.tunnel_proxy)
- return FALSE;
+ if(CONN_INUSE(check)) {
+ if(!canmultiplex) {
+ /* transfer can't be multiplexed and check is in use */
+ continue;
+ }
+ else {
+ /* Could multiplex, but not when check belongs to another multi */
+ struct Curl_llist_element *e = check->easyq.head;
+ struct Curl_easy *entry = e->ptr;
+ if(entry->multi != data->multi)
+ continue;
+ }
+ }
- if(!proxy_info_matches(&needle->http_proxy, &conn->http_proxy))
- return FALSE;
+ if(!Curl_conn_is_connected(check, FIRSTSOCKET)) {
+ foundPendingCandidate = TRUE;
+ /* Don't pick a connection that hasn't connected yet */
+ infof(data, "Connection #%" CURL_FORMAT_CURL_OFF_T
+ " isn't open enough, can't reuse", check->connection_id);
+ continue;
+ }
- if(IS_HTTPS_PROXY(needle->http_proxy.proxytype)) {
- /* https proxies come in different types, http/1.1, h2, ... */
- if(needle->http_proxy.proxytype != conn->http_proxy.proxytype)
- return FALSE;
- /* match SSL config to proxy */
- if(!Curl_ssl_conn_config_match(data, conn, TRUE)) {
- DEBUGF(infof(data,
- "Connection #%" FMT_OFF_T
- " has different SSL proxy parameters, cannot reuse",
- conn->connection_id));
- return FALSE;
+ /* `check` is connected. if it is in use and does not support multiplex,
+ * we cannot use it. */
+ if(!check->bits.multiplex && CONN_INUSE(check))
+ continue;
+
+#ifdef USE_UNIX_SOCKETS
+ if(needle->unix_domain_socket) {
+ if(!check->unix_domain_socket)
+ continue;
+ if(strcmp(needle->unix_domain_socket, check->unix_domain_socket))
+ continue;
+ if(needle->bits.abstract_unix_socket !=
+ check->bits.abstract_unix_socket)
+ continue;
+ }
+ else if(check->unix_domain_socket)
+ continue;
+#endif
+
+ if((needle->handler->flags&PROTOPT_SSL) !=
+ (check->handler->flags&PROTOPT_SSL))
+ /* don't do mixed SSL and non-SSL connections */
+ if(get_protocol_family(check->handler) !=
+ needle->handler->protocol || !check->bits.tls_upgraded)
+ /* except protocols that have been upgraded via TLS */
+ continue;
+
+ if(needle->bits.conn_to_host != check->bits.conn_to_host)
+ /* don't mix connections that use the "connect to host" feature and
+ * connections that don't use this feature */
+ continue;
+
+ if(needle->bits.conn_to_port != check->bits.conn_to_port)
+ /* don't mix connections that use the "connect to port" feature and
+ * connections that don't use this feature */
+ continue;
+
+#ifndef CURL_DISABLE_PROXY
+ if(needle->bits.httpproxy != check->bits.httpproxy ||
+ needle->bits.socksproxy != check->bits.socksproxy)
+ continue;
+
+ if(needle->bits.socksproxy &&
+ !socks_proxy_info_matches(&needle->socks_proxy,
+ &check->socks_proxy))
+ continue;
+
+ if(needle->bits.httpproxy) {
+ if(needle->bits.tunnel_proxy != check->bits.tunnel_proxy)
+ continue;
+
+ if(!proxy_info_matches(&needle->http_proxy, &check->http_proxy))
+ continue;
+
+ if(IS_HTTPS_PROXY(needle->http_proxy.proxytype)) {
+ /* https proxies come in different types, http/1.1, h2, ... */
+ if(needle->http_proxy.proxytype != check->http_proxy.proxytype)
+ continue;
+ /* match SSL config to proxy */
+ if(!Curl_ssl_conn_config_match(data, check, TRUE)) {
+ DEBUGF(infof(data,
+ "Connection #%" CURL_FORMAT_CURL_OFF_T
+ " has different SSL proxy parameters, can't reuse",
+ check->connection_id));
+ continue;
+ }
+ /* the SSL config to the server, which may apply here is checked
+ * further below */
}
- /* the SSL config to the server, which may apply here is checked
- * further below */
}
- }
#endif
- if(match->may_multiplex &&
- (data->state.httpwant == CURL_HTTP_VERSION_2_0) &&
- (needle->handler->protocol & CURLPROTO_HTTP) &&
- !conn->httpversion) {
- if(data->set.pipewait) {
- infof(data, "Server upgrade does not support multiplex yet, wait");
- match->found = NULL;
- match->wait_pipe = TRUE;
- return TRUE; /* stop searching, we want to wait */
- }
- infof(data, "Server upgrade cannot be used");
- return FALSE;
- }
-
- if(!(needle->handler->flags & PROTOPT_CREDSPERREQUEST)) {
- /* This protocol requires credentials per connection,
- so verify that we are using the same name and password as well */
- if(Curl_timestrcmp(needle->user, conn->user) ||
- Curl_timestrcmp(needle->passwd, conn->passwd) ||
- Curl_timestrcmp(needle->sasl_authzid, conn->sasl_authzid) ||
- Curl_timestrcmp(needle->oauth_bearer, conn->oauth_bearer)) {
- /* one of them was different */
- return FALSE;
+ if(h2upgrade && !check->httpversion && canmultiplex) {
+ if(data->set.pipewait) {
+ infof(data, "Server upgrade doesn't support multiplex yet, wait");
+ *waitpipe = TRUE;
+ CONNCACHE_UNLOCK(data);
+ return FALSE; /* no reuse */
+ }
+ infof(data, "Server upgrade cannot be used");
+ continue; /* can't be used atm */
+ }
+
+ if(needle->localdev || needle->localport) {
+ /* If we are bound to a specific local end (IP+port), we must not
+ reuse a random other one, although if we didn't ask for a
+ particular one we can reuse one that was bound.
+
+ This comparison is a bit rough and too strict. Since the input
+ parameters can be specified in numerous ways and still end up the
+ same it would take a lot of processing to make it really accurate.
+ Instead, this matching will assume that reuses of bound connections
+ will most likely also reuse the exact same binding parameters and
+ missing out a few edge cases shouldn't hurt anyone very much.
+ */
+ if((check->localport != needle->localport) ||
+ (check->localportrange != needle->localportrange) ||
+ (needle->localdev &&
+ (!check->localdev || strcmp(check->localdev, needle->localdev))))
+ continue;
+ }
+
+ if(!(needle->handler->flags & PROTOPT_CREDSPERREQUEST)) {
+ /* This protocol requires credentials per connection,
+ so verify that we're using the same name and password as well */
+ if(Curl_timestrcmp(needle->user, check->user) ||
+ Curl_timestrcmp(needle->passwd, check->passwd) ||
+ Curl_timestrcmp(needle->sasl_authzid, check->sasl_authzid) ||
+ Curl_timestrcmp(needle->oauth_bearer, check->oauth_bearer)) {
+ /* one of them was different */
+ continue;
+ }
}
- }
- /* GSS delegation differences do not actually affect every connection
- and auth method, but this check takes precaution before efficiency */
- if(needle->gssapi_delegation != conn->gssapi_delegation)
- return FALSE;
+ /* GSS delegation differences do not actually affect every connection
+ and auth method, but this check takes precaution before efficiency */
+ if(needle->gssapi_delegation != check->gssapi_delegation)
+ continue;
- /* If looking for HTTP and the HTTP version we want is less
- * than the HTTP version of conn, continue looking */
- if((needle->handler->protocol & PROTO_FAMILY_HTTP) &&
- (((conn->httpversion >= 20) &&
- (data->state.httpwant < CURL_HTTP_VERSION_2_0))
- || ((conn->httpversion >= 30) &&
- (data->state.httpwant < CURL_HTTP_VERSION_3))))
- return FALSE;
+ /* If looking for HTTP and the HTTP version we want is less
+ * than the HTTP version of the check connection, continue looking */
+ if((needle->handler->protocol & PROTO_FAMILY_HTTP) &&
+ (((check->httpversion >= 20) &&
+ (data->state.httpwant < CURL_HTTP_VERSION_2_0))
+ || ((check->httpversion >= 30) &&
+ (data->state.httpwant < CURL_HTTP_VERSION_3))))
+ continue;
#ifdef USE_SSH
- else if(get_protocol_family(needle->handler) & PROTO_FAMILY_SSH) {
- if(!ssh_config_matches(needle, conn))
- return FALSE;
- }
+ else if(get_protocol_family(needle->handler) & PROTO_FAMILY_SSH) {
+ if(!ssh_config_matches(needle, check))
+ continue;
+ }
#endif
#ifndef CURL_DISABLE_FTP
- else if(get_protocol_family(needle->handler) & PROTO_FAMILY_FTP) {
- /* Also match ACCOUNT, ALTERNATIVE-TO-USER, USE_SSL and CCC options */
- if(Curl_timestrcmp(needle->proto.ftpc.account,
- conn->proto.ftpc.account) ||
- Curl_timestrcmp(needle->proto.ftpc.alternative_to_user,
- conn->proto.ftpc.alternative_to_user) ||
- (needle->proto.ftpc.use_ssl != conn->proto.ftpc.use_ssl) ||
- (needle->proto.ftpc.ccc != conn->proto.ftpc.ccc))
- return FALSE;
- }
+ else if(get_protocol_family(needle->handler) & PROTO_FAMILY_FTP) {
+ /* Also match ACCOUNT, ALTERNATIVE-TO-USER, USE_SSL and CCC options */
+ if(Curl_timestrcmp(needle->proto.ftpc.account,
+ check->proto.ftpc.account) ||
+ Curl_timestrcmp(needle->proto.ftpc.alternative_to_user,
+ check->proto.ftpc.alternative_to_user) ||
+ (needle->proto.ftpc.use_ssl != check->proto.ftpc.use_ssl) ||
+ (needle->proto.ftpc.ccc != check->proto.ftpc.ccc))
+ continue;
+ }
#endif
- /* Additional match requirements if talking TLS OR
- * not talking to an HTTP proxy OR using a tunnel through a proxy */
- if((needle->handler->flags&PROTOPT_SSL)
+ /* Additional match requirements if talking TLS OR
+ * not talking to a HTTP proxy OR using a tunnel through a proxy */
+ if((needle->handler->flags&PROTOPT_SSL)
#ifndef CURL_DISABLE_PROXY
- || !needle->bits.httpproxy || needle->bits.tunnel_proxy
-#endif
- ) {
- /* Talking the same protocol scheme or a TLS upgraded protocol in the
- * same protocol family? */
- if(!strcasecompare(needle->handler->scheme, conn->handler->scheme) &&
- (get_protocol_family(conn->handler) !=
- needle->handler->protocol || !conn->bits.tls_upgraded))
- return FALSE;
-
- /* If needle has "conn_to_*" set, conn must match this */
- if((needle->bits.conn_to_host && !strcasecompare(
- needle->conn_to_host.name, conn->conn_to_host.name)) ||
- (needle->bits.conn_to_port &&
- needle->conn_to_port != conn->conn_to_port))
- return FALSE;
-
- /* hostname and port must match */
- if(!strcasecompare(needle->host.name, conn->host.name) ||
- needle->remote_port != conn->remote_port)
- return FALSE;
-
- /* If talking TLS, conn needs to use the same SSL options. */
- if((needle->handler->flags & PROTOPT_SSL) &&
- !Curl_ssl_conn_config_match(data, conn, FALSE)) {
- DEBUGF(infof(data,
- "Connection #%" FMT_OFF_T
- " has different SSL parameters, cannot reuse",
- conn->connection_id));
- return FALSE;
+ || !needle->bits.httpproxy || needle->bits.tunnel_proxy
+#endif
+ ) {
+ /* Talking the same protocol scheme or a TLS upgraded protocol in the
+ * same protocol family? */
+ if(!strcasecompare(needle->handler->scheme, check->handler->scheme) &&
+ (get_protocol_family(check->handler) !=
+ needle->handler->protocol || !check->bits.tls_upgraded))
+ continue;
+
+ /* If needle has "conn_to_*" set, check must match this */
+ if((needle->bits.conn_to_host && !strcasecompare(
+ needle->conn_to_host.name, check->conn_to_host.name)) ||
+ (needle->bits.conn_to_port &&
+ needle->conn_to_port != check->conn_to_port))
+ continue;
+
+ /* hostname and port must match */
+ if(!strcasecompare(needle->host.name, check->host.name) ||
+ needle->remote_port != check->remote_port)
+ continue;
+
+ /* If talking TLS, check needs to use the same SSL options. */
+ if((needle->handler->flags & PROTOPT_SSL) &&
+ !Curl_ssl_conn_config_match(data, check, FALSE)) {
+ DEBUGF(infof(data,
+ "Connection #%" CURL_FORMAT_CURL_OFF_T
+ " has different SSL parameters, can't reuse",
+ check->connection_id));
+ continue;
+ }
}
- }
#if defined(USE_NTLM)
- /* If we are looking for an HTTP+NTLM connection, check if this is
- already authenticating with the right credentials. If not, keep
- looking so that we can reuse NTLM connections if
- possible. (Especially we must not reuse the same connection if
- partway through a handshake!) */
- if(match->want_ntlm_http) {
- if(Curl_timestrcmp(needle->user, conn->user) ||
- Curl_timestrcmp(needle->passwd, conn->passwd)) {
-
- /* we prefer a credential match, but this is at least a connection
- that can be reused and "upgraded" to NTLM */
- if(conn->http_ntlm_state == NTLMSTATE_NONE)
- match->found = conn;
- return FALSE;
- }
- }
- else if(conn->http_ntlm_state != NTLMSTATE_NONE) {
- /* Connection is using NTLM auth but we do not want NTLM */
- return FALSE;
- }
+ /* If we are looking for an HTTP+NTLM connection, check if this is
+ already authenticating with the right credentials. If not, keep
+ looking so that we can reuse NTLM connections if
+ possible. (Especially we must not reuse the same connection if
+ partway through a handshake!) */
+ if(wantNTLMhttp) {
+ if(Curl_timestrcmp(needle->user, check->user) ||
+ Curl_timestrcmp(needle->passwd, check->passwd)) {
+
+ /* we prefer a credential match, but this is at least a connection
+ that can be reused and "upgraded" to NTLM */
+ if(check->http_ntlm_state == NTLMSTATE_NONE)
+ chosen = check;
+ continue;
+ }
+ }
+ else if(check->http_ntlm_state != NTLMSTATE_NONE) {
+ /* Connection is using NTLM auth but we don't want NTLM */
+ continue;
+ }
#ifndef CURL_DISABLE_PROXY
- /* Same for Proxy NTLM authentication */
- if(match->want_proxy_ntlm_http) {
- /* Both conn->http_proxy.user and conn->http_proxy.passwd can be
- * NULL */
- if(!conn->http_proxy.user || !conn->http_proxy.passwd)
- return FALSE;
-
- if(Curl_timestrcmp(needle->http_proxy.user,
- conn->http_proxy.user) ||
- Curl_timestrcmp(needle->http_proxy.passwd,
- conn->http_proxy.passwd))
- return FALSE;
- }
- else if(conn->proxy_ntlm_state != NTLMSTATE_NONE) {
- /* Proxy connection is using NTLM auth but we do not want NTLM */
- return FALSE;
- }
-#endif
- if(match->want_ntlm_http || match->want_proxy_ntlm_http) {
- /* Credentials are already checked, we may use this connection.
- * With NTLM being weird as it is, we MUST use a
- * connection where it has already been fully negotiated.
- * If it has not, we keep on looking for a better one. */
- match->found = conn;
-
- if((match->want_ntlm_http &&
- (conn->http_ntlm_state != NTLMSTATE_NONE)) ||
- (match->want_proxy_ntlm_http &&
- (conn->proxy_ntlm_state != NTLMSTATE_NONE))) {
- /* We must use this connection, no other */
- match->force_reuse = TRUE;
- return TRUE;
+ /* Same for Proxy NTLM authentication */
+ if(wantProxyNTLMhttp) {
+ /* Both check->http_proxy.user and check->http_proxy.passwd can be
+ * NULL */
+ if(!check->http_proxy.user || !check->http_proxy.passwd)
+ continue;
+
+ if(Curl_timestrcmp(needle->http_proxy.user,
+ check->http_proxy.user) ||
+ Curl_timestrcmp(needle->http_proxy.passwd,
+ check->http_proxy.passwd))
+ continue;
+ }
+ else if(check->proxy_ntlm_state != NTLMSTATE_NONE) {
+ /* Proxy connection is using NTLM auth but we don't want NTLM */
+ continue;
+ }
+#endif
+ if(wantNTLMhttp || wantProxyNTLMhttp) {
+ /* Credentials are already checked, we may use this connection.
+ * With NTLM being weird as it is, we MUST use a
+ * connection where it has already been fully negotiated.
+ * If it has not, we keep on looking for a better one. */
+ chosen = check;
+
+ if((wantNTLMhttp &&
+ (check->http_ntlm_state != NTLMSTATE_NONE)) ||
+ (wantProxyNTLMhttp &&
+ (check->proxy_ntlm_state != NTLMSTATE_NONE))) {
+ /* We must use this connection, no other */
+ *force_reuse = TRUE;
+ break;
+ }
+ /* Continue look up for a better connection */
+ continue;
}
- /* Continue look up for a better connection */
- return FALSE;
- }
#endif
- if(CONN_INUSE(conn)) {
- DEBUGASSERT(match->may_multiplex);
- DEBUGASSERT(conn->bits.multiplex);
- /* If multiplexed, make sure we do not go over concurrency limit */
- if(CONN_INUSE(conn) >=
- Curl_multi_max_concurrent_streams(data->multi)) {
- infof(data, "client side MAX_CONCURRENT_STREAMS reached"
- ", skip (%zu)", CONN_INUSE(conn));
- return FALSE;
+ if(CONN_INUSE(check)) {
+ DEBUGASSERT(canmultiplex);
+ DEBUGASSERT(check->bits.multiplex);
+ /* If multiplexed, make sure we don't go over concurrency limit */
+ if(CONN_INUSE(check) >=
+ Curl_multi_max_concurrent_streams(data->multi)) {
+ infof(data, "client side MAX_CONCURRENT_STREAMS reached"
+ ", skip (%zu)", CONN_INUSE(check));
+ continue;
+ }
+ if(CONN_INUSE(check) >=
+ Curl_conn_get_max_concurrent(data, check, FIRSTSOCKET)) {
+ infof(data, "MAX_CONCURRENT_STREAMS reached, skip (%zu)",
+ CONN_INUSE(check));
+ continue;
+ }
+ /* When not multiplexed, we have a match here! */
+ infof(data, "Multiplexed connection found");
}
- if(CONN_INUSE(conn) >=
- Curl_conn_get_max_concurrent(data, conn, FIRSTSOCKET)) {
- infof(data, "MAX_CONCURRENT_STREAMS reached, skip (%zu)",
- CONN_INUSE(conn));
- return FALSE;
+ else if(extract_if_dead(check, data)) {
+ /* disconnect it */
+ Curl_disconnect(data, check, TRUE);
+ continue;
}
- /* When not multiplexed, we have a match here! */
- infof(data, "Multiplexed connection found");
- }
- else if(Curl_conn_seems_dead(conn, data, NULL)) {
- /* removed and disconnect. Do not treat as aborted. */
- Curl_cpool_disconnect(data, conn, FALSE);
- return FALSE;
- }
- /* We have found a connection. Let's stop searching. */
- match->found = conn;
- return TRUE;
-}
+ /* We have found a connection. Let's stop searching. */
+ chosen = check;
+ break;
+ } /* loop over connection bundle */
-static bool url_match_result(bool result, void *userdata)
-{
- struct url_conn_match *match = userdata;
- (void)result;
- if(match->found) {
- /* Attach it now while still under lock, so the connection does
- * no longer appear idle and can be reaped. */
- Curl_attach_connection(match->data, match->found);
- return TRUE;
+ if(chosen) {
+ /* mark it as used before releasing the lock */
+ Curl_attach_connection(data, chosen);
+ CONNCACHE_UNLOCK(data);
+ *usethis = chosen;
+ return TRUE; /* yes, we found one to use! */
}
- else if(match->seen_single_use_conn && !match->seen_multiplex_conn) {
- /* We've seen a single-use, existing connection to the destination and
- * no multiplexed one. It seems safe to assume that the server does
- * not support multiplexing. */
- match->wait_pipe = FALSE;
- }
- else if(match->seen_pending_conn && match->data->set.pipewait) {
- infof(match->data,
+ CONNCACHE_UNLOCK(data);
+
+ if(foundPendingCandidate && data->set.pipewait) {
+ infof(data,
"Found pending candidate for reuse and CURLOPT_PIPEWAIT is set");
- match->wait_pipe = TRUE;
+ *waitpipe = TRUE;
}
- match->force_reuse = FALSE;
- return FALSE;
-}
-
-/*
- * Given one filled in connection struct (named needle), this function should
- * detect if there already is one that has all the significant details
- * exactly the same and thus should be used instead.
- *
- * If there is a match, this function returns TRUE - and has marked the
- * connection as 'in-use'. It must later be called with ConnectionDone() to
- * return back to 'idle' (unused) state.
- *
- * The force_reuse flag is set if the connection must be used.
- */
-static bool
-ConnectionExists(struct Curl_easy *data,
- struct connectdata *needle,
- struct connectdata **usethis,
- bool *force_reuse,
- bool *waitpipe)
-{
- struct url_conn_match match;
- bool result;
- memset(&match, 0, sizeof(match));
- match.data = data;
- match.needle = needle;
- match.may_multiplex = Curl_xfer_may_multiplex(data, needle);
-
-#ifdef USE_NTLM
- match.want_ntlm_http = ((data->state.authhost.want & CURLAUTH_NTLM) &&
- (needle->handler->protocol & PROTO_FAMILY_HTTP));
-#ifndef CURL_DISABLE_PROXY
- match.want_proxy_ntlm_http =
- (needle->bits.proxy_user_passwd &&
- (data->state.authproxy.want & CURLAUTH_NTLM) &&
- (needle->handler->protocol & PROTO_FAMILY_HTTP));
-#endif
-#endif
-
- /* Find a connection in the pool that matches what "data + needle"
- * requires. If a suitable candidate is found, it is attached to "data". */
- result = Curl_cpool_find(data, needle->destination, needle->destination_len,
- url_match_conn, url_match_result, &match);
-
- /* wait_pipe is TRUE if we encounter a bundle that is undecided. There
- * is no matching connection then, yet. */
- *usethis = match.found;
- *force_reuse = match.force_reuse;
- *waitpipe = match.wait_pipe;
- return result;
+ return FALSE; /* no matching connecting exists */
}
/*
@@ -1265,30 +1325,11 @@ ConnectionExists(struct Curl_easy *data,
*/
#ifndef CURL_DISABLE_VERBOSE_STRINGS
void Curl_verboseconnect(struct Curl_easy *data,
- struct connectdata *conn, int sockindex)
+ struct connectdata *conn)
{
- if(data->set.verbose && sockindex == SECONDARYSOCKET)
- infof(data, "Connected 2nd connection to %s port %u",
- conn->secondary.remote_ip, conn->secondary.remote_port);
- else
+ if(data->set.verbose)
infof(data, "Connected to %s (%s) port %u",
- CURL_CONN_HOST_DISPNAME(conn), conn->primary.remote_ip,
- conn->primary.remote_port);
-#if !defined(CURL_DISABLE_HTTP)
- if(conn->handler->protocol & PROTO_FAMILY_HTTP) {
- switch(conn->alpn) {
- case CURL_HTTP_VERSION_3:
- infof(data, "using HTTP/3");
- break;
- case CURL_HTTP_VERSION_2:
- infof(data, "using HTTP/2");
- break;
- default:
- infof(data, "using HTTP/1.x");
- break;
- }
- }
-#endif
+ CURL_CONN_HOST_DISPNAME(conn), conn->primary_ip, conn->port);
}
#endif
@@ -1305,13 +1346,11 @@ static struct connectdata *allocate_conn(struct Curl_easy *data)
conn->sock[FIRSTSOCKET] = CURL_SOCKET_BAD; /* no file descriptor */
conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD; /* no file descriptor */
- conn->sockfd = CURL_SOCKET_BAD;
- conn->writesockfd = CURL_SOCKET_BAD;
conn->connection_id = -1; /* no ID */
- conn->primary.remote_port = -1; /* unknown at this point */
+ conn->port = -1; /* unknown at this point */
conn->remote_port = -1; /* unknown at this point */
- /* Default protocol-independent behavior does not support persistent
+ /* Default protocol-independent behavior doesn't support persistent
connections, so we set this to force-close. Protocols that support
this need to set this to FALSE in their "curl_do" functions. */
connclose(conn, "Default to force-close");
@@ -1356,6 +1395,12 @@ static struct connectdata *allocate_conn(struct Curl_easy *data)
conn->connect_only = data->set.connect_only;
conn->transport = TRNSPRT_TCP; /* most of them are TCP streams */
+#if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM) && \
+ defined(NTLM_WB_ENABLED)
+ conn->ntlm.ntlm_auth_hlpr_socket = CURL_SOCKET_BAD;
+ conn->proxyntlm.ntlm_auth_hlpr_socket = CURL_SOCKET_BAD;
+#endif
+
/* Initialize the easy handle list */
Curl_llist_init(&conn->easyq, NULL);
@@ -1597,7 +1642,7 @@ const struct Curl_handler *Curl_getn_scheme_handler(const char *scheme,
unsigned int c = 978;
while(l) {
c <<= 5;
- c += (unsigned int)Curl_raw_tolower(*s);
+ c += Curl_raw_tolower(*s);
s++;
l--;
}
@@ -1632,12 +1677,11 @@ static CURLcode findprotocol(struct Curl_easy *data,
}
}
- /* The protocol was not found in the table, but we do not have to assign it
+ /* The protocol was not found in the table, but we don't have to assign it
to anything since it is already assigned to a dummy-struct in the
create_conn() function when the connectdata struct is allocated. */
- failf(data, "Protocol \"%s\" %s%s", protostr,
- p ? "disabled" : "not supported",
- data->state.this_is_a_follow ? " (in redirect)":"");
+ failf(data, "Protocol \"%s\" not supported or disabled in " LIBCURL_NAME,
+ protostr);
return CURLE_UNSUPPORTED_PROTOCOL;
}
@@ -1657,7 +1701,7 @@ CURLcode Curl_uc_to_curlcode(CURLUcode uc)
}
}
-#ifdef USE_IPV6
+#ifdef ENABLE_IPV6
/*
* If the URL was set with an IPv6 numerical address with a zone id part, set
* the scope_id based on that!
@@ -1750,12 +1794,12 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
if(!use_set_uh) {
char *newurl;
- uc = curl_url_set(uh, CURLUPART_URL, data->state.url, (unsigned int)
- (CURLU_GUESS_SCHEME |
- CURLU_NON_SUPPORT_SCHEME |
- (data->set.disallow_username_in_url ?
- CURLU_DISALLOW_USER : 0) |
- (data->set.path_as_is ? CURLU_PATH_AS_IS : 0)));
+ uc = curl_url_set(uh, CURLUPART_URL, data->state.url,
+ CURLU_GUESS_SCHEME |
+ CURLU_NON_SUPPORT_SCHEME |
+ (data->set.disallow_username_in_url ?
+ CURLU_DISALLOW_USER : 0) |
+ (data->set.path_as_is ? CURLU_PATH_AS_IS : 0));
if(uc) {
failf(data, "URL rejected: %s", curl_url_strerror(uc));
return Curl_uc_to_curlcode(uc);
@@ -1781,7 +1825,7 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
return CURLE_OUT_OF_MEMORY;
}
else if(strlen(data->state.up.hostname) > MAX_URL_LEN) {
- failf(data, "Too long hostname (maximum is %d)", MAX_URL_LEN);
+ failf(data, "Too long host name (maximum is %d)", MAX_URL_LEN);
return CURLE_URL_MALFORMAT;
}
hostname = data->state.up.hostname;
@@ -1799,7 +1843,7 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
zonefrom_url(uh, data, conn);
}
- /* make sure the connect struct gets its own copy of the hostname */
+ /* make sure the connect struct gets its own copy of the host name */
conn->host.rawalloc = strdup(hostname ? hostname : "");
if(!conn->host.rawalloc)
return CURLE_OUT_OF_MEMORY;
@@ -1846,7 +1890,7 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
return result;
/*
- * username and password set with their own options override the
+ * User name and password set with their own options override the
* credentials possibly set in the URL.
*/
if(!data->set.str[STRING_PASSWORD]) {
@@ -1868,7 +1912,7 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
}
if(!data->set.str[STRING_USERNAME]) {
- /* we do not use the URL API's URL decoder option here since it rejects
+ /* we don't use the URL API's URL decoder option here since it rejects
control codes and we want to allow them for some schemes in the user
and password fields */
uc = curl_url_get(uh, CURLUPART_USER, &data->state.up.user, 0);
@@ -1915,14 +1959,14 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
}
else {
unsigned long port = strtoul(data->state.up.port, NULL, 10);
- conn->primary.remote_port = conn->remote_port =
+ conn->port = conn->remote_port =
(data->set.use_port && data->state.allow_port) ?
data->set.use_port : curlx_ultous(port);
}
(void)curl_url_get(uh, CURLUPART_QUERY, &data->state.up.query, 0);
-#ifdef USE_IPV6
+#ifdef ENABLE_IPV6
if(data->set.scope_id)
/* Override any scope that was set above. */
conn->scope_id = data->set.scope_id;
@@ -1933,7 +1977,7 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
/*
- * If we are doing a resumed transfer, we need to setup our stuff
+ * If we're doing a resumed transfer, we need to setup our stuff
* properly.
*/
static CURLcode setup_range(struct Curl_easy *data)
@@ -1945,7 +1989,7 @@ static CURLcode setup_range(struct Curl_easy *data)
free(s->range);
if(s->resume_from)
- s->range = aprintf("%" FMT_OFF_T "-", s->resume_from);
+ s->range = aprintf("%" CURL_FORMAT_CURL_OFF_T "-", s->resume_from);
else
s->range = strdup(data->set.str[STRING_SET_RANGE]);
@@ -1977,8 +2021,6 @@ static CURLcode setup_connection_internals(struct Curl_easy *data,
struct connectdata *conn)
{
const struct Curl_handler *p;
- const char *hostname;
- int port;
CURLcode result;
/* Perform setup complement if some. */
@@ -1993,40 +2035,30 @@ static CURLcode setup_connection_internals(struct Curl_easy *data,
p = conn->handler; /* May have changed. */
}
- if(conn->primary.remote_port < 0)
+ if(conn->port < 0)
/* we check for -1 here since if proxy was detected already, this
was very likely already set to the proxy port */
- conn->primary.remote_port = p->defport;
+ conn->port = p->defport;
- /* Now create the destination name */
-#ifndef CURL_DISABLE_PROXY
- if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) {
- hostname = conn->http_proxy.host.name;
- port = conn->primary.remote_port;
- }
- else
-#endif
- {
- port = conn->remote_port;
- if(conn->bits.conn_to_host)
- hostname = conn->conn_to_host.name;
- else
- hostname = conn->host.name;
- }
-
-#ifdef USE_IPV6
- conn->destination = aprintf("%u/%d/%s", conn->scope_id, port, hostname);
-#else
- conn->destination = aprintf("%d/%s", port, hostname);
-#endif
- if(!conn->destination)
- return CURLE_OUT_OF_MEMORY;
+ return CURLE_OK;
+}
- conn->destination_len = strlen(conn->destination) + 1;
- Curl_strntolower(conn->destination, conn->destination,
- conn->destination_len - 1);
+/*
+ * Curl_free_request_state() should free temp data that was allocated in the
+ * Curl_easy for this single request.
+ */
- return CURLE_OK;
+void Curl_free_request_state(struct Curl_easy *data)
+{
+ Curl_safefree(data->req.p.http);
+ Curl_safefree(data->req.newurl);
+#ifndef CURL_DISABLE_DOH
+ if(data->req.doh) {
+ Curl_close(&data->req.doh->probe[0].easy);
+ Curl_close(&data->req.doh->probe[1].easy);
+ }
+#endif
+ Curl_client_cleanup(data);
}
@@ -2058,21 +2090,27 @@ static char *detect_proxy(struct Curl_easy *data,
* the first to check for.)
*
* For compatibility, the all-uppercase versions of these variables are
- * checked if the lowercase versions do not exist.
+ * checked if the lowercase versions don't exist.
*/
- char proxy_env[20];
+ char proxy_env[128];
+ const char *protop = conn->handler->scheme;
char *envp = proxy_env;
#ifdef CURL_DISABLE_VERBOSE_STRINGS
(void)data;
#endif
- msnprintf(proxy_env, sizeof(proxy_env), "%s_proxy", conn->handler->scheme);
+ /* Now, build <protocol>_proxy and check for such a one to use */
+ while(*protop)
+ *envp++ = Curl_raw_tolower(*protop++);
+
+ /* append _proxy */
+ strcpy(envp, "_proxy");
/* read the protocol proxy: */
proxy = curl_getenv(proxy_env);
/*
- * We do not try the uppercase version of HTTP_PROXY because of
+ * We don't try the uppercase version of HTTP_PROXY because of
* security reasons:
*
* When curl is used in a webserver application
@@ -2089,6 +2127,7 @@ static char *detect_proxy(struct Curl_easy *data,
proxy = curl_getenv(proxy_env);
}
+ envp = proxy_env;
if(!proxy) {
#ifdef USE_WEBSOCKETS
/* websocket proxy fallbacks */
@@ -2121,7 +2160,7 @@ static char *detect_proxy(struct Curl_easy *data,
/*
* If this is supposed to use a proxy, we need to figure out the proxy
- * hostname, so that we can reuse an existing connection
+ * host name, so that we can reuse an existing connection
* that may exist registered to the same proxy host.
*/
static CURLcode parse_proxy(struct Curl_easy *data,
@@ -2263,12 +2302,11 @@ static CURLcode parse_proxy(struct Curl_easy *data,
}
if(port >= 0) {
proxyinfo->port = port;
- if(conn->primary.remote_port < 0 || sockstype ||
- !conn->socks_proxy.host.rawalloc)
- conn->primary.remote_port = port;
+ if(conn->port < 0 || sockstype || !conn->socks_proxy.host.rawalloc)
+ conn->port = port;
}
- /* now, clone the proxy hostname */
+ /* now, clone the proxy host name */
uc = curl_url_get(uhp, CURLUPART_HOST, &host, CURLU_URLDECODE);
if(uc) {
result = CURLE_OUT_OF_MEMORY;
@@ -2336,20 +2374,21 @@ static CURLcode parse_proxy_auth(struct Curl_easy *data,
data->state.aptr.proxyuser : "";
const char *proxypasswd = data->state.aptr.proxypasswd ?
data->state.aptr.proxypasswd : "";
- CURLcode result = CURLE_OUT_OF_MEMORY;
-
- conn->http_proxy.user = strdup(proxyuser);
- if(conn->http_proxy.user) {
- conn->http_proxy.passwd = strdup(proxypasswd);
- if(conn->http_proxy.passwd)
- result = CURLE_OK;
- else
- Curl_safefree(conn->http_proxy.user);
- }
+ CURLcode result = Curl_urldecode(proxyuser, 0, &conn->http_proxy.user, NULL,
+ REJECT_ZERO);
+ if(!result)
+ result = Curl_setstropt(&data->state.aptr.proxyuser,
+ conn->http_proxy.user);
+ if(!result)
+ result = Curl_urldecode(proxypasswd, 0, &conn->http_proxy.passwd,
+ NULL, REJECT_ZERO);
+ if(!result)
+ result = Curl_setstropt(&data->state.aptr.proxypasswd,
+ conn->http_proxy.passwd);
return result;
}
-/* create_conn helper to parse and init proxy values. to be called after Unix
+/* create_conn helper to parse and init proxy values. to be called after unix
socket init but before any proxy vars are evaluated. */
static CURLcode create_conn_helper_init_proxy(struct Curl_easy *data,
struct connectdata *conn)
@@ -2358,6 +2397,7 @@ static CURLcode create_conn_helper_init_proxy(struct Curl_easy *data,
char *socksproxy = NULL;
char *no_proxy = NULL;
CURLcode result = CURLE_OK;
+ bool spacesep = FALSE;
/*************************************************************
* Extract the user and password from the authentication string
@@ -2404,7 +2444,8 @@ static CURLcode create_conn_helper_init_proxy(struct Curl_easy *data,
}
if(Curl_check_noproxy(conn->host.name, data->set.str[STRING_NOPROXY] ?
- data->set.str[STRING_NOPROXY] : no_proxy)) {
+ data->set.str[STRING_NOPROXY] : no_proxy,
+ &spacesep)) {
Curl_safefree(proxy);
Curl_safefree(socksproxy);
}
@@ -2413,10 +2454,13 @@ static CURLcode create_conn_helper_init_proxy(struct Curl_easy *data,
/* if the host is not in the noproxy list, detect proxy. */
proxy = detect_proxy(data, conn);
#endif /* CURL_DISABLE_HTTP */
+ if(spacesep)
+ infof(data, "space-separated NOPROXY patterns are deprecated");
+
Curl_safefree(no_proxy);
#ifdef USE_UNIX_SOCKETS
- /* For the time being do not mix proxy and Unix domain sockets. See #1274 */
+ /* For the time being do not mix proxy and unix domain sockets. See #1274 */
if(proxy && conn->unix_domain_socket) {
free(proxy);
proxy = NULL;
@@ -2424,14 +2468,14 @@ static CURLcode create_conn_helper_init_proxy(struct Curl_easy *data,
#endif
if(proxy && (!*proxy || (conn->handler->flags & PROTOPT_NONETWORK))) {
- free(proxy); /* Do not bother with an empty proxy string or if the
- protocol does not work with network */
+ free(proxy); /* Don't bother with an empty proxy string or if the
+ protocol doesn't work with network */
proxy = NULL;
}
if(socksproxy && (!*socksproxy ||
(conn->handler->flags & PROTOPT_NONETWORK))) {
- free(socksproxy); /* Do not bother with an empty socks proxy string or if
- the protocol does not work with network */
+ free(socksproxy); /* Don't bother with an empty socks proxy string or if
+ the protocol doesn't work with network */
socksproxy = NULL;
}
@@ -2503,7 +2547,7 @@ static CURLcode create_conn_helper_init_proxy(struct Curl_easy *data,
conn->bits.proxy = conn->bits.httpproxy || conn->bits.socksproxy;
if(!conn->bits.proxy) {
- /* we are not using the proxy after all... */
+ /* we aren't using the proxy after all... */
conn->bits.proxy = FALSE;
conn->bits.httpproxy = FALSE;
conn->bits.socksproxy = FALSE;
@@ -2525,7 +2569,7 @@ out:
/*
* Curl_parse_login_details()
*
- * This is used to parse a login string for username, password and options in
+ * This is used to parse a login string for user name, password and options in
* the following formats:
*
* user
@@ -2540,15 +2584,14 @@ out:
*
* Parameters:
*
- * login [in] - login string.
- * len [in] - length of the login string.
- * userp [in/out] - address where a pointer to newly allocated memory
+ * login [in] - The login string.
+ * len [in] - The length of the login string.
+ * userp [in/out] - The address where a pointer to newly allocated memory
* holding the user will be stored upon completion.
- * passwdp [in/out] - address where a pointer to newly allocated memory
+ * passwdp [in/out] - The address where a pointer to newly allocated memory
* holding the password will be stored upon completion.
- * optionsp [in/out] - OPTIONAL address where a pointer to newly allocated
- * memory holding the options will be stored upon
- * completion.
+ * optionsp [in/out] - The address where a pointer to newly allocated memory
+ * holding the options will be stored upon completion.
*
* Returns CURLE_OK on success.
*/
@@ -2556,19 +2599,19 @@ CURLcode Curl_parse_login_details(const char *login, const size_t len,
char **userp, char **passwdp,
char **optionsp)
{
+ CURLcode result = CURLE_OK;
char *ubuf = NULL;
char *pbuf = NULL;
+ char *obuf = NULL;
const char *psep = NULL;
const char *osep = NULL;
size_t ulen;
size_t plen;
size_t olen;
- DEBUGASSERT(userp);
- DEBUGASSERT(passwdp);
-
/* Attempt to find the password separator */
- psep = memchr(login, ':', len);
+ if(passwdp)
+ psep = memchr(login, ':', len);
/* Attempt to find the options separator */
if(optionsp)
@@ -2580,40 +2623,64 @@ CURLcode Curl_parse_login_details(const char *login, const size_t len,
(osep ? (size_t)(osep - login) : len));
plen = (psep ?
(osep && osep > psep ? (size_t)(osep - psep) :
- (size_t)(login + len - psep)) - 1 : 0);
+ (size_t)(login + len - psep)) - 1 : 0);
olen = (osep ?
(psep && psep > osep ? (size_t)(psep - osep) :
- (size_t)(login + len - osep)) - 1 : 0);
+ (size_t)(login + len - osep)) - 1 : 0);
- /* Clone the user portion buffer, which can be zero length */
- ubuf = Curl_memdup0(login, ulen);
- if(!ubuf)
- goto error;
+ /* Allocate the user portion buffer, which can be zero length */
+ if(userp) {
+ ubuf = malloc(ulen + 1);
+ if(!ubuf)
+ result = CURLE_OUT_OF_MEMORY;
+ }
- /* Clone the password portion buffer */
- if(psep) {
- pbuf = Curl_memdup0(&psep[1], plen);
- if(!pbuf)
- goto error;
+ /* Allocate the password portion buffer */
+ if(!result && passwdp && psep) {
+ pbuf = malloc(plen + 1);
+ if(!pbuf) {
+ free(ubuf);
+ result = CURLE_OUT_OF_MEMORY;
+ }
}
/* Allocate the options portion buffer */
- if(optionsp) {
- char *obuf = NULL;
- if(olen) {
- obuf = Curl_memdup0(&osep[1], olen);
- if(!obuf)
- goto error;
+ if(!result && optionsp && olen) {
+ obuf = malloc(olen + 1);
+ if(!obuf) {
+ free(pbuf);
+ free(ubuf);
+ result = CURLE_OUT_OF_MEMORY;
}
- *optionsp = obuf;
}
- *userp = ubuf;
- *passwdp = pbuf;
- return CURLE_OK;
-error:
- free(ubuf);
- free(pbuf);
- return CURLE_OUT_OF_MEMORY;
+
+ if(!result) {
+ /* Store the user portion if necessary */
+ if(ubuf) {
+ memcpy(ubuf, login, ulen);
+ ubuf[ulen] = '\0';
+ Curl_safefree(*userp);
+ *userp = ubuf;
+ }
+
+ /* Store the password portion if necessary */
+ if(pbuf) {
+ memcpy(pbuf, psep + 1, plen);
+ pbuf[plen] = '\0';
+ Curl_safefree(*passwdp);
+ *passwdp = pbuf;
+ }
+
+ /* Store the options portion if necessary */
+ if(obuf) {
+ memcpy(obuf, osep + 1, olen);
+ obuf[olen] = '\0';
+ Curl_safefree(*optionsp);
+ *optionsp = obuf;
+ }
+ }
+
+ return result;
}
/*************************************************************
@@ -2672,7 +2739,7 @@ static CURLcode override_login(struct Curl_easy *data,
bool url_provided = FALSE;
if(data->state.aptr.user) {
- /* there was a username in the URL. Use the URL decoded version */
+ /* there was a user name in the URL. Use the URL decoded version */
userp = &data->state.aptr.user;
url_provided = TRUE;
}
@@ -2753,7 +2820,7 @@ static CURLcode override_login(struct Curl_easy *data,
}
/*
- * Set the login details so they are available in the connection
+ * Set the login details so they're available in the connection
*/
static CURLcode set_login(struct Curl_easy *data,
struct connectdata *conn)
@@ -2824,7 +2891,7 @@ static CURLcode parse_connect_to_host_port(struct Curl_easy *data,
/* detect and extract RFC6874-style IPv6-addresses */
if(*hostptr == '[') {
-#ifdef USE_IPV6
+#ifdef ENABLE_IPV6
char *ptr = ++hostptr; /* advance beyond the initial bracket */
while(*ptr && (ISXDIGIT(*ptr) || (*ptr == ':') || (*ptr == '.')))
ptr++;
@@ -2844,8 +2911,8 @@ static CURLcode parse_connect_to_host_port(struct Curl_easy *data,
else
infof(data, "Invalid IPv6 address format");
portptr = ptr;
- /* Note that if this did not end with a bracket, we still advanced the
- * hostptr first, but I cannot see anything wrong with that as no host
+ /* Note that if this didn't end with a bracket, we still advanced the
+ * hostptr first, but I can't see anything wrong with that as no host
* name nor a numeric can legally start with a bracket.
*/
#else
@@ -2859,7 +2926,7 @@ static CURLcode parse_connect_to_host_port(struct Curl_easy *data,
host_portno = strchr(portptr, ':');
if(host_portno) {
char *endp = NULL;
- *host_portno = '\0'; /* cut off number from hostname */
+ *host_portno = '\0'; /* cut off number from host name */
host_portno++;
if(*host_portno) {
long portparse = strtol(host_portno, &endp, 10);
@@ -2874,7 +2941,7 @@ static CURLcode parse_connect_to_host_port(struct Curl_easy *data,
}
}
- /* now, clone the cleaned hostname */
+ /* now, clone the cleaned host name */
DEBUGASSERT(hostptr);
*hostname_result = strdup(hostptr);
if(!*hostname_result) {
@@ -3007,7 +3074,7 @@ static CURLcode parse_connect_to_slist(struct Curl_easy *data,
#ifndef CURL_DISABLE_ALTSVC
if(data->asi && !host && (port == -1) &&
((conn->handler->protocol == CURLPROTO_HTTPS) ||
-#ifdef DEBUGBUILD
+#ifdef CURLDEBUG
/* allow debug builds to circumvent the HTTPS restriction */
getenv("CURL_ALTSVC_HTTP")
#else
@@ -3022,7 +3089,7 @@ static CURLcode parse_connect_to_slist(struct Curl_easy *data,
#ifdef USE_HTTP2
| ALPN_h2
#endif
-#ifdef USE_HTTP3
+#ifdef ENABLE_QUIC
| ALPN_h3
#endif
) & data->asi->flags;
@@ -3070,7 +3137,7 @@ static CURLcode parse_connect_to_slist(struct Curl_easy *data,
conn->transport = TRNSPRT_QUIC;
conn->httpversion = 30;
break;
- default: /* should not be possible */
+ default: /* shouldn't be possible */
break;
}
}
@@ -3109,85 +3176,143 @@ static CURLcode resolve_unix(struct Curl_easy *data,
return longpath ? CURLE_COULDNT_RESOLVE_HOST : CURLE_OUT_OF_MEMORY;
}
- hostaddr->refcount = 1; /* connection is the only one holding this */
+ hostaddr->inuse++;
conn->dns_entry = hostaddr;
return CURLE_OK;
}
#endif
-/*************************************************************
- * Resolve the address of the server or proxy
- *************************************************************/
-static CURLcode resolve_server(struct Curl_easy *data,
- struct connectdata *conn,
- bool *async)
+#ifndef CURL_DISABLE_PROXY
+static CURLcode resolve_proxy(struct Curl_easy *data,
+ struct connectdata *conn,
+ bool *async)
{
- struct hostname *ehost;
+ struct Curl_dns_entry *hostaddr = NULL;
+ struct hostname *host;
timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
- const char *peertype = "host";
int rc;
-#ifdef USE_UNIX_SOCKETS
- char *unix_path = conn->unix_domain_socket;
-#ifndef CURL_DISABLE_PROXY
- if(!unix_path && CONN_IS_PROXIED(conn) && conn->socks_proxy.host.name &&
- !strncmp(UNIX_SOCKET_PREFIX"/",
- conn->socks_proxy.host.name, sizeof(UNIX_SOCKET_PREFIX)))
- unix_path = conn->socks_proxy.host.name + sizeof(UNIX_SOCKET_PREFIX) - 1;
-#endif
+ DEBUGASSERT(conn->dns_entry == NULL);
- if(unix_path) {
- /* TODO, this only works if previous transport is TRNSPRT_TCP. Check it? */
- conn->transport = TRNSPRT_UNIX;
- return resolve_unix(data, conn, unix_path);
+ host = conn->bits.socksproxy ? &conn->socks_proxy.host :
+ &conn->http_proxy.host;
+
+ conn->hostname_resolve = strdup(host->name);
+ if(!conn->hostname_resolve)
+ return CURLE_OUT_OF_MEMORY;
+
+ rc = Curl_resolv_timeout(data, conn->hostname_resolve, (int)conn->port,
+ &hostaddr, timeout_ms);
+ conn->dns_entry = hostaddr;
+ if(rc == CURLRESOLV_PENDING)
+ *async = TRUE;
+ else if(rc == CURLRESOLV_TIMEDOUT)
+ return CURLE_OPERATION_TIMEDOUT;
+ else if(!hostaddr) {
+ failf(data, "Couldn't resolve proxy '%s'", host->dispname);
+ return CURLE_COULDNT_RESOLVE_PROXY;
}
+
+ return CURLE_OK;
+}
#endif
+static CURLcode resolve_host(struct Curl_easy *data,
+ struct connectdata *conn,
+ bool *async)
+{
+ struct Curl_dns_entry *hostaddr = NULL;
+ struct hostname *connhost;
+ timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
+ int rc;
+
DEBUGASSERT(conn->dns_entry == NULL);
-#ifndef CURL_DISABLE_PROXY
- if(CONN_IS_PROXIED(conn)) {
- ehost = conn->bits.socksproxy ? &conn->socks_proxy.host :
- &conn->http_proxy.host;
- peertype = "proxy";
- }
- else
-#endif
- {
- ehost = conn->bits.conn_to_host ? &conn->conn_to_host : &conn->host;
- /* If not connecting via a proxy, extract the port from the URL, if it is
- * there, thus overriding any defaults that might have been set above. */
- conn->primary.remote_port = conn->bits.conn_to_port ? conn->conn_to_port :
- conn->remote_port;
- }
+ connhost = conn->bits.conn_to_host ? &conn->conn_to_host : &conn->host;
+
+ /* If not connecting via a proxy, extract the port from the URL, if it is
+ * there, thus overriding any defaults that might have been set above. */
+ conn->port = conn->bits.conn_to_port ? conn->conn_to_port :
+ conn->remote_port;
/* Resolve target host right on */
- conn->hostname_resolve = strdup(ehost->name);
+ conn->hostname_resolve = strdup(connhost->name);
if(!conn->hostname_resolve)
return CURLE_OUT_OF_MEMORY;
- rc = Curl_resolv_timeout(data, conn->hostname_resolve,
- conn->primary.remote_port,
- &conn->dns_entry, timeout_ms);
+ rc = Curl_resolv_timeout(data, conn->hostname_resolve, (int)conn->port,
+ &hostaddr, timeout_ms);
+ conn->dns_entry = hostaddr;
if(rc == CURLRESOLV_PENDING)
*async = TRUE;
else if(rc == CURLRESOLV_TIMEDOUT) {
- failf(data, "Failed to resolve %s '%s' with timeout after %"
- FMT_TIMEDIFF_T " ms", peertype, ehost->dispname,
+ failf(data, "Failed to resolve host '%s' with timeout after %"
+ CURL_FORMAT_TIMEDIFF_T " ms", connhost->dispname,
Curl_timediff(Curl_now(), data->progress.t_startsingle));
return CURLE_OPERATION_TIMEDOUT;
}
- else if(!conn->dns_entry) {
- failf(data, "Could not resolve %s: %s", peertype, ehost->dispname);
+ else if(!hostaddr) {
+ failf(data, "Could not resolve host: %s", connhost->dispname);
return CURLE_COULDNT_RESOLVE_HOST;
}
return CURLE_OK;
}
+/* Perform a fresh resolve */
+static CURLcode resolve_fresh(struct Curl_easy *data,
+ struct connectdata *conn,
+ bool *async)
+{
+#ifdef USE_UNIX_SOCKETS
+ char *unix_path = conn->unix_domain_socket;
+
+#ifndef CURL_DISABLE_PROXY
+ if(!unix_path && conn->socks_proxy.host.name &&
+ !strncmp(UNIX_SOCKET_PREFIX"/",
+ conn->socks_proxy.host.name, sizeof(UNIX_SOCKET_PREFIX)))
+ unix_path = conn->socks_proxy.host.name + sizeof(UNIX_SOCKET_PREFIX) - 1;
+#endif
+
+ if(unix_path) {
+ conn->transport = TRNSPRT_UNIX;
+ return resolve_unix(data, conn, unix_path);
+ }
+#endif
+
+#ifndef CURL_DISABLE_PROXY
+ if(CONN_IS_PROXIED(conn))
+ return resolve_proxy(data, conn, async);
+#endif
+
+ return resolve_host(data, conn, async);
+}
+
+/*************************************************************
+ * Resolve the address of the server or proxy
+ *************************************************************/
+static CURLcode resolve_server(struct Curl_easy *data,
+ struct connectdata *conn,
+ bool *async)
+{
+ DEBUGASSERT(conn);
+ DEBUGASSERT(data);
+
+ /* Resolve the name of the server or proxy */
+ if(conn->bits.reuse) {
+ /* We're reusing the connection - no need to resolve anything, and
+ idnconvert_hostname() was called already in create_conn() for the reuse
+ case. */
+ *async = FALSE;
+ return CURLE_OK;
+ }
+
+ return resolve_fresh(data, conn, async);
+}
+
/*
* Cleanup the connection `temp`, just allocated for `data`, before using the
- * previously `existing` one for `data`. All relevant info is copied over
+ * previously `existing` one for `data`. All relevant info is copied over
* and `temp` is freed.
*/
static void reuse_conn(struct Curl_easy *data,
@@ -3197,7 +3322,7 @@ static void reuse_conn(struct Curl_easy *data,
/* get the user+password information from the temp struct since it may
* be new for this request even when we reuse an existing connection */
if(temp->user) {
- /* use the new username and password though */
+ /* use the new user name and password though */
Curl_safefree(existing->user);
Curl_safefree(existing->passwd);
existing->user = temp->user;
@@ -3209,7 +3334,7 @@ static void reuse_conn(struct Curl_easy *data,
#ifndef CURL_DISABLE_PROXY
existing->bits.proxy_user_passwd = temp->bits.proxy_user_passwd;
if(existing->bits.proxy_user_passwd) {
- /* use the new proxy username and proxy password though */
+ /* use the new proxy user name and proxy password though */
Curl_safefree(existing->http_proxy.user);
Curl_safefree(existing->socks_proxy.user);
Curl_safefree(existing->http_proxy.passwd);
@@ -3225,7 +3350,7 @@ static void reuse_conn(struct Curl_easy *data,
}
#endif
- /* Finding a connection for reuse in the cpool matches, among other
+ /* Finding a connection for reuse in the cache matches, among other
* things on the "remote-relevant" hostname. This is not necessarily
* the authority of the URL, e.g. conn->host. For example:
* - we use a proxy (not tunneling). we want to send all requests
@@ -3256,14 +3381,14 @@ static void reuse_conn(struct Curl_easy *data,
temp->hostname_resolve = NULL;
/* reuse init */
- existing->bits.reuse = TRUE; /* yes, we are reusing here */
+ existing->bits.reuse = TRUE; /* yes, we're reusing here */
- Curl_conn_free(data, temp);
+ conn_free(data, temp);
}
/**
* create_conn() sets up a new connectdata struct, or reuses an already
- * existing one, and resolves hostname.
+ * existing one, and resolves host name.
*
* if this function returns CURLE_OK and *async is set to TRUE, the resolve
* response will be coming asynchronously. If *async is FALSE, the name is
@@ -3287,6 +3412,8 @@ static CURLcode create_conn(struct Curl_easy *data,
bool connections_available = TRUE;
bool force_reuse = FALSE;
bool waitpipe = FALSE;
+ size_t max_host_connections = Curl_multi_max_host_connections(data->multi);
+ size_t max_total_connections = Curl_multi_max_total_connections(data->multi);
*async = FALSE;
*in_connect = NULL;
@@ -3346,7 +3473,7 @@ static CURLcode create_conn(struct Curl_easy *data,
}
#endif
- /* After the Unix socket init but before the proxy vars are used, parse and
+ /* After the unix socket init but before the proxy vars are used, parse and
initialize the proxy vars */
#ifndef CURL_DISABLE_PROXY
result = create_conn_helper_init_proxy(data, conn);
@@ -3443,7 +3570,7 @@ static CURLcode create_conn(struct Curl_easy *data,
goto out;
/***********************************************************************
- * file: is a special case in that it does not need a network connection
+ * file: is a special case in that it doesn't need a network connection
***********************************************************************/
#ifndef CURL_DISABLE_FILE
if(conn->handler->flags & PROTOPT_NONETWORK) {
@@ -3451,15 +3578,13 @@ static CURLcode create_conn(struct Curl_easy *data,
/* this is supposed to be the connect function so we better at least check
that the file is present here! */
DEBUGASSERT(conn->handler->connect_it);
- data->info.conn_scheme = conn->handler->scheme;
- /* conn_protocol can only provide "old" protocols */
- data->info.conn_protocol = (conn->handler->protocol) & CURLPROTO_MASK;
+ Curl_persistconninfo(data, conn, NULL, -1);
result = conn->handler->connect_it(data, &done);
- /* Setup a "faked" transfer that will do nothing */
+ /* Setup a "faked" transfer that'll do nothing */
if(!result) {
Curl_attach_connection(data, conn);
- result = Curl_cpool_add_conn(data, conn);
+ result = Curl_conncache_add_conn(data);
if(result)
goto out;
@@ -3473,7 +3598,7 @@ static CURLcode create_conn(struct Curl_easy *data,
(void)conn->handler->done(data, result, FALSE);
goto out;
}
- Curl_xfer_setup_nop(data);
+ Curl_setup_transfer(data, -1, -1, FALSE, -1);
}
/* since we skip do_init() */
@@ -3484,10 +3609,10 @@ static CURLcode create_conn(struct Curl_easy *data,
#endif
/* Setup filter for network connections */
- conn->recv[FIRSTSOCKET] = Curl_cf_recv;
- conn->send[FIRSTSOCKET] = Curl_cf_send;
- conn->recv[SECONDARYSOCKET] = Curl_cf_recv;
- conn->send[SECONDARYSOCKET] = Curl_cf_send;
+ conn->recv[FIRSTSOCKET] = Curl_conn_recv;
+ conn->send[FIRSTSOCKET] = Curl_conn_send;
+ conn->recv[SECONDARYSOCKET] = Curl_conn_recv;
+ conn->send[SECONDARYSOCKET] = Curl_conn_send;
conn->bits.tcp_fastopen = data->set.tcp_fastopen;
/* Complete the easy's SSL configuration for connection cache matching */
@@ -3495,8 +3620,7 @@ static CURLcode create_conn(struct Curl_easy *data,
if(result)
goto out;
- /* FIXME: do we really want to run this every time we add a transfer? */
- Curl_cpool_prune_dead(data);
+ prune_dead_connections(data);
/*************************************************************
* Check the current list of connections to see if we can
@@ -3555,31 +3679,50 @@ static CURLcode create_conn(struct Curl_easy *data,
"soon", and we wait for that */
connections_available = FALSE;
else {
- switch(Curl_cpool_check_limits(data, conn)) {
- case CPOOL_LIMIT_DEST:
- infof(data, "No more connections allowed to host");
- connections_available = FALSE;
- break;
- case CPOOL_LIMIT_TOTAL:
-#ifndef CURL_DISABLE_DOH
- if(data->set.dohfor_mid >= 0)
- infof(data, "Allowing DoH to override max connection limit");
- else
-#endif
- {
- infof(data, "No connections available in cache");
+ /* this gets a lock on the conncache */
+ struct connectbundle *bundle =
+ Curl_conncache_find_bundle(data, conn, data->state.conn_cache);
+
+ if(max_host_connections > 0 && bundle &&
+ (bundle->num_connections >= max_host_connections)) {
+ struct connectdata *conn_candidate;
+
+ /* The bundle is full. Extract the oldest connection. */
+ conn_candidate = Curl_conncache_extract_bundle(data, bundle);
+ CONNCACHE_UNLOCK(data);
+
+ if(conn_candidate)
+ Curl_disconnect(data, conn_candidate, FALSE);
+ else {
+ infof(data, "No more connections allowed to host: %zu",
+ max_host_connections);
connections_available = FALSE;
}
- break;
- default:
- break;
+ }
+ else
+ CONNCACHE_UNLOCK(data);
+
+ }
+
+ if(connections_available &&
+ (max_total_connections > 0) &&
+ (Curl_conncache_size(data) >= max_total_connections)) {
+ struct connectdata *conn_candidate;
+
+ /* The cache is full. Let's see if we can kill a connection. */
+ conn_candidate = Curl_conncache_extract_oldest(data);
+ if(conn_candidate)
+ Curl_disconnect(data, conn_candidate, FALSE);
+ else {
+ infof(data, "No connections available in cache");
+ connections_available = FALSE;
}
}
if(!connections_available) {
infof(data, "No connections available.");
- Curl_conn_free(data, conn);
+ conn_free(data, conn);
*in_connect = NULL;
result = CURLE_NO_CONNECTION_AVAILABLE;
@@ -3596,24 +3739,52 @@ static CURLcode create_conn(struct Curl_easy *data,
goto out;
}
+ result = Curl_resolver_init(data, &conn->resolve_async.resolver);
+ if(result) {
+ DEBUGF(fprintf(stderr, "Error: resolver_init failed\n"));
+ goto out;
+ }
+
Curl_attach_connection(data, conn);
- result = Curl_cpool_add_conn(data, conn);
+
+#ifdef USE_ARES
+ result = Curl_set_dns_servers(data, data->set.str[STRING_DNS_SERVERS]);
+ if(result && result != CURLE_NOT_BUILT_IN)
+ goto out;
+
+ result = Curl_set_dns_interface(data,
+ data->set.str[STRING_DNS_INTERFACE]);
+ if(result && result != CURLE_NOT_BUILT_IN)
+ goto out;
+
+ result = Curl_set_dns_local_ip4(data,
+ data->set.str[STRING_DNS_LOCAL_IP4]);
+ if(result && result != CURLE_NOT_BUILT_IN)
+ goto out;
+
+ result = Curl_set_dns_local_ip6(data,
+ data->set.str[STRING_DNS_LOCAL_IP6]);
+ if(result && result != CURLE_NOT_BUILT_IN)
+ goto out;
+#endif /* USE_ARES */
+
+ result = Curl_conncache_add_conn(data);
if(result)
goto out;
}
#if defined(USE_NTLM)
- /* If NTLM is requested in a part of this connection, make sure we do not
+ /* If NTLM is requested in a part of this connection, make sure we don't
assume the state is fine as this is a fresh connection and NTLM is
connection based. */
- if((data->state.authhost.picked & CURLAUTH_NTLM) &&
+ if((data->state.authhost.picked & (CURLAUTH_NTLM | CURLAUTH_NTLM_WB)) &&
data->state.authhost.done) {
infof(data, "NTLM picked AND auth done set, clear picked");
data->state.authhost.picked = CURLAUTH_NONE;
data->state.authhost.done = FALSE;
}
- if((data->state.authproxy.picked & CURLAUTH_NTLM) &&
+ if((data->state.authproxy.picked & (CURLAUTH_NTLM | CURLAUTH_NTLM_WB)) &&
data->state.authproxy.done) {
infof(data, "NTLM-proxy picked AND auth done set, clear picked");
data->state.authproxy.picked = CURLAUTH_NONE;
@@ -3634,35 +3805,23 @@ static CURLcode create_conn(struct Curl_easy *data,
/* Continue connectdata initialization here. */
- if(conn->bits.reuse) {
- /* We are reusing the connection - no need to resolve anything, and
- idnconvert_hostname() was called already in create_conn() for the reuse
- case. */
- *async = FALSE;
- }
- else {
- /*************************************************************
- * Resolve the address of the server or proxy
- *************************************************************/
- result = resolve_server(data, conn, async);
- if(result)
- goto out;
- }
+ /*
+ * Inherit the proper values from the urldata struct AFTER we have arranged
+ * the persistent connection stuff
+ */
+ conn->seek_func = data->set.seek_func;
+ conn->seek_client = data->set.seek_client;
- /* persist the scheme and handler the transfer is using */
- data->info.conn_scheme = conn->handler->scheme;
- /* conn_protocol can only provide "old" protocols */
- data->info.conn_protocol = (conn->handler->protocol) & CURLPROTO_MASK;
- data->info.used_proxy =
-#ifdef CURL_DISABLE_PROXY
- 0
-#else
- conn->bits.proxy
-#endif
- ;
+ /*************************************************************
+ * Resolve the address of the server or proxy
+ *************************************************************/
+ result = resolve_server(data, conn, async);
+ if(result)
+ goto out;
/* Everything general done, inform filters that they need
- * to prepare for a data transfer. */
+ * to prepare for a data transfer.
+ */
result = Curl_conn_ev_data_setup(data);
out:
@@ -3688,15 +3847,24 @@ CURLcode Curl_setup_conn(struct Curl_easy *data,
return result;
}
+#ifndef CURL_DISABLE_PROXY
+ /* set proxy_connect_closed to false unconditionally already here since it
+ is used strictly to provide extra information to a parent function in the
+ case of proxy CONNECT failures and we must make sure we don't have it
+ lingering set from a previous invoke */
+ conn->bits.proxy_connect_closed = FALSE;
+#endif
+
+#ifdef CURL_DO_LINEEND_CONV
+ data->state.crlf_conversions = 0; /* reset CRLF conversion counter */
+#endif /* CURL_DO_LINEEND_CONV */
+
/* set start time here for timeout purposes in the connect procedure, it
is later set again for the progress meter purpose */
conn->now = Curl_now();
if(!conn->bits.reuse)
result = Curl_conn_setup(data, conn, FIRSTSOCKET, conn->dns_entry,
CURL_CF_SSL_DEFAULT);
- if(!result)
- result = Curl_headers_init(data);
-
/* not sure we need this flag to be passed around any more */
*protocol_done = FALSE;
return result;
@@ -3711,8 +3879,11 @@ CURLcode Curl_connect(struct Curl_easy *data,
*asyncp = FALSE; /* assume synchronous resolves by default */
- /* Set the request to virgin state based on transfer settings */
- Curl_req_hard_reset(&data->req, data);
+ /* init the single-transfer specific data */
+ Curl_free_request_state(data);
+ memset(&data->req, 0, sizeof(struct SingleRequest));
+ data->req.size = data->req.maxdownload = -1;
+ data->req.no_body = data->set.opt_no_body;
/* call the stuff that needs to be called */
result = create_conn(data, &conn, asyncp);
@@ -3722,7 +3893,7 @@ CURLcode Curl_connect(struct Curl_easy *data,
/* multiplexed */
*protocol_done = TRUE;
else if(!*asyncp) {
- /* DNS resolution is done: that is either because this is a reused
+ /* DNS resolution is done: that's either because this is a reused
connection, in which case DNS was unnecessary, or because DNS
really did finish already (synch resolver/fast async resolve) */
result = Curl_setup_conn(data, protocol_done);
@@ -3733,10 +3904,11 @@ CURLcode Curl_connect(struct Curl_easy *data,
return result;
}
else if(result && conn) {
- /* We are not allowed to return failure with memory left allocated in the
+ /* We're not allowed to return failure with memory left allocated in the
connectdata struct, free those here */
Curl_detach_connection(data);
- Curl_cpool_disconnect(data, conn, TRUE);
+ Curl_conncache_remove_conn(data, conn, TRUE);
+ Curl_disconnect(data, conn, TRUE);
}
return result;
@@ -3754,31 +3926,40 @@ CURLcode Curl_connect(struct Curl_easy *data,
CURLcode Curl_init_do(struct Curl_easy *data, struct connectdata *conn)
{
+ struct SingleRequest *k = &data->req;
+
/* if this is a pushed stream, we need this: */
- CURLcode result;
+ CURLcode result = Curl_preconnect(data);
+ if(result)
+ return result;
if(conn) {
- conn->bits.do_more = FALSE; /* by default there is no curl_do_more() to
+ conn->bits.do_more = FALSE; /* by default there's no curl_do_more() to
use */
- /* if the protocol used does not support wildcards, switch it off */
+ /* if the protocol used doesn't support wildcards, switch it off */
if(data->state.wildcardmatch &&
!(conn->handler->flags & PROTOPT_WILDCARD))
data->state.wildcardmatch = FALSE;
}
data->state.done = FALSE; /* *_done() is not called yet */
+ data->state.expect100header = FALSE;
if(data->req.no_body)
/* in HTTP lingo, no body means using the HEAD request... */
data->state.httpreq = HTTPREQ_HEAD;
- result = Curl_req_start(&data->req, data);
- if(!result) {
- Curl_speedinit(data);
- Curl_pgrsSetUploadCounter(data, 0);
- Curl_pgrsSetDownloadCounter(data, 0);
- }
- return result;
+ k->start = Curl_now(); /* start time */
+ k->header = TRUE; /* assume header */
+ k->bytecount = 0;
+ k->ignorebody = FALSE;
+
+ Curl_client_cleanup(data);
+ Curl_speedinit(data);
+ Curl_pgrsSetUploadCounter(data, 0);
+ Curl_pgrsSetDownloadCounter(data, 0);
+
+ return CURLE_OK;
}
#if defined(USE_HTTP2) || defined(USE_HTTP3)
diff --git a/contrib/libs/curl/lib/url.h b/contrib/libs/curl/lib/url.h
index 47c1db44f3..7c1a29bc3c 100644
--- a/contrib/libs/curl/lib/url.h
+++ b/contrib/libs/curl/lib/url.h
@@ -37,11 +37,11 @@ void Curl_freeset(struct Curl_easy *data);
CURLcode Curl_uc_to_curlcode(CURLUcode uc);
CURLcode Curl_close(struct Curl_easy **datap); /* opposite of curl_open() */
CURLcode Curl_connect(struct Curl_easy *, bool *async, bool *protocol_connect);
-bool Curl_on_disconnect(struct Curl_easy *data,
- struct connectdata *, bool aborted);
+void Curl_disconnect(struct Curl_easy *data,
+ struct connectdata *, bool dead_connection);
CURLcode Curl_setup_conn(struct Curl_easy *data,
bool *protocol_done);
-void Curl_conn_free(struct Curl_easy *data, struct connectdata *conn);
+void Curl_free_request_state(struct Curl_easy *data);
CURLcode Curl_parse_login_details(const char *login, const size_t len,
char **userptr, char **passwdptr,
char **optionsptr);
@@ -59,27 +59,11 @@ const struct Curl_handler *Curl_getn_scheme_handler(const char *scheme,
specified */
#ifdef CURL_DISABLE_VERBOSE_STRINGS
-#define Curl_verboseconnect(x,y,z) Curl_nop_stmt
+#define Curl_verboseconnect(x,y) Curl_nop_stmt
#else
-void Curl_verboseconnect(struct Curl_easy *data, struct connectdata *conn,
- int sockindex);
+void Curl_verboseconnect(struct Curl_easy *data, struct connectdata *conn);
#endif
-/**
- * Return TRUE iff the given connection is considered dead.
- * @param nowp NULL or pointer to time being checked against.
- */
-bool Curl_conn_seems_dead(struct connectdata *conn,
- struct Curl_easy *data,
- struct curltime *nowp);
-
-/**
- * Perform upkeep operations on the connection.
- */
-CURLcode Curl_conn_upkeep(struct Curl_easy *data,
- struct connectdata *conn,
- struct curltime *now);
-
#if defined(USE_HTTP2) || defined(USE_HTTP3)
void Curl_data_priority_clear_state(struct Curl_easy *data);
#else
diff --git a/contrib/libs/curl/lib/urlapi-int.h b/contrib/libs/curl/lib/urlapi-int.h
index fcffab2e95..d6e240aa36 100644
--- a/contrib/libs/curl/lib/urlapi-int.h
+++ b/contrib/libs/curl/lib/urlapi-int.h
@@ -28,11 +28,12 @@
size_t Curl_is_absolute_url(const char *url, char *buf, size_t buflen,
bool guess_scheme);
-CURLUcode Curl_url_set_authority(CURLU *u, const char *authority);
+CURLUcode Curl_url_set_authority(CURLU *u, const char *authority,
+ unsigned int flags);
-#ifdef UNITTESTS
-UNITTEST CURLUcode Curl_parse_port(struct Curl_URL *u, struct dynbuf *host,
- bool has_scheme);
+#ifdef DEBUGBUILD
+CURLUcode Curl_parse_port(struct Curl_URL *u, struct dynbuf *host,
+ bool has_scheme);
#endif
#endif /* HEADER_CURL_URLAPI_INT_H */
diff --git a/contrib/libs/curl/lib/urlapi.c b/contrib/libs/curl/lib/urlapi.c
index 3d4a3f94b8..0d11e48c92 100644
--- a/contrib/libs/curl/lib/urlapi.c
+++ b/contrib/libs/curl/lib/urlapi.c
@@ -41,13 +41,13 @@
#include "curl_memory.h"
#include "memdebug.h"
- /* MS-DOS/Windows style drive prefix, eg c: in c:foo */
+ /* MSDOS/Windows style drive prefix, eg c: in c:foo */
#define STARTS_WITH_DRIVE_PREFIX(str) \
((('a' <= str[0] && str[0] <= 'z') || \
('A' <= str[0] && str[0] <= 'Z')) && \
(str[1] == ':'))
- /* MS-DOS/Windows style drive prefix, optionally with
+ /* MSDOS/Windows style drive prefix, optionally with
* a '|' instead of ':', followed by a slash or NUL */
#define STARTS_WITH_URL_DRIVE_PREFIX(str) \
((('a' <= (str)[0] && (str)[0] <= 'z') || \
@@ -59,11 +59,11 @@
#define MAX_SCHEME_LEN 40
/*
- * If USE_IPV6 is disabled, we still want to parse IPv6 addresses, so make
+ * If ENABLE_IPV6 is disabled, we still want to parse IPv6 addresses, so make
* sure we have _some_ value for AF_INET6 without polluting our fake value
* everywhere.
*/
-#if !defined(USE_IPV6) && !defined(AF_INET6)
+#if !defined(ENABLE_IPV6) && !defined(AF_INET6)
#define AF_INET6 (AF_INET + 1)
#endif
@@ -79,10 +79,7 @@ struct Curl_URL {
char *path;
char *query;
char *fragment;
- unsigned short portnum; /* the numerical version (if 'port' is set) */
- BIT(query_present); /* to support blank */
- BIT(fragment_present); /* to support blank */
- BIT(guessed_scheme); /* when a URL without scheme is parsed */
+ long portnum; /* the numerical version */
};
#define DEFAULT_SCHEME "https"
@@ -102,7 +99,7 @@ static void free_urlhandle(struct Curl_URL *u)
}
/*
- * Find the separator at the end of the hostname, or the '?' in cases like
+ * Find the separator at the end of the host name, or the '?' in cases like
* http://www.example.com?id=2380
*/
static const char *find_host_sep(const char *url)
@@ -129,9 +126,6 @@ static const char *find_host_sep(const char *url)
return sep < query ? sep : query;
}
-/* convert CURLcode to CURLUcode */
-#define cc2cu(x) ((x) == CURLE_TOO_LARGE ? CURLUE_TOO_LARGE : \
- CURLUE_OUT_OF_MEMORY)
/*
* Decide whether a character in a URL must be escaped.
*/
@@ -141,7 +135,7 @@ static const char hexdigits[] = "0123456789abcdef";
/* urlencode_str() writes data into an output dynbuf and URL-encodes the
* spaces in the source URL accordingly.
*
- * URL encoding should be skipped for hostnames, otherwise IDN resolution
+ * URL encoding should be skipped for host names, otherwise IDN resolution
* will fail.
*/
static CURLUcode urlencode_str(struct dynbuf *o, const char *url,
@@ -152,7 +146,6 @@ static CURLUcode urlencode_str(struct dynbuf *o, const char *url,
bool left = !query;
const unsigned char *iptr;
const unsigned char *host_sep = (const unsigned char *) url;
- CURLcode result;
if(!relative)
host_sep = (const unsigned char *) find_host_sep(url);
@@ -161,19 +154,20 @@ static CURLUcode urlencode_str(struct dynbuf *o, const char *url,
len; iptr++, len--) {
if(iptr < host_sep) {
- result = Curl_dyn_addn(o, iptr, 1);
- if(result)
- return cc2cu(result);
+ if(Curl_dyn_addn(o, iptr, 1))
+ return CURLUE_OUT_OF_MEMORY;
continue;
}
if(*iptr == ' ') {
- if(left)
- result = Curl_dyn_addn(o, "%20", 3);
- else
- result = Curl_dyn_addn(o, "+", 1);
- if(result)
- return cc2cu(result);
+ if(left) {
+ if(Curl_dyn_addn(o, "%20", 3))
+ return CURLUE_OUT_OF_MEMORY;
+ }
+ else {
+ if(Curl_dyn_addn(o, "+", 1))
+ return CURLUE_OUT_OF_MEMORY;
+ }
continue;
}
@@ -184,12 +178,13 @@ static CURLUcode urlencode_str(struct dynbuf *o, const char *url,
char out[3]={'%'};
out[1] = hexdigits[*iptr>>4];
out[2] = hexdigits[*iptr & 0xf];
- result = Curl_dyn_addn(o, out, 3);
+ if(Curl_dyn_addn(o, out, 3))
+ return CURLUE_OUT_OF_MEMORY;
+ }
+ else {
+ if(Curl_dyn_addn(o, iptr, 1))
+ return CURLUE_OUT_OF_MEMORY;
}
- else
- result = Curl_dyn_addn(o, iptr, 1);
- if(result)
- return cc2cu(result);
}
return CURLUE_OK;
@@ -206,7 +201,7 @@ static CURLUcode urlencode_str(struct dynbuf *o, const char *url,
size_t Curl_is_absolute_url(const char *url, char *buf, size_t buflen,
bool guess_scheme)
{
- size_t i = 0;
+ int i = 0;
DEBUGASSERT(!buf || (buflen > MAX_SCHEME_LEN));
(void)buflen; /* only used in debug-builds */
if(buf)
@@ -230,13 +225,15 @@ size_t Curl_is_absolute_url(const char *url, char *buf, size_t buflen,
if(i && (url[i] == ':') && ((url[i + 1] == '/') || !guess_scheme)) {
/* If this does not guess scheme, the scheme always ends with the colon so
that this also detects data: URLs etc. In guessing mode, data: could
- be the hostname "data" with a specified port number. */
+ be the host name "data" with a specified port number. */
/* the length of the scheme is the name part only */
size_t len = i;
if(buf) {
- Curl_strntolower(buf, url, i);
buf[i] = 0;
+ while(i--) {
+ buf[i] = Curl_raw_tolower(url[i]);
+ }
}
return len;
}
@@ -251,7 +248,7 @@ size_t Curl_is_absolute_url(const char *url, char *buf, size_t buflen,
*
* Note that this function destroys the 'base' string.
*/
-static CURLcode concat_url(char *base, const char *relurl, char **newurl)
+static char *concat_url(char *base, const char *relurl)
{
/***
TRY to append this new path to the old URL
@@ -263,12 +260,8 @@ static CURLcode concat_url(char *base, const char *relurl, char **newurl)
char *pathsep;
bool host_changed = FALSE;
const char *useurl = relurl;
- CURLcode result = CURLE_OK;
- CURLUcode uc;
- bool skip_slash = FALSE;
- *newurl = NULL;
- /* protsep points to the start of the hostname */
+ /* protsep points to the start of the host name */
protsep = strstr(base, "//");
if(!protsep)
protsep = base;
@@ -278,57 +271,55 @@ static CURLcode concat_url(char *base, const char *relurl, char **newurl)
if('/' != relurl[0]) {
int level = 0;
- /* First we need to find out if there is a ?-letter in the URL,
+ /* First we need to find out if there's a ?-letter in the URL,
and cut it and the right-side of that off */
pathsep = strchr(protsep, '?');
if(pathsep)
*pathsep = 0;
- /* we have a relative path to append to the last slash if there is one
- available, or the new URL is just a query string (starts with a '?') or
- a fragment (starts with '#') we append the new one at the end of the
- current URL */
- if((useurl[0] != '?') && (useurl[0] != '#')) {
+ /* we have a relative path to append to the last slash if there's one
+ available, or if the new URL is just a query string (starts with a
+ '?') we append the new one at the end of the entire currently worked
+ out URL */
+ if(useurl[0] != '?') {
pathsep = strrchr(protsep, '/');
if(pathsep)
*pathsep = 0;
+ }
- /* Check if there is any slash after the hostname, and if so, remember
- that position instead */
- pathsep = strchr(protsep, '/');
- if(pathsep)
- protsep = pathsep + 1;
- else
- protsep = NULL;
+ /* Check if there's any slash after the host name, and if so, remember
+ that position instead */
+ pathsep = strchr(protsep, '/');
+ if(pathsep)
+ protsep = pathsep + 1;
+ else
+ protsep = NULL;
- /* now deal with one "./" or any amount of "../" in the newurl
- and act accordingly */
+ /* now deal with one "./" or any amount of "../" in the newurl
+ and act accordingly */
- if((useurl[0] == '.') && (useurl[1] == '/'))
- useurl += 2; /* just skip the "./" */
+ if((useurl[0] == '.') && (useurl[1] == '/'))
+ useurl += 2; /* just skip the "./" */
- while((useurl[0] == '.') &&
- (useurl[1] == '.') &&
- (useurl[2] == '/')) {
- level++;
- useurl += 3; /* pass the "../" */
- }
+ while((useurl[0] == '.') &&
+ (useurl[1] == '.') &&
+ (useurl[2] == '/')) {
+ level++;
+ useurl += 3; /* pass the "../" */
+ }
- if(protsep) {
- while(level--) {
- /* cut off one more level from the right of the original URL */
- pathsep = strrchr(protsep, '/');
- if(pathsep)
- *pathsep = 0;
- else {
- *protsep = 0;
- break;
- }
+ if(protsep) {
+ while(level--) {
+ /* cut off one more level from the right of the original URL */
+ pathsep = strrchr(protsep, '/');
+ if(pathsep)
+ *pathsep = 0;
+ else {
+ *protsep = 0;
+ break;
}
}
}
- else
- skip_slash = TRUE;
}
else {
/* We got a new absolute path for this server */
@@ -348,7 +339,7 @@ static CURLcode concat_url(char *base, const char *relurl, char **newurl)
if(pathsep) {
/* When people use badly formatted URLs, such as
"http://www.example.com?dir=/home/daniel" we must not use the first
- slash, if there is a ?-letter before it! */
+ slash, if there's a ?-letter before it! */
char *sep = strchr(protsep, '?');
if(sep && (sep < pathsep))
pathsep = sep;
@@ -356,8 +347,8 @@ static CURLcode concat_url(char *base, const char *relurl, char **newurl)
}
else {
/* There was no slash. Now, since we might be operating on a badly
- formatted URL, such as "http://www.example.com?id=2380" which does
- not use a slash separator as it is supposed to, we need to check
+ formatted URL, such as "http://www.example.com?id=2380" which
+ doesn't use a slash separator as it is supposed to, we need to check
for a ?-letter as well! */
pathsep = strchr(protsep, '?');
if(pathsep)
@@ -368,28 +359,22 @@ static CURLcode concat_url(char *base, const char *relurl, char **newurl)
Curl_dyn_init(&newest, CURL_MAX_INPUT_LENGTH);
- /* copy over the root URL part */
- result = Curl_dyn_add(&newest, base);
- if(result)
- return result;
+ /* copy over the root url part */
+ if(Curl_dyn_add(&newest, base))
+ return NULL;
/* check if we need to append a slash */
- if(('/' == useurl[0]) || (protsep && !*protsep) || skip_slash)
+ if(('/' == useurl[0]) || (protsep && !*protsep) || ('?' == useurl[0]))
;
else {
- result = Curl_dyn_addn(&newest, "/", 1);
- if(result)
- return result;
+ if(Curl_dyn_addn(&newest, "/", 1))
+ return NULL;
}
/* then append the new piece on the right side */
- uc = urlencode_str(&newest, useurl, strlen(useurl), !host_changed,
- FALSE);
- if(uc)
- return (uc == CURLUE_TOO_LARGE) ? CURLE_TOO_LARGE : CURLE_OUT_OF_MEMORY;
+ urlencode_str(&newest, useurl, strlen(useurl), !host_changed, FALSE);
- *newurl = Curl_dyn_ptr(&newest);
- return CURLE_OK;
+ return Curl_dyn_ptr(&newest);
}
/* scan for byte values <= 31, 127 and sometimes space */
@@ -421,15 +406,15 @@ static CURLUcode junkscan(const char *url, size_t *urllen, unsigned int flags)
/*
* parse_hostname_login()
*
- * Parse the login details (username, password and options) from the URL and
- * strip them out of the hostname
+ * Parse the login details (user name, password and options) from the URL and
+ * strip them out of the host name
*
*/
static CURLUcode parse_hostname_login(struct Curl_URL *u,
const char *login,
size_t len,
unsigned int flags,
- size_t *offset) /* to the hostname */
+ size_t *offset) /* to the host name */
{
CURLUcode result = CURLUE_OK;
CURLcode ccode;
@@ -476,7 +461,7 @@ static CURLUcode parse_hostname_login(struct Curl_URL *u,
if(userp) {
if(flags & CURLU_DISALLOW_USER) {
- /* Option DISALLOW_USER is set and URL contains username. */
+ /* Option DISALLOW_USER is set and url contains username. */
result = CURLUE_USER_NOT_ALLOWED;
goto out;
}
@@ -494,7 +479,7 @@ static CURLUcode parse_hostname_login(struct Curl_URL *u,
u->options = optionsp;
}
- /* the hostname starts at this offset */
+ /* the host name starts at this offset */
*offset = ptr - login;
return CURLUE_OK;
@@ -535,15 +520,15 @@ UNITTEST CURLUcode Curl_parse_port(struct Curl_URL *u, struct dynbuf *host,
portptr = strchr(hostname, ':');
if(portptr) {
- char *rest = NULL;
- unsigned long port;
+ char *rest;
+ long port;
size_t keep = portptr - hostname;
- /* Browser behavior adaptation. If there is a colon with no digits after,
+ /* Browser behavior adaptation. If there's a colon with no digits after,
just cut off the name there which makes us ignore the colon and just
use the default port. Firefox, Chrome and Safari all do that.
- Do not do it if the URL has no scheme, to make something that looks like
+ Don't do it if the URL has no scheme, to make something that looks like
a scheme not work!
*/
Curl_dyn_setlen(host, keep);
@@ -554,13 +539,15 @@ UNITTEST CURLUcode Curl_parse_port(struct Curl_URL *u, struct dynbuf *host,
if(!ISDIGIT(*portptr))
return CURLUE_BAD_PORT_NUMBER;
- errno = 0;
- port = strtoul(portptr, &rest, 10); /* Port number must be decimal */
+ port = strtol(portptr, &rest, 10); /* Port number must be decimal */
- if(errno || (port > 0xffff) || *rest)
+ if(port > 0xffff)
return CURLUE_BAD_PORT_NUMBER;
- u->portnum = (unsigned short) port;
+ if(rest[0])
+ return CURLUE_BAD_PORT_NUMBER;
+
+ u->portnum = port;
/* generate a new port number string to get rid of leading zeroes etc */
free(u->port);
u->port = aprintf("%ld", port);
@@ -592,7 +579,7 @@ static CURLUcode ipv6_parse(struct Curl_URL *u, char *hostname,
char zoneid[16];
int i = 0;
char *h = &hostname[len + 1];
- /* pass '25' if present and is a URL encoded percent sign */
+ /* pass '25' if present and is a url encoded percent sign */
if(!strncmp(h, "25", 2) && h[2] && (h[2] != ']'))
h += 2;
while(*h && (*h != ']') && (i < 15))
@@ -665,6 +652,7 @@ static CURLUcode hostname_check(struct Curl_URL *u, char *hostname,
*/
#define HOST_ERROR -1 /* out of memory */
+#define HOST_BAD -2 /* bad IPv4 address */
#define HOST_NAME 1
#define HOST_IPV4 2
@@ -681,21 +669,13 @@ static int ipv4_normalize(struct dynbuf *host)
if(*c == '[')
return HOST_IPV6;
- errno = 0; /* for strtoul */
while(!done) {
- char *endp = NULL;
+ char *endp;
unsigned long l;
if(!ISDIGIT(*c))
- /* most importantly this does not allow a leading plus or minus */
+ /* most importantly this doesn't allow a leading plus or minus */
return HOST_NAME;
l = strtoul(c, &endp, 0);
- if(errno)
- return HOST_NAME;
-#if SIZEOF_LONG > 4
- /* a value larger than 32 bits */
- if(l > UINT_MAX)
- return HOST_NAME;
-#endif
parts[n] = l;
c = endp;
@@ -715,6 +695,16 @@ static int ipv4_normalize(struct dynbuf *host)
default:
return HOST_NAME;
}
+
+ /* overflow */
+ if((l == ULONG_MAX) && (errno == ERANGE))
+ return HOST_NAME;
+
+#if SIZEOF_LONG > 4
+ /* a value larger than 32 bits */
+ if(l > UINT_MAX)
+ return HOST_NAME;
+#endif
}
switch(n) {
@@ -722,30 +712,24 @@ static int ipv4_normalize(struct dynbuf *host)
Curl_dyn_reset(host);
result = Curl_dyn_addf(host, "%u.%u.%u.%u",
- (unsigned int)(parts[0] >> 24),
- (unsigned int)((parts[0] >> 16) & 0xff),
- (unsigned int)((parts[0] >> 8) & 0xff),
- (unsigned int)(parts[0] & 0xff));
+ parts[0] >> 24, (parts[0] >> 16) & 0xff,
+ (parts[0] >> 8) & 0xff, parts[0] & 0xff);
break;
case 1: /* a.b -- 8.24 bits */
if((parts[0] > 0xff) || (parts[1] > 0xffffff))
return HOST_NAME;
Curl_dyn_reset(host);
result = Curl_dyn_addf(host, "%u.%u.%u.%u",
- (unsigned int)(parts[0]),
- (unsigned int)((parts[1] >> 16) & 0xff),
- (unsigned int)((parts[1] >> 8) & 0xff),
- (unsigned int)(parts[1] & 0xff));
+ parts[0], (parts[1] >> 16) & 0xff,
+ (parts[1] >> 8) & 0xff, parts[1] & 0xff);
break;
case 2: /* a.b.c -- 8.8.16 bits */
if((parts[0] > 0xff) || (parts[1] > 0xff) || (parts[2] > 0xffff))
return HOST_NAME;
Curl_dyn_reset(host);
result = Curl_dyn_addf(host, "%u.%u.%u.%u",
- (unsigned int)(parts[0]),
- (unsigned int)(parts[1]),
- (unsigned int)((parts[2] >> 8) & 0xff),
- (unsigned int)(parts[2] & 0xff));
+ parts[0], parts[1], (parts[2] >> 8) & 0xff,
+ parts[2] & 0xff);
break;
case 3: /* a.b.c.d -- 8.8.8.8 bits */
if((parts[0] > 0xff) || (parts[1] > 0xff) || (parts[2] > 0xff) ||
@@ -753,10 +737,7 @@ static int ipv4_normalize(struct dynbuf *host)
return HOST_NAME;
Curl_dyn_reset(host);
result = Curl_dyn_addf(host, "%u.%u.%u.%u",
- (unsigned int)(parts[0]),
- (unsigned int)(parts[1]),
- (unsigned int)(parts[2]),
- (unsigned int)(parts[3]));
+ parts[0], parts[1], parts[2], parts[3]);
break;
}
if(result)
@@ -785,7 +766,7 @@ static CURLUcode urldecode_host(struct dynbuf *host)
result = Curl_dyn_addn(host, decoded, dlen);
free(decoded);
if(result)
- return cc2cu(result);
+ return CURLUE_OUT_OF_MEMORY;
}
return CURLUE_OK;
@@ -798,24 +779,22 @@ static CURLUcode parse_authority(struct Curl_URL *u,
bool has_scheme)
{
size_t offset;
- CURLUcode uc;
- CURLcode result;
+ CURLUcode result;
/*
- * Parse the login details and strip them out of the hostname.
+ * Parse the login details and strip them out of the host name.
*/
- uc = parse_hostname_login(u, auth, authlen, flags, &offset);
- if(uc)
+ result = parse_hostname_login(u, auth, authlen, flags, &offset);
+ if(result)
goto out;
- result = Curl_dyn_addn(host, auth + offset, authlen - offset);
- if(result) {
- uc = cc2cu(result);
+ if(Curl_dyn_addn(host, auth + offset, authlen - offset)) {
+ result = CURLUE_OUT_OF_MEMORY;
goto out;
}
- uc = Curl_parse_port(u, host, has_scheme);
- if(uc)
+ result = Curl_parse_port(u, host, has_scheme);
+ if(result)
goto out;
if(!Curl_dyn_len(host))
@@ -825,27 +804,28 @@ static CURLUcode parse_authority(struct Curl_URL *u,
case HOST_IPV4:
break;
case HOST_IPV6:
- uc = ipv6_parse(u, Curl_dyn_ptr(host), Curl_dyn_len(host));
+ result = ipv6_parse(u, Curl_dyn_ptr(host), Curl_dyn_len(host));
break;
case HOST_NAME:
- uc = urldecode_host(host);
- if(!uc)
- uc = hostname_check(u, Curl_dyn_ptr(host), Curl_dyn_len(host));
+ result = urldecode_host(host);
+ if(!result)
+ result = hostname_check(u, Curl_dyn_ptr(host), Curl_dyn_len(host));
break;
case HOST_ERROR:
- uc = CURLUE_OUT_OF_MEMORY;
+ result = CURLUE_OUT_OF_MEMORY;
break;
+ case HOST_BAD:
default:
- uc = CURLUE_BAD_HOSTNAME; /* Bad IPv4 address even */
+ result = CURLUE_BAD_HOSTNAME; /* Bad IPv4 address even */
break;
}
out:
- return uc;
+ return result;
}
-/* used for HTTP/2 server push */
-CURLUcode Curl_url_set_authority(CURLU *u, const char *authority)
+CURLUcode Curl_url_set_authority(CURLU *u, const char *authority,
+ unsigned int flags)
{
CURLUcode result;
struct dynbuf host;
@@ -853,8 +833,8 @@ CURLUcode Curl_url_set_authority(CURLU *u, const char *authority)
DEBUGASSERT(authority);
Curl_dyn_init(&host, CURL_MAX_INPUT_LENGTH);
- result = parse_authority(u, authority, strlen(authority),
- CURLU_DISALLOW_USER, &host, !!u->scheme);
+ result = parse_authority(u, authority, strlen(authority), flags,
+ &host, !!u->scheme);
if(result)
Curl_dyn_free(&host);
else {
@@ -906,7 +886,7 @@ UNITTEST int dedotdotify(const char *input, size_t clen, char **outp)
do {
bool dotdot = TRUE;
if(*input == '.') {
- /* A. If the input buffer begins with a prefix of "../" or "./", then
+ /* A. If the input buffer begins with a prefix of "../" or "./", then
remove that prefix from the input buffer; otherwise, */
if(!strncmp("./", input, 2)) {
@@ -917,7 +897,7 @@ UNITTEST int dedotdotify(const char *input, size_t clen, char **outp)
input += 3;
clen -= 3;
}
- /* D. if the input buffer consists only of "." or "..", then remove
+ /* D. if the input buffer consists only of "." or "..", then remove
that from the input buffer; otherwise, */
else if(!strcmp(".", input) || !strcmp("..", input) ||
@@ -929,7 +909,7 @@ UNITTEST int dedotdotify(const char *input, size_t clen, char **outp)
dotdot = FALSE;
}
else if(*input == '/') {
- /* B. if the input buffer begins with a prefix of "/./" or "/.", where
+ /* B. if the input buffer begins with a prefix of "/./" or "/.", where
"." is a complete path segment, then replace that prefix with "/" in
the input buffer; otherwise, */
if(!strncmp("/./", input, 3)) {
@@ -942,7 +922,7 @@ UNITTEST int dedotdotify(const char *input, size_t clen, char **outp)
break;
}
- /* C. if the input buffer begins with a prefix of "/../" or "/..",
+ /* C. if the input buffer begins with a prefix of "/../" or "/..",
where ".." is a complete path segment, then replace that prefix with
"/" in the input buffer and remove the last segment and its
preceding "/" (if any) from the output buffer; otherwise, */
@@ -976,7 +956,7 @@ UNITTEST int dedotdotify(const char *input, size_t clen, char **outp)
dotdot = FALSE;
if(!dotdot) {
- /* E. move the first path segment in the input buffer to the end of
+ /* E. move the first path segment in the input buffer to the end of
the output buffer, including the initial "/" character (if any) and
any subsequent characters up to, but not including, the next "/"
character or the end of the input buffer. */
@@ -1069,7 +1049,7 @@ static CURLUcode parseurl(const char *url, CURLU *u, unsigned int flags)
* Appendix E, but believe me, it was meant to be there. --MK)
*/
if(ptr[0] != '/' && !STARTS_WITH_URL_DRIVE_PREFIX(ptr)) {
- /* the URL includes a hostname, it must match "localhost" or
+ /* the URL includes a host name, it must match "localhost" or
"127.0.0.1" to be valid */
if(checkprefix("localhost/", ptr) ||
checkprefix("127.0.0.1/", ptr)) {
@@ -1079,9 +1059,9 @@ static CURLUcode parseurl(const char *url, CURLU *u, unsigned int flags)
#if defined(_WIN32)
size_t len;
- /* the hostname, NetBIOS computer name, can not contain disallowed
+ /* the host name, NetBIOS computer name, can not contain disallowed
chars, and the delimiting slash character must be appended to the
- hostname */
+ host name */
path = strpbrk(ptr, "/\\:*?\"<>|");
if(!path || *path != '/') {
result = CURLUE_BAD_FILE_URL;
@@ -1090,9 +1070,8 @@ static CURLUcode parseurl(const char *url, CURLU *u, unsigned int flags)
len = path - ptr;
if(len) {
- CURLcode code = Curl_dyn_addn(&host, ptr, len);
- if(code) {
- result = cc2cu(code);
+ if(Curl_dyn_addn(&host, ptr, len)) {
+ result = CURLUE_OUT_OF_MEMORY;
goto fail;
}
uncpath = TRUE;
@@ -1117,11 +1096,11 @@ static CURLUcode parseurl(const char *url, CURLU *u, unsigned int flags)
Curl_dyn_reset(&host);
#if !defined(_WIN32) && !defined(MSDOS) && !defined(__CYGWIN__)
- /* Do not allow Windows drive letters when not in Windows.
+ /* Don't allow Windows drive letters when not in Windows.
* This catches both "file:/c:" and "file:c:" */
if(('/' == path[0] && STARTS_WITH_URL_DRIVE_PREFIX(&path[1])) ||
STARTS_WITH_URL_DRIVE_PREFIX(path)) {
- /* File drive letters are only accepted in MS-DOS/Windows */
+ /* File drive letters are only accepted in MSDOS/Windows */
result = CURLUE_BAD_FILE_URL;
goto fail;
}
@@ -1161,7 +1140,7 @@ static CURLUcode parseurl(const char *url, CURLU *u, unsigned int flags)
result = CURLUE_BAD_SLASHES;
goto fail;
}
- hostp = p; /* hostname starts here */
+ hostp = p; /* host name starts here */
}
else {
/* no scheme! */
@@ -1187,7 +1166,7 @@ static CURLUcode parseurl(const char *url, CURLU *u, unsigned int flags)
}
}
- /* find the end of the hostname + port number */
+ /* find the end of the host name + port number */
hostlen = strcspn(hostp, "/?#");
path = &hostp[hostlen];
@@ -1201,7 +1180,7 @@ static CURLUcode parseurl(const char *url, CURLU *u, unsigned int flags)
if((flags & CURLU_GUESS_SCHEME) && !schemep) {
const char *hostname = Curl_dyn_ptr(&host);
- /* legacy curl-style guess based on hostname */
+ /* legacy curl-style guess based on host name */
if(checkprefix("ftp.", hostname))
schemep = "ftp";
else if(checkprefix("dict.", hostname))
@@ -1222,7 +1201,6 @@ static CURLUcode parseurl(const char *url, CURLU *u, unsigned int flags)
result = CURLUE_OUT_OF_MEMORY;
goto fail;
}
- u->guessed_scheme = TRUE;
}
}
else if(flags & CURLU_NO_AUTHORITY) {
@@ -1241,19 +1219,19 @@ static CURLUcode parseurl(const char *url, CURLU *u, unsigned int flags)
fragment = strchr(path, '#');
if(fragment) {
fraglen = pathlen - (fragment - path);
- u->fragment_present = TRUE;
if(fraglen > 1) {
/* skip the leading '#' in the copy but include the terminating null */
if(flags & CURLU_URLENCODE) {
struct dynbuf enc;
Curl_dyn_init(&enc, CURL_MAX_INPUT_LENGTH);
- result = urlencode_str(&enc, fragment + 1, fraglen - 1, TRUE, FALSE);
- if(result)
+ if(urlencode_str(&enc, fragment + 1, fraglen - 1, TRUE, FALSE)) {
+ result = CURLUE_OUT_OF_MEMORY;
goto fail;
+ }
u->fragment = Curl_dyn_ptr(&enc);
}
else {
- u->fragment = Curl_memdup0(fragment + 1, fraglen - 1);
+ u->fragment = Curl_strndup(fragment + 1, fraglen - 1);
if(!u->fragment) {
result = CURLUE_OUT_OF_MEMORY;
goto fail;
@@ -1264,24 +1242,25 @@ static CURLUcode parseurl(const char *url, CURLU *u, unsigned int flags)
pathlen -= fraglen;
}
+ DEBUGASSERT(pathlen < urllen);
query = memchr(path, '?', pathlen);
if(query) {
size_t qlen = fragment ? (size_t)(fragment - query) :
pathlen - (query - path);
pathlen -= qlen;
- u->query_present = TRUE;
if(qlen > 1) {
if(flags & CURLU_URLENCODE) {
struct dynbuf enc;
Curl_dyn_init(&enc, CURL_MAX_INPUT_LENGTH);
/* skip the leading question mark */
- result = urlencode_str(&enc, query + 1, qlen - 1, TRUE, TRUE);
- if(result)
+ if(urlencode_str(&enc, query + 1, qlen - 1, TRUE, TRUE)) {
+ result = CURLUE_OUT_OF_MEMORY;
goto fail;
+ }
u->query = Curl_dyn_ptr(&enc);
}
else {
- u->query = Curl_memdup0(query + 1, qlen - 1);
+ u->query = Curl_strndup(query + 1, qlen - 1);
if(!u->query) {
result = CURLUE_OUT_OF_MEMORY;
goto fail;
@@ -1301,9 +1280,10 @@ static CURLUcode parseurl(const char *url, CURLU *u, unsigned int flags)
if(pathlen && (flags & CURLU_URLENCODE)) {
struct dynbuf enc;
Curl_dyn_init(&enc, CURL_MAX_INPUT_LENGTH);
- result = urlencode_str(&enc, path, pathlen, TRUE, FALSE);
- if(result)
+ if(urlencode_str(&enc, path, pathlen, TRUE, FALSE)) {
+ result = CURLUE_OUT_OF_MEMORY;
goto fail;
+ }
pathlen = Curl_dyn_len(&enc);
path = u->path = Curl_dyn_ptr(&enc);
}
@@ -1314,7 +1294,7 @@ static CURLUcode parseurl(const char *url, CURLU *u, unsigned int flags)
}
else {
if(!u->path) {
- u->path = Curl_memdup0(path, pathlen);
+ u->path = Curl_strndup(path, pathlen);
if(!u->path) {
result = CURLUE_OUT_OF_MEMORY;
goto fail;
@@ -1405,8 +1385,6 @@ CURLU *curl_url_dup(const CURLU *in)
DUP(u, in, fragment);
DUP(u, in, zoneid);
u->portnum = in->portnum;
- u->fragment_present = in->fragment_present;
- u->query_present = in->query_present;
}
return u;
fail:
@@ -1437,8 +1415,6 @@ CURLUcode curl_url_get(const CURLU *u, CURLUPart what,
ptr = u->scheme;
ifmissing = CURLUE_NO_SCHEME;
urldecode = FALSE; /* never for schemes */
- if((flags & CURLU_NO_GUESS_SCHEME) && u->guessed_scheme)
- return CURLUE_NO_SCHEME;
break;
case CURLUPART_USER:
ptr = u->user;
@@ -1467,7 +1443,7 @@ CURLUcode curl_url_get(const CURLU *u, CURLUPart what,
ifmissing = CURLUE_NO_PORT;
urldecode = FALSE; /* never for port */
if(!ptr && (flags & CURLU_DEFAULT_PORT) && u->scheme) {
- /* there is no stored port number, but asked to deliver
+ /* there's no stored port number, but asked to deliver
a default one for the scheme */
const struct Curl_handler *h = Curl_get_scheme_handler(u->scheme);
if(h) {
@@ -1493,16 +1469,10 @@ CURLUcode curl_url_get(const CURLU *u, CURLUPart what,
ptr = u->query;
ifmissing = CURLUE_NO_QUERY;
plusdecode = urldecode;
- if(ptr && !ptr[0] && !(flags & CURLU_GET_EMPTY))
- /* there was a blank query and the user do not ask for it */
- ptr = NULL;
break;
case CURLUPART_FRAGMENT:
ptr = u->fragment;
ifmissing = CURLUE_NO_FRAGMENT;
- if(!ptr && u->fragment_present && flags & CURLU_GET_EMPTY)
- /* there was a blank fragment and the user asks for it */
- ptr = "";
break;
case CURLUPART_URL: {
char *url;
@@ -1510,24 +1480,18 @@ CURLUcode curl_url_get(const CURLU *u, CURLUPart what,
char *options = u->options;
char *port = u->port;
char *allochost = NULL;
- bool show_fragment =
- u->fragment || (u->fragment_present && flags & CURLU_GET_EMPTY);
- bool show_query =
- (u->query && u->query[0]) ||
- (u->query_present && flags & CURLU_GET_EMPTY);
punycode = (flags & CURLU_PUNYCODE)?1:0;
depunyfy = (flags & CURLU_PUNY2IDN)?1:0;
if(u->scheme && strcasecompare("file", u->scheme)) {
url = aprintf("file://%s%s%s",
u->path,
- show_fragment ? "#": "",
- u->fragment ? u->fragment : "");
+ u->fragment? "#": "",
+ u->fragment? u->fragment : "");
}
else if(!u->host)
return CURLUE_NO_HOST;
else {
const struct Curl_handler *h = NULL;
- char schemebuf[MAX_SCHEME_LEN + 5];
if(u->scheme)
scheme = u->scheme;
else if(flags & CURLU_DEFAULT_SCHEME)
@@ -1537,7 +1501,7 @@ CURLUcode curl_url_get(const CURLU *u, CURLUPart what,
h = Curl_get_scheme_handler(scheme);
if(!port && (flags & CURLU_DEFAULT_PORT)) {
- /* there is no stored port number, but asked to deliver
+ /* there's no stored port number, but asked to deliver
a default one for the scheme */
if(h) {
msnprintf(portbuf, sizeof(portbuf), "%u", h->defport);
@@ -1598,13 +1562,8 @@ CURLUcode curl_url_get(const CURLU *u, CURLUPart what,
}
}
- if(!(flags & CURLU_NO_GUESS_SCHEME) || !u->guessed_scheme)
- msnprintf(schemebuf, sizeof(schemebuf), "%s://", scheme);
- else
- schemebuf[0] = 0;
-
- url = aprintf("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
- schemebuf,
+ url = aprintf("%s://%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
+ scheme,
u->user ? u->user : "",
u->password ? ":": "",
u->password ? u->password : "",
@@ -1615,9 +1574,9 @@ CURLUcode curl_url_get(const CURLU *u, CURLUPart what,
port ? ":": "",
port ? port : "",
u->path ? u->path : "/",
- show_query ? "?": "",
- u->query ? u->query : "",
- show_fragment ? "#": "",
+ (u->query && u->query[0]) ? "?": "",
+ (u->query && u->query[0]) ? u->query : "",
+ u->fragment? "#": "",
u->fragment? u->fragment : "");
free(allochost);
}
@@ -1633,7 +1592,7 @@ CURLUcode curl_url_get(const CURLU *u, CURLUPart what,
if(ptr) {
size_t partlen = strlen(ptr);
size_t i = 0;
- *part = Curl_memdup0(ptr, partlen);
+ *part = Curl_strndup(ptr, partlen);
if(!*part)
return CURLUE_OUT_OF_MEMORY;
if(plusdecode) {
@@ -1660,11 +1619,10 @@ CURLUcode curl_url_get(const CURLU *u, CURLUPart what,
}
if(urlencode) {
struct dynbuf enc;
- CURLUcode uc;
Curl_dyn_init(&enc, CURL_MAX_INPUT_LENGTH);
- uc = urlencode_str(&enc, *part, partlen, TRUE, what == CURLUPART_QUERY);
- if(uc)
- return uc;
+ if(urlencode_str(&enc, *part, partlen, TRUE,
+ what == CURLUPART_QUERY))
+ return CURLUE_OUT_OF_MEMORY;
free(*part);
*part = Curl_dyn_ptr(&enc);
}
@@ -1709,6 +1667,7 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
const char *part, unsigned int flags)
{
char **storep = NULL;
+ long port = 0;
bool urlencode = (flags & CURLU_URLENCODE)? 1 : 0;
bool plusencode = FALSE;
bool urlskipslash = FALSE;
@@ -1726,7 +1685,6 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
break;
case CURLUPART_SCHEME:
storep = &u->scheme;
- u->guessed_scheme = FALSE;
break;
case CURLUPART_USER:
storep = &u->user;
@@ -1752,11 +1710,9 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
break;
case CURLUPART_QUERY:
storep = &u->query;
- u->query_present = FALSE;
break;
case CURLUPART_FRAGMENT:
storep = &u->fragment;
- u->fragment_present = FALSE;
break;
default:
return CURLUE_UNKNOWN_PART;
@@ -1799,7 +1755,6 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
}
else
return CURLUE_BAD_SCHEME;
- u->guessed_scheme = FALSE;
break;
}
case CURLUPART_USER:
@@ -1819,26 +1774,18 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
storep = &u->zoneid;
break;
case CURLUPART_PORT:
- if(!ISDIGIT(part[0]))
- /* not a number */
+ {
+ char *endp;
+ urlencode = FALSE; /* never */
+ port = strtol(part, &endp, 10); /* Port number must be decimal */
+ if((port <= 0) || (port > 0xffff))
return CURLUE_BAD_PORT_NUMBER;
- else {
- char *tmp;
- char *endp;
- unsigned long port;
- errno = 0;
- port = strtoul(part, &endp, 10); /* must be decimal */
- if(errno || (port > 0xffff) || *endp)
- /* weirdly provided number, not good! */
- return CURLUE_BAD_PORT_NUMBER;
- tmp = strdup(part);
- if(!tmp)
- return CURLUE_OUT_OF_MEMORY;
- free(u->port);
- u->port = tmp;
- u->portnum = (unsigned short)port;
- return CURLUE_OK;
- }
+ if(*endp)
+ /* weirdly provided number, not good! */
+ return CURLUE_BAD_PORT_NUMBER;
+ storep = &u->port;
+ }
+ break;
case CURLUPART_PATH:
urlskipslash = TRUE;
leadingslash = TRUE; /* enforce */
@@ -1849,11 +1796,9 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
appendquery = (flags & CURLU_APPENDQUERY)?1:0;
equalsencode = appendquery;
storep = &u->query;
- u->query_present = TRUE;
break;
case CURLUPART_FRAGMENT:
storep = &u->fragment;
- u->fragment_present = TRUE;
break;
case CURLUPART_URL: {
/*
@@ -1862,8 +1807,7 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
* If the existing contents is enough for a URL, allow a relative URL to
* replace it.
*/
- CURLcode result;
- CURLUcode uc;
+ CURLUcode result;
char *oldurl;
char *redired_url;
@@ -1872,7 +1816,7 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
return CURLUE_MALFORMED_INPUT;
/* if the new thing is absolute or the old one is not
- * (we could not get an absolute URL in 'oldurl'),
+ * (we could not get an absolute url in 'oldurl'),
* then replace the existing with the new. */
if(Curl_is_absolute_url(part, NULL, 0,
flags & (CURLU_GUESS_SCHEME|
@@ -1883,14 +1827,14 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
/* apply the relative part to create a new URL
* and replace the existing one with it. */
- result = concat_url(oldurl, part, &redired_url);
+ redired_url = concat_url(oldurl, part);
free(oldurl);
- if(result)
- return cc2cu(result);
+ if(!redired_url)
+ return CURLUE_OUT_OF_MEMORY;
- uc = parseurl_and_replace(redired_url, u, flags);
+ result = parseurl_and_replace(redired_url, u, flags);
free(redired_url);
- return uc;
+ return result;
}
default:
return CURLUE_UNKNOWN_PART;
@@ -1904,7 +1848,7 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
if(leadingslash && (part[0] != '/')) {
CURLcode result = Curl_dyn_addn(&enc, "/", 1);
if(result)
- return cc2cu(result);
+ return CURLUE_OUT_OF_MEMORY;
}
if(urlencode) {
const unsigned char *i;
@@ -1924,7 +1868,7 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
equalsencode = FALSE;
result = Curl_dyn_addn(&enc, i, 1);
if(result)
- return cc2cu(result);
+ return CURLUE_OUT_OF_MEMORY;
}
else {
char out[3]={'%'};
@@ -1932,7 +1876,7 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
out[2] = hexdigits[*i & 0xf];
result = Curl_dyn_addn(&enc, out, 3);
if(result)
- return cc2cu(result);
+ return CURLUE_OUT_OF_MEMORY;
}
}
}
@@ -1940,7 +1884,7 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
char *p;
CURLcode result = Curl_dyn_add(&enc, part);
if(result)
- return cc2cu(result);
+ return CURLUE_OUT_OF_MEMORY;
p = Curl_dyn_ptr(&enc);
while(*p) {
/* make sure percent encoded are lower case */
@@ -1988,26 +1932,10 @@ nomem:
else if(what == CURLUPART_HOST) {
size_t n = Curl_dyn_len(&enc);
if(!n && (flags & CURLU_NO_AUTHORITY)) {
- /* Skip hostname check, it is allowed to be empty. */
+ /* Skip hostname check, it's allowed to be empty. */
}
else {
- bool bad = FALSE;
- if(!n)
- bad = TRUE; /* empty hostname is not okay */
- else if(!urlencode) {
- /* if the host name part was not URL encoded here, it was set ready
- URL encoded so we need to decode it to check */
- size_t dlen;
- char *decoded = NULL;
- CURLcode result =
- Curl_urldecode(newp, n, &decoded, &dlen, REJECT_CTRL);
- if(result || hostname_check(u, decoded, dlen))
- bad = TRUE;
- free(decoded);
- }
- else if(hostname_check(u, (char *)newp, n))
- bad = TRUE;
- if(bad) {
+ if(!n || hostname_check(u, (char *)newp, n)) {
Curl_dyn_free(&enc);
return CURLUE_BAD_HOSTNAME;
}
@@ -2017,5 +1945,9 @@ nomem:
free(*storep);
*storep = (char *)newp;
}
+ /* set after the string, to make it not assigned if the allocation above
+ fails */
+ if(port)
+ u->portnum = port;
return CURLUE_OK;
}
diff --git a/contrib/libs/curl/lib/urldata.h b/contrib/libs/curl/lib/urldata.h
index 950210a556..db0e73719e 100644
--- a/contrib/libs/curl/lib/urldata.h
+++ b/contrib/libs/curl/lib/urldata.h
@@ -53,21 +53,10 @@
#define PORT_GOPHER 70
#define PORT_MQTT 1883
-struct curl_trc_featt;
-
-#ifdef USE_ECH
-/* CURLECH_ bits for the tls_ech option */
-# define CURLECH_DISABLE (1<<0)
-# define CURLECH_GREASE (1<<1)
-# define CURLECH_ENABLE (1<<2)
-# define CURLECH_HARD (1<<3)
-# define CURLECH_CLA_CFG (1<<4)
-#endif
-
#ifdef USE_WEBSOCKETS
/* CURLPROTO_GOPHERS (29) is the highest publicly used protocol bit number,
* the rest are internal information. If we use higher bits we only do this on
- * platforms that have a >= 64-bit type and then we use such a type for the
+ * platforms that have a >= 64 bit type and then we use such a type for the
* protocol fields in the protocol handler.
*/
#define CURLPROTO_WS (1<<30)
@@ -77,10 +66,6 @@ struct curl_trc_featt;
#define CURLPROTO_WSS 0
#endif
-/* the default protocols accepting a redirect to */
-#define CURLPROTO_REDIR (CURLPROTO_HTTP | CURLPROTO_HTTPS | CURLPROTO_FTP | \
- CURLPROTO_FTPS)
-
/* This should be undefined once we need bit 32 or higher */
#define PROTO_TYPE_SMALL
@@ -105,12 +90,6 @@ typedef unsigned int curl_prot_t;
#define CURL_DEFAULT_USER "anonymous"
#define CURL_DEFAULT_PASSWORD "ftp@example.com"
-#if !defined(_WIN32) && !defined(MSDOS) && !defined(__EMX__)
-/* do FTP line-end CRLF => LF conversions on platforms that prefer LF-only. It
- also means: keep CRLF line endings on the CRLF platforms */
-#define CURL_PREFER_LF_LINEENDS
-#endif
-
/* Convenience defines for checking protocols or their SSL based version. Each
protocol handler should only ever have a single CURLPROTO_ in its protocol
field. */
@@ -123,7 +102,7 @@ typedef unsigned int curl_prot_t;
#define PROTO_FAMILY_SSH (CURLPROTO_SCP|CURLPROTO_SFTP)
#if !defined(CURL_DISABLE_FTP) || defined(USE_SSH) || \
- !defined(CURL_DISABLE_POP3) || !defined(CURL_DISABLE_FILE)
+ !defined(CURL_DISABLE_POP3)
/* these protocols support CURLOPT_DIRLISTONLY */
#define CURL_LIST_ONLY_PROTOCOL 1
#endif
@@ -162,14 +141,12 @@ typedef unsigned int curl_prot_t;
#include "splay.h"
#include "dynbuf.h"
#include "dynhds.h"
-#include "request.h"
/* return the count of bytes sent, or -1 on error */
typedef ssize_t (Curl_send)(struct Curl_easy *data, /* transfer */
int sockindex, /* socketindex */
const void *buf, /* data to write */
size_t len, /* max amount to write */
- bool eos, /* last chunk */
CURLcode *err); /* error to return */
/* return the count of bytes read, or -1 on error */
@@ -183,6 +160,7 @@ typedef ssize_t (Curl_recv)(struct Curl_easy *data, /* transfer */
typedef CURLcode (*Curl_datastream)(struct Curl_easy *data,
struct connectdata *conn,
int *didwhat,
+ bool *done,
int select_res);
#endif
@@ -252,7 +230,8 @@ typedef CURLcode (*Curl_datastream)(struct Curl_easy *data,
#ifdef HAVE_GSSAPI
/* Types needed for krb5-ftp connections */
struct krb5buffer {
- struct dynbuf buf;
+ void *data;
+ size_t size;
size_t index;
BIT(eof_flag);
};
@@ -268,26 +247,34 @@ enum protection_level {
};
#endif
-/* SSL backend-specific data; declared differently by each SSL backend */
-struct ssl_backend_data;
+/* enum for the nonblocking SSL connection state machine */
+typedef enum {
+ ssl_connect_1,
+ ssl_connect_2,
+ ssl_connect_2_reading,
+ ssl_connect_2_writing,
+ ssl_connect_3,
+ ssl_connect_done
+} ssl_connect_state;
typedef enum {
- CURL_SSL_PEER_DNS,
- CURL_SSL_PEER_IPV4,
- CURL_SSL_PEER_IPV6
-} ssl_peer_type;
+ ssl_connection_none,
+ ssl_connection_negotiating,
+ ssl_connection_complete
+} ssl_connection_state;
+
+/* SSL backend-specific data; declared differently by each SSL backend */
+struct ssl_backend_data;
struct ssl_peer {
char *hostname; /* hostname for verification */
char *dispname; /* display version of hostname */
char *sni; /* SNI version of hostname or NULL if not usable */
- ssl_peer_type type; /* type of the peer information */
- int port; /* port we are talking to */
- int transport; /* one of TRNSPRT_* defines */
+ BIT(is_ip_address); /* if hostname is an IPv4|6 address */
};
struct ssl_primary_config {
- char *CApath; /* certificate dir (does not work on Windows) */
+ char *CApath; /* certificate dir (doesn't work on windows) */
char *CAfile; /* certificate to verify peer against */
char *issuercert; /* optional issuer certificate filename */
char *clientcert;
@@ -309,7 +296,7 @@ struct ssl_primary_config {
BIT(verifypeer); /* set TRUE if this is desired */
BIT(verifyhost); /* set TRUE if CN/SAN must match hostname */
BIT(verifystatus); /* set TRUE if certificate status must be checked */
- BIT(cache_session); /* cache session or not */
+ BIT(sessionid); /* cache session IDs or not */
};
struct ssl_config_data {
@@ -318,7 +305,7 @@ struct ssl_config_data {
curl_ssl_ctx_callback fsslctx; /* function to initialize ssl ctx */
void *fsslctxp; /* parameter for call back */
char *cert_type; /* format for certificate (default: PEM)*/
- char *key; /* private key filename */
+ char *key; /* private key file name */
struct curl_blob *key_blob;
char *key_type; /* format for private key (default: PEM) */
char *key_passwd; /* plain text private key password */
@@ -326,7 +313,7 @@ struct ssl_config_data {
BIT(falsestart);
BIT(enable_beast); /* allow this flaw for interoperability's sake */
BIT(no_revoke); /* disable SSL certificate revocation checks */
- BIT(no_partialchain); /* do not accept partial certificate chains */
+ BIT(no_partialchain); /* don't accept partial certificate chains */
BIT(revoke_best_effort); /* ignore SSL revocation offline/missing revocation
list errors */
BIT(native_ca_store); /* use the native ca store of operating system */
@@ -339,20 +326,16 @@ struct ssl_general_config {
int ca_cache_timeout; /* Certificate store cache timeout (seconds) */
};
-typedef void Curl_ssl_sessionid_dtor(void *sessionid, size_t idsize);
-
/* information stored about one single SSL session */
struct Curl_ssl_session {
- char *name; /* hostname for which this ID was used */
- char *conn_to_host; /* hostname for the connection (may be NULL) */
+ char *name; /* host name for which this ID was used */
+ char *conn_to_host; /* host name for the connection (may be NULL) */
const char *scheme; /* protocol scheme used */
void *sessionid; /* as returned from the SSL layer */
size_t idsize; /* if known, otherwise 0 */
- Curl_ssl_sessionid_dtor *sessionid_free; /* free `sessionid` callback */
long age; /* just a number, the higher the more recent */
int remote_port; /* remote port */
int conn_to_port; /* remote port for the connection (may be -1) */
- int transport; /* TCP or QUIC */
struct ssl_primary_config ssl_config; /* setup for this session */
};
@@ -452,7 +435,15 @@ struct ntlmdata {
unsigned int flags;
unsigned char nonce[8];
unsigned int target_info_len;
- void *target_info; /* TargetInfo received in the NTLM type-2 message */
+ void *target_info; /* TargetInfo received in the ntlm type-2 message */
+
+#if defined(NTLM_WB_ENABLED)
+ /* used for communication with Samba's winbind daemon helper ntlm_auth */
+ curl_socket_t ntlm_auth_hlpr_socket;
+ pid_t ntlm_auth_hlpr_pid;
+ char *challenge; /* The received base64 encoded ntlm type-2 message */
+ char *response; /* The generated base64 ntlm type-1/type-3 message */
+#endif
#endif
};
#endif
@@ -465,7 +456,6 @@ struct negotiatedata {
gss_ctx_id_t context;
gss_name_t spn;
gss_buffer_desc output_token;
- struct dynbuf channel_binding_data;
#else
#ifdef USE_WINDOWS_SSPI
#ifdef SECPKG_ATTR_ENDPOINT_BINDINGS
@@ -507,6 +497,9 @@ struct ConnectBits {
This is implicit when SSL-protocols are used through
proxies, but can also be enabled explicitly by
apps */
+ BIT(proxy_connect_closed); /* TRUE if a proxy disconnected the connection
+ in a CONNECT request with auth, so that
+ libcurl should reconnect and continue. */
BIT(proxy); /* if set, this transfer is done through a proxy - any type */
#endif
/* always modify bits.close with the connclose() and connkeep() macros! */
@@ -526,12 +519,16 @@ struct ConnectBits {
the TCP layer connect */
BIT(retry); /* this connection is about to get closed and then
re-attempted at another connection. */
+ BIT(authneg); /* TRUE when the auth phase has started, which means
+ that we are creating a request with an auth header,
+ but it is not the final request in the auth
+ negotiation. */
#ifndef CURL_DISABLE_FTP
BIT(ftp_use_epsv); /* As set with CURLOPT_FTP_USE_EPSV, but if we find out
- EPSV does not work we disable it for the forthcoming
+ EPSV doesn't work we disable it for the forthcoming
requests */
BIT(ftp_use_eprt); /* As set with CURLOPT_FTP_USE_EPRT, but if we find out
- EPRT does not work we disable it for the forthcoming
+ EPRT doesn't work we disable it for the forthcoming
requests */
BIT(ftp_use_data_ssl); /* Enabled SSL for the data connection */
BIT(ftp_use_control_ssl); /* Enabled SSL for the control connection */
@@ -541,7 +538,6 @@ struct ConnectBits {
#endif
BIT(bound); /* set true if bind() has already been done on this socket/
connection */
- BIT(asks_multiplex); /* connection asks for multiplexing, but is not yet */
BIT(multiplex); /* connection is multiplexed */
BIT(tcp_fastopen); /* use TCP Fast Open */
BIT(tls_enable_alpn); /* TLS ALPN extension? */
@@ -556,10 +552,6 @@ struct ConnectBits {
accept() */
BIT(parallel_connect); /* set TRUE when a parallel connect attempt has
started (happy eyeballs) */
- BIT(aborted); /* connection was aborted, e.g. in unclean state */
- BIT(shutdown_handler); /* connection shutdown: handler shut down */
- BIT(shutdown_filters); /* connection shutdown: filters shut down */
- BIT(in_cpool); /* connection is kept in a connection pool */
};
struct hostname {
@@ -583,14 +575,6 @@ struct hostname {
#define KEEP_RECV_PAUSE (1<<4) /* reading is paused */
#define KEEP_SEND_PAUSE (1<<5) /* writing is paused */
-/* KEEP_SEND_TIMED is set when the transfer should attempt sending
- * at timer (or other) events. A transfer waiting on a timer will
- * remove KEEP_SEND to suppress POLLOUTs of the connection.
- * Adding KEEP_SEND_TIMED will then attempt to send whenever the transfer
- * enters the "readwrite" loop, e.g. when a timer fires.
- * This is used in HTTP for 'Expect: 100-continue' waiting. */
-#define KEEP_SEND_TIMED (1<<6)
-
#define KEEP_RECVBITS (KEEP_RECV | KEEP_RECV_HOLD | KEEP_RECV_PAUSE)
#define KEEP_SENDBITS (KEEP_SEND | KEEP_SEND_HOLD | KEEP_SEND_PAUSE)
@@ -599,7 +583,7 @@ struct hostname {
(((data)->req.keepon & KEEP_SENDBITS) == KEEP_SEND)
/* transfer receive is not on PAUSE or HOLD */
#define CURL_WANT_RECV(data) \
- (((data)->req.keepon & KEEP_RECVBITS) == KEEP_RECV)
+ (!((data)->req.keepon & (KEEP_RECV_PAUSE|KEEP_RECV_HOLD)))
#if defined(CURLRES_ASYNCH) || !defined(CURL_DISABLE_DOH)
#define USE_CURL_ASYNC
@@ -628,12 +612,151 @@ struct easy_pollset {
unsigned char actions[MAX_SOCKSPEREASYHANDLE];
};
+enum expect100 {
+ EXP100_SEND_DATA, /* enough waiting, just send the body now */
+ EXP100_AWAITING_CONTINUE, /* waiting for the 100 Continue header */
+ EXP100_SENDING_REQUEST, /* still sending the request but will wait for
+ the 100 header once done with the request */
+ EXP100_FAILED /* used on 417 Expectation Failed */
+};
+
+enum upgrade101 {
+ UPGR101_INIT, /* default state */
+ UPGR101_WS, /* upgrade to WebSockets requested */
+ UPGR101_H2, /* upgrade to HTTP/2 requested */
+ UPGR101_RECEIVED, /* 101 response received */
+ UPGR101_WORKING /* talking upgraded protocol */
+};
+
+enum doh_slots {
+ /* Explicit values for first two symbols so as to match hard-coded
+ * constants in existing code
+ */
+ DOH_PROBE_SLOT_IPADDR_V4 = 0, /* make 'V4' stand out for readability */
+ DOH_PROBE_SLOT_IPADDR_V6 = 1, /* 'V6' likewise */
+
+ /* Space here for (possibly build-specific) additional slot definitions */
+
+ /* for example */
+ /* #ifdef WANT_DOH_FOOBAR_TXT */
+ /* DOH_PROBE_SLOT_FOOBAR_TXT, */
+ /* #endif */
+
+ /* AFTER all slot definitions, establish how many we have */
+ DOH_PROBE_SLOTS
+};
+
+/*
+ * Request specific data in the easy handle (Curl_easy). Previously,
+ * these members were on the connectdata struct but since a conn struct may
+ * now be shared between different Curl_easys, we store connection-specific
+ * data here. This struct only keeps stuff that's interesting for *this*
+ * request, as it will be cleared between multiple ones
+ */
+struct SingleRequest {
+ curl_off_t size; /* -1 if unknown at this point */
+ curl_off_t maxdownload; /* in bytes, the maximum amount of data to fetch,
+ -1 means unlimited */
+ curl_off_t bytecount; /* total number of bytes read */
+ curl_off_t writebytecount; /* number of bytes written */
+
+ curl_off_t pendingheader; /* this many bytes left to send is actually
+ header and not body */
+ struct curltime start; /* transfer started at this time */
+ unsigned int headerbytecount; /* received server headers (not CONNECT
+ headers) */
+ unsigned int allheadercount; /* all received headers (server + CONNECT) */
+ unsigned int deductheadercount; /* this amount of bytes doesn't count when
+ we check if anything has been transferred
+ at the end of a connection. We use this
+ counter to make only a 100 reply (without
+ a following second response code) result
+ in a CURLE_GOT_NOTHING error code */
+ int headerline; /* counts header lines to better track the
+ first one */
+ curl_off_t offset; /* possible resume offset read from the
+ Content-Range: header */
+ int httpcode; /* error code from the 'HTTP/1.? XXX' or
+ 'RTSP/1.? XXX' line */
+ int keepon;
+ struct curltime start100; /* time stamp to wait for the 100 code from */
+ enum expect100 exp100; /* expect 100 continue state */
+ enum upgrade101 upgr101; /* 101 upgrade state */
+
+ /* Content unencoding stack. See sec 3.5, RFC2616. */
+ struct Curl_cwriter *writer_stack;
+ time_t timeofdoc;
+ long bodywrites;
+ char *location; /* This points to an allocated version of the Location:
+ header data */
+ char *newurl; /* Set to the new URL to use when a redirect or a retry is
+ wanted */
+
+ /* 'upload_present' is used to keep a byte counter of how much data there is
+ still left in the buffer, aimed for upload. */
+ ssize_t upload_present;
+
+ /* 'upload_fromhere' is used as a read-pointer when we uploaded parts of a
+ buffer, so the next read should read from where this pointer points to,
+ and the 'upload_present' contains the number of bytes available at this
+ position */
+ char *upload_fromhere;
+
+ /* Allocated protocol-specific data. Each protocol handler makes sure this
+ points to data it needs. */
+ union {
+ struct FILEPROTO *file;
+ struct FTP *ftp;
+ struct HTTP *http;
+ struct IMAP *imap;
+ struct ldapreqinfo *ldap;
+ struct MQTT *mqtt;
+ struct POP3 *pop3;
+ struct RTSP *rtsp;
+ struct smb_request *smb;
+ struct SMTP *smtp;
+ struct SSHPROTO *ssh;
+ struct TELNET *telnet;
+ } p;
+#ifndef CURL_DISABLE_DOH
+ struct dohdata *doh; /* DoH specific data for this request */
+#endif
+#if defined(_WIN32) && defined(USE_WINSOCK)
+ struct curltime last_sndbuf_update; /* last time readwrite_upload called
+ win_update_buffer_size */
+#endif
+ char fread_eof[2]; /* the body read callback (index 0) returned EOF or
+ the trailer read callback (index 1) returned EOF */
+#ifndef CURL_DISABLE_COOKIES
+ unsigned char setcookies;
+#endif
+ unsigned char writer_stack_depth; /* Unencoding stack depth. */
+ BIT(header); /* incoming data has HTTP header */
+ BIT(badheader); /* header parsing found sth not a header */
+ BIT(content_range); /* set TRUE if Content-Range: was found */
+ BIT(download_done); /* set to TRUE when download is complete */
+ BIT(upload_done); /* set to TRUE when doing chunked transfer-encoding
+ upload and we're uploading the last chunk */
+ BIT(ignorebody); /* we read a response-body but we ignore it! */
+ BIT(http_bodyless); /* HTTP response status code is between 100 and 199,
+ 204 or 304 */
+ BIT(chunk); /* if set, this is a chunked transfer-encoding */
+ BIT(ignore_cl); /* ignore content-length */
+ BIT(upload_chunky); /* set TRUE if we are doing chunked transfer-encoding
+ on upload */
+ BIT(getheader); /* TRUE if header parsing is wanted */
+ BIT(forbidchunk); /* used only to explicitly forbid chunk-upload for
+ specific upload buffers. See readmoredata() in http.c
+ for details. */
+ BIT(no_body); /* the response has no body */
+};
+
/*
* Specific protocol handler.
*/
struct Curl_handler {
- const char *scheme; /* URL scheme name in lowercase */
+ const char *scheme; /* URL scheme name. */
/* Complement to setup_connection_internals(). This is done before the
transfer "owns" the connection. */
@@ -653,7 +776,7 @@ struct Curl_handler {
/* This function *MAY* be set to a protocol-dependent function that is run
* after the connect() and everything is done, as a step in the connection.
* The 'done' pointer points to a bool that should be set to TRUE if the
- * function completes before return. If it does not complete, the caller
+ * function completes before return. If it doesn't complete, the caller
* should call the ->connecting() function until it is.
*/
CURLcode (*connect_it)(struct Curl_easy *data, bool *done);
@@ -684,7 +807,7 @@ struct Curl_handler {
struct connectdata *conn, curl_socket_t *socks);
/* This function *MAY* be set to a protocol-dependent function that is run
- * by the curl_disconnect(), as a step in the disconnection. If the handler
+ * by the curl_disconnect(), as a step in the disconnection. If the handler
* is called because the connection has been considered dead,
* dead_connection is set to TRUE. The connection is (again) associated with
* the transfer here.
@@ -692,17 +815,11 @@ struct Curl_handler {
CURLcode (*disconnect)(struct Curl_easy *, struct connectdata *,
bool dead_connection);
- /* If used, this function gets called from transfer.c to
- allow the protocol to do extra handling in writing response to
- the client. */
- CURLcode (*write_resp)(struct Curl_easy *data, const char *buf, size_t blen,
- bool is_eos);
-
- /* If used, this function gets called from transfer.c to
- allow the protocol to do extra handling in writing a single response
- header line to the client. */
- CURLcode (*write_resp_hd)(struct Curl_easy *data,
- const char *hd, size_t hdlen, bool is_eos);
+ /* If used, this function gets called from transfer.c:readwrite_data() to
+ allow the protocol to do extra reads/writes */
+ CURLcode (*readwrite)(struct Curl_easy *data, struct connectdata *conn,
+ const char *buf, size_t blen,
+ size_t *pconsumed, bool *readmore);
/* This function can perform various checks on the connection. See
CONNCHECK_* for more information about the checks that can be performed,
@@ -732,11 +849,11 @@ struct Curl_handler {
the send function might need to be called while uploading, or vice versa.
*/
#define PROTOPT_DIRLOCK (1<<3)
-#define PROTOPT_NONETWORK (1<<4) /* protocol does not use the network! */
+#define PROTOPT_NONETWORK (1<<4) /* protocol doesn't use the network! */
#define PROTOPT_NEEDSPWD (1<<5) /* needs a password, and if none is set it
gets a default */
-#define PROTOPT_NOURLQUERY (1<<6) /* protocol cannot handle
- URL query strings (?foo=bar) ! */
+#define PROTOPT_NOURLQUERY (1<<6) /* protocol can't handle
+ url query strings (?foo=bar) ! */
#define PROTOPT_CREDSPERREQUEST (1<<7) /* requires login credentials per
request instead of per connection */
#define PROTOPT_ALPN (1<<8) /* set ALPN for this */
@@ -747,9 +864,9 @@ struct Curl_handler {
HTTP proxy as HTTP proxies may know
this protocol and act as a gateway */
#define PROTOPT_WILDCARD (1<<12) /* protocol supports wildcard matching */
-#define PROTOPT_USERPWDCTRL (1<<13) /* Allow "control bytes" (< 32 ASCII) in
- username and password */
-#define PROTOPT_NOTCPPROXY (1<<14) /* this protocol cannot proxy over TCP */
+#define PROTOPT_USERPWDCTRL (1<<13) /* Allow "control bytes" (< 32 ascii) in
+ user name and password */
+#define PROTOPT_NOTCPPROXY (1<<14) /* this protocol can't proxy over TCP */
#define CONNCHECK_NONE 0 /* No checks */
#define CONNCHECK_ISDEAD (1<<0) /* Check if the connection is dead. */
@@ -758,19 +875,12 @@ struct Curl_handler {
#define CONNRESULT_NONE 0 /* No extra information. */
#define CONNRESULT_DEAD (1<<0) /* The connection is dead. */
-struct ip_quadruple {
- char remote_ip[MAX_IPADR_LEN];
- char local_ip[MAX_IPADR_LEN];
- int remote_port;
- int local_port;
-};
-
struct proxy_info {
struct hostname host;
int port;
unsigned char proxytype; /* curl_proxytype: what kind of proxy that is in
use */
- char *user; /* proxy username string, allocated */
+ char *user; /* proxy user name string, allocated */
char *passwd; /* proxy password string, allocated */
};
@@ -786,70 +896,69 @@ struct ldapconninfo;
* unique for an entire connection.
*/
struct connectdata {
- struct Curl_llist_node cpool_node; /* conncache lists */
+ struct Curl_llist_element bundle_node; /* conncache */
+
+ /* chunk is for HTTP chunked encoding, but is in the general connectdata
+ struct only because we can do just about any protocol through an HTTP
+ proxy and an HTTP proxy may in fact respond using chunked encoding */
+ struct Curl_chunker chunk;
curl_closesocket_callback fclosesocket; /* function closing the socket(s) */
void *closesocket_client;
- /* This is used by the connection pool logic. If this returns TRUE, this
+ /* This is used by the connection cache logic. If this returns TRUE, this
handle is still used by one or more easy handles and can only used by any
other easy handle without careful consideration (== only for
multiplexing) and it cannot be used by another multi handle! */
-#define CONN_INUSE(c) Curl_llist_count(&(c)->easyq)
+#define CONN_INUSE(c) ((c)->easyq.size)
/**** Fields set when inited and not modified again */
curl_off_t connection_id; /* Contains a unique number to make it easier to
track the connections in the log output */
- char *destination; /* string carrying normalized hostname+port+scope */
- size_t destination_len; /* strlen(destination) + 1 */
/* 'dns_entry' is the particular host we use. This points to an entry in the
DNS cache and it will not get pruned while locked. It gets unlocked in
multi_done(). This entry will be NULL if the connection is reused as then
there is no name resolve done. */
struct Curl_dns_entry *dns_entry;
+#ifdef USE_CURL_ASYNC
+ struct Curl_async resolve_async; /* asynchronous name resolver data */
+#endif
/* 'remote_addr' is the particular IP we connected to. it is owned, set
* and NULLed by the connected socket filter (if there is one). */
const struct Curl_sockaddr_ex *remote_addr;
struct hostname host;
- char *hostname_resolve; /* hostname to resolve to address, allocated */
- char *secondaryhostname; /* secondary socket hostname (ftp) */
+ char *hostname_resolve; /* host name to resolve to address, allocated */
+ char *secondaryhostname; /* secondary socket host name (ftp) */
struct hostname conn_to_host; /* the host to connect to. valid only if
bits.conn_to_host is set */
#ifndef CURL_DISABLE_PROXY
struct proxy_info socks_proxy;
struct proxy_info http_proxy;
#endif
- /* 'primary' and 'secondary' get filled with IP quadruple
- (local/remote numerical ip address and port) whenever a connect is
- *attempted*.
- When more than one address is tried for a connection these will hold data
+ /* 'primary_ip' and 'primary_port' get filled with peer's numerical
+ ip address and port number whenever an outgoing connection is
+ *attempted* from the primary socket to a remote address. When more
+ than one address is tried for a connection these will hold data
for the last attempt. When the connection is actually established
these are updated with data which comes directly from the socket. */
- struct ip_quadruple primary;
- struct ip_quadruple secondary;
- char *user; /* username string, allocated */
+
+ char primary_ip[MAX_IPADR_LEN];
+ char *user; /* user name string, allocated */
char *passwd; /* password string, allocated */
char *options; /* options string, allocated */
char *sasl_authzid; /* authorization identity string, allocated */
char *oauth_bearer; /* OAUTH2 bearer, allocated */
struct curltime now; /* "current" time */
struct curltime created; /* creation time */
- struct curltime lastused; /* when returned to the connection poolas idle */
+ struct curltime lastused; /* when returned to the connection cache */
curl_socket_t sock[2]; /* two sockets, the second is used for the data
transfer when doing FTP */
Curl_recv *recv[2];
Curl_send *send[2];
struct Curl_cfilter *cfilter[2]; /* connection filters */
- struct {
- struct curltime start[2]; /* when filter shutdown started */
- unsigned int timeout_ms; /* 0 means no timeout */
- } shutdown;
- /* Last pollset used in connection shutdown. Used to detect changes
- * for multi_socket API. */
- struct easy_pollset shutdown_poll;
struct ssl_primary_config ssl_config;
#ifndef CURL_DISABLE_PROXY
@@ -889,6 +998,8 @@ struct connectdata {
#endif /* however, some of them are ftp specific. */
struct Curl_llist easyq; /* List of easy handles using this connection */
+ curl_seek_callback seek_func; /* function that seeks the input */
+ void *seek_client; /* pointer to pass to the seek() above */
/*************** Request - specific items ************/
#if defined(USE_WINDOWS_SSPI) && defined(SECPKG_ATTR_ENDPOINT_BINDINGS)
@@ -917,6 +1028,11 @@ struct connectdata {
struct negotiatedata proxyneg; /* state data for proxy Negotiate auth */
#endif
+#ifndef CURL_DISABLE_HTTP
+ /* for chunked-encoded trailer */
+ struct dynbuf trailer;
+#endif
+
union {
#ifndef CURL_DISABLE_FTP
struct ftp_conn ftpc;
@@ -957,6 +1073,7 @@ struct connectdata {
unsigned int unused:1; /* avoids empty union */
} proto;
+ struct connectbundle *bundle; /* The bundle we are member of */
#ifdef USE_UNIX_SOCKETS
char *unix_domain_socket;
#endif
@@ -967,7 +1084,7 @@ struct connectdata {
/* When this connection is created, store the conditions for the local end
bind. This is stored before the actual bind and before any connection is
made and will serve the purpose of being used for comparison reasons so
- that subsequent bound-requested connections are not accidentally reusing
+ that subsequent bound-requested connections aren't accidentally reusing
wrong connections. */
char *localdev;
unsigned short localportrange;
@@ -976,15 +1093,17 @@ struct connectdata {
int socks5_gssapi_enctype;
#endif
/* The field below gets set in connect.c:connecthost() */
+ int port; /* which port to use locally - to connect to */
int remote_port; /* the remote port, not the proxy port! */
int conn_to_port; /* the remote port to connect to. valid only if
bits.conn_to_port is set */
-#ifdef USE_IPV6
+#ifdef ENABLE_IPV6
unsigned int scope_id; /* Scope id for IPv6 */
#endif
unsigned short localport;
unsigned short secondary_port; /* secondary socket remote port to connect to
(ftp) */
+ unsigned char cselect_bits; /* bitmask of socket events */
unsigned char alpn; /* APLN TLS negotiated protocol, a CURL_HTTP_VERSION*
value */
#ifndef CURL_DISABLE_PROXY
@@ -1026,47 +1145,43 @@ struct PureInfo {
unsigned long httpauthavail; /* what host auth types were announced */
long numconnects; /* how many new connection did libcurl created */
char *contenttype; /* the content type of the object */
- char *wouldredirect; /* URL this would have been redirected to if asked to */
+ char *wouldredirect; /* URL this would've been redirected to if asked to */
curl_off_t retry_after; /* info from Retry-After: header */
unsigned int header_size; /* size of read header(s) in bytes */
- /* PureInfo primary ip_quadruple is copied over from the connectdata
- struct in order to allow curl_easy_getinfo() to return this information
- even when the session handle is no longer associated with a connection,
- and also allow curl_easy_reset() to clear this information from the
- session handle without disturbing information which is still alive, and
- that might be reused, in the connection pool. */
- struct ip_quadruple primary;
+ /* PureInfo members 'conn_primary_ip', 'conn_primary_port', 'conn_local_ip'
+ and, 'conn_local_port' are copied over from the connectdata struct in
+ order to allow curl_easy_getinfo() to return this information even when
+ the session handle is no longer associated with a connection, and also
+ allow curl_easy_reset() to clear this information from the session handle
+ without disturbing information which is still alive, and that might be
+ reused, in the connection cache. */
+
+ char conn_primary_ip[MAX_IPADR_LEN];
+ int conn_primary_port; /* this is the destination port to the connection,
+ which might have been a proxy */
int conn_remote_port; /* this is the "remote port", which is the port
number of the used URL, independent of proxy or
not */
+ char conn_local_ip[MAX_IPADR_LEN];
+ int conn_local_port;
const char *conn_scheme;
unsigned int conn_protocol;
struct curl_certinfo certs; /* info about the certs. Asked for with
CURLOPT_CERTINFO / CURLINFO_CERTINFO */
CURLproxycode pxcode;
- BIT(timecond); /* set to TRUE if the time condition did not match, which
+ BIT(timecond); /* set to TRUE if the time condition didn't match, which
thus made the document NOT get fetched */
- BIT(used_proxy); /* the transfer used a proxy */
};
-struct pgrs_measure {
- struct curltime start; /* when measure started */
- curl_off_t start_size; /* the 'cur_size' the measure started at */
-};
-
-struct pgrs_dir {
- curl_off_t total_size; /* total expected bytes */
- curl_off_t cur_size; /* transferred bytes so far */
- curl_off_t speed; /* bytes per second transferred */
- struct pgrs_measure limit;
-};
struct Progress {
time_t lastshow; /* time() of the last displayed progress meter or NULL to
force redraw at next call */
- struct pgrs_dir ul;
- struct pgrs_dir dl;
+ curl_off_t size_dl; /* total expected size */
+ curl_off_t size_ul; /* total expected size */
+ curl_off_t downloaded; /* transferred so far */
+ curl_off_t uploaded; /* transferred so far */
curl_off_t current_speed; /* uses the currently fastest transfer */
@@ -1075,12 +1190,13 @@ struct Progress {
timediff_t timespent;
- timediff_t t_postqueue;
+ curl_off_t dlspeed;
+ curl_off_t ulspeed;
+
timediff_t t_nslookup;
timediff_t t_connect;
timediff_t t_appconnect;
timediff_t t_pretransfer;
- timediff_t t_posttransfer;
timediff_t t_starttransfer;
timediff_t t_redirect;
@@ -1089,6 +1205,14 @@ struct Progress {
struct curltime t_startop;
struct curltime t_acceptdata;
+
+ /* upload speed limit */
+ struct curltime ul_limit_start;
+ curl_off_t ul_limit_size;
+ /* download speed limit */
+ struct curltime dl_limit_start;
+ curl_off_t dl_limit_size;
+
#define CURR_TIME (5 + 1) /* 6 entries for 5 seconds */
curl_off_t speeder[ CURR_TIME ];
@@ -1152,6 +1276,18 @@ struct Curl_data_priority {
#endif
};
+/*
+ * This struct is for holding data that was attempted to get sent to the user's
+ * callback but is held due to pausing. One instance per type (BOTH, HEADER,
+ * BODY).
+ */
+struct tempbuf {
+ struct dynbuf b;
+ int type; /* type of the 'tempwrite' buffer as a bitmask that is used with
+ Curl_client_write() */
+ BIT(paused_body); /* if PAUSE happened before/during BODY write */
+};
+
/* Timers */
typedef enum {
EXPIRE_100_TIMEOUT,
@@ -1185,7 +1321,7 @@ typedef enum {
* One instance for each timeout an easy handle can set.
*/
struct time_node {
- struct Curl_llist_node list;
+ struct Curl_llist_element list;
struct curltime time;
expire_id eid;
};
@@ -1203,6 +1339,8 @@ struct urlpieces {
};
struct UrlState {
+ /* Points to the connection cache */
+ struct conncache *conn_cache;
/* buffers to store authentication data in, as parsed from input options */
struct curltime keeps_speed; /* for the progress meter really */
@@ -1212,11 +1350,13 @@ struct UrlState {
struct dynbuf headerb; /* buffer to store headers in */
struct curl_slist *hstslist; /* list of HSTS files set by
curl_easy_setopt(HSTS) calls */
+ char *buffer; /* download buffer */
+ char *ulbuf; /* allocated upload buffer or NULL */
curl_off_t current_speed; /* the ProgressShow() function sets this,
bytes / second */
- /* hostname, port number and protocol of the first (not followed) request.
- if set, this should be the hostname that we will sent authorization to,
+ /* host name, port number and protocol of the first (not followed) request.
+ if set, this should be the host name that we will sent authorization to,
no else. Used to make Location: following not keep sending user+password.
This is strdup()ed data. */
char *first_host;
@@ -1226,7 +1366,10 @@ struct UrlState {
int retrycount; /* number of retries on a new connection */
struct Curl_ssl_session *session; /* array of 'max_ssl_sessions' size */
long sessionage; /* number of the most recent session */
+ struct tempbuf tempwrite[3]; /* BOTH, HEADER, BODY */
+ unsigned int tempcount; /* number of entries in use in tempwrite, 0 - 3 */
int os_errno; /* filled in with errno whenever an error occurs */
+ char *scratch; /* huge buffer[set.buffer_size*2] for upload CRLF replacing */
long followlocation; /* redirect counter */
int requests; /* request counter: redirects + authentication retakes */
#ifdef HAVE_SIGNAL
@@ -1239,9 +1382,6 @@ struct UrlState {
#endif
struct auth authhost; /* auth details for host */
struct auth authproxy; /* auth details for proxy */
-#ifdef USE_CURL_ASYNC
- struct Curl_async async; /* asynchronous name resolver data */
-#endif
#if defined(USE_OPENSSL)
/* void instead of ENGINE to avoid bleeding OpenSSL into this header */
@@ -1254,6 +1394,14 @@ struct UrlState {
/* a place to store the most recently set (S)FTP entrypath */
char *most_recent_ftp_entrypath;
+#if !defined(_WIN32) && !defined(MSDOS) && !defined(__EMX__)
+/* do FTP line-end conversions on most platforms */
+#define CURL_DO_LINEEND_CONV
+ /* for FTP downloads: track CRLF sequences that span blocks */
+ BIT(prev_block_had_trailing_cr);
+ /* for FTP downloads: how many CRLFs did we converted to LFs? */
+ curl_off_t crlf_conversions;
+#endif
char *range; /* range, if used. See README for detailed specification on
this syntax. */
curl_off_t resume_from; /* continue [ftp] transfer from here */
@@ -1284,10 +1432,8 @@ struct UrlState {
this should be dealt with in pretransfer */
#ifndef CURL_DISABLE_HTTP
curl_mimepart *mimepost;
-#ifndef CURL_DISABLE_FORM_API
curl_mimepart *formp; /* storage for old API form-posting, allocated on
demand */
-#endif
size_t trailers_bytes_sent;
struct dynbuf trailers_buf; /* a buffer containing the compiled trailing
headers */
@@ -1306,35 +1452,25 @@ struct UrlState {
CURLcode hresult; /* used to pass return codes back from hyper callbacks */
#endif
-#ifndef CURL_DISABLE_VERBOSE_STRINGS
- struct curl_trc_feat *feat; /* opt. trace feature transfer is part of */
-#endif
-
/* Dynamically allocated strings, MUST be freed before this struct is
killed. */
struct dynamically_allocated_data {
+ char *proxyuserpwd;
char *uagent;
char *accept_encoding;
char *userpwd;
char *rangeline;
char *ref;
char *host;
-#ifndef CURL_DISABLE_COOKIES
char *cookiehost;
-#endif
-#ifndef CURL_DISABLE_RTSP
char *rtsp_transport;
-#endif
char *te; /* TE: request header */
/* transfer credentials */
char *user;
char *passwd;
-#ifndef CURL_DISABLE_PROXY
- char *proxyuserpwd;
char *proxyuser;
char *proxypasswd;
-#endif
} aptr;
unsigned char httpwant; /* when non-zero, a specific HTTP version requested
@@ -1343,9 +1479,12 @@ struct UrlState {
server involved in this request */
unsigned char httpreq; /* Curl_HttpReq; what kind of HTTP request (if any)
is this */
- unsigned char select_bits; /* != 0 -> bitmask of socket events for this
+ unsigned char dselect_bits; /* != 0 -> bitmask of socket events for this
transfer overriding anything the socket may
report */
+#ifdef CURLDEBUG
+ BIT(conncache_lock);
+#endif
/* when curl_easy_perform() is called, the multi handle is "owned" by
the easy handle so curl_easy_cleanup() on such an easy handle will
also close the multi handle! */
@@ -1358,9 +1497,10 @@ struct UrlState {
called. */
BIT(allow_port); /* Is set.use_port allowed to take effect or not. This
is always set TRUE when curl_easy_perform() is called. */
- BIT(authproblem); /* TRUE if there is some problem authenticating */
+ BIT(authproblem); /* TRUE if there's some problem authenticating */
/* set after initial USER failure, to prevent an authentication loop */
BIT(wildcardmatch); /* enable wildcard matching */
+ BIT(expect100header); /* TRUE if we added Expect: 100-continue */
BIT(disableexpect); /* TRUE if Expect: is disabled due to a previous
417 response */
BIT(use_range);
@@ -1368,6 +1508,7 @@ struct UrlState {
BIT(done); /* set to FALSE when Curl_init_do() is called and set to TRUE
when multi_done() is called, to prevent multi_done() to get
invoked twice when the multi interface is used. */
+ BIT(previouslypending); /* this transfer WAS in the multi->pending queue */
#ifndef CURL_DISABLE_COOKIES
BIT(cookie_engine);
#endif
@@ -1378,6 +1519,9 @@ struct UrlState {
BIT(url_alloc); /* URL string is malloc()'ed */
BIT(referer_alloc); /* referer string is malloc()ed */
BIT(wildcard_resolve); /* Set to true if any resolve change is a wildcard */
+ BIT(rewindbeforesend);/* TRUE when the sending couldn't be stopped even
+ though it will be discarded. We must call the data
+ rewind callback before trying to send again. */
BIT(upload); /* upload request */
BIT(internal); /* internal: true if this easy handle was created for
internal use and the user does not have ownership of the
@@ -1395,129 +1539,95 @@ struct UrlState {
struct Curl_multi; /* declared in multihandle.c */
+/*
+ * This enumeration MUST not use conditional directives (#ifdefs), new
+ * null terminated strings MUST be added to the enumeration immediately
+ * before STRING_LASTZEROTERMINATED, binary fields immediately before
+ * STRING_LAST. When doing so, ensure that the packages/OS400/chkstring.c
+ * test is updated and applicable changes for EBCDIC to ASCII conversion
+ * are catered for in curl_easy_setopt_ccsid()
+ */
enum dupstring {
- STRING_CERT, /* client certificate filename */
+ STRING_CERT, /* client certificate file name */
+ STRING_CERT_PROXY, /* client certificate file name */
STRING_CERT_TYPE, /* format for certificate (default: PEM)*/
- STRING_KEY, /* private key filename */
- STRING_KEY_PASSWD, /* plain text private key password */
- STRING_KEY_TYPE, /* format for private key (default: PEM) */
- STRING_SSL_CAPATH, /* CA directory name (does not work on Windows) */
- STRING_SSL_CAFILE, /* certificate file to verify peer against */
- STRING_SSL_PINNEDPUBLICKEY, /* public key file to verify peer against */
- STRING_SSL_CIPHER_LIST, /* list of ciphers to use */
- STRING_SSL_CIPHER13_LIST, /* list of TLS 1.3 ciphers to use */
- STRING_SSL_CRLFILE, /* crl file to check certificate */
- STRING_SSL_ISSUERCERT, /* issuer cert file to check certificate */
- STRING_SERVICE_NAME, /* Service name */
-#ifndef CURL_DISABLE_PROXY
- STRING_CERT_PROXY, /* client certificate filename */
STRING_CERT_TYPE_PROXY, /* format for certificate (default: PEM)*/
- STRING_KEY_PROXY, /* private key filename */
- STRING_KEY_PASSWD_PROXY, /* plain text private key password */
- STRING_KEY_TYPE_PROXY, /* format for private key (default: PEM) */
- STRING_SSL_CAPATH_PROXY, /* CA directory name (does not work on Windows) */
- STRING_SSL_CAFILE_PROXY, /* certificate file to verify peer against */
- STRING_SSL_PINNEDPUBLICKEY_PROXY, /* public key file to verify proxy */
- STRING_SSL_CIPHER_LIST_PROXY, /* list of ciphers to use */
- STRING_SSL_CIPHER13_LIST_PROXY, /* list of TLS 1.3 ciphers to use */
- STRING_SSL_CRLFILE_PROXY, /* crl file to check certificate */
- STRING_SSL_ISSUERCERT_PROXY, /* issuer cert file to check certificate */
- STRING_PROXY_SERVICE_NAME, /* Proxy service name */
-#endif
-#ifndef CURL_DISABLE_COOKIES
STRING_COOKIE, /* HTTP cookie string to send */
STRING_COOKIEJAR, /* dump all cookies to this file */
-#endif
STRING_CUSTOMREQUEST, /* HTTP/FTP/RTSP request/method to use */
- STRING_DEFAULT_PROTOCOL, /* Protocol to use when the URL does not specify */
+ STRING_DEFAULT_PROTOCOL, /* Protocol to use when the URL doesn't specify */
STRING_DEVICE, /* local network interface/address to use */
- STRING_INTERFACE, /* local network interface to use */
- STRING_BINDHOST, /* local address to use */
STRING_ENCODING, /* Accept-Encoding string */
-#ifndef CURL_DISABLE_FTP
STRING_FTP_ACCOUNT, /* ftp account data */
STRING_FTP_ALTERNATIVE_TO_USER, /* command to send if USER/PASS fails */
STRING_FTPPORT, /* port to send with the FTP PORT command */
-#endif
-#if defined(HAVE_GSSAPI)
+ STRING_KEY, /* private key file name */
+ STRING_KEY_PROXY, /* private key file name */
+ STRING_KEY_PASSWD, /* plain text private key password */
+ STRING_KEY_PASSWD_PROXY, /* plain text private key password */
+ STRING_KEY_TYPE, /* format for private key (default: PEM) */
+ STRING_KEY_TYPE_PROXY, /* format for private key (default: PEM) */
STRING_KRB_LEVEL, /* krb security level */
-#endif
-#ifndef CURL_DISABLE_NETRC
STRING_NETRC_FILE, /* if not NULL, use this instead of trying to find
$HOME/.netrc */
-#endif
-#ifndef CURL_DISABLE_PROXY
STRING_PROXY, /* proxy to use */
STRING_PRE_PROXY, /* pre socks proxy to use */
-#endif
STRING_SET_RANGE, /* range, if used */
STRING_SET_REFERER, /* custom string for the HTTP referer field */
STRING_SET_URL, /* what original URL to work on */
+ STRING_SSL_CAPATH, /* CA directory name (doesn't work on windows) */
+ STRING_SSL_CAPATH_PROXY, /* CA directory name (doesn't work on windows) */
+ STRING_SSL_CAFILE, /* certificate file to verify peer against */
+ STRING_SSL_CAFILE_PROXY, /* certificate file to verify peer against */
+ STRING_SSL_PINNEDPUBLICKEY, /* public key file to verify peer against */
+ STRING_SSL_PINNEDPUBLICKEY_PROXY, /* public key file to verify proxy */
+ STRING_SSL_CIPHER_LIST, /* list of ciphers to use */
+ STRING_SSL_CIPHER_LIST_PROXY, /* list of ciphers to use */
+ STRING_SSL_CIPHER13_LIST, /* list of TLS 1.3 ciphers to use */
+ STRING_SSL_CIPHER13_LIST_PROXY, /* list of TLS 1.3 ciphers to use */
STRING_USERAGENT, /* User-Agent string */
+ STRING_SSL_CRLFILE, /* crl file to check certificate */
+ STRING_SSL_CRLFILE_PROXY, /* crl file to check certificate */
+ STRING_SSL_ISSUERCERT, /* issuer cert file to check certificate */
+ STRING_SSL_ISSUERCERT_PROXY, /* issuer cert file to check certificate */
STRING_SSL_ENGINE, /* name of ssl engine */
STRING_USERNAME, /* <username>, if used */
STRING_PASSWORD, /* <password>, if used */
STRING_OPTIONS, /* <options>, if used */
-#ifndef CURL_DISABLE_PROXY
STRING_PROXYUSERNAME, /* Proxy <username>, if used */
STRING_PROXYPASSWORD, /* Proxy <password>, if used */
STRING_NOPROXY, /* List of hosts which should not use the proxy, if
used */
-#endif
-#ifndef CURL_DISABLE_RTSP
STRING_RTSP_SESSION_ID, /* Session ID to use */
STRING_RTSP_STREAM_URI, /* Stream URI for this request */
STRING_RTSP_TRANSPORT, /* Transport for this session */
-#endif
-#ifdef USE_SSH
STRING_SSH_PRIVATE_KEY, /* path to the private key file for auth */
STRING_SSH_PUBLIC_KEY, /* path to the public key file for auth */
- STRING_SSH_HOST_PUBLIC_KEY_MD5, /* md5 of host public key in ASCII hex */
+ STRING_SSH_HOST_PUBLIC_KEY_MD5, /* md5 of host public key in ascii hex */
STRING_SSH_HOST_PUBLIC_KEY_SHA256, /* sha256 of host public key in base64 */
- STRING_SSH_KNOWNHOSTS, /* filename of knownhosts file */
-#endif
-#ifndef CURL_DISABLE_SMTP
+ STRING_SSH_KNOWNHOSTS, /* file name of knownhosts file */
+ STRING_PROXY_SERVICE_NAME, /* Proxy service name */
+ STRING_SERVICE_NAME, /* Service name */
STRING_MAIL_FROM,
STRING_MAIL_AUTH,
-#endif
-#ifdef USE_TLS_SRP
STRING_TLSAUTH_USERNAME, /* TLS auth <username> */
- STRING_TLSAUTH_PASSWORD, /* TLS auth <password> */
-#ifndef CURL_DISABLE_PROXY
STRING_TLSAUTH_USERNAME_PROXY, /* TLS auth <username> */
+ STRING_TLSAUTH_PASSWORD, /* TLS auth <password> */
STRING_TLSAUTH_PASSWORD_PROXY, /* TLS auth <password> */
-#endif
-#endif
STRING_BEARER, /* <bearer>, if used */
-#ifdef USE_UNIX_SOCKETS
STRING_UNIX_SOCKET_PATH, /* path to Unix socket, if used */
-#endif
STRING_TARGET, /* CURLOPT_REQUEST_TARGET */
-#ifndef CURL_DISABLE_DOH
STRING_DOH, /* CURLOPT_DOH_URL */
-#endif
-#ifndef CURL_DISABLE_ALTSVC
STRING_ALTSVC, /* CURLOPT_ALTSVC */
-#endif
-#ifndef CURL_DISABLE_HSTS
STRING_HSTS, /* CURLOPT_HSTS */
-#endif
STRING_SASL_AUTHZID, /* CURLOPT_SASL_AUTHZID */
-#ifdef USE_ARES
STRING_DNS_SERVERS,
STRING_DNS_INTERFACE,
STRING_DNS_LOCAL_IP4,
STRING_DNS_LOCAL_IP6,
-#endif
STRING_SSL_EC_CURVES,
-#ifndef CURL_DISABLE_AWS
STRING_AWS_SIGV4, /* Parameters for V4 signature */
-#endif
-#ifndef CURL_DISABLE_PROXY
STRING_HAPROXY_CLIENT_IP, /* CURLOPT_HAPROXY_CLIENT_IP */
-#endif
- STRING_ECH_CONFIG, /* CURLOPT_ECH_CONFIG */
- STRING_ECH_PUBLIC, /* CURLOPT_ECH_PUBLIC */
/* -- end of null-terminated strings -- */
@@ -1532,20 +1642,18 @@ enum dupstring {
enum dupblob {
BLOB_CERT,
- BLOB_KEY,
- BLOB_SSL_ISSUERCERT,
- BLOB_CAINFO,
-#ifndef CURL_DISABLE_PROXY
BLOB_CERT_PROXY,
+ BLOB_KEY,
BLOB_KEY_PROXY,
+ BLOB_SSL_ISSUERCERT,
BLOB_SSL_ISSUERCERT_PROXY,
+ BLOB_CAINFO,
BLOB_CAINFO_PROXY,
-#endif
BLOB_LAST
};
/* callback that gets called when this easy handle is completed within a multi
- handle. Only used for internally created transfers, like for example
+ handle. Only used for internally created transfers, like for example
DoH. */
typedef int (*multidone_func)(struct Curl_easy *easy, CURLcode result);
@@ -1570,7 +1678,7 @@ struct UserDefined {
#ifndef CURL_DISABLE_BINDLOCAL
unsigned short localport; /* local port number to bind to */
unsigned short localportrange; /* number of additional port numbers to test
- in case the 'localport' one cannot be
+ in case the 'localport' one can't be
bind()ed */
#endif
curl_write_callback fwrite_func; /* function that stores the output */
@@ -1603,10 +1711,9 @@ struct UserDefined {
void *progress_client; /* pointer to pass to the progress callback */
void *ioctl_client; /* pointer to pass to the ioctl callback */
unsigned int timeout; /* ms, 0 means no timeout */
- unsigned int connecttimeout; /* ms, 0 means default timeout */
+ unsigned int connecttimeout; /* ms, 0 means no timeout */
unsigned int happy_eyeballs_timeout; /* ms, 0 is a valid value */
unsigned int server_response_timeout; /* ms, 0 means no timeout */
- unsigned int shutdowntimeout; /* ms, 0 means default timeout */
long maxage_conn; /* in seconds, max idle time to allow a connection that
is to be reused */
long maxlifetime_conn; /* in seconds, max time since creation to allow a
@@ -1623,9 +1730,7 @@ struct UserDefined {
curl_off_t set_resume_from; /* continue [ftp] transfer from here */
struct curl_slist *headers; /* linked list of extra headers */
struct curl_httppost *httppost; /* linked list of old POST data */
-#if !defined(CURL_DISABLE_MIME) || !defined(CURL_DISABLE_FORM_API)
curl_mimepart mimepost; /* MIME/POST data. */
-#endif
#ifndef CURL_DISABLE_TELNET
struct curl_slist *telnet_options; /* linked list of telnet options */
#endif
@@ -1671,7 +1776,7 @@ struct UserDefined {
struct curl_slist *postquote; /* after the transfer */
struct curl_slist *prequote; /* before the transfer, after type */
/* Despite the name, ftp_create_missing_dirs is for FTP(S) and SFTP
- 1 - create directories that do not exist
+ 1 - create directories that don't exist
2 - the same but also allow MKD to fail once
*/
unsigned char ftp_create_missing_dirs;
@@ -1692,7 +1797,7 @@ struct UserDefined {
unsigned int new_file_perms; /* when creating remote files */
char *str[STRING_LAST]; /* array of strings, pointing to allocated memory */
struct curl_blob *blobs[BLOB_LAST];
-#ifdef USE_IPV6
+#ifdef ENABLE_IPV6
unsigned int scope_id; /* Scope id for IPv6 */
#endif
curl_prot_t allowed_protocols;
@@ -1718,7 +1823,6 @@ struct UserDefined {
int tcp_keepidle; /* seconds in idle before sending keepalive probe */
int tcp_keepintvl; /* seconds between TCP keepalive probes */
- int tcp_keepcnt; /* maximum number of keepalive probes */
long expect_100_timeout; /* in milliseconds */
#if defined(USE_HTTP2) || defined(USE_HTTP3)
@@ -1730,7 +1834,7 @@ struct UserDefined {
long upkeep_interval_ms; /* Time between calls for connection upkeep. */
multidone_func fmultidone;
#ifndef CURL_DISABLE_DOH
- curl_off_t dohfor_mid; /* this is a DoH request for that transfer */
+ struct Curl_easy *dohfor; /* this is a DoH request for that transfer */
#endif
CURLU *uh; /* URL handle for the current parsed URL */
#ifndef CURL_DISABLE_HTTP
@@ -1761,21 +1865,17 @@ struct UserDefined {
BIT(cookiesession); /* new cookie session? */
#endif
BIT(crlf); /* convert crlf on ftp upload(?) */
-#ifdef USE_SSH
BIT(ssh_compression); /* enable SSH compression */
-#endif
/* Here follows boolean settings that define how to behave during
this session. They are STATIC, set by libcurl users or at least initially
- and they do not change during operations. */
+ and they don't change during operations. */
BIT(quick_exit); /* set 1L when it is okay to leak things (like
- threads), as we are about to exit() anyway and
- do not want lengthy cleanups to delay termination,
+ threads), as we're about to exit() anyway and
+ don't want lengthy cleanups to delay termination,
e.g. after a DNS timeout */
BIT(get_filetime); /* get the time and get of the remote file */
-#ifndef CURL_DISABLE_PROXY
BIT(tunnel_thru_httpproxy); /* use CONNECT through an HTTP proxy */
-#endif
BIT(prefer_ascii); /* ASCII rather than binary */
BIT(remote_append); /* append, not overwrite, on upload */
#ifdef CURL_LIST_ONLY_PROTOCOL
@@ -1790,7 +1890,7 @@ struct UserDefined {
us */
BIT(wildcard_enabled); /* enable wildcard matching */
#endif
- BIT(hide_progress); /* do not use the progress meter */
+ BIT(hide_progress); /* don't use the progress meter */
BIT(http_fail_on_error); /* fail on HTTP error codes >= 400 */
BIT(http_keep_sending_on_error); /* for HTTP status codes >= 300 */
BIT(http_follow_location); /* follow HTTP redirects */
@@ -1802,9 +1902,7 @@ struct UserDefined {
location: */
BIT(opt_no_body); /* as set with CURLOPT_NOBODY */
BIT(verbose); /* output verbosity */
-#if defined(HAVE_GSSAPI)
BIT(krb); /* Kerberos connection requested */
-#endif
BIT(reuse_forbid); /* forbidden to be reused, close after use */
BIT(reuse_fresh); /* do not reuse an existing connection */
BIT(no_signal); /* do not use any signal/alarm handler */
@@ -1829,14 +1927,10 @@ struct UserDefined {
BIT(suppress_connect_headers); /* suppress proxy CONNECT response headers
from user callbacks */
BIT(dns_shuffle_addresses); /* whether to shuffle addresses before use */
-#ifndef CURL_DISABLE_PROXY
BIT(haproxyprotocol); /* whether to send HAProxy PROXY protocol v1
header */
-#endif
-#ifdef USE_UNIX_SOCKETS
BIT(abstract_unix_socket);
-#endif
- BIT(disallow_username_in_url); /* disallow username in URL */
+ BIT(disallow_username_in_url); /* disallow username in url */
#ifndef CURL_DISABLE_DOH
BIT(doh); /* DNS-over-HTTPS enabled */
BIT(doh_verifypeer); /* DoH certificate peer verification */
@@ -1847,17 +1941,8 @@ struct UserDefined {
#ifdef USE_WEBSOCKETS
BIT(ws_raw_mode);
#endif
-#ifdef USE_ECH
- int tls_ech; /* TLS ECH configuration */
-#endif
};
-#ifndef CURL_DISABLE_MIME
-#define IS_MIME_POST(a) ((a)->set.mimepost.kind != MIMEKIND_NONE)
-#else
-#define IS_MIME_POST(a) FALSE
-#endif
-
struct Names {
struct Curl_hash *hostcache;
enum {
@@ -1881,23 +1966,22 @@ struct Curl_easy {
/* First a simple identifier to easier detect if a user mix up this easy
handle with a multi handle. Set this to CURLEASY_MAGIC_NUMBER */
unsigned int magic;
- /* once an easy handle is tied to a connection pool
+ /* once an easy handle is tied to a connection cache
a non-negative number to distinguish this transfer from
- other using the same pool. For easier tracking
+ other using the same cache. For easier tracking
in log output.
This may wrap around after LONG_MAX to 0 again, so it
- has no uniqueness guarantee for very large processings.
- Note: it has no uniqueness either IFF more than one connection pool
- is used by the libcurl application. */
+ has no uniqueness guarantee for very large processings. */
curl_off_t id;
- /* once an easy handle is added to a multi, either explicitly by the
- * libcurl application or implicitly during `curl_easy_perform()`,
- * a unique identifier inside this one multi instance. */
- curl_off_t mid;
+
+ /* first, two fields for the linked list of these */
+ struct Curl_easy *next;
+ struct Curl_easy *prev;
struct connectdata *conn;
- struct Curl_llist_node multi_queue; /* for multihandle list management */
- struct Curl_llist_node conn_queue; /* list per connectdata */
+ struct Curl_llist_element connect_queue; /* for the pending and msgsent
+ lists */
+ struct Curl_llist_element conn_queue; /* list per connectdata */
CURLMstate mstate; /* the handle's state */
CURLcode result; /* previous result */
diff --git a/contrib/libs/curl/lib/vauth/cleartext.c b/contrib/libs/curl/lib/vauth/cleartext.c
index cf8108ac5b..972a874480 100644
--- a/contrib/libs/curl/lib/vauth/cleartext.c
+++ b/contrib/libs/curl/lib/vauth/cleartext.c
@@ -100,38 +100,39 @@ CURLcode Curl_auth_create_plain_message(const char *authzid,
* Curl_auth_create_login_message()
*
* This is used to generate an already encoded LOGIN message containing the
- * username or password ready for sending to the recipient.
+ * user name or password ready for sending to the recipient.
*
* Parameters:
*
- * valuep [in] - The username or user's password.
+ * valuep [in] - The user name or user's password.
* out [out] - The result storage.
*
- * Returns void.
+ * Returns CURLE_OK on success.
*/
-void Curl_auth_create_login_message(const char *valuep, struct bufref *out)
+CURLcode Curl_auth_create_login_message(const char *valuep, struct bufref *out)
{
Curl_bufref_set(out, valuep, strlen(valuep), NULL);
+ return CURLE_OK;
}
/*
* Curl_auth_create_external_message()
*
* This is used to generate an already encoded EXTERNAL message containing
- * the username ready for sending to the recipient.
+ * the user name ready for sending to the recipient.
*
* Parameters:
*
- * user [in] - The username.
+ * user [in] - The user name.
* out [out] - The result storage.
*
- * Returns void.
+ * Returns CURLE_OK on success.
*/
-void Curl_auth_create_external_message(const char *user,
+CURLcode Curl_auth_create_external_message(const char *user,
struct bufref *out)
{
/* This is the same formatting as the login message */
- Curl_auth_create_login_message(user, out);
+ return Curl_auth_create_login_message(user, out);
}
#endif /* if no users */
diff --git a/contrib/libs/curl/lib/vauth/cram.c b/contrib/libs/curl/lib/vauth/cram.c
index f8bdd5458d..91fb261c57 100644
--- a/contrib/libs/curl/lib/vauth/cram.c
+++ b/contrib/libs/curl/lib/vauth/cram.c
@@ -51,7 +51,7 @@
* Parameters:
*
* chlg [in] - The challenge.
- * userp [in] - The username.
+ * userp [in] - The user name.
* passwdp [in] - The user's password.
* out [out] - The result storage.
*
diff --git a/contrib/libs/curl/lib/vauth/digest.c b/contrib/libs/curl/lib/vauth/digest.c
index 4fc5b1c28f..416da0fcc7 100644
--- a/contrib/libs/curl/lib/vauth/digest.c
+++ b/contrib/libs/curl/lib/vauth/digest.c
@@ -38,7 +38,6 @@
#include "curl_hmac.h"
#include "curl_md5.h"
#include "curl_sha256.h"
-#include "curl_sha512_256.h"
#include "vtls/vtls.h"
#include "warnless.h"
#include "strtok.h"
@@ -103,7 +102,7 @@ bool Curl_auth_digest_get_pair(const char *str, char *value, char *content,
case ',':
if(!starts_with_quote) {
- /* This signals the end of the content if we did not get a starting
+ /* This signals the end of the content if we didn't get a starting
quote and then we do "sloppy" parsing */
c = 0; /* the end */
continue;
@@ -142,7 +141,7 @@ bool Curl_auth_digest_get_pair(const char *str, char *value, char *content,
}
#if !defined(USE_WINDOWS_SSPI)
-/* Convert md5 chunk to RFC2617 (section 3.1.3) -suitable ASCII string */
+/* Convert md5 chunk to RFC2617 (section 3.1.3) -suitable ascii string */
static void auth_digest_md5_to_ascii(unsigned char *source, /* 16 bytes */
unsigned char *dest) /* 33 bytes */
{
@@ -151,7 +150,7 @@ static void auth_digest_md5_to_ascii(unsigned char *source, /* 16 bytes */
msnprintf((char *) &dest[i * 2], 3, "%02x", source[i]);
}
-/* Convert sha256 or SHA-512/256 chunk to RFC7616 -suitable ASCII string */
+/* Convert sha256 chunk to RFC7616 -suitable ascii string */
static void auth_digest_sha256_to_ascii(unsigned char *source, /* 32 bytes */
unsigned char *dest) /* 65 bytes */
{
@@ -288,7 +287,7 @@ static CURLcode auth_decode_digest_md5_message(const struct bufref *chlgref,
/* Retrieve realm string from the challenge */
if(!auth_digest_get_key_value(chlg, "realm=\"", realm, rlen, '\"')) {
/* Challenge does not have a realm, set empty string [RFC2831] page 6 */
- *realm = '\0';
+ strcpy(realm, "");
}
/* Retrieve algorithm string from the challenge */
@@ -326,7 +325,7 @@ bool Curl_auth_is_digest_supported(void)
*
* data [in] - The session handle.
* chlg [in] - The challenge message.
- * userp [in] - The username.
+ * userp [in] - The user name.
* passwdp [in] - The user's password.
* service [in] - The service type such as http, smtp, pop or imap.
* out [out] - The result storage.
@@ -602,20 +601,10 @@ CURLcode Curl_auth_decode_digest_http_message(const char *chlg,
digest->algo = ALGO_SHA256;
else if(strcasecompare(content, "SHA-256-SESS"))
digest->algo = ALGO_SHA256SESS;
- else if(strcasecompare(content, "SHA-512-256")) {
-#ifdef CURL_HAVE_SHA512_256
+ else if(strcasecompare(content, "SHA-512-256"))
digest->algo = ALGO_SHA512_256;
-#else /* ! CURL_HAVE_SHA512_256 */
- return CURLE_NOT_BUILT_IN;
-#endif /* ! CURL_HAVE_SHA512_256 */
- }
- else if(strcasecompare(content, "SHA-512-256-SESS")) {
-#ifdef CURL_HAVE_SHA512_256
+ else if(strcasecompare(content, "SHA-512-256-SESS"))
digest->algo = ALGO_SHA512_256SESS;
-#else /* ! CURL_HAVE_SHA512_256 */
- return CURLE_NOT_BUILT_IN;
-#endif /* ! CURL_HAVE_SHA512_256 */
- }
else
return CURLE_BAD_CONTENT_ENCODING;
}
@@ -629,7 +618,7 @@ CURLcode Curl_auth_decode_digest_http_message(const char *chlg,
}
}
else
- break; /* We are done here */
+ break; /* We're done here */
/* Pass all additional spaces here */
while(*chlg && ISBLANK(*chlg))
@@ -646,7 +635,7 @@ CURLcode Curl_auth_decode_digest_http_message(const char *chlg,
if(before && !digest->stale)
return CURLE_BAD_CONTENT_ENCODING;
- /* We got this header without a nonce, that is a bad Digest line! */
+ /* We got this header without a nonce, that's a bad Digest line! */
if(!digest->nonce)
return CURLE_BAD_CONTENT_ENCODING;
@@ -666,7 +655,7 @@ CURLcode Curl_auth_decode_digest_http_message(const char *chlg,
* Parameters:
*
* data [in] - The session handle.
- * userp [in] - The username.
+ * userp [in] - The user name.
* passwdp [in] - The user's password.
* request [in] - The HTTP request.
* uripath [in] - The path of the HTTP uri.
@@ -728,10 +717,8 @@ static CURLcode auth_create_digest_http_message(
if(!hashthis)
return CURLE_OUT_OF_MEMORY;
- result = hash(hashbuf, (unsigned char *) hashthis, strlen(hashthis));
+ hash(hashbuf, (unsigned char *) hashthis, strlen(hashthis));
free(hashthis);
- if(result)
- return result;
convert_to_ascii(hashbuf, (unsigned char *)userh);
}
@@ -751,10 +738,8 @@ static CURLcode auth_create_digest_http_message(
if(!hashthis)
return CURLE_OUT_OF_MEMORY;
- result = hash(hashbuf, (unsigned char *) hashthis, strlen(hashthis));
+ hash(hashbuf, (unsigned char *) hashthis, strlen(hashthis));
free(hashthis);
- if(result)
- return result;
convert_to_ascii(hashbuf, ha1);
if(digest->algo & SESSION_ALGO) {
@@ -763,10 +748,8 @@ static CURLcode auth_create_digest_http_message(
if(!tmp)
return CURLE_OUT_OF_MEMORY;
- result = hash(hashbuf, (unsigned char *) tmp, strlen(tmp));
+ hash(hashbuf, (unsigned char *) tmp, strlen(tmp));
free(tmp);
- if(result)
- return result;
convert_to_ascii(hashbuf, ha1);
}
@@ -788,15 +771,11 @@ static CURLcode auth_create_digest_http_message(
return CURLE_OUT_OF_MEMORY;
if(digest->qop && strcasecompare(digest->qop, "auth-int")) {
- /* We do not support auth-int for PUT or POST */
+ /* We don't support auth-int for PUT or POST */
char hashed[65];
char *hashthis2;
- result = hash(hashbuf, (const unsigned char *)"", 0);
- if(result) {
- free(hashthis);
- return result;
- }
+ hash(hashbuf, (const unsigned char *)"", 0);
convert_to_ascii(hashbuf, (unsigned char *)hashed);
hashthis2 = aprintf("%s:%s", hashthis, hashed);
@@ -807,10 +786,8 @@ static CURLcode auth_create_digest_http_message(
if(!hashthis)
return CURLE_OUT_OF_MEMORY;
- result = hash(hashbuf, (unsigned char *) hashthis, strlen(hashthis));
+ hash(hashbuf, (unsigned char *) hashthis, strlen(hashthis));
free(hashthis);
- if(result)
- return result;
convert_to_ascii(hashbuf, ha2);
if(digest->qop) {
@@ -824,10 +801,8 @@ static CURLcode auth_create_digest_http_message(
if(!hashthis)
return CURLE_OUT_OF_MEMORY;
- result = hash(hashbuf, (unsigned char *) hashthis, strlen(hashthis));
+ hash(hashbuf, (unsigned char *) hashthis, strlen(hashthis));
free(hashthis);
- if(result)
- return result;
convert_to_ascii(hashbuf, request_digest);
/* For test case 64 (snooped from a Mozilla 1.3a request)
@@ -835,12 +810,12 @@ static CURLcode auth_create_digest_http_message(
Authorization: Digest username="testuser", realm="testrealm", \
nonce="1053604145", uri="/64", response="c55f7f30d83d774a3d2dcacf725abaca"
- Digest parameters are all quoted strings. Username which is provided by
+ Digest parameters are all quoted strings. Username which is provided by
the user will need double quotes and backslashes within it escaped.
realm, nonce, and opaque will need backslashes as well as they were
- de-escaped when copied from request header. cnonce is generated with
- web-safe characters. uri is already percent encoded. nc is 8 hex
- characters. algorithm and qop with standard values only contain web-safe
+ de-escaped when copied from request header. cnonce is generated with
+ web-safe characters. uri is already percent encoded. nc is 8 hex
+ characters. algorithm and qop with standard values only contain web-safe
characters.
*/
userp_quoted = auth_digest_string_quoted(digest->userhash ? userh : userp);
@@ -957,7 +932,7 @@ static CURLcode auth_create_digest_http_message(
* Parameters:
*
* data [in] - The session handle.
- * userp [in] - The username.
+ * userp [in] - The user name.
* passwdp [in] - The user's password.
* request [in] - The HTTP request.
* uripath [in] - The path of the HTTP uri.
@@ -982,24 +957,12 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data,
outptr, outlen,
auth_digest_md5_to_ascii,
Curl_md5it);
-
- if(digest->algo <= ALGO_SHA256SESS)
- return auth_create_digest_http_message(data, userp, passwdp,
- request, uripath, digest,
- outptr, outlen,
- auth_digest_sha256_to_ascii,
- Curl_sha256it);
-#ifdef CURL_HAVE_SHA512_256
- if(digest->algo <= ALGO_SHA512_256SESS)
- return auth_create_digest_http_message(data, userp, passwdp,
- request, uripath, digest,
- outptr, outlen,
- auth_digest_sha256_to_ascii,
- Curl_sha512_256it);
-#endif /* CURL_HAVE_SHA512_256 */
-
- /* Should be unreachable */
- return CURLE_BAD_CONTENT_ENCODING;
+ DEBUGASSERT(digest->algo <= ALGO_SHA512_256SESS);
+ return auth_create_digest_http_message(data, userp, passwdp,
+ request, uripath, digest,
+ outptr, outlen,
+ auth_digest_sha256_to_ascii,
+ Curl_sha256it);
}
/*
diff --git a/contrib/libs/curl/lib/vauth/digest_sspi.c b/contrib/libs/curl/lib/vauth/digest_sspi.c
index 39a0c306d8..02e36ea5ed 100644
--- a/contrib/libs/curl/lib/vauth/digest_sspi.c
+++ b/contrib/libs/curl/lib/vauth/digest_sspi.c
@@ -60,13 +60,12 @@ bool Curl_auth_is_digest_supported(void)
SECURITY_STATUS status;
/* Query the security package for Digest */
- status =
- Curl_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_DIGEST),
- &SecurityPackage);
+ status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_DIGEST),
+ &SecurityPackage);
/* Release the package buffer as it is not required anymore */
if(status == SEC_E_OK) {
- Curl_pSecFn->FreeContextBuffer(SecurityPackage);
+ s_pSecFn->FreeContextBuffer(SecurityPackage);
}
return (status == SEC_E_OK ? TRUE : FALSE);
@@ -82,7 +81,7 @@ bool Curl_auth_is_digest_supported(void)
*
* data [in] - The session handle.
* chlg [in] - The challenge message.
- * userp [in] - The username in the format User or Domain\User.
+ * userp [in] - The user name in the format User or Domain\User.
* passwdp [in] - The user's password.
* service [in] - The service type such as http, smtp, pop or imap.
* out [out] - The result storage.
@@ -120,18 +119,17 @@ CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data,
}
/* Query the security package for DigestSSP */
- status =
- Curl_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_DIGEST),
- &SecurityPackage);
+ status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_DIGEST),
+ &SecurityPackage);
if(status != SEC_E_OK) {
- failf(data, "SSPI: could not get auth info");
+ failf(data, "SSPI: couldn't get auth info");
return CURLE_AUTH_ERROR;
}
token_max = SecurityPackage->cbMaxToken;
/* Release the package buffer as it is not required anymore */
- Curl_pSecFn->FreeContextBuffer(SecurityPackage);
+ s_pSecFn->FreeContextBuffer(SecurityPackage);
/* Allocate our response buffer */
output_token = malloc(token_max);
@@ -162,7 +160,7 @@ CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data,
p_identity = NULL;
/* Acquire our credentials handle */
- status = Curl_pSecFn->AcquireCredentialsHandle(NULL,
+ status = s_pSecFn->AcquireCredentialsHandle(NULL,
(TCHAR *) TEXT(SP_NAME_DIGEST),
SECPKG_CRED_OUTBOUND, NULL,
p_identity, NULL, NULL,
@@ -192,20 +190,20 @@ CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data,
resp_buf.cbBuffer = curlx_uztoul(token_max);
/* Generate our response message */
- status = Curl_pSecFn->InitializeSecurityContext(&credentials, NULL, spn,
+ status = s_pSecFn->InitializeSecurityContext(&credentials, NULL, spn,
0, 0, 0, &chlg_desc, 0,
&context, &resp_desc, &attrs,
&expiry);
if(status == SEC_I_COMPLETE_NEEDED ||
status == SEC_I_COMPLETE_AND_CONTINUE)
- Curl_pSecFn->CompleteAuthToken(&credentials, &resp_desc);
+ s_pSecFn->CompleteAuthToken(&credentials, &resp_desc);
else if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) {
#if !defined(CURL_DISABLE_VERBOSE_STRINGS)
char buffer[STRERROR_LEN];
#endif
- Curl_pSecFn->FreeCredentialsHandle(&credentials);
+ s_pSecFn->FreeCredentialsHandle(&credentials);
Curl_sspi_free_identity(p_identity);
free(spn);
free(output_token);
@@ -213,10 +211,8 @@ CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data,
if(status == SEC_E_INSUFFICIENT_MEMORY)
return CURLE_OUT_OF_MEMORY;
-#if !defined(CURL_DISABLE_VERBOSE_STRINGS)
infof(data, "schannel: InitializeSecurityContext failed: %s",
Curl_sspi_strerror(status, buffer, sizeof(buffer)));
-#endif
return CURLE_AUTH_ERROR;
}
@@ -225,8 +221,8 @@ CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data,
Curl_bufref_set(out, output_token, resp_buf.cbBuffer, curl_free);
/* Free our handles */
- Curl_pSecFn->DeleteSecurityContext(&context);
- Curl_pSecFn->FreeCredentialsHandle(&credentials);
+ s_pSecFn->DeleteSecurityContext(&context);
+ s_pSecFn->FreeCredentialsHandle(&credentials);
/* Free the identity structure */
Curl_sspi_free_identity(p_identity);
@@ -293,7 +289,7 @@ CURLcode Curl_override_sspi_http_realm(const char *chlg,
}
}
else
- break; /* We are done here */
+ break; /* We're done here */
/* Pass all additional spaces here */
while(*chlg && ISBLANK(*chlg))
@@ -326,8 +322,8 @@ CURLcode Curl_auth_decode_digest_http_message(const char *chlg,
{
size_t chlglen = strlen(chlg);
- /* We had an input token before so if there is another one now that means we
- provided bad credentials in the previous request or it is stale. */
+ /* We had an input token before so if there's another one now that means we
+ provided bad credentials in the previous request or it's stale. */
if(digest->input_token) {
bool stale = false;
const char *p = chlg;
@@ -381,7 +377,7 @@ CURLcode Curl_auth_decode_digest_http_message(const char *chlg,
* Parameters:
*
* data [in] - The session handle.
- * userp [in] - The username in the format User or Domain\User.
+ * userp [in] - The user name in the format User or Domain\User.
* passwdp [in] - The user's password.
* request [in] - The HTTP request.
* uripath [in] - The path of the HTTP uri.
@@ -412,18 +408,17 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data,
(void) data;
/* Query the security package for DigestSSP */
- status =
- Curl_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_DIGEST),
- &SecurityPackage);
+ status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_DIGEST),
+ &SecurityPackage);
if(status != SEC_E_OK) {
- failf(data, "SSPI: could not get auth info");
+ failf(data, "SSPI: couldn't get auth info");
return CURLE_AUTH_ERROR;
}
token_max = SecurityPackage->cbMaxToken;
/* Release the package buffer as it is not required anymore */
- Curl_pSecFn->FreeContextBuffer(SecurityPackage);
+ s_pSecFn->FreeContextBuffer(SecurityPackage);
/* Allocate the output buffer according to the max token size as indicated
by the security package */
@@ -439,7 +434,7 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data,
(userp && digest->user && Curl_timestrcmp(userp, digest->user)) ||
(passwdp && digest->passwd && Curl_timestrcmp(passwdp, digest->passwd))) {
if(digest->http_context) {
- Curl_pSecFn->DeleteSecurityContext(digest->http_context);
+ s_pSecFn->DeleteSecurityContext(digest->http_context);
Curl_safefree(digest->http_context);
}
Curl_safefree(digest->user);
@@ -466,14 +461,13 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data,
chlg_buf[4].pvBuffer = output_token;
chlg_buf[4].cbBuffer = curlx_uztoul(token_max);
- status = Curl_pSecFn->MakeSignature(digest->http_context, 0, &chlg_desc,
- 0);
+ status = s_pSecFn->MakeSignature(digest->http_context, 0, &chlg_desc, 0);
if(status == SEC_E_OK)
output_token_len = chlg_buf[4].cbBuffer;
else { /* delete the context so a new one can be made */
infof(data, "digest_sspi: MakeSignature failed, error 0x%08lx",
(long)status);
- Curl_pSecFn->DeleteSecurityContext(digest->http_context);
+ s_pSecFn->DeleteSecurityContext(digest->http_context);
Curl_safefree(digest->http_context);
}
}
@@ -533,7 +527,7 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data,
}
/* Acquire our credentials handle */
- status = Curl_pSecFn->AcquireCredentialsHandle(NULL,
+ status = s_pSecFn->AcquireCredentialsHandle(NULL,
(TCHAR *) TEXT(SP_NAME_DIGEST),
SECPKG_CRED_OUTBOUND, NULL,
p_identity, NULL, NULL,
@@ -569,7 +563,7 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data,
spn = curlx_convert_UTF8_to_tchar((char *) uripath);
if(!spn) {
- Curl_pSecFn->FreeCredentialsHandle(&credentials);
+ s_pSecFn->FreeCredentialsHandle(&credentials);
Curl_sspi_free_identity(p_identity);
free(output_token);
@@ -583,7 +577,7 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data,
return CURLE_OUT_OF_MEMORY;
/* Generate our response message */
- status = Curl_pSecFn->InitializeSecurityContext(&credentials, NULL,
+ status = s_pSecFn->InitializeSecurityContext(&credentials, NULL,
spn,
ISC_REQ_USE_HTTP_STYLE, 0, 0,
&chlg_desc, 0,
@@ -593,13 +587,13 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data,
if(status == SEC_I_COMPLETE_NEEDED ||
status == SEC_I_COMPLETE_AND_CONTINUE)
- Curl_pSecFn->CompleteAuthToken(&credentials, &resp_desc);
+ s_pSecFn->CompleteAuthToken(&credentials, &resp_desc);
else if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) {
#if !defined(CURL_DISABLE_VERBOSE_STRINGS)
char buffer[STRERROR_LEN];
#endif
- Curl_pSecFn->FreeCredentialsHandle(&credentials);
+ s_pSecFn->FreeCredentialsHandle(&credentials);
Curl_sspi_free_identity(p_identity);
free(output_token);
@@ -609,17 +603,15 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data,
if(status == SEC_E_INSUFFICIENT_MEMORY)
return CURLE_OUT_OF_MEMORY;
-#if !defined(CURL_DISABLE_VERBOSE_STRINGS)
infof(data, "schannel: InitializeSecurityContext failed: %s",
Curl_sspi_strerror(status, buffer, sizeof(buffer)));
-#endif
return CURLE_AUTH_ERROR;
}
output_token_len = resp_buf.cbBuffer;
- Curl_pSecFn->FreeCredentialsHandle(&credentials);
+ s_pSecFn->FreeCredentialsHandle(&credentials);
Curl_sspi_free_identity(p_identity);
}
@@ -664,7 +656,7 @@ void Curl_auth_digest_cleanup(struct digestdata *digest)
/* Delete security context */
if(digest->http_context) {
- Curl_pSecFn->DeleteSecurityContext(digest->http_context);
+ s_pSecFn->DeleteSecurityContext(digest->http_context);
Curl_safefree(digest->http_context);
}
diff --git a/contrib/libs/curl/lib/vauth/krb5_gssapi.c b/contrib/libs/curl/lib/vauth/krb5_gssapi.c
index 4bec9047c3..b9c3289b82 100644
--- a/contrib/libs/curl/lib/vauth/krb5_gssapi.c
+++ b/contrib/libs/curl/lib/vauth/krb5_gssapi.c
@@ -65,10 +65,10 @@ bool Curl_auth_is_gssapi_supported(void)
* Parameters:
*
* data [in] - The session handle.
- * userp [in] - The username.
+ * userp [in] - The user name.
* passwdp [in] - The user's password.
* service [in] - The service type such as http, smtp, pop or imap.
- * host [in[ - The hostname.
+ * host [in[ - The host name.
* mutual_auth [in] - Flag specifying whether or not mutual authentication
* is enabled.
* chlg [in] - Optional challenge message.
@@ -226,8 +226,7 @@ CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data,
/* Extract the security layer and the maximum message size */
indata = output_token.value;
sec_layer = indata[0];
- max_size = ((unsigned int)indata[1] << 16) |
- ((unsigned int)indata[2] << 8) | indata[3];
+ max_size = (indata[1] << 16) | (indata[2] << 8) | indata[3];
/* Free the challenge as it is not required anymore */
gss_release_buffer(&unused_status, &output_token);
@@ -243,7 +242,7 @@ CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data,
/* Process the maximum message size the server can receive */
if(max_size > 0) {
/* The server has told us it supports a maximum receive buffer, however, as
- we do not require one unless we are encrypting data, we tell the server
+ we don't require one unless we are encrypting data, we tell the server
our receive buffer is zero. */
max_size = 0;
}
diff --git a/contrib/libs/curl/lib/vauth/krb5_sspi.c b/contrib/libs/curl/lib/vauth/krb5_sspi.c
index b168a27ad8..c487149b9d 100644
--- a/contrib/libs/curl/lib/vauth/krb5_sspi.c
+++ b/contrib/libs/curl/lib/vauth/krb5_sspi.c
@@ -55,13 +55,13 @@ bool Curl_auth_is_gssapi_supported(void)
SECURITY_STATUS status;
/* Query the security package for Kerberos */
- status = Curl_pSecFn->QuerySecurityPackageInfo((TCHAR *)
+ status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *)
TEXT(SP_NAME_KERBEROS),
&SecurityPackage);
/* Release the package buffer as it is not required anymore */
if(status == SEC_E_OK) {
- Curl_pSecFn->FreeContextBuffer(SecurityPackage);
+ s_pSecFn->FreeContextBuffer(SecurityPackage);
}
return (status == SEC_E_OK ? TRUE : FALSE);
@@ -76,10 +76,10 @@ bool Curl_auth_is_gssapi_supported(void)
* Parameters:
*
* data [in] - The session handle.
- * userp [in] - The username in the format User or Domain\User.
+ * userp [in] - The user name in the format User or Domain\User.
* passwdp [in] - The user's password.
* service [in] - The service type such as http, smtp, pop or imap.
- * host [in] - The hostname.
+ * host [in] - The host name.
* mutual_auth [in] - Flag specifying whether or not mutual authentication
* is enabled.
* chlg [in] - Optional challenge message.
@@ -118,18 +118,18 @@ CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data,
if(!krb5->output_token) {
/* Query the security package for Kerberos */
- status = Curl_pSecFn->QuerySecurityPackageInfo((TCHAR *)
+ status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *)
TEXT(SP_NAME_KERBEROS),
&SecurityPackage);
if(status != SEC_E_OK) {
- failf(data, "SSPI: could not get auth info");
+ failf(data, "SSPI: couldn't get auth info");
return CURLE_AUTH_ERROR;
}
krb5->token_max = SecurityPackage->cbMaxToken;
/* Release the package buffer as it is not required anymore */
- Curl_pSecFn->FreeContextBuffer(SecurityPackage);
+ s_pSecFn->FreeContextBuffer(SecurityPackage);
/* Allocate our response buffer */
krb5->output_token = malloc(krb5->token_max);
@@ -158,7 +158,7 @@ CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data,
return CURLE_OUT_OF_MEMORY;
/* Acquire our credentials handle */
- status = Curl_pSecFn->AcquireCredentialsHandle(NULL,
+ status = s_pSecFn->AcquireCredentialsHandle(NULL,
(TCHAR *)
TEXT(SP_NAME_KERBEROS),
SECPKG_CRED_OUTBOUND, NULL,
@@ -197,7 +197,7 @@ CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data,
resp_buf.cbBuffer = curlx_uztoul(krb5->token_max);
/* Generate our challenge-response message */
- status = Curl_pSecFn->InitializeSecurityContext(krb5->credentials,
+ status = s_pSecFn->InitializeSecurityContext(krb5->credentials,
chlg ? krb5->context : NULL,
krb5->spn,
(mutual_auth ?
@@ -215,7 +215,7 @@ CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data,
return CURLE_AUTH_ERROR;
if(memcmp(&context, krb5->context, sizeof(context))) {
- Curl_pSecFn->DeleteSecurityContext(krb5->context);
+ s_pSecFn->DeleteSecurityContext(krb5->context);
memcpy(krb5->context, &context, sizeof(context));
}
@@ -282,7 +282,7 @@ CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data,
}
/* Get our response size information */
- status = Curl_pSecFn->QueryContextAttributes(krb5->context,
+ status = s_pSecFn->QueryContextAttributes(krb5->context,
SECPKG_ATTR_SIZES,
&sizes);
@@ -304,7 +304,7 @@ CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data,
input_buf[1].cbBuffer = 0;
/* Decrypt the inbound challenge and obtain the qop */
- status = Curl_pSecFn->DecryptMessage(krb5->context, &input_desc, 0, &qop);
+ status = s_pSecFn->DecryptMessage(krb5->context, &input_desc, 0, &qop);
if(status != SEC_E_OK) {
infof(data, "GSSAPI handshake failure (empty security message)");
return CURLE_BAD_CONTENT_ENCODING;
@@ -319,11 +319,10 @@ CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data,
/* Extract the security layer and the maximum message size */
indata = input_buf[1].pvBuffer;
sec_layer = indata[0];
- max_size = ((unsigned long)indata[1] << 16) |
- ((unsigned long)indata[2] << 8) | indata[3];
+ max_size = (indata[1] << 16) | (indata[2] << 8) | indata[3];
/* Free the challenge as it is not required anymore */
- Curl_pSecFn->FreeContextBuffer(input_buf[1].pvBuffer);
+ s_pSecFn->FreeContextBuffer(input_buf[1].pvBuffer);
/* Process the security layer */
if(!(sec_layer & KERB_WRAP_NO_ENCRYPT)) {
@@ -335,7 +334,7 @@ CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data,
/* Process the maximum message size the server can receive */
if(max_size > 0) {
/* The server has told us it supports a maximum receive buffer, however, as
- we do not require one unless we are encrypting data, we tell the server
+ we don't require one unless we are encrypting data, we tell the server
our receive buffer is zero. */
max_size = 0;
}
@@ -392,7 +391,7 @@ CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data,
wrap_buf[2].cbBuffer = sizes.cbBlockSize;
/* Encrypt the data */
- status = Curl_pSecFn->EncryptMessage(krb5->context, KERB_WRAP_NO_ENCRYPT,
+ status = s_pSecFn->EncryptMessage(krb5->context, KERB_WRAP_NO_ENCRYPT,
&wrap_desc, 0);
if(status != SEC_E_OK) {
free(padding);
@@ -448,14 +447,14 @@ void Curl_auth_cleanup_gssapi(struct kerberos5data *krb5)
{
/* Free our security context */
if(krb5->context) {
- Curl_pSecFn->DeleteSecurityContext(krb5->context);
+ s_pSecFn->DeleteSecurityContext(krb5->context);
free(krb5->context);
krb5->context = NULL;
}
/* Free our credentials handle */
if(krb5->credentials) {
- Curl_pSecFn->FreeCredentialsHandle(krb5->credentials);
+ s_pSecFn->FreeCredentialsHandle(krb5->credentials);
free(krb5->credentials);
krb5->credentials = NULL;
}
diff --git a/contrib/libs/curl/lib/vauth/ntlm.c b/contrib/libs/curl/lib/vauth/ntlm.c
index 0050b4132c..ed7cee8def 100644
--- a/contrib/libs/curl/lib/vauth/ntlm.c
+++ b/contrib/libs/curl/lib/vauth/ntlm.c
@@ -44,7 +44,6 @@
#include "warnless.h"
#include "rand.h"
#include "vtls/vtls.h"
-#include "strdup.h"
#define BUILDING_CURL_NTLM_MSGS_C
#include "vauth/vauth.h"
@@ -59,6 +58,10 @@
/* "NTLMSSP" signature is always in ASCII regardless of the platform */
#define NTLMSSP_SIGNATURE "\x4e\x54\x4c\x4d\x53\x53\x50"
+/* The fixed host name we provide, in order to not leak our real local host
+ name. Copy the name used by Firefox. */
+#define NTLM_HOSTNAME "WORKSTATION"
+
#if DEBUG_ME
# define DEBUG_OUT(x) x
static void ntlm_print_flags(FILE *handle, unsigned long flags)
@@ -181,10 +184,11 @@ static CURLcode ntlm_decode_type2_target(struct Curl_easy *data,
}
free(ntlm->target_info); /* replace any previous data */
- ntlm->target_info = Curl_memdup(&type2[target_info_offset],
- target_info_len);
+ ntlm->target_info = malloc(target_info_len);
if(!ntlm->target_info)
return CURLE_OUT_OF_MEMORY;
+
+ memcpy(ntlm->target_info, &type2[target_info_offset], target_info_len);
}
}
@@ -321,10 +325,10 @@ static void unicodecpy(unsigned char *dest, const char *src, size_t length)
* Parameters:
*
* data [in] - The session handle.
- * userp [in] - The username in the format User or Domain\User.
+ * userp [in] - The user name in the format User or Domain\User.
* passwdp [in] - The user's password.
* service [in] - The service type such as http, smtp, pop or imap.
- * host [in] - The hostname.
+ * host [in] - The host name.
* ntlm [in/out] - The NTLM data struct being used and modified.
* out [out] - The result storage.
*
@@ -380,9 +384,9 @@ CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data,
"%c%c" /* 2 zeroes */
"%c%c" /* host length */
"%c%c" /* host allocated space */
- "%c%c" /* hostname offset */
+ "%c%c" /* host name offset */
"%c%c" /* 2 zeroes */
- "%s" /* hostname */
+ "%s" /* host name */
"%s", /* domain string */
0, /* trailing zero */
0, 0, 0, /* part of type-1 long */
@@ -444,7 +448,7 @@ CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data,
* Parameters:
*
* data [in] - The session handle.
- * userp [in] - The username in the format User or Domain\User.
+ * userp [in] - The user name in the format User or Domain\User.
* passwdp [in] - The user's password.
* ntlm [in/out] - The NTLM data struct being used and modified.
* out [out] - The result storage.
@@ -466,7 +470,7 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data,
12 LM/LMv2 Response security buffer
20 NTLM/NTLMv2 Response security buffer
28 Target Name security buffer
- 36 username security buffer
+ 36 User Name security buffer
44 Workstation Name security buffer
(52) Session Key security buffer (*)
(60) Flags long (*)
@@ -478,17 +482,15 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data,
CURLcode result = CURLE_OK;
size_t size;
unsigned char ntlmbuf[NTLM_BUFSIZE];
- unsigned int lmrespoff;
+ int lmrespoff;
unsigned char lmresp[24]; /* fixed-size */
- unsigned int ntrespoff;
+ int ntrespoff;
unsigned int ntresplen = 24;
unsigned char ntresp[24]; /* fixed-size */
unsigned char *ptr_ntresp = &ntresp[0];
unsigned char *ntlmv2resp = NULL;
bool unicode = (ntlm->flags & NTLMFLAG_NEGOTIATE_UNICODE) ? TRUE : FALSE;
- /* The fixed hostname we provide, in order to not leak our real local host
- name. Copy the name used by Firefox. */
- static const char host[] = "WORKSTATION";
+ char host[HOSTNAME_MAX + 1] = "";
const char *user;
const char *domain = "";
size_t hostoff = 0;
@@ -513,7 +515,21 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data,
user = userp;
userlen = strlen(user);
- hostlen = sizeof(host) - 1;
+
+#ifndef NTLM_HOSTNAME
+ /* Get the machine's un-qualified host name as NTLM doesn't like the fully
+ qualified domain name */
+ if(Curl_gethostname(host, sizeof(host))) {
+ infof(data, "gethostname() failed, continuing without");
+ hostlen = 0;
+ }
+ else {
+ hostlen = strlen(host);
+ }
+#else
+ (void)msnprintf(host, sizeof(host), "%s", NTLM_HOSTNAME);
+ hostlen = sizeof(NTLM_HOSTNAME)-1;
+#endif
if(ntlm->flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY) {
unsigned char ntbuffer[0x18];
@@ -569,7 +585,7 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data,
return result;
Curl_ntlm_core_lm_resp(lmbuffer, &ntlm->nonce[0], lmresp);
- ntlm->flags &= ~(unsigned int)NTLMFLAG_NEGOTIATE_NTLM2_KEY;
+ ntlm->flags &= ~NTLMFLAG_NEGOTIATE_NTLM2_KEY;
/* A safer but less compatible alternative is:
* Curl_ntlm_core_lm_resp(ntbuffer, &ntlm->nonce[0], lmresp);
@@ -706,7 +722,7 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data,
/* Make sure that the domain, user and host strings fit in the
buffer before we copy them there. */
if(size + userlen + domlen + hostlen >= NTLM_BUFSIZE) {
- failf(data, "user + domain + hostname too big");
+ failf(data, "user + domain + host name too big");
return CURLE_OUT_OF_MEMORY;
}
diff --git a/contrib/libs/curl/lib/vauth/ntlm_sspi.c b/contrib/libs/curl/lib/vauth/ntlm_sspi.c
index 55ec8201d8..5118963f4d 100644
--- a/contrib/libs/curl/lib/vauth/ntlm_sspi.c
+++ b/contrib/libs/curl/lib/vauth/ntlm_sspi.c
@@ -34,7 +34,6 @@
#include "warnless.h"
#include "curl_multibyte.h"
#include "sendf.h"
-#include "strdup.h"
/* The last #include files should be: */
#include "curl_memory.h"
@@ -55,12 +54,12 @@ bool Curl_auth_is_ntlm_supported(void)
SECURITY_STATUS status;
/* Query the security package for NTLM */
- status = Curl_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_NTLM),
+ status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_NTLM),
&SecurityPackage);
/* Release the package buffer as it is not required anymore */
if(status == SEC_E_OK) {
- Curl_pSecFn->FreeContextBuffer(SecurityPackage);
+ s_pSecFn->FreeContextBuffer(SecurityPackage);
}
return (status == SEC_E_OK ? TRUE : FALSE);
@@ -75,10 +74,10 @@ bool Curl_auth_is_ntlm_supported(void)
* Parameters:
*
* data [in] - The session handle.
- * userp [in] - The username in the format User or Domain\User.
+ * userp [in] - The user name in the format User or Domain\User.
* passwdp [in] - The user's password.
* service [in] - The service type such as http, smtp, pop or imap.
- * host [in] - The hostname.
+ * host [in] - The host name.
* ntlm [in/out] - The NTLM data struct being used and modified.
* out [out] - The result storage.
*
@@ -103,17 +102,17 @@ CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data,
Curl_auth_cleanup_ntlm(ntlm);
/* Query the security package for NTLM */
- status = Curl_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_NTLM),
+ status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_NTLM),
&SecurityPackage);
if(status != SEC_E_OK) {
- failf(data, "SSPI: could not get auth info");
+ failf(data, "SSPI: couldn't get auth info");
return CURLE_AUTH_ERROR;
}
ntlm->token_max = SecurityPackage->cbMaxToken;
/* Release the package buffer as it is not required anymore */
- Curl_pSecFn->FreeContextBuffer(SecurityPackage);
+ s_pSecFn->FreeContextBuffer(SecurityPackage);
/* Allocate our output buffer */
ntlm->output_token = malloc(ntlm->token_max);
@@ -141,7 +140,7 @@ CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data,
return CURLE_OUT_OF_MEMORY;
/* Acquire our credentials handle */
- status = Curl_pSecFn->AcquireCredentialsHandle(NULL,
+ status = s_pSecFn->AcquireCredentialsHandle(NULL,
(TCHAR *) TEXT(SP_NAME_NTLM),
SECPKG_CRED_OUTBOUND, NULL,
ntlm->p_identity, NULL, NULL,
@@ -167,7 +166,7 @@ CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data,
type_1_buf.cbBuffer = curlx_uztoul(ntlm->token_max);
/* Generate our type-1 message */
- status = Curl_pSecFn->InitializeSecurityContext(ntlm->credentials, NULL,
+ status = s_pSecFn->InitializeSecurityContext(ntlm->credentials, NULL,
ntlm->spn,
0, 0, SECURITY_NETWORK_DREP,
NULL, 0,
@@ -175,7 +174,7 @@ CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data,
&attrs, &expiry);
if(status == SEC_I_COMPLETE_NEEDED ||
status == SEC_I_COMPLETE_AND_CONTINUE)
- Curl_pSecFn->CompleteAuthToken(ntlm->context, &type_1_desc);
+ s_pSecFn->CompleteAuthToken(ntlm->context, &type_1_desc);
else if(status == SEC_E_INSUFFICIENT_MEMORY)
return CURLE_OUT_OF_MEMORY;
else if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED)
@@ -214,10 +213,11 @@ CURLcode Curl_auth_decode_ntlm_type2_message(struct Curl_easy *data,
}
/* Store the challenge for later use */
- ntlm->input_token = Curl_memdup0((const char *)Curl_bufref_ptr(type2),
- Curl_bufref_len(type2));
+ ntlm->input_token = malloc(Curl_bufref_len(type2) + 1);
if(!ntlm->input_token)
return CURLE_OUT_OF_MEMORY;
+ memcpy(ntlm->input_token, Curl_bufref_ptr(type2), Curl_bufref_len(type2));
+ ntlm->input_token[Curl_bufref_len(type2)] = '\0';
ntlm->input_token_len = Curl_bufref_len(type2);
return CURLE_OK;
@@ -233,7 +233,7 @@ CURLcode Curl_auth_decode_ntlm_type2_message(struct Curl_easy *data,
* Parameters:
*
* data [in] - The session handle.
- * userp [in] - The username in the format User or Domain\User.
+ * userp [in] - The user name in the format User or Domain\User.
* passwdp [in] - The user's password.
* ntlm [in/out] - The NTLM data struct being used and modified.
* out [out] - The result storage.
@@ -282,7 +282,7 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data,
SEC_CHANNEL_BINDINGS channelBindings;
SecPkgContext_Bindings pkgBindings;
pkgBindings.Bindings = &channelBindings;
- status = Curl_pSecFn->QueryContextAttributes(
+ status = s_pSecFn->QueryContextAttributes(
ntlm->sslContext,
SECPKG_ATTR_ENDPOINT_BINDINGS,
&pkgBindings
@@ -305,7 +305,7 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data,
type_3_buf.cbBuffer = curlx_uztoul(ntlm->token_max);
/* Generate our type-3 message */
- status = Curl_pSecFn->InitializeSecurityContext(ntlm->credentials,
+ status = s_pSecFn->InitializeSecurityContext(ntlm->credentials,
ntlm->context,
ntlm->spn,
0, 0, SECURITY_NETWORK_DREP,
@@ -314,7 +314,7 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data,
&type_3_desc,
&attrs, &expiry);
if(status != SEC_E_OK) {
- infof(data, "NTLM handshake failure (type-3 message): Status=%lx",
+ infof(data, "NTLM handshake failure (type-3 message): Status=%x",
status);
if(status == SEC_E_INSUFFICIENT_MEMORY)
@@ -343,14 +343,14 @@ void Curl_auth_cleanup_ntlm(struct ntlmdata *ntlm)
{
/* Free our security context */
if(ntlm->context) {
- Curl_pSecFn->DeleteSecurityContext(ntlm->context);
+ s_pSecFn->DeleteSecurityContext(ntlm->context);
free(ntlm->context);
ntlm->context = NULL;
}
/* Free our credentials handle */
if(ntlm->credentials) {
- Curl_pSecFn->FreeCredentialsHandle(ntlm->credentials);
+ s_pSecFn->FreeCredentialsHandle(ntlm->credentials);
free(ntlm->credentials);
ntlm->credentials = NULL;
}
diff --git a/contrib/libs/curl/lib/vauth/oauth2.c b/contrib/libs/curl/lib/vauth/oauth2.c
index dc94afa365..a4adbdcf15 100644
--- a/contrib/libs/curl/lib/vauth/oauth2.c
+++ b/contrib/libs/curl/lib/vauth/oauth2.c
@@ -49,8 +49,8 @@
*
* Parameters:
*
- * user[in] - The username.
- * host[in] - The hostname.
+ * user[in] - The user name.
+ * host[in] - The host name.
* port[in] - The port(when not Port 80).
* bearer[in] - The bearer token.
* out[out] - The result storage.
@@ -87,7 +87,7 @@ CURLcode Curl_auth_create_oauth_bearer_message(const char *user,
*
* Parameters:
*
- * user[in] - The username.
+ * user[in] - The user name.
* bearer[in] - The bearer token.
* out[out] - The result storage.
*
diff --git a/contrib/libs/curl/lib/vauth/spnego_gssapi.c b/contrib/libs/curl/lib/vauth/spnego_gssapi.c
index d6b41a2105..59cc2ae422 100644
--- a/contrib/libs/curl/lib/vauth/spnego_gssapi.c
+++ b/contrib/libs/curl/lib/vauth/spnego_gssapi.c
@@ -65,10 +65,10 @@ bool Curl_auth_is_spnego_supported(void)
* Parameters:
*
* data [in] - The session handle.
- * userp [in] - The username in the format User or Domain\User.
+ * userp [in] - The user name in the format User or Domain\User.
* passwdp [in] - The user's password.
* service [in] - The service type such as http, smtp, pop or imap.
- * host [in] - The hostname.
+ * host [in] - The host name.
* chlg64 [in] - The optional base64 encoded challenge message.
* nego [in/out] - The Negotiate data struct being used and modified.
*
@@ -91,16 +91,14 @@ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data,
gss_buffer_desc spn_token = GSS_C_EMPTY_BUFFER;
gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
- gss_channel_bindings_t chan_bindings = GSS_C_NO_CHANNEL_BINDINGS;
- struct gss_channel_bindings_struct chan;
(void) user;
(void) password;
if(nego->context && nego->status == GSS_S_COMPLETE) {
/* We finished successfully our part of authentication, but server
- * rejected it (since we are again here). Exit with an error since we
- * cannot invent anything better */
+ * rejected it (since we're again here). Exit with an error since we
+ * can't invent anything better */
Curl_auth_cleanup_spnego(nego);
return CURLE_LOGIN_DENIED;
}
@@ -150,21 +148,13 @@ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data,
input_token.length = chlglen;
}
- /* Set channel binding data if available */
- if(nego->channel_binding_data.leng > 0) {
- memset(&chan, 0, sizeof(struct gss_channel_bindings_struct));
- chan.application_data.length = nego->channel_binding_data.leng;
- chan.application_data.value = nego->channel_binding_data.bufr;
- chan_bindings = &chan;
- }
-
/* Generate our challenge-response message */
major_status = Curl_gss_init_sec_context(data,
&minor_status,
&nego->context,
nego->spn,
&Curl_spnego_mech_oid,
- chan_bindings,
+ GSS_C_NO_CHANNEL_BINDINGS,
&input_token,
&output_token,
TRUE,
diff --git a/contrib/libs/curl/lib/vauth/spnego_sspi.c b/contrib/libs/curl/lib/vauth/spnego_sspi.c
index 38b26ab90c..d3245d0b18 100644
--- a/contrib/libs/curl/lib/vauth/spnego_sspi.c
+++ b/contrib/libs/curl/lib/vauth/spnego_sspi.c
@@ -57,13 +57,13 @@ bool Curl_auth_is_spnego_supported(void)
SECURITY_STATUS status;
/* Query the security package for Negotiate */
- status = Curl_pSecFn->QuerySecurityPackageInfo((TCHAR *)
+ status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *)
TEXT(SP_NAME_NEGOTIATE),
&SecurityPackage);
/* Release the package buffer as it is not required anymore */
if(status == SEC_E_OK) {
- Curl_pSecFn->FreeContextBuffer(SecurityPackage);
+ s_pSecFn->FreeContextBuffer(SecurityPackage);
}
@@ -79,10 +79,10 @@ bool Curl_auth_is_spnego_supported(void)
* Parameters:
*
* data [in] - The session handle.
- * user [in] - The username in the format User or Domain\User.
+ * user [in] - The user name in the format User or Domain\User.
* password [in] - The user's password.
* service [in] - The service type such as http, smtp, pop or imap.
- * host [in] - The hostname.
+ * host [in] - The host name.
* chlg64 [in] - The optional base64 encoded challenge message.
* nego [in/out] - The Negotiate data struct being used and modified.
*
@@ -113,8 +113,8 @@ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data,
if(nego->context && nego->status == SEC_E_OK) {
/* We finished successfully our part of authentication, but server
- * rejected it (since we are again here). Exit with an error since we
- * cannot invent anything better */
+ * rejected it (since we're again here). Exit with an error since we
+ * can't invent anything better */
Curl_auth_cleanup_spnego(nego);
return CURLE_LOGIN_DENIED;
}
@@ -128,18 +128,18 @@ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data,
if(!nego->output_token) {
/* Query the security package for Negotiate */
- nego->status = (DWORD)Curl_pSecFn->QuerySecurityPackageInfo((TCHAR *)
- TEXT(SP_NAME_NEGOTIATE),
- &SecurityPackage);
+ nego->status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *)
+ TEXT(SP_NAME_NEGOTIATE),
+ &SecurityPackage);
if(nego->status != SEC_E_OK) {
- failf(data, "SSPI: could not get auth info");
+ failf(data, "SSPI: couldn't get auth info");
return CURLE_AUTH_ERROR;
}
nego->token_max = SecurityPackage->cbMaxToken;
/* Release the package buffer as it is not required anymore */
- Curl_pSecFn->FreeContextBuffer(SecurityPackage);
+ s_pSecFn->FreeContextBuffer(SecurityPackage);
/* Allocate our output buffer */
nego->output_token = malloc(nego->token_max);
@@ -168,8 +168,8 @@ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data,
return CURLE_OUT_OF_MEMORY;
/* Acquire our credentials handle */
- nego->status = (DWORD)
- Curl_pSecFn->AcquireCredentialsHandle(NULL,
+ nego->status =
+ s_pSecFn->AcquireCredentialsHandle(NULL,
(TCHAR *)TEXT(SP_NAME_NEGOTIATE),
SECPKG_CRED_OUTBOUND, NULL,
nego->p_identity, NULL, NULL,
@@ -218,7 +218,7 @@ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data,
SEC_CHANNEL_BINDINGS channelBindings;
SecPkgContext_Bindings pkgBindings;
pkgBindings.Bindings = &channelBindings;
- nego->status = (DWORD)Curl_pSecFn->QueryContextAttributes(
+ nego->status = s_pSecFn->QueryContextAttributes(
nego->sslContext,
SECPKG_ATTR_ENDPOINT_BINDINGS,
&pkgBindings
@@ -242,16 +242,16 @@ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data,
resp_buf.cbBuffer = curlx_uztoul(nego->token_max);
/* Generate our challenge-response message */
- nego->status =
- (DWORD)Curl_pSecFn->InitializeSecurityContext(nego->credentials,
- chlg ? nego->context : NULL,
- nego->spn,
- ISC_REQ_CONFIDENTIALITY,
- 0, SECURITY_NATIVE_DREP,
- chlg ? &chlg_desc : NULL,
- 0, nego->context,
- &resp_desc, &attrs,
- &expiry);
+ nego->status = s_pSecFn->InitializeSecurityContext(nego->credentials,
+ chlg ? nego->context :
+ NULL,
+ nego->spn,
+ ISC_REQ_CONFIDENTIALITY,
+ 0, SECURITY_NATIVE_DREP,
+ chlg ? &chlg_desc : NULL,
+ 0, nego->context,
+ &resp_desc, &attrs,
+ &expiry);
/* Free the decoded challenge as it is not required anymore */
free(chlg);
@@ -259,7 +259,7 @@ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data,
if(GSS_ERROR(nego->status)) {
char buffer[STRERROR_LEN];
failf(data, "InitializeSecurityContext failed: %s",
- Curl_sspi_strerror((int)nego->status, buffer, sizeof(buffer)));
+ Curl_sspi_strerror(nego->status, buffer, sizeof(buffer)));
if(nego->status == (DWORD)SEC_E_INSUFFICIENT_MEMORY)
return CURLE_OUT_OF_MEMORY;
@@ -269,12 +269,11 @@ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data,
if(nego->status == SEC_I_COMPLETE_NEEDED ||
nego->status == SEC_I_COMPLETE_AND_CONTINUE) {
- nego->status = (DWORD)Curl_pSecFn->CompleteAuthToken(nego->context,
- &resp_desc);
+ nego->status = s_pSecFn->CompleteAuthToken(nego->context, &resp_desc);
if(GSS_ERROR(nego->status)) {
char buffer[STRERROR_LEN];
failf(data, "CompleteAuthToken failed: %s",
- Curl_sspi_strerror((int)nego->status, buffer, sizeof(buffer)));
+ Curl_sspi_strerror(nego->status, buffer, sizeof(buffer)));
if(nego->status == (DWORD)SEC_E_INSUFFICIENT_MEMORY)
return CURLE_OUT_OF_MEMORY;
@@ -333,14 +332,14 @@ void Curl_auth_cleanup_spnego(struct negotiatedata *nego)
{
/* Free our security context */
if(nego->context) {
- Curl_pSecFn->DeleteSecurityContext(nego->context);
+ s_pSecFn->DeleteSecurityContext(nego->context);
free(nego->context);
nego->context = NULL;
}
/* Free our credentials handle */
if(nego->credentials) {
- Curl_pSecFn->FreeCredentialsHandle(nego->credentials);
+ s_pSecFn->FreeCredentialsHandle(nego->credentials);
free(nego->credentials);
nego->credentials = NULL;
}
diff --git a/contrib/libs/curl/lib/vauth/vauth.c b/contrib/libs/curl/lib/vauth/vauth.c
index ace43c47d1..62fc7c40fe 100644
--- a/contrib/libs/curl/lib/vauth/vauth.c
+++ b/contrib/libs/curl/lib/vauth/vauth.c
@@ -48,7 +48,7 @@
* Parameters:
*
* service [in] - The service type such as http, smtp, pop or imap.
- * host [in] - The hostname.
+ * host [in] - The host name.
* realm [in] - The realm.
*
* Returns a pointer to the newly allocated SPN.
@@ -93,7 +93,7 @@ TCHAR *Curl_auth_build_spn(const char *service, const char *host,
return NULL;
/* Allocate and return a TCHAR based SPN. Since curlx_convert_UTF8_to_tchar
- must be freed by curlx_unicodefree we will dupe the result so that the
+ must be freed by curlx_unicodefree we'll dupe the result so that the
pointer this function returns can be normally free'd. */
tchar_spn = curlx_convert_UTF8_to_tchar(utf8_spn);
free(utf8_spn);
@@ -115,14 +115,14 @@ TCHAR *Curl_auth_build_spn(const char *service, const char *host,
* Domain/User (curl Down-level format - for compatibility with existing code)
* User@Domain (User Principal Name)
*
- * Note: The username may be empty when using a GSS-API library or Windows
+ * Note: The user name may be empty when using a GSS-API library or Windows
* SSPI as the user and domain are either obtained from the credentials cache
* when using GSS-API or via the currently logged in user's credentials when
* using Windows SSPI.
*
* Parameters:
*
- * user [in] - The username.
+ * user [in] - The user name.
*
* Returns TRUE on success; otherwise FALSE.
*/
diff --git a/contrib/libs/curl/lib/vauth/vauth.h b/contrib/libs/curl/lib/vauth/vauth.h
index 7e823484f6..9da0540892 100644
--- a/contrib/libs/curl/lib/vauth/vauth.h
+++ b/contrib/libs/curl/lib/vauth/vauth.h
@@ -79,10 +79,12 @@ CURLcode Curl_auth_create_plain_message(const char *authzid,
struct bufref *out);
/* This is used to generate a LOGIN cleartext message */
-void Curl_auth_create_login_message(const char *value, struct bufref *out);
+CURLcode Curl_auth_create_login_message(const char *value,
+ struct bufref *out);
/* This is used to generate an EXTERNAL cleartext message */
-void Curl_auth_create_external_message(const char *user, struct bufref *out);
+CURLcode Curl_auth_create_external_message(const char *user,
+ struct bufref *out);
#ifndef CURL_DISABLE_DIGEST_AUTH
/* This is used to generate a CRAM-MD5 response message */
diff --git a/contrib/libs/curl/lib/version.c b/contrib/libs/curl/lib/version.c
index 749f8625b5..0aca34a4cd 100644
--- a/contrib/libs/curl/lib/version.c
+++ b/contrib/libs/curl/lib/version.c
@@ -55,7 +55,6 @@
#ifdef USE_LIBRTMP
#error #include <librtmp/rtmp.h>
-#include "curl_rtmp.h"
#endif
#ifdef HAVE_LIBZ
@@ -153,7 +152,7 @@ char *curl_version(void)
#ifdef USE_NGHTTP2
char h2_version[40];
#endif
-#ifdef USE_HTTP3
+#ifdef ENABLE_QUIC
char h3_version[40];
#endif
#ifdef USE_LIBRTMP
@@ -175,7 +174,8 @@ char *curl_version(void)
/* Override version string when environment variable CURL_VERSION is set */
const char *debugversion = getenv("CURL_VERSION");
if(debugversion) {
- msnprintf(out, sizeof(out), "%s", debugversion);
+ strncpy(out, debugversion, sizeof(out)-1);
+ out[sizeof(out)-1] = '\0';
return out;
}
#endif
@@ -208,23 +208,11 @@ char *curl_version(void)
src[i++] = idn_version;
#elif defined(USE_WIN32_IDN)
src[i++] = (char *)"WinIDN";
-#elif defined(USE_APPLE_IDN)
- src[i++] = (char *)"AppleIDN";
#endif
#ifdef USE_LIBPSL
- {
-#if defined(PSL_VERSION_MAJOR) && (PSL_VERSION_MAJOR > 0 || \
- PSL_VERSION_MINOR >= 11)
- int num = psl_check_version_number(0);
- msnprintf(psl_version, sizeof(psl_version), "libpsl/%d.%d.%d",
- num >> 16, (num >> 8) & 0xff, num & 0xff);
-#else
- msnprintf(psl_version, sizeof(psl_version), "libpsl/%s",
- psl_get_version());
-#endif
- src[i++] = psl_version;
- }
+ msnprintf(psl_version, sizeof(psl_version), "libpsl/%s", psl_get_version());
+ src[i++] = psl_version;
#endif
#ifdef USE_SSH
@@ -235,13 +223,25 @@ char *curl_version(void)
Curl_http2_ver(h2_version, sizeof(h2_version));
src[i++] = h2_version;
#endif
-#ifdef USE_HTTP3
+#ifdef ENABLE_QUIC
Curl_quic_ver(h3_version, sizeof(h3_version));
src[i++] = h3_version;
#endif
#ifdef USE_LIBRTMP
- Curl_rtmp_version(rtmp_version, sizeof(rtmp_version));
- src[i++] = rtmp_version;
+ {
+ char suff[2];
+ if(RTMP_LIB_VERSION & 0xff) {
+ suff[0] = (RTMP_LIB_VERSION & 0xff) + 'a' - 1;
+ suff[1] = '\0';
+ }
+ else
+ suff[0] = '\0';
+
+ msnprintf(rtmp_version, sizeof(rtmp_version), "librtmp/%d.%d%s",
+ RTMP_LIB_VERSION >> 16, (RTMP_LIB_VERSION >> 8) & 0xff,
+ suff);
+ src[i++] = rtmp_version;
+ }
#endif
#ifdef USE_HYPER
msnprintf(hyper_buf, sizeof(hyper_buf), "Hyper/%s", hyper_version());
@@ -258,11 +258,10 @@ char *curl_version(void)
api.ldapai_info_version = LDAP_API_INFO_VERSION;
if(ldap_get_option(NULL, LDAP_OPT_API_INFO, &api) == LDAP_OPT_SUCCESS) {
- unsigned int patch = (unsigned int)(api.ldapai_vendor_version % 100);
- unsigned int major = (unsigned int)(api.ldapai_vendor_version / 10000);
+ unsigned int patch = api.ldapai_vendor_version % 100;
+ unsigned int major = api.ldapai_vendor_version / 10000;
unsigned int minor =
- (((unsigned int)api.ldapai_vendor_version - major * 10000)
- - patch) / 100;
+ ((api.ldapai_vendor_version - major * 10000) - patch) / 100;
msnprintf(ldap_buf, sizeof(ldap_buf), "%s/%u.%u.%u",
api.ldapai_vendor_name, major, minor, patch);
src[i++] = ldap_buf;
@@ -395,7 +394,7 @@ static const char * const supported_protocols[] = {
};
/*
- * Feature presence runtime check functions.
+ * Feature presence run-time check functions.
*
* Warning: the value returned by these should not change between
* curl_global_init() and curl_global_cleanup() calls.
@@ -419,14 +418,6 @@ static int https_proxy_present(curl_version_info_data *info)
}
#endif
-#if defined(USE_SSL) && defined(USE_ECH)
-static int ech_present(curl_version_info_data *info)
-{
- (void) info;
- return Curl_ssl_supports(NULL, SSLSUPP_ECH);
-}
-#endif
-
/*
* Features table.
*
@@ -455,9 +446,6 @@ static const struct feat features_table[] = {
#ifdef DEBUGBUILD
FEATURE("Debug", NULL, CURL_VERSION_DEBUG),
#endif
-#if defined(USE_SSL) && defined(USE_ECH)
- FEATURE("ECH", ech_present, 0),
-#endif
#ifdef USE_GSASL
FEATURE("gsasl", NULL, CURL_VERSION_GSASL),
#endif
@@ -470,17 +458,17 @@ static const struct feat features_table[] = {
#if defined(USE_NGHTTP2)
FEATURE("HTTP2", NULL, CURL_VERSION_HTTP2),
#endif
-#if defined(USE_HTTP3)
+#if defined(ENABLE_QUIC)
FEATURE("HTTP3", NULL, CURL_VERSION_HTTP3),
#endif
#if defined(USE_SSL) && !defined(CURL_DISABLE_PROXY) && \
!defined(CURL_DISABLE_HTTP)
FEATURE("HTTPS-proxy", https_proxy_present, CURL_VERSION_HTTPS_PROXY),
#endif
-#if defined(USE_LIBIDN2) || defined(USE_WIN32_IDN) || defined(USE_APPLE_IDN)
+#if defined(USE_LIBIDN2) || defined(USE_WIN32_IDN)
FEATURE("IDN", idn_present, CURL_VERSION_IDN),
#endif
-#ifdef USE_IPV6
+#ifdef ENABLE_IPV6
FEATURE("IPv6", NULL, CURL_VERSION_IPV6),
#endif
#ifdef USE_KERBEROS5
@@ -499,6 +487,10 @@ static const struct feat features_table[] = {
#ifdef USE_NTLM
FEATURE("NTLM", NULL, CURL_VERSION_NTLM),
#endif
+#if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM) && \
+ defined(NTLM_WB_ENABLED)
+ FEATURE("NTLM_WB", NULL, CURL_VERSION_NTLM_WB),
+#endif
#if defined(USE_LIBPSL)
FEATURE("PSL", NULL, CURL_VERSION_PSL),
#endif
@@ -541,7 +533,7 @@ static curl_version_info_data version_info = {
LIBCURL_VERSION,
LIBCURL_VERSION_NUM,
OS, /* as found by configure or set by hand at build-time */
- 0, /* features bitmask is built at runtime */
+ 0, /* features bitmask is built at run-time */
NULL, /* ssl_version */
0, /* ssl_version_num, this is kept at zero */
NULL, /* zlib_version */
@@ -570,8 +562,7 @@ static curl_version_info_data version_info = {
NULL, /* zstd version */
NULL, /* Hyper version */
NULL, /* gsasl version */
- feature_names,
- NULL /* rtmp version */
+ feature_names
};
curl_version_info_data *curl_version_info(CURLversion stamp)
@@ -581,7 +572,7 @@ curl_version_info_data *curl_version_info(CURLversion stamp)
int features = 0;
#if defined(USE_SSH)
- static char ssh_buf[80]; /* 'ssh_buffer' clashes with libssh/libssh.h */
+ static char ssh_buffer[80];
#endif
#ifdef USE_SSL
#ifdef CURL_WITH_MULTI_SSL
@@ -597,7 +588,7 @@ curl_version_info_data *curl_version_info(CURLversion stamp)
static char zstd_buffer[80];
#endif
- (void)stamp; /* avoid compiler warnings, we do not use this */
+ (void)stamp; /* avoid compiler warnings, we don't use this */
#ifdef USE_SSL
Curl_ssl_version(ssl_buffer, sizeof(ssl_buffer));
@@ -622,8 +613,8 @@ curl_version_info_data *curl_version_info(CURLversion stamp)
#endif
#if defined(USE_SSH)
- Curl_ssh_version(ssh_buf, sizeof(ssh_buf));
- version_info.libssh_version = ssh_buf;
+ Curl_ssh_version(ssh_buffer, sizeof(ssh_buffer));
+ version_info.libssh_version = ssh_buffer;
#endif
#ifdef HAVE_BROTLI
@@ -641,12 +632,12 @@ curl_version_info_data *curl_version_info(CURLversion stamp)
#ifdef USE_NGHTTP2
{
nghttp2_info *h2 = nghttp2_version(0);
- version_info.nghttp2_ver_num = (unsigned int)h2->version_num;
+ version_info.nghttp2_ver_num = h2->version_num;
version_info.nghttp2_version = h2->version_str;
}
#endif
-#ifdef USE_HTTP3
+#ifdef ENABLE_QUIC
{
static char quicbuffer[80];
Curl_quic_ver(quicbuffer, sizeof(quicbuffer));
@@ -679,13 +670,5 @@ curl_version_info_data *curl_version_info(CURLversion stamp)
feature_names[n] = NULL; /* Terminate array. */
version_info.features = features;
-#ifdef USE_LIBRTMP
- {
- static char rtmp_version[30];
- Curl_rtmp_version(rtmp_version, sizeof(rtmp_version));
- version_info.rtmp_version = rtmp_version;
- }
-#endif
-
return &version_info;
}
diff --git a/contrib/libs/curl/lib/version_win32.c b/contrib/libs/curl/lib/version_win32.c
index 25ec827462..e0f239e15d 100644
--- a/contrib/libs/curl/lib/version_win32.c
+++ b/contrib/libs/curl/lib/version_win32.c
@@ -30,10 +30,8 @@
#include "version_win32.h"
#include "warnless.h"
-/* The last 2 #include files should be in this order */
-#ifdef BUILDING_LIBCURL
+/* The last #include files should be: */
#include "curl_memory.h"
-#endif
#include "memdebug.h"
/* This Unicode version struct works for VerifyVersionInfoW (OSVERSIONINFOEXW)
@@ -55,7 +53,7 @@ struct OUR_OSVERSIONINFOEXW {
/*
* curlx_verify_windows_version()
*
- * This is used to verify if we are running on a specific Windows version.
+ * This is used to verify if we are running on a specific windows version.
*
* Parameters:
*
@@ -65,7 +63,7 @@ struct OUR_OSVERSIONINFOEXW {
* ignored.
* platform [in] - The optional platform identifier.
* condition [in] - The test condition used to specifier whether we are
- * checking a version less than, equal to or greater than
+ * checking a version less then, equal to or greater than
* what is specified in the major and minor version
* numbers.
*
@@ -80,13 +78,13 @@ bool curlx_verify_windows_version(const unsigned int majorVersion,
bool matched = FALSE;
#if defined(CURL_WINDOWS_APP)
+ (void)buildVersion;
+
/* We have no way to determine the Windows version from Windows apps,
- so let's assume we are running on the target Windows version. */
+ so let's assume we're running on the target Windows version. */
const WORD fullVersion = MAKEWORD(minorVersion, majorVersion);
const WORD targetVersion = (WORD)_WIN32_WINNT;
- (void)buildVersion;
-
switch(condition) {
case VERSION_LESS_THAN:
matched = targetVersion < fullVersion;
@@ -110,7 +108,7 @@ bool curlx_verify_windows_version(const unsigned int majorVersion,
}
if(matched && (platform == PLATFORM_WINDOWS)) {
- /* we are always running on PLATFORM_WINNT */
+ /* we're always running on PLATFORM_WINNT */
matched = FALSE;
}
#elif !defined(_WIN32_WINNT) || !defined(_WIN32_WINNT_WIN2K) || \
diff --git a/contrib/libs/curl/lib/version_win32.h b/contrib/libs/curl/lib/version_win32.h
index 95a9e7f215..95c066112c 100644
--- a/contrib/libs/curl/lib/version_win32.h
+++ b/contrib/libs/curl/lib/version_win32.h
@@ -44,7 +44,7 @@ typedef enum {
PLATFORM_WINNT
} PlatformIdentifier;
-/* This is used to verify if we are running on a specific Windows version */
+/* This is used to verify if we are running on a specific windows version */
bool curlx_verify_windows_version(const unsigned int majorVersion,
const unsigned int minorVersion,
const unsigned int buildVersion,
diff --git a/contrib/libs/curl/lib/vquic/curl_msh3.c b/contrib/libs/curl/lib/vquic/curl_msh3.c
index ac7865c1ac..8ae3672400 100644
--- a/contrib/libs/curl/lib/vquic/curl_msh3.c
+++ b/contrib/libs/curl/lib/vquic/curl_msh3.c
@@ -27,7 +27,6 @@
#ifdef USE_MSH3
#include "urldata.h"
-#include "hash.h"
#include "timeval.h"
#include "multiif.h"
#include "sendf.h"
@@ -119,40 +118,15 @@ struct cf_msh3_ctx {
struct cf_call_data call_data;
struct curltime connect_started; /* time the current attempt started */
struct curltime handshake_at; /* time connect handshake finished */
- struct Curl_hash streams; /* hash `data->mid` to `stream_ctx` */
/* Flags written by msh3/msquic thread */
bool handshake_complete;
bool handshake_succeeded;
bool connected;
- BIT(initialized);
/* Flags written by curl thread */
BIT(verbose);
BIT(active);
};
-static void h3_stream_hash_free(void *stream);
-
-static void cf_msh3_ctx_init(struct cf_msh3_ctx *ctx,
- const struct Curl_addrinfo *ai)
-{
- DEBUGASSERT(!ctx->initialized);
- Curl_hash_offt_init(&ctx->streams, 63, h3_stream_hash_free);
- Curl_sock_assign_addr(&ctx->addr, ai, TRNSPRT_QUIC);
- ctx->sock[SP_LOCAL] = CURL_SOCKET_BAD;
- ctx->sock[SP_REMOTE] = CURL_SOCKET_BAD;
- ctx->initialized = TRUE;
-}
-
-static void cf_msh3_ctx_free(struct cf_msh3_ctx *ctx)
-{
- if(ctx && ctx->initialized) {
- Curl_hash_destroy(&ctx->streams);
- }
- free(ctx);
-}
-
-static struct cf_msh3_ctx *h3_get_msh3_ctx(struct Curl_easy *data);
-
/* How to access `call_data` from a cf_msh3 filter */
#undef CF_CTX_CALL_DATA
#define CF_CTX_CALL_DATA(cf) \
@@ -179,26 +153,18 @@ struct stream_ctx {
bool recv_header_complete;
};
-#define H3_STREAM_CTX(ctx,data) ((struct stream_ctx *)((data && ctx)? \
- Curl_hash_offt_get(&(ctx)->streams, (data)->mid) : NULL))
+#define H3_STREAM_CTX(d) ((struct stream_ctx *)(((d) && (d)->req.p.http)? \
+ ((struct HTTP *)(d)->req.p.http)->h3_ctx \
+ : NULL))
+#define H3_STREAM_LCTX(d) ((struct HTTP *)(d)->req.p.http)->h3_ctx
+#define H3_STREAM_ID(d) (H3_STREAM_CTX(d)? \
+ H3_STREAM_CTX(d)->id : -2)
-static void h3_stream_ctx_free(struct stream_ctx *stream)
-{
- Curl_bufq_free(&stream->recvbuf);
- free(stream);
-}
-
-static void h3_stream_hash_free(void *stream)
-{
- DEBUGASSERT(stream);
- h3_stream_ctx_free((struct stream_ctx *)stream);
-}
static CURLcode h3_data_setup(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
- struct cf_msh3_ctx *ctx = cf->ctx;
- struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
+ struct stream_ctx *stream = H3_STREAM_CTX(data);
if(stream)
return CURLE_OK;
@@ -207,29 +173,25 @@ static CURLcode h3_data_setup(struct Curl_cfilter *cf,
if(!stream)
return CURLE_OUT_OF_MEMORY;
+ H3_STREAM_LCTX(data) = stream;
stream->req = ZERO_NULL;
msh3_lock_initialize(&stream->recv_lock);
Curl_bufq_init2(&stream->recvbuf, H3_STREAM_CHUNK_SIZE,
H3_STREAM_RECV_CHUNKS, BUFQ_OPT_SOFT_LIMIT);
CURL_TRC_CF(data, cf, "data setup");
-
- if(!Curl_hash_offt_set(&ctx->streams, data->mid, stream)) {
- h3_stream_ctx_free(stream);
- return CURLE_OUT_OF_MEMORY;
- }
-
return CURLE_OK;
}
static void h3_data_done(struct Curl_cfilter *cf, struct Curl_easy *data)
{
- struct cf_msh3_ctx *ctx = cf->ctx;
- struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
+ struct stream_ctx *stream = H3_STREAM_CTX(data);
(void)cf;
if(stream) {
CURL_TRC_CF(data, cf, "easy handle is done");
- Curl_hash_offt_remove(&ctx->streams, data->mid);
+ Curl_bufq_free(&stream->recvbuf);
+ free(stream);
+ H3_STREAM_LCTX(data) = NULL;
}
}
@@ -242,8 +204,8 @@ static void drain_stream_from_other_thread(struct Curl_easy *data,
bits = CURL_CSELECT_IN;
if(stream && !stream->upload_done)
bits |= CURL_CSELECT_OUT;
- if(data->state.select_bits != bits) {
- data->state.select_bits = bits;
+ if(data->state.dselect_bits != bits) {
+ data->state.dselect_bits = bits;
/* cannot expire from other thread */
}
}
@@ -251,16 +213,15 @@ static void drain_stream_from_other_thread(struct Curl_easy *data,
static void drain_stream(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
- struct cf_msh3_ctx *ctx = cf->ctx;
- struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
+ struct stream_ctx *stream = H3_STREAM_CTX(data);
unsigned char bits;
(void)cf;
bits = CURL_CSELECT_IN;
if(stream && !stream->upload_done)
bits |= CURL_CSELECT_OUT;
- if(data->state.select_bits != bits) {
- data->state.select_bits = bits;
+ if(data->state.dselect_bits != bits) {
+ data->state.dselect_bits = bits;
Curl_expire(data, 0, EXPIRE_RUN_NOW);
}
}
@@ -315,7 +276,7 @@ static const MSH3_REQUEST_IF msh3_request_if = {
msh3_data_sent
};
-/* Decode HTTP status code. Returns -1 if no valid status code was
+/* Decode HTTP status code. Returns -1 if no valid status code was
decoded. (duplicate from http2.c) */
static int decode_status_code(const char *value, size_t len)
{
@@ -350,8 +311,7 @@ static int decode_status_code(const char *value, size_t len)
static CURLcode write_resp_raw(struct Curl_easy *data,
const void *mem, size_t memlen)
{
- struct cf_msh3_ctx *ctx = h3_get_msh3_ctx(data);
- struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
+ struct stream_ctx *stream = H3_STREAM_CTX(data);
CURLcode result = CURLE_OK;
ssize_t nwritten;
@@ -377,12 +337,10 @@ static void MSH3_CALL msh3_header_received(MSH3_REQUEST *Request,
const MSH3_HEADER *hd)
{
struct Curl_easy *data = userp;
- struct cf_msh3_ctx *ctx = h3_get_msh3_ctx(data);
- struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
+ struct stream_ctx *stream = H3_STREAM_CTX(data);
CURLcode result;
(void)Request;
- DEBUGF(infof(data, "[MSH3] header received, stream=%d", !!stream));
if(!stream || stream->recv_header_complete) {
return;
}
@@ -428,8 +386,7 @@ static bool MSH3_CALL msh3_data_received(MSH3_REQUEST *Request,
const uint8_t *buf)
{
struct Curl_easy *data = IfContext;
- struct cf_msh3_ctx *ctx = h3_get_msh3_ctx(data);
- struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
+ struct stream_ctx *stream = H3_STREAM_CTX(data);
CURLcode result;
bool rv = FALSE;
@@ -468,8 +425,7 @@ static void MSH3_CALL msh3_complete(MSH3_REQUEST *Request, void *IfContext,
bool aborted, uint64_t error)
{
struct Curl_easy *data = IfContext;
- struct cf_msh3_ctx *ctx = h3_get_msh3_ctx(data);
- struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
+ struct stream_ctx *stream = H3_STREAM_CTX(data);
(void)Request;
if(!stream)
@@ -488,8 +444,7 @@ static void MSH3_CALL msh3_shutdown_complete(MSH3_REQUEST *Request,
void *IfContext)
{
struct Curl_easy *data = IfContext;
- struct cf_msh3_ctx *ctx = h3_get_msh3_ctx(data);
- struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
+ struct stream_ctx *stream = H3_STREAM_CTX(data);
if(!stream)
return;
@@ -501,8 +456,7 @@ static void MSH3_CALL msh3_data_sent(MSH3_REQUEST *Request,
void *IfContext, void *SendContext)
{
struct Curl_easy *data = IfContext;
- struct cf_msh3_ctx *ctx = h3_get_msh3_ctx(data);
- struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
+ struct stream_ctx *stream = H3_STREAM_CTX(data);
if(!stream)
return;
(void)Request;
@@ -514,8 +468,7 @@ static ssize_t recv_closed_stream(struct Curl_cfilter *cf,
struct Curl_easy *data,
CURLcode *err)
{
- struct cf_msh3_ctx *ctx = cf->ctx;
- struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
+ struct stream_ctx *stream = H3_STREAM_CTX(data);
ssize_t nread = -1;
if(!stream) {
@@ -548,8 +501,7 @@ out:
static void set_quic_expire(struct Curl_cfilter *cf, struct Curl_easy *data)
{
- struct cf_msh3_ctx *ctx = cf->ctx;
- struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
+ struct stream_ctx *stream = H3_STREAM_CTX(data);
/* we have no indication from msh3 when it would be a good time
* to juggle the connection again. So, we compromise by calling
@@ -566,17 +518,17 @@ static void set_quic_expire(struct Curl_cfilter *cf, struct Curl_easy *data)
static ssize_t cf_msh3_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
char *buf, size_t len, CURLcode *err)
{
- struct cf_msh3_ctx *ctx = cf->ctx;
- struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
+ struct stream_ctx *stream = H3_STREAM_CTX(data);
ssize_t nread = -1;
struct cf_call_data save;
- CURL_TRC_CF(data, cf, "cf_recv(len=%zu), stream=%d", len, !!stream);
+ (void)cf;
if(!stream) {
*err = CURLE_RECV_ERROR;
return -1;
}
CF_DATA_SAVE(save, cf, data);
+ CURL_TRC_CF(data, cf, "req: recv with %zu byte buffer", len);
msh3_lock_acquire(&stream->recv_lock);
@@ -615,17 +567,17 @@ out:
}
static ssize_t cf_msh3_send(struct Curl_cfilter *cf, struct Curl_easy *data,
- const void *buf, size_t len, bool eos,
- CURLcode *err)
+ const void *buf, size_t len, CURLcode *err)
{
struct cf_msh3_ctx *ctx = cf->ctx;
- struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
+ struct stream_ctx *stream = H3_STREAM_CTX(data);
struct h1_req_parser h1;
struct dynhds h2_headers;
MSH3_HEADER *nva = NULL;
size_t nheader, i;
ssize_t nwritten = -1;
struct cf_call_data save;
+ bool eos;
CF_DATA_SAVE(save, cf, data);
@@ -668,6 +620,21 @@ static ssize_t cf_msh3_send(struct Curl_cfilter *cf, struct Curl_easy *data,
nva[i].ValueLength = e->valuelen;
}
+ switch(data->state.httpreq) {
+ case HTTPREQ_POST:
+ case HTTPREQ_POST_FORM:
+ case HTTPREQ_POST_MIME:
+ case HTTPREQ_PUT:
+ /* known request body size or -1 */
+ eos = FALSE;
+ break;
+ default:
+ /* there is not request body */
+ eos = TRUE;
+ stream->upload_done = TRUE;
+ break;
+ }
+
CURL_TRC_CF(data, cf, "req: send %zu headers", nheader);
stream->req = MsH3RequestOpen(ctx->qconn, &msh3_request_if, data,
nva, nheader,
@@ -696,7 +663,7 @@ static ssize_t cf_msh3_send(struct Curl_cfilter *cf, struct Curl_easy *data,
}
/* TODO - msh3/msquic will hold onto this memory until the send complete
- event. How do we make sure curl does not free it until then? */
+ event. How do we make sure curl doesn't free it until then? */
*err = CURLE_OK;
nwritten = len;
}
@@ -715,7 +682,7 @@ static void cf_msh3_adjust_pollset(struct Curl_cfilter *cf,
struct easy_pollset *ps)
{
struct cf_msh3_ctx *ctx = cf->ctx;
- struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
+ struct stream_ctx *stream = H3_STREAM_CTX(data);
struct cf_call_data save;
CF_DATA_SAVE(save, cf, data);
@@ -734,8 +701,7 @@ static void cf_msh3_adjust_pollset(struct Curl_cfilter *cf,
static bool cf_msh3_data_pending(struct Curl_cfilter *cf,
const struct Curl_easy *data)
{
- struct cf_msh3_ctx *ctx = cf->ctx;
- struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
+ struct stream_ctx *stream = H3_STREAM_CTX(data);
struct cf_call_data save;
bool pending = FALSE;
@@ -756,6 +722,23 @@ static bool cf_msh3_data_pending(struct Curl_cfilter *cf,
return pending;
}
+static void cf_msh3_active(struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+ struct cf_msh3_ctx *ctx = cf->ctx;
+
+ /* use this socket from now on */
+ cf->conn->sock[cf->sockindex] = ctx->sock[SP_LOCAL];
+ /* the first socket info gets set at conn and data */
+ if(cf->sockindex == FIRSTSOCKET) {
+ cf->conn->remote_addr = &ctx->addr;
+ #ifdef ENABLE_IPV6
+ cf->conn->bits.ipv6 = (ctx->addr.family == AF_INET6)? TRUE : FALSE;
+ #endif
+ Curl_persistconninfo(data, cf->conn, ctx->l_ip, ctx->l_port);
+ }
+ ctx->active = TRUE;
+}
+
static CURLcode h3_data_pause(struct Curl_cfilter *cf,
struct Curl_easy *data,
bool pause)
@@ -771,8 +754,7 @@ static CURLcode cf_msh3_data_event(struct Curl_cfilter *cf,
struct Curl_easy *data,
int event, int arg1, void *arg2)
{
- struct cf_msh3_ctx *ctx = cf->ctx;
- struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
+ struct stream_ctx *stream = H3_STREAM_CTX(data);
struct cf_call_data save;
CURLcode result = CURLE_OK;
@@ -803,6 +785,10 @@ static CURLcode cf_msh3_data_event(struct Curl_cfilter *cf,
}
}
break;
+ case CF_CTRL_CONN_INFO_UPDATE:
+ CURL_TRC_CF(data, cf, "req: update info");
+ cf_msh3_active(cf, data);
+ break;
default:
break;
}
@@ -820,7 +806,6 @@ static CURLcode cf_connect_start(struct Curl_cfilter *cf,
CURLcode result;
bool verify;
- DEBUGASSERT(ctx->initialized);
conn_config = Curl_ssl_cf_get_primary_config(cf);
if(!conn_config)
return CURLE_FAILED_INIT;
@@ -847,7 +832,7 @@ static CURLcode cf_connect_start(struct Curl_cfilter *cf,
ctx->api = MsH3ApiOpen();
if(!ctx->api) {
- failf(data, "cannot create msh3 api");
+ failf(data, "can't create msh3 api");
return CURLE_FAILED_INIT;
}
@@ -858,7 +843,7 @@ static CURLcode cf_connect_start(struct Curl_cfilter *cf,
&addr,
!verify);
if(!ctx->qconn) {
- failf(data, "cannot create msh3 connection");
+ failf(data, "can't create msh3 connection");
if(ctx->api) {
MsH3ApiClose(ctx->api);
ctx->api = NULL;
@@ -890,7 +875,7 @@ static CURLcode cf_msh3_connect(struct Curl_cfilter *cf,
CF_DATA_SAVE(save, cf, data);
if(ctx->sock[SP_LOCAL] == CURL_SOCKET_BAD) {
- if(Curl_socketpair(AF_UNIX, SOCK_STREAM, 0, &ctx->sock[0], FALSE) < 0) {
+ if(Curl_socketpair(AF_UNIX, SOCK_STREAM, 0, &ctx->sock[0]) < 0) {
ctx->sock[SP_LOCAL] = CURL_SOCKET_BAD;
ctx->sock[SP_REMOTE] = CURL_SOCKET_BAD;
return CURLE_COULDNT_CONNECT;
@@ -911,6 +896,7 @@ static CURLcode cf_msh3_connect(struct Curl_cfilter *cf,
CURL_TRC_CF(data, cf, "handshake succeeded");
cf->conn->bits.multiplex = TRUE; /* at least potentially multiplexed */
cf->conn->httpversion = 30;
+ cf->conn->bundle->multiuse = BUNDLE_MULTIPLEX;
cf->connected = TRUE;
cf->conn->alpn = CURL_HTTP_VERSION_3;
*done = TRUE;
@@ -984,11 +970,10 @@ static void cf_msh3_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
CF_DATA_SAVE(save, cf, data);
cf_msh3_close(cf, data);
- if(cf->ctx) {
- cf_msh3_ctx_free(cf->ctx);
- cf->ctx = NULL;
- }
+ free(cf->ctx);
+ cf->ctx = NULL;
/* no CF_DATA_RESTORE(cf, save); its gone */
+
}
static CURLcode cf_msh3_query(struct Curl_cfilter *cf,
@@ -1044,7 +1029,6 @@ struct Curl_cftype Curl_cft_http3 = {
cf_msh3_destroy,
cf_msh3_connect,
cf_msh3_close,
- Curl_cf_def_shutdown,
Curl_cf_def_get_host,
cf_msh3_adjust_pollset,
cf_msh3_data_pending,
@@ -1056,20 +1040,6 @@ struct Curl_cftype Curl_cft_http3 = {
cf_msh3_query,
};
-static struct cf_msh3_ctx *h3_get_msh3_ctx(struct Curl_easy *data)
-{
- if(data && data->conn) {
- struct Curl_cfilter *cf = data->conn->cfilter[FIRSTSOCKET];
- while(cf) {
- if(cf->cft == &Curl_cft_http3)
- return cf->ctx;
- cf = cf->next;
- }
- }
- DEBUGF(infof(data, "no filter context found"));
- return NULL;
-}
-
CURLcode Curl_cf_msh3_create(struct Curl_cfilter **pcf,
struct Curl_easy *data,
struct connectdata *conn,
@@ -1087,7 +1057,9 @@ CURLcode Curl_cf_msh3_create(struct Curl_cfilter **pcf,
result = CURLE_OUT_OF_MEMORY;
goto out;
}
- cf_msh3_ctx_init(ctx, ai);
+ Curl_sock_assign_addr(&ctx->addr, ai, TRNSPRT_QUIC);
+ ctx->sock[SP_LOCAL] = CURL_SOCKET_BAD;
+ ctx->sock[SP_REMOTE] = CURL_SOCKET_BAD;
result = Curl_cf_create(&cf, &Curl_cft_http3, ctx);
@@ -1095,7 +1067,7 @@ out:
*pcf = (!result)? cf : NULL;
if(result) {
Curl_safefree(cf);
- cf_msh3_ctx_free(ctx);
+ Curl_safefree(ctx);
}
return result;
diff --git a/contrib/libs/curl/lib/vquic/curl_ngtcp2.c b/contrib/libs/curl/lib/vquic/curl_ngtcp2.c
index faced3116a..416c8fb3ec 100644
--- a/contrib/libs/curl/lib/vquic/curl_ngtcp2.c
+++ b/contrib/libs/curl/lib/vquic/curl_ngtcp2.c
@@ -41,10 +41,10 @@
#include "vtls/gtls.h"
#elif defined(USE_WOLFSSL)
#error #include <ngtcp2/ngtcp2_crypto_wolfssl.h>
+#include "vtls/wolfssl.h"
#endif
#include "urldata.h"
-#include "hash.h"
#include "sendf.h"
#include "strdup.h"
#include "rand.h"
@@ -59,10 +59,8 @@
#include "http1.h"
#include "select.h"
#include "inet_pton.h"
-#include "transfer.h"
#include "vquic.h"
#include "vquic_int.h"
-#error #include "vquic-tls.h"
#include "vtls/keylog.h"
#include "vtls/vtls.h"
#include "curl_ngtcp2.h"
@@ -75,6 +73,9 @@
#include "memdebug.h"
+#define H3_ALPN_H3_29 "\x5h3-29"
+#define H3_ALPN_H3 "\x2h3"
+
#define QUIC_MAX_STREAMS (256*1024)
#define QUIC_MAX_DATA (1*1024*1024)
#define QUIC_HANDSHAKE_TIMEOUT (10*NGTCP2_SECONDS)
@@ -88,7 +89,7 @@
/* The pool keeps spares around and half of a full stream windows
* seems good. More does not seem to improve performance.
* The benefit of the pool is that stream buffer to not keep
- * spares. Memory consumption goes down when streams run empty,
+ * spares. So memory consumption goes down when streams run empty,
* have a large upload done, etc. */
#define H3_STREAM_POOL_SPARES \
(H3_STREAM_WINDOW_SIZE / H3_STREAM_CHUNK_SIZE ) / 2
@@ -100,6 +101,25 @@
(H3_STREAM_WINDOW_SIZE / H3_STREAM_CHUNK_SIZE)
+#ifdef USE_OPENSSL
+#define QUIC_CIPHERS \
+ "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_" \
+ "POLY1305_SHA256:TLS_AES_128_CCM_SHA256"
+#define QUIC_GROUPS "P-256:X25519:P-384:P-521"
+#elif defined(USE_GNUTLS)
+#define QUIC_PRIORITY \
+ "NORMAL:-VERS-ALL:+VERS-TLS1.3:-CIPHER-ALL:+AES-128-GCM:+AES-256-GCM:" \
+ "+CHACHA20-POLY1305:+AES-128-CCM:-GROUP-ALL:+GROUP-SECP256R1:" \
+ "+GROUP-X25519:+GROUP-SECP384R1:+GROUP-SECP521R1:" \
+ "%DISABLE_TLS13_COMPAT_MODE"
+#elif defined(USE_WOLFSSL)
+#define QUIC_CIPHERS \
+ "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_" \
+ "POLY1305_SHA256:TLS_AES_128_CCM_SHA256"
+#define QUIC_GROUPS "P-256:P-384:P-521"
+#endif
+
+
/*
* Store ngtcp2 version info in this buffer.
*/
@@ -114,7 +134,6 @@ void Curl_ngtcp2_ver(char *p, size_t len)
struct cf_ngtcp2_ctx {
struct cf_quic_ctx q;
struct ssl_peer peer;
- struct curl_tls_ctx tls;
ngtcp2_path connected_path;
ngtcp2_conn *qconn;
ngtcp2_cid dcid;
@@ -124,21 +143,30 @@ struct cf_ngtcp2_ctx {
ngtcp2_transport_params transport_params;
ngtcp2_ccerr last_error;
ngtcp2_crypto_conn_ref conn_ref;
+#ifdef USE_OPENSSL
+ SSL_CTX *sslctx;
+ SSL *ssl;
+#elif defined(USE_GNUTLS)
+ struct gtls_instance *gtls;
+#elif defined(USE_WOLFSSL)
+ WOLFSSL_CTX *sslctx;
+ WOLFSSL *ssl;
+#endif
struct cf_call_data call_data;
nghttp3_conn *h3conn;
nghttp3_settings h3settings;
struct curltime started_at; /* time the current attempt started */
struct curltime handshake_at; /* time connect handshake finished */
+ struct curltime first_byte_at; /* when first byte was recvd */
+ struct curltime reconnect_at; /* time the next attempt should start */
struct bufc_pool stream_bufcp; /* chunk pool for streams */
- struct dynbuf scratch; /* temp buffer for header construction */
- struct Curl_hash streams; /* hash `data->mid` to `h3_stream_ctx` */
size_t max_stream_window; /* max flow window for one stream */
uint64_t max_idle_ms; /* max idle time for QUIC connection */
- uint64_t used_bidi_streams; /* bidi streams we have opened */
- uint64_t max_bidi_streams; /* max bidi streams we can open */
int qlogfd;
- BIT(initialized);
- BIT(shutdown_started); /* queued shutdown packets */
+ BIT(got_first_byte); /* if first byte was received */
+#ifdef USE_OPENSSL
+ BIT(x509_store_setup); /* if x509 store has been set up */
+#endif
};
/* How to access `call_data` from a cf_ngtcp2 filter */
@@ -146,54 +174,20 @@ struct cf_ngtcp2_ctx {
#define CF_CTX_CALL_DATA(cf) \
((struct cf_ngtcp2_ctx *)(cf)->ctx)->call_data
-static void h3_stream_hash_free(void *stream);
-
-static void cf_ngtcp2_ctx_init(struct cf_ngtcp2_ctx *ctx)
-{
- DEBUGASSERT(!ctx->initialized);
- ctx->qlogfd = -1;
- ctx->version = NGTCP2_PROTO_VER_MAX;
- ctx->max_stream_window = H3_STREAM_WINDOW_SIZE;
- ctx->max_idle_ms = CURL_QUIC_MAX_IDLE_MS;
- Curl_bufcp_init(&ctx->stream_bufcp, H3_STREAM_CHUNK_SIZE,
- H3_STREAM_POOL_SPARES);
- Curl_dyn_init(&ctx->scratch, CURL_MAX_HTTP_HEADER);
- Curl_hash_offt_init(&ctx->streams, 63, h3_stream_hash_free);
- ctx->initialized = TRUE;
-}
-
-static void cf_ngtcp2_ctx_free(struct cf_ngtcp2_ctx *ctx)
-{
- if(ctx && ctx->initialized) {
- Curl_bufcp_free(&ctx->stream_bufcp);
- Curl_dyn_free(&ctx->scratch);
- Curl_hash_clean(&ctx->streams);
- Curl_hash_destroy(&ctx->streams);
- Curl_ssl_peer_cleanup(&ctx->peer);
- }
- free(ctx);
-}
-
-struct pkt_io_ctx;
-static CURLcode cf_progress_ingress(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- struct pkt_io_ctx *pktx);
-static CURLcode cf_progress_egress(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- struct pkt_io_ctx *pktx);
-
/**
* All about the H3 internals of a stream
*/
struct h3_stream_ctx {
- curl_int64_t id; /* HTTP/3 protocol identifier */
+ int64_t id; /* HTTP/3 protocol identifier */
struct bufq sendbuf; /* h3 request body */
+ struct bufq recvbuf; /* h3 response body */
struct h1_req_parser h1; /* h1 request parsing */
size_t sendbuf_len_in_flight; /* sendbuf amount "in flight" */
- curl_uint64_t error3; /* HTTP/3 stream error code */
+ size_t upload_blocked_len; /* the amount written last and EGAINed */
+ size_t recv_buf_nonflow; /* buffered bytes, not counting for flow control */
+ uint64_t error3; /* HTTP/3 stream error code */
curl_off_t upload_left; /* number of request bytes left to upload */
int status_code; /* HTTP status code */
- CURLcode xfer_result; /* result from xfer_resp_write(_hd) */
bool resp_hds_complete; /* we have a complete, final response */
bool closed; /* TRUE on stream close */
bool reset; /* TRUE on stream reset */
@@ -201,32 +195,23 @@ struct h3_stream_ctx {
BIT(quic_flow_blocked); /* stream is blocked by QUIC flow control */
};
-#define H3_STREAM_CTX(ctx,data) ((struct h3_stream_ctx *)(\
- data? Curl_hash_offt_get(&(ctx)->streams, (data)->mid) : NULL))
-#define H3_STREAM_CTX_ID(ctx,id) ((struct h3_stream_ctx *)(\
- Curl_hash_offt_get(&(ctx)->streams, (id))))
-
-static void h3_stream_ctx_free(struct h3_stream_ctx *stream)
-{
- Curl_bufq_free(&stream->sendbuf);
- Curl_h1_req_parse_free(&stream->h1);
- free(stream);
-}
-
-static void h3_stream_hash_free(void *stream)
-{
- DEBUGASSERT(stream);
- h3_stream_ctx_free((struct h3_stream_ctx *)stream);
-}
+#define H3_STREAM_CTX(d) ((struct h3_stream_ctx *)(((d) && (d)->req.p.http)? \
+ ((struct HTTP *)(d)->req.p.http)->h3_ctx \
+ : NULL))
+#define H3_STREAM_LCTX(d) ((struct HTTP *)(d)->req.p.http)->h3_ctx
+#define H3_STREAM_ID(d) (H3_STREAM_CTX(d)? \
+ H3_STREAM_CTX(d)->id : -2)
static CURLcode h3_data_setup(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
struct cf_ngtcp2_ctx *ctx = cf->ctx;
- struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
- if(!data)
+ if(!data || !data->req.p.http) {
+ failf(data, "initialization failure, transfer not http initialized");
return CURLE_FAILED_INIT;
+ }
if(stream)
return CURLE_OK;
@@ -240,96 +225,75 @@ static CURLcode h3_data_setup(struct Curl_cfilter *cf,
Curl_bufq_initp(&stream->sendbuf, &ctx->stream_bufcp,
H3_STREAM_SEND_CHUNKS, BUFQ_OPT_NONE);
stream->sendbuf_len_in_flight = 0;
+ /* on recv, we need a flexible buffer limit since we also write
+ * headers to it that are not counted against the nghttp3 flow limits. */
+ Curl_bufq_initp(&stream->recvbuf, &ctx->stream_bufcp,
+ H3_STREAM_RECV_CHUNKS, BUFQ_OPT_SOFT_LIMIT);
+ stream->recv_buf_nonflow = 0;
Curl_h1_req_parse_init(&stream->h1, H1_PARSE_DEFAULT_MAX_LINE_LEN);
- if(!Curl_hash_offt_set(&ctx->streams, data->mid, stream)) {
- h3_stream_ctx_free(stream);
- return CURLE_OUT_OF_MEMORY;
- }
-
+ H3_STREAM_LCTX(data) = stream;
return CURLE_OK;
}
-static void cf_ngtcp2_stream_close(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- struct h3_stream_ctx *stream)
-{
- struct cf_ngtcp2_ctx *ctx = cf->ctx;
- DEBUGASSERT(data);
- DEBUGASSERT(stream);
- if(!stream->closed && ctx->qconn && ctx->h3conn) {
- CURLcode result;
-
- nghttp3_conn_set_stream_user_data(ctx->h3conn, stream->id, NULL);
- ngtcp2_conn_set_stream_user_data(ctx->qconn, stream->id, NULL);
- stream->closed = TRUE;
- (void)ngtcp2_conn_shutdown_stream(ctx->qconn, 0, stream->id,
- NGHTTP3_H3_REQUEST_CANCELLED);
- result = cf_progress_egress(cf, data, NULL);
- if(result)
- CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] cancel stream -> %d",
- stream->id, result);
- }
-}
-
static void h3_data_done(struct Curl_cfilter *cf, struct Curl_easy *data)
{
struct cf_ngtcp2_ctx *ctx = cf->ctx;
- struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
+
(void)cf;
if(stream) {
- CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] easy handle is done",
- stream->id);
- cf_ngtcp2_stream_close(cf, data, stream);
- Curl_hash_offt_remove(&ctx->streams, data->mid);
+ CURL_TRC_CF(data, cf, "[%"PRId64"] easy handle is done", stream->id);
+ if(ctx->h3conn && !stream->closed) {
+ nghttp3_conn_shutdown_stream_read(ctx->h3conn, stream->id);
+ nghttp3_conn_close_stream(ctx->h3conn, stream->id,
+ NGHTTP3_H3_REQUEST_CANCELLED);
+ nghttp3_conn_set_stream_user_data(ctx->h3conn, stream->id, NULL);
+ ngtcp2_conn_set_stream_user_data(ctx->qconn, stream->id, NULL);
+ stream->closed = TRUE;
+ }
+
+ Curl_bufq_free(&stream->sendbuf);
+ Curl_bufq_free(&stream->recvbuf);
+ Curl_h1_req_parse_free(&stream->h1);
+ free(stream);
+ H3_STREAM_LCTX(data) = NULL;
}
}
static struct Curl_easy *get_stream_easy(struct Curl_cfilter *cf,
struct Curl_easy *data,
- int64_t stream_id,
- struct h3_stream_ctx **pstream)
+ int64_t stream_id)
{
- struct cf_ngtcp2_ctx *ctx = cf->ctx;
- struct h3_stream_ctx *stream;
+ struct Curl_easy *sdata;
(void)cf;
- stream = H3_STREAM_CTX(ctx, data);
- if(stream && stream->id == stream_id) {
- *pstream = stream;
+ if(H3_STREAM_ID(data) == stream_id) {
return data;
}
else {
- struct Curl_llist_node *e;
DEBUGASSERT(data->multi);
- for(e = Curl_llist_head(&data->multi->process); e; e = Curl_node_next(e)) {
- struct Curl_easy *sdata = Curl_node_elem(e);
- if(sdata->conn != data->conn)
- continue;
- stream = H3_STREAM_CTX(ctx, sdata);
- if(stream && stream->id == stream_id) {
- *pstream = stream;
+ for(sdata = data->multi->easyp; sdata; sdata = sdata->next) {
+ if((sdata->conn == data->conn) && H3_STREAM_ID(sdata) == stream_id) {
return sdata;
}
}
}
- *pstream = NULL;
return NULL;
}
static void h3_drain_stream(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
- struct cf_ngtcp2_ctx *ctx = cf->ctx;
- struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
unsigned char bits;
(void)cf;
bits = CURL_CSELECT_IN;
if(stream && stream->upload_left && !stream->send_closed)
bits |= CURL_CSELECT_OUT;
- if(data->state.select_bits != bits) {
- data->state.select_bits = bits;
+ if(data->state.dselect_bits != bits) {
+ data->state.dselect_bits = bits;
Curl_expire(data, 0, EXPIRE_RUN_NOW);
}
}
@@ -352,8 +316,8 @@ static void pktx_update_time(struct pkt_io_ctx *pktx,
struct cf_ngtcp2_ctx *ctx = cf->ctx;
vquic_ctx_update_time(&ctx->q);
- pktx->ts = (ngtcp2_tstamp)ctx->q.last_op.tv_sec * NGTCP2_SECONDS +
- (ngtcp2_tstamp)ctx->q.last_op.tv_usec * NGTCP2_MICROSECONDS;
+ pktx->ts = ctx->q.last_op.tv_sec * NGTCP2_SECONDS +
+ ctx->q.last_op.tv_usec * NGTCP2_MICROSECONDS;
}
static void pktx_init(struct pkt_io_ctx *pktx,
@@ -367,6 +331,12 @@ static void pktx_init(struct pkt_io_ctx *pktx,
pktx_update_time(pktx, cf);
}
+static CURLcode cf_progress_ingress(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ struct pkt_io_ctx *pktx);
+static CURLcode cf_progress_egress(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ struct pkt_io_ctx *pktx);
static int cb_h3_acked_req_body(nghttp3_conn *conn, int64_t stream_id,
uint64_t datalen, void *user_data,
void *stream_user_data);
@@ -443,69 +413,432 @@ static void quic_settings(struct cf_ngtcp2_ctx *ctx,
}
}
-static CURLcode init_ngh3_conn(struct Curl_cfilter *cf);
-
-static int cb_handshake_completed(ngtcp2_conn *tconn, void *user_data)
+#ifdef USE_OPENSSL
+static void keylog_callback(const SSL *ssl, const char *line)
{
- (void)user_data;
- (void)tconn;
+ (void)ssl;
+ Curl_tls_keylog_write_line(line);
+}
+#elif defined(USE_GNUTLS)
+static int keylog_callback(gnutls_session_t session, const char *label,
+ const gnutls_datum_t *secret)
+{
+ gnutls_datum_t crandom;
+ gnutls_datum_t srandom;
+
+ gnutls_session_get_random(session, &crandom, &srandom);
+ if(crandom.size != 32) {
+ return -1;
+ }
+
+ Curl_tls_keylog_write(label, crandom.data, secret->data, secret->size);
return 0;
}
+#elif defined(USE_WOLFSSL)
+#if defined(HAVE_SECRET_CALLBACK)
+static void keylog_callback(const WOLFSSL *ssl, const char *line)
+{
+ (void)ssl;
+ Curl_tls_keylog_write_line(line);
+}
+#endif
+#endif
+
+static int init_ngh3_conn(struct Curl_cfilter *cf);
+
+#ifdef USE_OPENSSL
+static CURLcode quic_ssl_ctx(SSL_CTX **pssl_ctx,
+ struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+ struct cf_ngtcp2_ctx *ctx = cf->ctx;
+ struct ssl_primary_config *conn_config;
+ CURLcode result = CURLE_FAILED_INIT;
+
+ SSL_CTX *ssl_ctx = SSL_CTX_new(TLS_method());
+ if(!ssl_ctx) {
+ result = CURLE_OUT_OF_MEMORY;
+ goto out;
+ }
+ conn_config = Curl_ssl_cf_get_primary_config(cf);
+ if(!conn_config) {
+ result = CURLE_FAILED_INIT;
+ goto out;
+ }
+
+#if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC)
+ if(ngtcp2_crypto_boringssl_configure_client_context(ssl_ctx) != 0) {
+ failf(data, "ngtcp2_crypto_boringssl_configure_client_context failed");
+ goto out;
+ }
+#else
+ if(ngtcp2_crypto_quictls_configure_client_context(ssl_ctx) != 0) {
+ failf(data, "ngtcp2_crypto_quictls_configure_client_context failed");
+ goto out;
+ }
+#endif
+
+ SSL_CTX_set_default_verify_paths(ssl_ctx);
+
+ {
+ const char *curves = conn_config->curves ?
+ conn_config->curves : QUIC_GROUPS;
+ if(!SSL_CTX_set1_curves_list(ssl_ctx, curves)) {
+ failf(data, "failed setting curves list for QUIC: '%s'", curves);
+ return CURLE_SSL_CIPHER;
+ }
+ }
+
+#ifndef OPENSSL_IS_BORINGSSL
+ {
+ const char *ciphers13 = conn_config->cipher_list13 ?
+ conn_config->cipher_list13 : QUIC_CIPHERS;
+ if(SSL_CTX_set_ciphersuites(ssl_ctx, ciphers13) != 1) {
+ failf(data, "failed setting QUIC cipher suite: %s", ciphers13);
+ return CURLE_SSL_CIPHER;
+ }
+ infof(data, "QUIC cipher selection: %s", ciphers13);
+ }
+#endif
+
+ /* Open the file if a TLS or QUIC backend has not done this before. */
+ Curl_tls_keylog_open();
+ if(Curl_tls_keylog_enabled()) {
+ SSL_CTX_set_keylog_callback(ssl_ctx, keylog_callback);
+ }
+
+ /* OpenSSL always tries to verify the peer, this only says whether it should
+ * fail to connect if the verification fails, or if it should continue
+ * anyway. In the latter case the result of the verification is checked with
+ * SSL_get_verify_result() below. */
+ SSL_CTX_set_verify(ssl_ctx, conn_config->verifypeer ?
+ SSL_VERIFY_PEER : SSL_VERIFY_NONE, NULL);
+
+ /* give application a chance to interfere with SSL set up. */
+ if(data->set.ssl.fsslctx) {
+ /* When a user callback is installed to modify the SSL_CTX,
+ * we need to do the full initialization before calling it.
+ * See: #11800 */
+ if(!ctx->x509_store_setup) {
+ result = Curl_ssl_setup_x509_store(cf, data, ssl_ctx);
+ if(result)
+ goto out;
+ ctx->x509_store_setup = TRUE;
+ }
+ Curl_set_in_callback(data, true);
+ result = (*data->set.ssl.fsslctx)(data, ssl_ctx,
+ data->set.ssl.fsslctxp);
+ Curl_set_in_callback(data, false);
+ if(result) {
+ failf(data, "error signaled by ssl ctx callback");
+ goto out;
+ }
+ }
+ result = CURLE_OK;
-static void cf_ngtcp2_conn_close(struct Curl_cfilter *cf,
- struct Curl_easy *data);
+out:
+ *pssl_ctx = result? NULL : ssl_ctx;
+ if(result && ssl_ctx)
+ SSL_CTX_free(ssl_ctx);
+ return result;
+}
-static bool cf_ngtcp2_err_is_fatal(int code)
+static CURLcode quic_set_client_cert(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
- return (NGTCP2_ERR_FATAL >= code) ||
- (NGTCP2_ERR_DROP_CONN == code) ||
- (NGTCP2_ERR_IDLE_CLOSE == code);
+ struct cf_ngtcp2_ctx *ctx = cf->ctx;
+ SSL_CTX *ssl_ctx = ctx->sslctx;
+ const struct ssl_config_data *ssl_config;
+
+ ssl_config = Curl_ssl_cf_get_config(cf, data);
+ DEBUGASSERT(ssl_config);
+
+ if(ssl_config->primary.clientcert || ssl_config->primary.cert_blob
+ || ssl_config->cert_type) {
+ return Curl_ossl_set_client_cert(
+ data, ssl_ctx, ssl_config->primary.clientcert,
+ ssl_config->primary.cert_blob, ssl_config->cert_type,
+ ssl_config->key, ssl_config->key_blob,
+ ssl_config->key_type, ssl_config->key_passwd);
+ }
+
+ return CURLE_OK;
}
-static void cf_ngtcp2_err_set(struct Curl_cfilter *cf,
- struct Curl_easy *data, int code)
+/** SSL callbacks ***/
+
+static CURLcode quic_init_ssl(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
struct cf_ngtcp2_ctx *ctx = cf->ctx;
- if(!ctx->last_error.error_code) {
- if(NGTCP2_ERR_CRYPTO == code) {
- ngtcp2_ccerr_set_tls_alert(&ctx->last_error,
- ngtcp2_conn_get_tls_alert(ctx->qconn),
- NULL, 0);
+ const uint8_t *alpn = NULL;
+ size_t alpnlen = 0;
+
+ DEBUGASSERT(!ctx->ssl);
+ ctx->ssl = SSL_new(ctx->sslctx);
+
+ SSL_set_app_data(ctx->ssl, &ctx->conn_ref);
+ SSL_set_connect_state(ctx->ssl);
+ SSL_set_quic_use_legacy_codepoint(ctx->ssl, 0);
+
+ alpn = (const uint8_t *)H3_ALPN_H3_29 H3_ALPN_H3;
+ alpnlen = sizeof(H3_ALPN_H3_29) - 1 + sizeof(H3_ALPN_H3) - 1;
+ if(alpn)
+ SSL_set_alpn_protos(ctx->ssl, alpn, (int)alpnlen);
+
+ /* set SNI */
+ if(ctx->peer.sni) {
+ if(!SSL_set_tlsext_host_name(ctx->ssl, ctx->peer.sni)) {
+ failf(data, "Failed set SNI");
+ SSL_free(ctx->ssl);
+ ctx->ssl = NULL;
+ return CURLE_QUIC_CONNECT_ERROR;
}
+ }
+ return CURLE_OK;
+}
+#elif defined(USE_GNUTLS)
+static CURLcode quic_init_ssl(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
+{
+ struct cf_ngtcp2_ctx *ctx = cf->ctx;
+ struct ssl_primary_config *conn_config;
+ CURLcode result;
+ gnutls_datum_t alpn[2];
+ /* this will need some attention when HTTPS proxy over QUIC get fixed */
+ long * const pverifyresult = &data->set.ssl.certverifyresult;
+ int rc;
+
+ conn_config = Curl_ssl_cf_get_primary_config(cf);
+ if(!conn_config)
+ return CURLE_FAILED_INIT;
+
+ DEBUGASSERT(ctx->gtls == NULL);
+ ctx->gtls = calloc(1, sizeof(*(ctx->gtls)));
+ if(!ctx->gtls)
+ return CURLE_OUT_OF_MEMORY;
+
+ result = gtls_client_init(data, conn_config, &data->set.ssl,
+ &ctx->peer, ctx->gtls, pverifyresult);
+ if(result)
+ return result;
+
+ gnutls_session_set_ptr(ctx->gtls->session, &ctx->conn_ref);
+
+ if(ngtcp2_crypto_gnutls_configure_client_session(ctx->gtls->session) != 0) {
+ CURL_TRC_CF(data, cf,
+ "ngtcp2_crypto_gnutls_configure_client_session failed\n");
+ return CURLE_QUIC_CONNECT_ERROR;
+ }
+
+ rc = gnutls_priority_set_direct(ctx->gtls->session, QUIC_PRIORITY, NULL);
+ if(rc < 0) {
+ CURL_TRC_CF(data, cf, "gnutls_priority_set_direct failed: %s\n",
+ gnutls_strerror(rc));
+ return CURLE_QUIC_CONNECT_ERROR;
+ }
+
+ /* Open the file if a TLS or QUIC backend has not done this before. */
+ Curl_tls_keylog_open();
+ if(Curl_tls_keylog_enabled()) {
+ gnutls_session_set_keylog_function(ctx->gtls->session, keylog_callback);
+ }
+
+ /* strip the first byte (the length) from NGHTTP3_ALPN_H3 */
+ alpn[0].data = (unsigned char *)H3_ALPN_H3_29 + 1;
+ alpn[0].size = sizeof(H3_ALPN_H3_29) - 2;
+ alpn[1].data = (unsigned char *)H3_ALPN_H3 + 1;
+ alpn[1].size = sizeof(H3_ALPN_H3) - 2;
+
+ gnutls_alpn_set_protocols(ctx->gtls->session,
+ alpn, 2, GNUTLS_ALPN_MANDATORY);
+ return CURLE_OK;
+}
+#elif defined(USE_WOLFSSL)
+
+static CURLcode quic_ssl_ctx(WOLFSSL_CTX **pssl_ctx,
+ struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+ CURLcode result = CURLE_FAILED_INIT;
+ struct ssl_primary_config *conn_config;
+ WOLFSSL_CTX *ssl_ctx = NULL;
+
+ conn_config = Curl_ssl_cf_get_primary_config(cf);
+ if(!conn_config) {
+ result = CURLE_FAILED_INIT;
+ goto out;
+ }
+
+ ssl_ctx = wolfSSL_CTX_new(wolfTLSv1_3_client_method());
+ if(!ssl_ctx) {
+ result = CURLE_OUT_OF_MEMORY;
+ goto out;
+ }
+
+ if(ngtcp2_crypto_wolfssl_configure_client_context(ssl_ctx) != 0) {
+ failf(data, "ngtcp2_crypto_wolfssl_configure_client_context failed");
+ result = CURLE_FAILED_INIT;
+ goto out;
+ }
+
+ wolfSSL_CTX_set_default_verify_paths(ssl_ctx);
+
+ if(wolfSSL_CTX_set_cipher_list(ssl_ctx, conn_config->cipher_list13 ?
+ conn_config->cipher_list13 :
+ QUIC_CIPHERS) != 1) {
+ char error_buffer[256];
+ ERR_error_string_n(ERR_get_error(), error_buffer, sizeof(error_buffer));
+ failf(data, "wolfSSL failed to set ciphers: %s", error_buffer);
+ goto out;
+ }
+
+ if(wolfSSL_CTX_set1_groups_list(ssl_ctx, conn_config->curves ?
+ conn_config->curves :
+ (char *)QUIC_GROUPS) != 1) {
+ failf(data, "wolfSSL failed to set curves");
+ goto out;
+ }
+
+ /* Open the file if a TLS or QUIC backend has not done this before. */
+ Curl_tls_keylog_open();
+ if(Curl_tls_keylog_enabled()) {
+#if defined(HAVE_SECRET_CALLBACK)
+ wolfSSL_CTX_set_keylog_callback(ssl_ctx, keylog_callback);
+#else
+ failf(data, "wolfSSL was built without keylog callback");
+ goto out;
+#endif
+ }
+
+ if(conn_config->verifypeer) {
+ const char * const ssl_cafile = conn_config->CAfile;
+ const char * const ssl_capath = conn_config->CApath;
+
+ wolfSSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, NULL);
+ if(ssl_cafile || ssl_capath) {
+ /* tell wolfSSL where to find CA certificates that are used to verify
+ the server's certificate. */
+ int rc =
+ wolfSSL_CTX_load_verify_locations_ex(ssl_ctx, ssl_cafile, ssl_capath,
+ WOLFSSL_LOAD_FLAG_IGNORE_ERR);
+ if(SSL_SUCCESS != rc) {
+ /* Fail if we insist on successfully verifying the server. */
+ failf(data, "error setting certificate verify locations:"
+ " CAfile: %s CApath: %s",
+ ssl_cafile ? ssl_cafile : "none",
+ ssl_capath ? ssl_capath : "none");
+ goto out;
+ }
+ infof(data, " CAfile: %s", ssl_cafile ? ssl_cafile : "none");
+ infof(data, " CApath: %s", ssl_capath ? ssl_capath : "none");
+ }
+#ifdef CURL_CA_FALLBACK
else {
- ngtcp2_ccerr_set_liberr(&ctx->last_error, code, NULL, 0);
+ /* verifying the peer without any CA certificates won't work so
+ use wolfssl's built-in default as fallback */
+ wolfSSL_CTX_set_default_verify_paths(ssl_ctx);
+ }
+#endif
+ }
+ else {
+ wolfSSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_NONE, NULL);
+ }
+
+ /* give application a chance to interfere with SSL set up. */
+ if(data->set.ssl.fsslctx) {
+ Curl_set_in_callback(data, true);
+ result = (*data->set.ssl.fsslctx)(data, ssl_ctx,
+ data->set.ssl.fsslctxp);
+ Curl_set_in_callback(data, false);
+ if(result) {
+ failf(data, "error signaled by ssl ctx callback");
+ goto out;
}
}
- if(cf_ngtcp2_err_is_fatal(code))
- cf_ngtcp2_conn_close(cf, data);
+ result = CURLE_OK;
+
+out:
+ *pssl_ctx = result? NULL : ssl_ctx;
+ if(result && ssl_ctx)
+ SSL_CTX_free(ssl_ctx);
+ return result;
+}
+
+/** SSL callbacks ***/
+
+static CURLcode quic_init_ssl(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
+{
+ struct cf_ngtcp2_ctx *ctx = cf->ctx;
+ const uint8_t *alpn = NULL;
+ size_t alpnlen = 0;
+ /* this will need some attention when HTTPS proxy over QUIC get fixed */
+ const char * const hostname = cf->conn->host.name;
+
+ (void)data;
+ DEBUGASSERT(!ctx->ssl);
+ ctx->ssl = wolfSSL_new(ctx->sslctx);
+
+ wolfSSL_set_app_data(ctx->ssl, &ctx->conn_ref);
+ wolfSSL_set_connect_state(ctx->ssl);
+ wolfSSL_set_quic_use_legacy_codepoint(ctx->ssl, 0);
+
+ alpn = (const uint8_t *)H3_ALPN_H3_29 H3_ALPN_H3;
+ alpnlen = sizeof(H3_ALPN_H3_29) - 1 + sizeof(H3_ALPN_H3) - 1;
+ if(alpn)
+ wolfSSL_set_alpn_protos(ctx->ssl, alpn, (int)alpnlen);
+
+ /* set SNI */
+ wolfSSL_UseSNI(ctx->ssl, WOLFSSL_SNI_HOST_NAME,
+ hostname, (unsigned short)strlen(hostname));
+
+ return CURLE_OK;
}
+#endif /* defined(USE_WOLFSSL) */
-static bool cf_ngtcp2_h3_err_is_fatal(int code)
+static int cb_handshake_completed(ngtcp2_conn *tconn, void *user_data)
{
- return (NGHTTP3_ERR_FATAL >= code) ||
- (NGHTTP3_ERR_H3_CLOSED_CRITICAL_STREAM == code);
+ (void)user_data;
+ (void)tconn;
+ return 0;
}
-static void cf_ngtcp2_h3_err_set(struct Curl_cfilter *cf,
- struct Curl_easy *data, int code)
+static void report_consumed_data(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ size_t consumed)
{
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
struct cf_ngtcp2_ctx *ctx = cf->ctx;
- if(!ctx->last_error.error_code) {
- ngtcp2_ccerr_set_application_error(&ctx->last_error,
- nghttp3_err_infer_quic_app_error_code(code), NULL, 0);
+
+ if(!stream)
+ return;
+ /* the HTTP/1.1 response headers are written to the buffer, but
+ * consuming those does not count against flow control. */
+ if(stream->recv_buf_nonflow) {
+ if(consumed >= stream->recv_buf_nonflow) {
+ consumed -= stream->recv_buf_nonflow;
+ stream->recv_buf_nonflow = 0;
+ }
+ else {
+ stream->recv_buf_nonflow -= consumed;
+ consumed = 0;
+ }
+ }
+ if(consumed > 0) {
+ CURL_TRC_CF(data, cf, "[%" PRId64 "] ACK %zu bytes of DATA",
+ stream->id, consumed);
+ ngtcp2_conn_extend_max_stream_offset(ctx->qconn, stream->id,
+ consumed);
+ ngtcp2_conn_extend_max_offset(ctx->qconn, consumed);
}
- if(cf_ngtcp2_h3_err_is_fatal(code))
- cf_ngtcp2_conn_close(cf, data);
}
static int cb_recv_stream_data(ngtcp2_conn *tconn, uint32_t flags,
- int64_t sid, uint64_t offset,
+ int64_t stream_id, uint64_t offset,
const uint8_t *buf, size_t buflen,
void *user_data, void *stream_user_data)
{
struct Curl_cfilter *cf = user_data;
struct cf_ngtcp2_ctx *ctx = cf->ctx;
- curl_int64_t stream_id = (curl_int64_t)sid;
nghttp3_ssize nconsumed;
int fin = (flags & NGTCP2_STREAM_DATA_FLAG_FIN) ? 1 : 0;
struct Curl_easy *data = stream_user_data;
@@ -514,26 +847,26 @@ static int cb_recv_stream_data(ngtcp2_conn *tconn, uint32_t flags,
nconsumed =
nghttp3_conn_read_stream(ctx->h3conn, stream_id, buf, buflen, fin);
- if(!data)
- data = CF_DATA_CURRENT(cf);
- if(data)
- CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] read_stream(len=%zu) -> %zd",
- stream_id, buflen, nconsumed);
+ CURL_TRC_CF(data, cf, "[%" PRId64 "] read_stream(len=%zu) -> %zd",
+ stream_id, buflen, nconsumed);
if(nconsumed < 0) {
- struct h3_stream_ctx *stream = H3_STREAM_CTX_ID(ctx, stream_id);
- if(data && stream) {
- CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] error on known stream, "
- "reset=%d, closed=%d",
- stream_id, stream->reset, stream->closed);
+ if(!data) {
+ struct Curl_easy *cdata = CF_DATA_CURRENT(cf);
+ CURL_TRC_CF(cdata, cf, "[%" PRId64 "] nghttp3 error on stream not "
+ "used by us, ignored", stream_id);
+ return 0;
}
+ ngtcp2_ccerr_set_application_error(
+ &ctx->last_error,
+ nghttp3_err_infer_quic_app_error_code((int)nconsumed), NULL, 0);
return NGTCP2_ERR_CALLBACK_FAILURE;
}
/* number of bytes inside buflen which consists of framing overhead
* including QPACK HEADERS. In other words, it does not consume payload of
* DATA frame. */
- ngtcp2_conn_extend_max_stream_offset(tconn, stream_id, (uint64_t)nconsumed);
- ngtcp2_conn_extend_max_offset(tconn, (uint64_t)nconsumed);
+ ngtcp2_conn_extend_max_stream_offset(tconn, stream_id, nconsumed);
+ ngtcp2_conn_extend_max_offset(tconn, nconsumed);
return 0;
}
@@ -561,45 +894,41 @@ cb_acked_stream_data_offset(ngtcp2_conn *tconn, int64_t stream_id,
}
static int cb_stream_close(ngtcp2_conn *tconn, uint32_t flags,
- int64_t sid, uint64_t app_error_code,
+ int64_t stream3_id, uint64_t app_error_code,
void *user_data, void *stream_user_data)
{
struct Curl_cfilter *cf = user_data;
- struct cf_ngtcp2_ctx *ctx = cf->ctx;
struct Curl_easy *data = stream_user_data;
- curl_int64_t stream_id = (curl_int64_t)sid;
+ struct cf_ngtcp2_ctx *ctx = cf->ctx;
int rv;
(void)tconn;
+ (void)data;
/* stream is closed... */
- if(!data)
- data = CF_DATA_CURRENT(cf);
- if(!data)
- return NGTCP2_ERR_CALLBACK_FAILURE;
if(!(flags & NGTCP2_STREAM_CLOSE_FLAG_APP_ERROR_CODE_SET)) {
app_error_code = NGHTTP3_H3_NO_ERROR;
}
- rv = nghttp3_conn_close_stream(ctx->h3conn, stream_id, app_error_code);
- CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] quic close(app_error=%"
- FMT_PRIu64 ") -> %d", stream_id, (curl_uint64_t)app_error_code,
- rv);
+ rv = nghttp3_conn_close_stream(ctx->h3conn, stream3_id,
+ app_error_code);
+ CURL_TRC_CF(data, cf, "[%" PRId64 "] quic close(err=%"
+ PRIu64 ") -> %d", stream3_id, app_error_code, rv);
if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) {
- cf_ngtcp2_h3_err_set(cf, data, rv);
+ ngtcp2_ccerr_set_application_error(
+ &ctx->last_error, nghttp3_err_infer_quic_app_error_code(rv), NULL, 0);
return NGTCP2_ERR_CALLBACK_FAILURE;
}
return 0;
}
-static int cb_stream_reset(ngtcp2_conn *tconn, int64_t sid,
+static int cb_stream_reset(ngtcp2_conn *tconn, int64_t stream_id,
uint64_t final_size, uint64_t app_error_code,
void *user_data, void *stream_user_data)
{
struct Curl_cfilter *cf = user_data;
struct cf_ngtcp2_ctx *ctx = cf->ctx;
- curl_int64_t stream_id = (curl_int64_t)sid;
struct Curl_easy *data = stream_user_data;
int rv;
(void)tconn;
@@ -608,7 +937,7 @@ static int cb_stream_reset(ngtcp2_conn *tconn, int64_t sid,
(void)data;
rv = nghttp3_conn_shutdown_stream_read(ctx->h3conn, stream_id);
- CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] reset -> %d", stream_id, rv);
+ CURL_TRC_CF(data, cf, "[%" PRId64 "] reset -> %d", stream_id, rv);
if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) {
return NGTCP2_ERR_CALLBACK_FAILURE;
}
@@ -639,26 +968,19 @@ static int cb_extend_max_local_streams_bidi(ngtcp2_conn *tconn,
uint64_t max_streams,
void *user_data)
{
- struct Curl_cfilter *cf = user_data;
- struct cf_ngtcp2_ctx *ctx = cf->ctx;
- struct Curl_easy *data = CF_DATA_CURRENT(cf);
-
(void)tconn;
- ctx->max_bidi_streams = max_streams;
- if(data)
- CURL_TRC_CF(data, cf, "max bidi streams now %" FMT_PRIu64
- ", used %" FMT_PRIu64, (curl_uint64_t)ctx->max_bidi_streams,
- (curl_uint64_t)ctx->used_bidi_streams);
+ (void)max_streams;
+ (void)user_data;
+
return 0;
}
-static int cb_extend_max_stream_data(ngtcp2_conn *tconn, int64_t sid,
+static int cb_extend_max_stream_data(ngtcp2_conn *tconn, int64_t stream_id,
uint64_t max_data, void *user_data,
void *stream_user_data)
{
struct Curl_cfilter *cf = user_data;
struct cf_ngtcp2_ctx *ctx = cf->ctx;
- curl_int64_t stream_id = (curl_int64_t)sid;
struct Curl_easy *data = CF_DATA_CURRENT(cf);
struct Curl_easy *s_data;
struct h3_stream_ctx *stream;
@@ -671,11 +993,12 @@ static int cb_extend_max_stream_data(ngtcp2_conn *tconn, int64_t sid,
if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) {
return NGTCP2_ERR_CALLBACK_FAILURE;
}
- s_data = get_stream_easy(cf, data, stream_id, &stream);
- if(s_data && stream && stream->quic_flow_blocked) {
- CURL_TRC_CF(s_data, cf, "[%" FMT_PRId64 "] unblock quic flow", stream_id);
+ s_data = get_stream_easy(cf, data, stream_id);
+ stream = H3_STREAM_CTX(s_data);
+ if(stream && stream->quic_flow_blocked) {
+ CURL_TRC_CF(data, cf, "[%" PRId64 "] unblock quic flow", stream_id);
stream->quic_flow_blocked = FALSE;
- h3_drain_stream(cf, s_data);
+ h3_drain_stream(cf, data);
}
return 0;
}
@@ -688,7 +1011,7 @@ static void cb_rand(uint8_t *dest, size_t destlen,
result = Curl_rand(NULL, dest, destlen);
if(result) {
- /* cb_rand is only used for non-cryptographic context. If Curl_rand
+ /* cb_rand is only used for non-cryptographic context. If Curl_rand
failed, just fill 0 and call it *random*. */
memset(dest, 0, destlen);
}
@@ -731,11 +1054,6 @@ static int cb_recv_rx_key(ngtcp2_conn *tconn, ngtcp2_encryption_level level,
return 0;
}
-#if defined(_MSC_VER) && defined(_DLL)
-# pragma warning(push)
-# pragma warning(disable:4232) /* MSVC extension, dllimport identity */
-#endif
-
static ngtcp2_callbacks ng_callbacks = {
ngtcp2_crypto_client_initial_cb,
NULL, /* recv_client_initial */
@@ -779,10 +1097,6 @@ static ngtcp2_callbacks ng_callbacks = {
NULL, /* early_data_rejected */
};
-#if defined(_MSC_VER) && defined(_DLL)
-# pragma warning(pop)
-#endif
-
/**
* Connection maintenance like timeouts on packet ACKs etc. are done by us, not
* the OS like for TCP. POLL events on the socket therefore are not
@@ -814,7 +1128,7 @@ static CURLcode check_and_set_expiry(struct Curl_cfilter *cf,
if(rv) {
failf(data, "ngtcp2_conn_handle_expiry returned error: %s",
ngtcp2_strerror(rv));
- cf_ngtcp2_err_set(cf, data, rv);
+ ngtcp2_ccerr_set_liberr(&ctx->last_error, rv, NULL, 0);
return CURLE_SEND_ERROR;
}
result = cf_progress_ingress(cf, data, pktx);
@@ -832,8 +1146,7 @@ static CURLcode check_and_set_expiry(struct Curl_cfilter *cf,
if(timeout % NGTCP2_MILLISECONDS) {
timeout += NGTCP2_MILLISECONDS;
}
- Curl_expire(data, (timediff_t)(timeout / NGTCP2_MILLISECONDS),
- EXPIRE_QUIC);
+ Curl_expire(data, timeout / NGTCP2_MILLISECONDS, EXPIRE_QUIC);
}
}
return CURLE_OK;
@@ -844,17 +1157,11 @@ static void cf_ngtcp2_adjust_pollset(struct Curl_cfilter *cf,
struct easy_pollset *ps)
{
struct cf_ngtcp2_ctx *ctx = cf->ctx;
- bool want_recv, want_send;
-
- if(!ctx->qconn)
- return;
+ bool want_recv = CURL_WANT_RECV(data);
+ bool want_send = CURL_WANT_SEND(data);
- Curl_pollset_check(data, ps, ctx->q.sockfd, &want_recv, &want_send);
- if(!want_send && !Curl_bufq_is_empty(&ctx->q.sendbuf))
- want_send = TRUE;
-
- if(want_recv || want_send) {
- struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
+ if(ctx->qconn && (want_recv || want_send)) {
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
struct cf_call_data save;
bool c_exhaust, s_exhaust;
@@ -872,15 +1179,13 @@ static void cf_ngtcp2_adjust_pollset(struct Curl_cfilter *cf,
}
}
-static int cb_h3_stream_close(nghttp3_conn *conn, int64_t sid,
+static int cb_h3_stream_close(nghttp3_conn *conn, int64_t stream_id,
uint64_t app_error_code, void *user_data,
void *stream_user_data)
{
struct Curl_cfilter *cf = user_data;
- struct cf_ngtcp2_ctx *ctx = cf->ctx;
struct Curl_easy *data = stream_user_data;
- curl_int64_t stream_id = (curl_int64_t)sid;
- struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
(void)conn;
(void)stream_id;
@@ -889,60 +1194,63 @@ static int cb_h3_stream_close(nghttp3_conn *conn, int64_t sid,
return 0;
stream->closed = TRUE;
- stream->error3 = (curl_uint64_t)app_error_code;
+ stream->error3 = app_error_code;
if(stream->error3 != NGHTTP3_H3_NO_ERROR) {
stream->reset = TRUE;
stream->send_closed = TRUE;
- CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] RESET: error %" FMT_PRIu64,
+ CURL_TRC_CF(data, cf, "[%" PRId64 "] RESET: error %" PRId64,
stream->id, stream->error3);
}
else {
- CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] CLOSED", stream->id);
+ CURL_TRC_CF(data, cf, "[%" PRId64 "] CLOSED", stream->id);
}
h3_drain_stream(cf, data);
return 0;
}
-static void h3_xfer_write_resp_hd(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- struct h3_stream_ctx *stream,
- const char *buf, size_t blen, bool eos)
+/*
+ * write_resp_raw() copies response data in raw format to the `data`'s
+ * receive buffer. If not enough space is available, it appends to the
+ * `data`'s overflow buffer.
+ */
+static CURLcode write_resp_raw(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ const void *mem, size_t memlen,
+ bool flow)
{
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
+ CURLcode result = CURLE_OK;
+ ssize_t nwritten;
- /* If we already encountered an error, skip further writes */
- if(!stream->xfer_result) {
- stream->xfer_result = Curl_xfer_write_resp_hd(data, buf, blen, eos);
- if(stream->xfer_result)
- CURL_TRC_CF(data, cf, "[%"FMT_PRId64"] error %d writing %zu "
- "bytes of headers", stream->id, stream->xfer_result, blen);
+ (void)cf;
+ if(!stream) {
+ return CURLE_RECV_ERROR;
+ }
+ nwritten = Curl_bufq_write(&stream->recvbuf, mem, memlen, &result);
+ if(nwritten < 0) {
+ return result;
}
-}
-static void h3_xfer_write_resp(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- struct h3_stream_ctx *stream,
- const char *buf, size_t blen, bool eos)
-{
+ if(!flow)
+ stream->recv_buf_nonflow += (size_t)nwritten;
- /* If we already encountered an error, skip further writes */
- if(!stream->xfer_result) {
- stream->xfer_result = Curl_xfer_write_resp(data, buf, blen, eos);
- /* If the transfer write is errored, we do not want any more data */
- if(stream->xfer_result) {
- CURL_TRC_CF(data, cf, "[%"FMT_PRId64"] error %d writing %zu bytes "
- "of data", stream->id, stream->xfer_result, blen);
- }
+ if((size_t)nwritten < memlen) {
+ /* This MUST not happen. Our recbuf is dimensioned to hold the
+ * full max_stream_window and then some for this very reason. */
+ DEBUGASSERT(0);
+ return CURLE_RECV_ERROR;
}
+ return result;
}
static int cb_h3_recv_data(nghttp3_conn *conn, int64_t stream3_id,
- const uint8_t *buf, size_t blen,
+ const uint8_t *buf, size_t buflen,
void *user_data, void *stream_user_data)
{
struct Curl_cfilter *cf = user_data;
- struct cf_ngtcp2_ctx *ctx = cf->ctx;
struct Curl_easy *data = stream_user_data;
- struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
+ CURLcode result;
(void)conn;
(void)stream3_id;
@@ -950,14 +1258,14 @@ static int cb_h3_recv_data(nghttp3_conn *conn, int64_t stream3_id,
if(!stream)
return NGHTTP3_ERR_CALLBACK_FAILURE;
- h3_xfer_write_resp(cf, data, stream, (char *)buf, blen, FALSE);
- if(blen) {
- CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] ACK %zu bytes of DATA",
- stream->id, blen);
- ngtcp2_conn_extend_max_stream_offset(ctx->qconn, stream->id, blen);
- ngtcp2_conn_extend_max_offset(ctx->qconn, blen);
+ result = write_resp_raw(cf, data, buf, buflen, TRUE);
+ if(result) {
+ CURL_TRC_CF(data, cf, "[%" PRId64 "] DATA len=%zu, ERROR receiving %d",
+ stream->id, buflen, result);
+ return NGHTTP3_ERR_CALLBACK_FAILURE;
}
- CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] DATA len=%zu", stream->id, blen);
+ CURL_TRC_CF(data, cf, "[%" PRId64 "] DATA len=%zu", stream->id, buflen);
+ h3_drain_stream(cf, data);
return 0;
}
@@ -977,14 +1285,13 @@ static int cb_h3_deferred_consume(nghttp3_conn *conn, int64_t stream3_id,
return 0;
}
-static int cb_h3_end_headers(nghttp3_conn *conn, int64_t sid,
+static int cb_h3_end_headers(nghttp3_conn *conn, int64_t stream_id,
int fin, void *user_data, void *stream_user_data)
{
struct Curl_cfilter *cf = user_data;
- struct cf_ngtcp2_ctx *ctx = cf->ctx;
struct Curl_easy *data = stream_user_data;
- curl_int64_t stream_id = (curl_int64_t)sid;
- struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
+ CURLcode result = CURLE_OK;
(void)conn;
(void)stream_id;
(void)fin;
@@ -992,10 +1299,13 @@ static int cb_h3_end_headers(nghttp3_conn *conn, int64_t sid,
if(!stream)
return 0;
- /* add a CRLF only if we have received some headers */
- h3_xfer_write_resp_hd(cf, data, stream, STRCONST("\r\n"), stream->closed);
+ /* add a CRLF only if we've received some headers */
+ result = write_resp_raw(cf, data, "\r\n", 2, FALSE);
+ if(result) {
+ return -1;
+ }
- CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] end_headers, status=%d",
+ CURL_TRC_CF(data, cf, "[%" PRId64 "] end_headers, status=%d",
stream_id, stream->status_code);
if(stream->status_code / 100 != 1) {
stream->resp_hds_complete = TRUE;
@@ -1004,18 +1314,16 @@ static int cb_h3_end_headers(nghttp3_conn *conn, int64_t sid,
return 0;
}
-static int cb_h3_recv_header(nghttp3_conn *conn, int64_t sid,
+static int cb_h3_recv_header(nghttp3_conn *conn, int64_t stream_id,
int32_t token, nghttp3_rcbuf *name,
nghttp3_rcbuf *value, uint8_t flags,
void *user_data, void *stream_user_data)
{
struct Curl_cfilter *cf = user_data;
- struct cf_ngtcp2_ctx *ctx = cf->ctx;
- curl_int64_t stream_id = (curl_int64_t)sid;
nghttp3_vec h3name = nghttp3_rcbuf_get_buf(name);
nghttp3_vec h3val = nghttp3_rcbuf_get_buf(value);
struct Curl_easy *data = stream_user_data;
- struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
CURLcode result = CURLE_OK;
(void)conn;
(void)stream_id;
@@ -1028,45 +1336,42 @@ static int cb_h3_recv_header(nghttp3_conn *conn, int64_t sid,
return 0;
if(token == NGHTTP3_QPACK_TOKEN__STATUS) {
+ char line[14]; /* status line is always 13 characters long */
+ size_t ncopy;
result = Curl_http_decode_status(&stream->status_code,
(const char *)h3val.base, h3val.len);
if(result)
return -1;
- Curl_dyn_reset(&ctx->scratch);
- result = Curl_dyn_addn(&ctx->scratch, STRCONST("HTTP/3 "));
- if(!result)
- result = Curl_dyn_addn(&ctx->scratch,
- (const char *)h3val.base, h3val.len);
- if(!result)
- result = Curl_dyn_addn(&ctx->scratch, STRCONST(" \r\n"));
- if(!result)
- h3_xfer_write_resp_hd(cf, data, stream, Curl_dyn_ptr(&ctx->scratch),
- Curl_dyn_len(&ctx->scratch), FALSE);
- CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] status: %s",
- stream_id, Curl_dyn_ptr(&ctx->scratch));
+ ncopy = msnprintf(line, sizeof(line), "HTTP/3 %03d \r\n",
+ stream->status_code);
+ CURL_TRC_CF(data, cf, "[%" PRId64 "] status: %s", stream_id, line);
+ result = write_resp_raw(cf, data, line, ncopy, FALSE);
if(result) {
return -1;
}
}
else {
/* store as an HTTP1-style header */
- CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] header: %.*s: %.*s",
+ CURL_TRC_CF(data, cf, "[%" PRId64 "] header: %.*s: %.*s",
stream_id, (int)h3name.len, h3name.base,
(int)h3val.len, h3val.base);
- Curl_dyn_reset(&ctx->scratch);
- result = Curl_dyn_addn(&ctx->scratch,
- (const char *)h3name.base, h3name.len);
- if(!result)
- result = Curl_dyn_addn(&ctx->scratch, STRCONST(": "));
- if(!result)
- result = Curl_dyn_addn(&ctx->scratch,
- (const char *)h3val.base, h3val.len);
- if(!result)
- result = Curl_dyn_addn(&ctx->scratch, STRCONST("\r\n"));
- if(!result)
- h3_xfer_write_resp_hd(cf, data, stream, Curl_dyn_ptr(&ctx->scratch),
- Curl_dyn_len(&ctx->scratch), FALSE);
+ result = write_resp_raw(cf, data, h3name.base, h3name.len, FALSE);
+ if(result) {
+ return -1;
+ }
+ result = write_resp_raw(cf, data, ": ", 2, FALSE);
+ if(result) {
+ return -1;
+ }
+ result = write_resp_raw(cf, data, h3val.base, h3val.len, FALSE);
+ if(result) {
+ return -1;
+ }
+ result = write_resp_raw(cf, data, "\r\n", 2, FALSE);
+ if(result) {
+ return -1;
+ }
}
return 0;
}
@@ -1084,18 +1389,17 @@ static int cb_h3_stop_sending(nghttp3_conn *conn, int64_t stream_id,
rv = ngtcp2_conn_shutdown_stream_read(ctx->qconn, 0, stream_id,
app_error_code);
if(rv && rv != NGTCP2_ERR_STREAM_NOT_FOUND) {
- return NGHTTP3_ERR_CALLBACK_FAILURE;
+ return NGTCP2_ERR_CALLBACK_FAILURE;
}
return 0;
}
-static int cb_h3_reset_stream(nghttp3_conn *conn, int64_t sid,
+static int cb_h3_reset_stream(nghttp3_conn *conn, int64_t stream_id,
uint64_t app_error_code, void *user_data,
void *stream_user_data) {
struct Curl_cfilter *cf = user_data;
struct cf_ngtcp2_ctx *ctx = cf->ctx;
- curl_int64_t stream_id = (curl_int64_t)sid;
struct Curl_easy *data = stream_user_data;
int rv;
(void)conn;
@@ -1103,9 +1407,9 @@ static int cb_h3_reset_stream(nghttp3_conn *conn, int64_t sid,
rv = ngtcp2_conn_shutdown_stream_write(ctx->qconn, 0, stream_id,
app_error_code);
- CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] reset -> %d", stream_id, rv);
+ CURL_TRC_CF(data, cf, "[%" PRId64 "] reset -> %d", stream_id, rv);
if(rv && rv != NGTCP2_ERR_STREAM_NOT_FOUND) {
- return NGHTTP3_ERR_CALLBACK_FAILURE;
+ return NGTCP2_ERR_CALLBACK_FAILURE;
}
return 0;
@@ -1129,7 +1433,7 @@ static nghttp3_callbacks ngh3_callbacks = {
NULL /* recv_settings */
};
-static CURLcode init_ngh3_conn(struct Curl_cfilter *cf)
+static int init_ngh3_conn(struct Curl_cfilter *cf)
{
struct cf_ngtcp2_ctx *ctx = cf->ctx;
CURLcode result;
@@ -1198,14 +1502,15 @@ static ssize_t recv_closed_stream(struct Curl_cfilter *cf,
(void)cf;
if(stream->reset) {
- failf(data, "HTTP/3 stream %" FMT_PRId64 " reset by server", stream->id);
- *err = data->req.bytecount? CURLE_PARTIAL_FILE : CURLE_HTTP3;
+ failf(data,
+ "HTTP/3 stream %" PRId64 " reset by server", stream->id);
+ *err = stream->resp_hds_complete? CURLE_PARTIAL_FILE : CURLE_HTTP3;
goto out;
}
else if(!stream->resp_hds_complete) {
failf(data,
- "HTTP/3 stream %" FMT_PRId64 " was closed cleanly, but before "
- "getting all response header fields, treated as error",
+ "HTTP/3 stream %" PRId64 " was closed cleanly, but before getting"
+ " all response header fields, treated as error",
stream->id);
*err = CURLE_HTTP3;
goto out;
@@ -1219,16 +1524,15 @@ out:
/* incoming data frames on the h3 stream */
static ssize_t cf_ngtcp2_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
- char *buf, size_t blen, CURLcode *err)
+ char *buf, size_t len, CURLcode *err)
{
struct cf_ngtcp2_ctx *ctx = cf->ctx;
- struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
ssize_t nread = -1;
struct cf_call_data save;
struct pkt_io_ctx pktx;
(void)ctx;
- (void)buf;
CF_DATA_SAVE(save, cf, data);
DEBUGASSERT(cf->connected);
@@ -1239,30 +1543,51 @@ static ssize_t cf_ngtcp2_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
pktx_init(&pktx, cf, data);
- if(!stream || ctx->shutdown_started) {
+ if(!stream) {
*err = CURLE_RECV_ERROR;
goto out;
}
+ if(!Curl_bufq_is_empty(&stream->recvbuf)) {
+ nread = Curl_bufq_read(&stream->recvbuf,
+ (unsigned char *)buf, len, err);
+ if(nread < 0) {
+ CURL_TRC_CF(data, cf, "[%" PRId64 "] read recvbuf(len=%zu) "
+ "-> %zd, %d", stream->id, len, nread, *err);
+ goto out;
+ }
+ report_consumed_data(cf, data, nread);
+ }
+
if(cf_progress_ingress(cf, data, &pktx)) {
*err = CURLE_RECV_ERROR;
nread = -1;
goto out;
}
- if(stream->xfer_result) {
- CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] xfer write failed", stream->id);
- cf_ngtcp2_stream_close(cf, data, stream);
- *err = stream->xfer_result;
- nread = -1;
- goto out;
+ /* recvbuf had nothing before, maybe after progressing ingress? */
+ if(nread < 0 && !Curl_bufq_is_empty(&stream->recvbuf)) {
+ nread = Curl_bufq_read(&stream->recvbuf,
+ (unsigned char *)buf, len, err);
+ if(nread < 0) {
+ CURL_TRC_CF(data, cf, "[%" PRId64 "] read recvbuf(len=%zu) "
+ "-> %zd, %d", stream->id, len, nread, *err);
+ goto out;
+ }
+ report_consumed_data(cf, data, nread);
}
- else if(stream->closed) {
- nread = recv_closed_stream(cf, data, stream, err);
- goto out;
+
+ if(nread > 0) {
+ h3_drain_stream(cf, data);
+ }
+ else {
+ if(stream->closed) {
+ nread = recv_closed_stream(cf, data, stream, err);
+ goto out;
+ }
+ *err = CURLE_AGAIN;
+ nread = -1;
}
- *err = CURLE_AGAIN;
- nread = -1;
out:
if(cf_progress_egress(cf, data, &pktx)) {
@@ -1276,8 +1601,8 @@ out:
nread = -1;
}
}
- CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] cf_recv(blen=%zu) -> %zd, %d",
- stream? stream->id : -1, blen, nread, *err);
+ CURL_TRC_CF(data, cf, "[%" PRId64 "] cf_recv(len=%zu) -> %zd, %d",
+ stream? stream->id : -1, len, nread, *err);
CF_DATA_RESTORE(cf, save);
return nread;
}
@@ -1287,9 +1612,8 @@ static int cb_h3_acked_req_body(nghttp3_conn *conn, int64_t stream_id,
void *stream_user_data)
{
struct Curl_cfilter *cf = user_data;
- struct cf_ngtcp2_ctx *ctx = cf->ctx;
struct Curl_easy *data = stream_user_data;
- struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
size_t skiplen;
(void)cf;
@@ -1305,11 +1629,11 @@ static int cb_h3_acked_req_body(nghttp3_conn *conn, int64_t stream_id,
Curl_bufq_skip(&stream->sendbuf, skiplen);
stream->sendbuf_len_in_flight -= skiplen;
- /* Resume upload processing if we have more data to send */
- if(stream->sendbuf_len_in_flight < Curl_bufq_len(&stream->sendbuf)) {
+ /* Everything ACKed, we resume upload processing */
+ if(!stream->sendbuf_len_in_flight) {
int rv = nghttp3_conn_resume_stream(conn, stream_id);
if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) {
- return NGHTTP3_ERR_CALLBACK_FAILURE;
+ return NGTCP2_ERR_CALLBACK_FAILURE;
}
}
return 0;
@@ -1322,9 +1646,8 @@ cb_h3_read_req_body(nghttp3_conn *conn, int64_t stream_id,
void *stream_user_data)
{
struct Curl_cfilter *cf = user_data;
- struct cf_ngtcp2_ctx *ctx = cf->ctx;
struct Curl_easy *data = stream_user_data;
- struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
ssize_t nwritten = 0;
size_t nvecs = 0;
(void)cf;
@@ -1367,13 +1690,14 @@ cb_h3_read_req_body(nghttp3_conn *conn, int64_t stream_id,
}
else if(!nwritten) {
/* Not EOF, and nothing to give, we signal WOULDBLOCK. */
- CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] read req body -> AGAIN",
+ CURL_TRC_CF(data, cf, "[%" PRId64 "] read req body -> AGAIN",
stream->id);
return NGHTTP3_ERR_WOULDBLOCK;
}
- CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] read req body -> "
- "%d vecs%s with %zu (buffered=%zu, left=%" FMT_OFF_T ")",
+ CURL_TRC_CF(data, cf, "[%" PRId64 "] read req body -> "
+ "%d vecs%s with %zu (buffered=%zu, left=%"
+ CURL_FORMAT_CURL_OFF_T ")",
stream->id, (int)nvecs,
*pflags == NGHTTP3_DATA_FLAG_EOF?" EOF":"",
nwritten, Curl_bufq_len(&stream->sendbuf),
@@ -1392,7 +1716,6 @@ static ssize_t h3_stream_open(struct Curl_cfilter *cf,
{
struct cf_ngtcp2_ctx *ctx = cf->ctx;
struct h3_stream_ctx *stream = NULL;
- int64_t sid;
struct dynhds h2_headers;
size_t nheader;
nghttp3_nv *nva = NULL;
@@ -1407,7 +1730,7 @@ static ssize_t h3_stream_open(struct Curl_cfilter *cf,
*err = h3_data_setup(cf, data);
if(*err)
goto out;
- stream = H3_STREAM_CTX(ctx, data);
+ stream = H3_STREAM_CTX(data);
DEBUGASSERT(stream);
if(!stream) {
*err = CURLE_FAILED_INIT;
@@ -1448,15 +1771,12 @@ static ssize_t h3_stream_open(struct Curl_cfilter *cf,
nva[i].flags = NGHTTP3_NV_FLAG_NONE;
}
- rc = ngtcp2_conn_open_bidi_stream(ctx->qconn, &sid, data);
+ rc = ngtcp2_conn_open_bidi_stream(ctx->qconn, &stream->id, data);
if(rc) {
failf(data, "can get bidi streams");
*err = CURLE_SEND_ERROR;
- nwritten = -1;
goto out;
}
- stream->id = (curl_int64_t)sid;
- ++ctx->used_bidi_streams;
switch(data->state.httpreq) {
case HTTPREQ_POST:
@@ -1487,12 +1807,12 @@ static ssize_t h3_stream_open(struct Curl_cfilter *cf,
if(rc) {
switch(rc) {
case NGHTTP3_ERR_CONN_CLOSING:
- CURL_TRC_CF(data, cf, "h3sid[%" FMT_PRId64 "] failed to send, "
+ CURL_TRC_CF(data, cf, "h3sid[%"PRId64"] failed to send, "
"connection is closing", stream->id);
break;
default:
- CURL_TRC_CF(data, cf, "h3sid[%" FMT_PRId64 "] failed to send -> "
- "%d (%s)", stream->id, rc, nghttp3_strerror(rc));
+ CURL_TRC_CF(data, cf, "h3sid[%"PRId64"] failed to send -> %d (%s)",
+ stream->id, rc, ngtcp2_strerror(rc));
break;
}
*err = CURLE_SEND_ERROR;
@@ -1501,10 +1821,10 @@ static ssize_t h3_stream_open(struct Curl_cfilter *cf,
}
if(Curl_trc_is_verbose(data)) {
- infof(data, "[HTTP/3] [%" FMT_PRId64 "] OPENED stream for %s",
+ infof(data, "[HTTP/3] [%" PRId64 "] OPENED stream for %s",
stream->id, data->state.url);
for(i = 0; i < nheader; ++i) {
- infof(data, "[HTTP/3] [%" FMT_PRId64 "] [%.*s: %.*s]", stream->id,
+ infof(data, "[HTTP/3] [%" PRId64 "] [%.*s: %.*s]", stream->id,
(int)nva[i].namelen, nva[i].name,
(int)nva[i].valuelen, nva[i].value);
}
@@ -1517,11 +1837,10 @@ out:
}
static ssize_t cf_ngtcp2_send(struct Curl_cfilter *cf, struct Curl_easy *data,
- const void *buf, size_t len, bool eos,
- CURLcode *err)
+ const void *buf, size_t len, CURLcode *err)
{
struct cf_ngtcp2_ctx *ctx = cf->ctx;
- struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
ssize_t sent = 0;
struct cf_call_data save;
struct pkt_io_ctx pktx;
@@ -1534,7 +1853,6 @@ static ssize_t cf_ngtcp2_send(struct Curl_cfilter *cf, struct Curl_easy *data,
pktx_init(&pktx, cf, data);
*err = CURLE_OK;
- (void)eos; /* TODO: use for stream EOF and block handling */
result = cf_progress_ingress(cf, data, &pktx);
if(result) {
*err = result;
@@ -1542,25 +1860,27 @@ static ssize_t cf_ngtcp2_send(struct Curl_cfilter *cf, struct Curl_easy *data,
}
if(!stream || stream->id < 0) {
- if(ctx->shutdown_started) {
- CURL_TRC_CF(data, cf, "cannot open stream on closed connection");
- *err = CURLE_SEND_ERROR;
- sent = -1;
- goto out;
- }
sent = h3_stream_open(cf, data, buf, len, err);
if(sent < 0) {
CURL_TRC_CF(data, cf, "failed to open stream -> %d", *err);
goto out;
}
- stream = H3_STREAM_CTX(ctx, data);
- }
- else if(stream->xfer_result) {
- CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] xfer write failed", stream->id);
- cf_ngtcp2_stream_close(cf, data, stream);
- *err = stream->xfer_result;
- sent = -1;
- goto out;
+ stream = H3_STREAM_CTX(data);
+ }
+ else if(stream->upload_blocked_len) {
+ /* the data in `buf` has already been submitted or added to the
+ * buffers, but have been EAGAINed on the last invocation. */
+ DEBUGASSERT(len >= stream->upload_blocked_len);
+ if(len < stream->upload_blocked_len) {
+ /* Did we get called again with a smaller `len`? This should not
+ * happen. We are not prepared to handle that. */
+ failf(data, "HTTP/3 send again with decreased length");
+ *err = CURLE_HTTP3;
+ sent = -1;
+ goto out;
+ }
+ sent = (ssize_t)stream->upload_blocked_len;
+ stream->upload_blocked_len = 0;
}
else if(stream->closed) {
if(stream->resp_hds_complete) {
@@ -1569,27 +1889,19 @@ static ssize_t cf_ngtcp2_send(struct Curl_cfilter *cf, struct Curl_easy *data,
* body. This happens on 30x or 40x responses.
* We silently discard the data sent, since this is not a transport
* error situation. */
- CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] discarding data"
+ CURL_TRC_CF(data, cf, "[%" PRId64 "] discarding data"
"on closed stream with response", stream->id);
*err = CURLE_OK;
sent = (ssize_t)len;
goto out;
}
- CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] send_body(len=%zu) "
- "-> stream closed", stream->id, len);
*err = CURLE_HTTP3;
sent = -1;
goto out;
}
- else if(ctx->shutdown_started) {
- CURL_TRC_CF(data, cf, "cannot send on closed connection");
- *err = CURLE_SEND_ERROR;
- sent = -1;
- goto out;
- }
else {
sent = Curl_bufq_write(&stream->sendbuf, buf, len, err);
- CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] cf_send, add to "
+ CURL_TRC_CF(data, cf, "[%" PRId64 "] cf_send, add to "
"sendbuf(len=%zu) -> %zd, %d",
stream->id, len, sent, *err);
if(sent < 0) {
@@ -1605,13 +1917,25 @@ static ssize_t cf_ngtcp2_send(struct Curl_cfilter *cf, struct Curl_easy *data,
sent = -1;
}
+ if(stream && sent > 0 && stream->sendbuf_len_in_flight) {
+ /* We have unacknowledged DATA and cannot report success to our
+ * caller. Instead we EAGAIN and remember how much we have already
+ * "written" into our various internal connection buffers. */
+ stream->upload_blocked_len = sent;
+ CURL_TRC_CF(data, cf, "[%" PRId64 "] cf_send(len=%zu), "
+ "%zu bytes in flight -> EGAIN", stream->id, len,
+ stream->sendbuf_len_in_flight);
+ *err = CURLE_AGAIN;
+ sent = -1;
+ }
+
out:
result = check_and_set_expiry(cf, data, &pktx);
if(result) {
*err = result;
sent = -1;
}
- CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] cf_send(len=%zu) -> %zd, %d",
+ CURL_TRC_CF(data, cf, "[%" PRId64 "] cf_send(len=%zu) -> %zd, %d",
stream? stream->id : -1, len, sent, *err);
CF_DATA_RESTORE(cf, save);
return sent;
@@ -1621,11 +1945,49 @@ static CURLcode qng_verify_peer(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
struct cf_ngtcp2_ctx *ctx = cf->ctx;
+ struct ssl_primary_config *conn_config;
+ CURLcode result = CURLE_OK;
+
+ conn_config = Curl_ssl_cf_get_primary_config(cf);
+ if(!conn_config)
+ return CURLE_FAILED_INIT;
cf->conn->bits.multiplex = TRUE; /* at least potentially multiplexed */
cf->conn->httpversion = 30;
+ cf->conn->bundle->multiuse = BUNDLE_MULTIPLEX;
- return Curl_vquic_tls_verify_peer(&ctx->tls, cf, data, &ctx->peer);
+ if(conn_config->verifyhost) {
+#ifdef USE_OPENSSL
+ X509 *server_cert;
+ server_cert = SSL_get1_peer_certificate(ctx->ssl);
+ if(!server_cert) {
+ return CURLE_PEER_FAILED_VERIFICATION;
+ }
+ result = Curl_ossl_verifyhost(data, cf->conn, &ctx->peer, server_cert);
+ X509_free(server_cert);
+ if(result)
+ return result;
+#elif defined(USE_GNUTLS)
+ result = Curl_gtls_verifyserver(data, ctx->gtls->session,
+ conn_config, &data->set.ssl, &ctx->peer,
+ data->set.str[STRING_SSL_PINNEDPUBLICKEY]);
+ if(result)
+ return result;
+#elif defined(USE_WOLFSSL)
+ if(!ctx->peer.sni ||
+ wolfSSL_check_domain_name(ctx->ssl, ctx->peer.sni) == SSL_FAILURE)
+ return CURLE_PEER_FAILED_VERIFICATION;
+#endif
+ infof(data, "Verified certificate just fine");
+ }
+ else
+ infof(data, "Skipped certificate verification");
+#ifdef USE_OPENSSL
+ if(data->set.ssl.certinfo)
+ /* asked to gather certificate info */
+ (void)Curl_ossl_certchain(data, ctx->ssl);
+#endif
+ return result;
}
static CURLcode recv_pkt(const unsigned char *pkt, size_t pktlen,
@@ -1641,7 +2003,7 @@ static CURLcode recv_pkt(const unsigned char *pkt, size_t pktlen,
++pktx->pkt_count;
ngtcp2_addr_init(&path.local, (struct sockaddr *)&ctx->q.local_addr,
- (socklen_t)ctx->q.local_addrlen);
+ ctx->q.local_addrlen);
ngtcp2_addr_init(&path.remote, (struct sockaddr *)remote_addr,
remote_addrlen);
pi.ecn = (uint8_t)ecn;
@@ -1650,7 +2012,16 @@ static CURLcode recv_pkt(const unsigned char *pkt, size_t pktlen,
if(rv) {
CURL_TRC_CF(pktx->data, pktx->cf, "ingress, read_pkt -> %s (%d)",
ngtcp2_strerror(rv), rv);
- cf_ngtcp2_err_set(pktx->cf, pktx->data, rv);
+ if(!ctx->last_error.error_code) {
+ if(rv == NGTCP2_ERR_CRYPTO) {
+ ngtcp2_ccerr_set_tls_alert(&ctx->last_error,
+ ngtcp2_conn_get_tls_alert(ctx->qconn),
+ NULL, 0);
+ }
+ else {
+ ngtcp2_ccerr_set_liberr(&ctx->last_error, rv, NULL, 0);
+ }
+ }
if(rv == NGTCP2_ERR_CRYPTO)
/* this is a "TLS problem", but a failed certificate verification
@@ -1669,6 +2040,7 @@ static CURLcode cf_progress_ingress(struct Curl_cfilter *cf,
struct cf_ngtcp2_ctx *ctx = cf->ctx;
struct pkt_io_ctx local_pktx;
size_t pkts_chunk = 128, i;
+ size_t pkts_max = 10 * pkts_chunk;
CURLcode result = CURLE_OK;
if(!pktx) {
@@ -1679,17 +2051,26 @@ static CURLcode cf_progress_ingress(struct Curl_cfilter *cf,
pktx_update_time(pktx, cf);
}
- result = Curl_vquic_tls_before_recv(&ctx->tls, cf, data);
- if(result)
- return result;
+#ifdef USE_OPENSSL
+ if(!ctx->x509_store_setup) {
+ result = Curl_ssl_setup_x509_store(cf, data, ctx->sslctx);
+ if(result)
+ return result;
+ ctx->x509_store_setup = TRUE;
+ }
+#endif
- for(i = 0; i < 4; ++i) {
- if(i)
- pktx_update_time(pktx, cf);
+ for(i = 0; i < pkts_max; i += pkts_chunk) {
pktx->pkt_count = 0;
result = vquic_recv_packets(cf, data, &ctx->q, pkts_chunk,
recv_pkt, pktx);
- if(result || !pktx->pkt_count) /* error or got nothing */
+ if(result) /* error */
+ break;
+ if(pktx->pkt_count < pkts_chunk) /* got less than we could */
+ break;
+ /* give egress a chance before we receive more */
+ result = cf_progress_egress(cf, data, pktx);
+ if(result) /* error */
break;
}
return result;
@@ -1733,7 +2114,9 @@ static ssize_t read_pkt_to_send(void *userp,
if(veccnt < 0) {
failf(x->data, "nghttp3_conn_writev_stream returned error: %s",
nghttp3_strerror((int)veccnt));
- cf_ngtcp2_h3_err_set(x->cf, x->data, (int)veccnt);
+ ngtcp2_ccerr_set_application_error(
+ &ctx->last_error,
+ nghttp3_err_infer_quic_app_error_code((int)veccnt), NULL, 0);
*err = CURLE_SEND_ERROR;
return -1;
}
@@ -1754,11 +2137,11 @@ static ssize_t read_pkt_to_send(void *userp,
else if(n < 0) {
switch(n) {
case NGTCP2_ERR_STREAM_DATA_BLOCKED: {
- struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, x->data);
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(x->data);
DEBUGASSERT(ndatalen == -1);
nghttp3_conn_block_stream(ctx->h3conn, stream_id);
- CURL_TRC_CF(x->data, x->cf, "[%" FMT_PRId64 "] block quic flow",
- (curl_int64_t)stream_id);
+ CURL_TRC_CF(x->data, x->cf, "[%" PRId64 "] block quic flow",
+ stream_id);
DEBUGASSERT(stream);
if(stream)
stream->quic_flow_blocked = TRUE;
@@ -1780,7 +2163,7 @@ static ssize_t read_pkt_to_send(void *userp,
DEBUGASSERT(ndatalen == -1);
failf(x->data, "ngtcp2_conn_writev_stream returned error: %s",
ngtcp2_strerror((int)n));
- cf_ngtcp2_err_set(x->cf, x->data, (int)n);
+ ngtcp2_ccerr_set_liberr(&ctx->last_error, (int)n, NULL, 0);
*err = CURLE_SEND_ERROR;
nwritten = -1;
goto out;
@@ -1838,7 +2221,7 @@ static CURLcode cf_progress_egress(struct Curl_cfilter *cf,
}
/* In UDP, there is a maximum theoretical packet paload length and
- * a minimum payload length that is "guaranteed" to work.
+ * a minimum payload length that is "guarantueed" to work.
* To detect if this minimum payload can be increased, ngtcp2 sends
* now and then a packet payload larger than the minimum. It that
* is ACKed by the peer, both parties know that it works and
@@ -1877,7 +2260,7 @@ static CURLcode cf_progress_egress(struct Curl_cfilter *cf,
DEBUGASSERT(nread > 0);
if(pktcnt == 0) {
/* first packet in buffer. This is either of a known, "good"
- * payload size or it is a PMTUD. We will see. */
+ * payload size or it is a PMTUD. We'll see. */
gsolen = (size_t)nread;
}
else if((size_t)nread > gsolen ||
@@ -1926,9 +2309,9 @@ out:
static bool cf_ngtcp2_data_pending(struct Curl_cfilter *cf,
const struct Curl_easy *data)
{
+ const struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
(void)cf;
- (void)data;
- return FALSE;
+ return stream && !Curl_bufq_is_empty(&stream->recvbuf);
}
static CURLcode h3_data_pause(struct Curl_cfilter *cf,
@@ -1968,17 +2351,16 @@ static CURLcode cf_ngtcp2_data_event(struct Curl_cfilter *cf,
h3_data_done(cf, data);
break;
case CF_CTRL_DATA_DONE_SEND: {
- struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
if(stream && !stream->send_closed) {
stream->send_closed = TRUE;
- stream->upload_left = Curl_bufq_len(&stream->sendbuf) -
- stream->sendbuf_len_in_flight;
+ stream->upload_left = Curl_bufq_len(&stream->sendbuf);
(void)nghttp3_conn_resume_stream(ctx->h3conn, stream->id);
}
break;
}
case CF_CTRL_DATA_IDLE: {
- struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
+ struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
CURL_TRC_CF(data, cf, "data idle");
if(stream && !stream->closed) {
result = check_and_set_expiry(cf, data, NULL);
@@ -1994,205 +2376,88 @@ static CURLcode cf_ngtcp2_data_event(struct Curl_cfilter *cf,
return result;
}
-static void cf_ngtcp2_ctx_close(struct cf_ngtcp2_ctx *ctx)
+static void cf_ngtcp2_ctx_clear(struct cf_ngtcp2_ctx *ctx)
{
struct cf_call_data save = ctx->call_data;
- if(!ctx->initialized)
- return;
if(ctx->qlogfd != -1) {
close(ctx->qlogfd);
}
- ctx->qlogfd = -1;
- Curl_vquic_tls_cleanup(&ctx->tls);
+#ifdef USE_OPENSSL
+ if(ctx->ssl)
+ SSL_free(ctx->ssl);
+ if(ctx->sslctx)
+ SSL_CTX_free(ctx->sslctx);
+#elif defined(USE_GNUTLS)
+ if(ctx->gtls) {
+ if(ctx->gtls->cred)
+ gnutls_certificate_free_credentials(ctx->gtls->cred);
+ if(ctx->gtls->session)
+ gnutls_deinit(ctx->gtls->session);
+ free(ctx->gtls);
+ }
+#elif defined(USE_WOLFSSL)
+ if(ctx->ssl)
+ wolfSSL_free(ctx->ssl);
+ if(ctx->sslctx)
+ wolfSSL_CTX_free(ctx->sslctx);
+#endif
vquic_ctx_free(&ctx->q);
if(ctx->h3conn)
nghttp3_conn_del(ctx->h3conn);
if(ctx->qconn)
ngtcp2_conn_del(ctx->qconn);
+ Curl_bufcp_free(&ctx->stream_bufcp);
+ Curl_ssl_peer_cleanup(&ctx->peer);
+
+ memset(ctx, 0, sizeof(*ctx));
+ ctx->qlogfd = -1;
ctx->call_data = save;
}
-static CURLcode cf_ngtcp2_shutdown(struct Curl_cfilter *cf,
- struct Curl_easy *data, bool *done)
+static void cf_ngtcp2_close(struct Curl_cfilter *cf, struct Curl_easy *data)
{
struct cf_ngtcp2_ctx *ctx = cf->ctx;
struct cf_call_data save;
- struct pkt_io_ctx pktx;
- CURLcode result = CURLE_OK;
-
- if(cf->shutdown || !ctx->qconn) {
- *done = TRUE;
- return CURLE_OK;
- }
CF_DATA_SAVE(save, cf, data);
- *done = FALSE;
- pktx_init(&pktx, cf, data);
-
- if(!ctx->shutdown_started) {
+ if(ctx && ctx->qconn) {
char buffer[NGTCP2_MAX_UDP_PAYLOAD_SIZE];
- ngtcp2_ssize nwritten;
-
- if(!Curl_bufq_is_empty(&ctx->q.sendbuf)) {
- CURL_TRC_CF(data, cf, "shutdown, flushing sendbuf");
- result = cf_progress_egress(cf, data, &pktx);
- if(!Curl_bufq_is_empty(&ctx->q.sendbuf)) {
- CURL_TRC_CF(data, cf, "sending shutdown packets blocked");
- result = CURLE_OK;
- goto out;
- }
- else if(result) {
- CURL_TRC_CF(data, cf, "shutdown, error %d flushing sendbuf", result);
- *done = TRUE;
- goto out;
- }
- }
+ struct pkt_io_ctx pktx;
+ ngtcp2_ssize rc;
- ctx->shutdown_started = TRUE;
- nwritten = ngtcp2_conn_write_connection_close(
- ctx->qconn, NULL, /* path */
- NULL, /* pkt_info */
- (uint8_t *)buffer, sizeof(buffer),
- &ctx->last_error, pktx.ts);
- CURL_TRC_CF(data, cf, "start shutdown(err_type=%d, err_code=%"
- FMT_PRIu64 ") -> %d", ctx->last_error.type,
- (curl_uint64_t)ctx->last_error.error_code, (int)nwritten);
- if(nwritten > 0) {
- Curl_bufq_write(&ctx->q.sendbuf, (const unsigned char *)buffer,
- (size_t)nwritten, &result);
- if(result) {
- CURL_TRC_CF(data, cf, "error %d adding shutdown packets to sendbuf, "
- "aborting shutdown", result);
- goto out;
- }
- ctx->q.no_gso = TRUE;
- ctx->q.gsolen = (size_t)nwritten;
- ctx->q.split_len = 0;
+ CURL_TRC_CF(data, cf, "close");
+ pktx_init(&pktx, cf, data);
+ rc = ngtcp2_conn_write_connection_close(ctx->qconn, NULL, /* path */
+ NULL, /* pkt_info */
+ (uint8_t *)buffer, sizeof(buffer),
+ &ctx->last_error, pktx.ts);
+ if(rc > 0) {
+ while((send(ctx->q.sockfd, buffer, (SEND_TYPE_ARG3)rc, 0) == -1) &&
+ SOCKERRNO == EINTR);
}
- }
- if(!Curl_bufq_is_empty(&ctx->q.sendbuf)) {
- CURL_TRC_CF(data, cf, "shutdown, flushing egress");
- result = vquic_flush(cf, data, &ctx->q);
- if(result == CURLE_AGAIN) {
- CURL_TRC_CF(data, cf, "sending shutdown packets blocked");
- result = CURLE_OK;
- goto out;
- }
- else if(result) {
- CURL_TRC_CF(data, cf, "shutdown, error %d flushing sendbuf", result);
- *done = TRUE;
- goto out;
- }
+ cf_ngtcp2_ctx_clear(ctx);
}
- if(Curl_bufq_is_empty(&ctx->q.sendbuf)) {
- /* Sent everything off. ngtcp2 seems to have no support for graceful
- * shutdowns. So, we are done. */
- CURL_TRC_CF(data, cf, "shutdown completely sent off, done");
- *done = TRUE;
- result = CURLE_OK;
- }
-out:
+ cf->connected = FALSE;
CF_DATA_RESTORE(cf, save);
- return result;
-}
-
-static void cf_ngtcp2_conn_close(struct Curl_cfilter *cf,
- struct Curl_easy *data)
-{
- bool done;
- cf_ngtcp2_shutdown(cf, data, &done);
}
-static void cf_ngtcp2_close(struct Curl_cfilter *cf, struct Curl_easy *data)
+static void cf_ngtcp2_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
{
struct cf_ngtcp2_ctx *ctx = cf->ctx;
struct cf_call_data save;
CF_DATA_SAVE(save, cf, data);
- if(ctx && ctx->qconn) {
- cf_ngtcp2_conn_close(cf, data);
- cf_ngtcp2_ctx_close(ctx);
- CURL_TRC_CF(data, cf, "close");
- }
- cf->connected = FALSE;
- CF_DATA_RESTORE(cf, save);
-}
-
-static void cf_ngtcp2_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
-{
CURL_TRC_CF(data, cf, "destroy");
- if(cf->ctx) {
- cf_ngtcp2_ctx_free(cf->ctx);
- cf->ctx = NULL;
- }
-}
-
-#ifdef USE_OPENSSL
-/* The "new session" callback must return zero if the session can be removed
- * or non-zero if the session has been put into the session cache.
- */
-static int quic_ossl_new_session_cb(SSL *ssl, SSL_SESSION *ssl_sessionid)
-{
- struct Curl_cfilter *cf;
- struct cf_ngtcp2_ctx *ctx;
- struct Curl_easy *data;
- ngtcp2_crypto_conn_ref *cref;
-
- cref = (ngtcp2_crypto_conn_ref *)SSL_get_app_data(ssl);
- cf = cref? cref->user_data : NULL;
- ctx = cf? cf->ctx : NULL;
- data = cf? CF_DATA_CURRENT(cf) : NULL;
- if(cf && data && ctx) {
- Curl_ossl_add_session(cf, data, &ctx->peer, ssl_sessionid);
- return 1;
- }
- return 0;
-}
-#endif /* USE_OPENSSL */
-
-static CURLcode tls_ctx_setup(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- void *user_data)
-{
- struct curl_tls_ctx *ctx = user_data;
- (void)cf;
-#ifdef USE_OPENSSL
-#if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC)
- if(ngtcp2_crypto_boringssl_configure_client_context(ctx->ossl.ssl_ctx)
- != 0) {
- failf(data, "ngtcp2_crypto_boringssl_configure_client_context failed");
- return CURLE_FAILED_INIT;
- }
-#else
- if(ngtcp2_crypto_quictls_configure_client_context(ctx->ossl.ssl_ctx) != 0) {
- failf(data, "ngtcp2_crypto_quictls_configure_client_context failed");
- return CURLE_FAILED_INIT;
- }
-#endif /* !OPENSSL_IS_BORINGSSL && !OPENSSL_IS_AWSLC */
- /* Enable the session cache because it is a prerequisite for the
- * "new session" callback. Use the "external storage" mode to prevent
- * OpenSSL from creating an internal session cache.
- */
- SSL_CTX_set_session_cache_mode(ctx->ossl.ssl_ctx,
- SSL_SESS_CACHE_CLIENT |
- SSL_SESS_CACHE_NO_INTERNAL);
- SSL_CTX_sess_set_new_cb(ctx->ossl.ssl_ctx, quic_ossl_new_session_cb);
-
-#elif defined(USE_GNUTLS)
- if(ngtcp2_crypto_gnutls_configure_client_session(ctx->gtls.session) != 0) {
- failf(data, "ngtcp2_crypto_gnutls_configure_client_session failed");
- return CURLE_FAILED_INIT;
- }
-#elif defined(USE_WOLFSSL)
- if(ngtcp2_crypto_wolfssl_configure_client_context(ctx->wssl.ctx) != 0) {
- failf(data, "ngtcp2_crypto_wolfssl_configure_client_context failed");
- return CURLE_FAILED_INIT;
+ if(ctx) {
+ cf_ngtcp2_ctx_clear(ctx);
+ free(ctx);
}
-#endif
- return CURLE_OK;
+ cf->ctx = NULL;
+ /* No CF_DATA_RESTORE(cf, save) possible */
+ (void)save;
}
/*
@@ -2209,22 +2474,34 @@ static CURLcode cf_connect_start(struct Curl_cfilter *cf,
const struct Curl_sockaddr_ex *sockaddr = NULL;
int qfd;
- DEBUGASSERT(ctx->initialized);
- result = Curl_ssl_peer_init(&ctx->peer, cf, TRNSPRT_QUIC);
+ ctx->version = NGTCP2_PROTO_VER_MAX;
+ ctx->max_stream_window = H3_STREAM_WINDOW_SIZE;
+ ctx->max_idle_ms = CURL_QUIC_MAX_IDLE_MS;
+ Curl_bufcp_init(&ctx->stream_bufcp, H3_STREAM_CHUNK_SIZE,
+ H3_STREAM_POOL_SPARES);
+
+ result = Curl_ssl_peer_init(&ctx->peer, cf);
if(result)
return result;
-#define H3_ALPN "\x2h3\x5h3-29"
- result = Curl_vquic_tls_init(&ctx->tls, cf, data, &ctx->peer,
- H3_ALPN, sizeof(H3_ALPN) - 1,
- tls_ctx_setup, &ctx->tls, &ctx->conn_ref);
+#ifdef USE_OPENSSL
+ result = quic_ssl_ctx(&ctx->sslctx, cf, data);
if(result)
return result;
-#ifdef USE_OPENSSL
- SSL_set_quic_use_legacy_codepoint(ctx->tls.ossl.ssl, 0);
+ result = quic_set_client_cert(cf, data);
+ if(result)
+ return result;
+#elif defined(USE_WOLFSSL)
+ result = quic_ssl_ctx(&ctx->sslctx, cf, data);
+ if(result)
+ return result;
#endif
+ result = quic_init_ssl(cf, data);
+ if(result)
+ return result;
+
ctx->dcid.datalen = NGTCP2_MAX_CIDLEN;
result = Curl_rand(data, ctx->dcid.data, NGTCP2_MAX_CIDLEN);
if(result)
@@ -2243,7 +2520,8 @@ static CURLcode cf_connect_start(struct Curl_cfilter *cf,
if(result)
return result;
- Curl_cf_socket_peek(cf->next, data, &ctx->q.sockfd, &sockaddr, NULL);
+ Curl_cf_socket_peek(cf->next, data, &ctx->q.sockfd,
+ &sockaddr, NULL, NULL, NULL, NULL);
if(!sockaddr)
return CURLE_QUIC_CONNECT_ERROR;
ctx->q.local_addrlen = sizeof(ctx->q.local_addr);
@@ -2256,7 +2534,7 @@ static CURLcode cf_connect_start(struct Curl_cfilter *cf,
(struct sockaddr *)&ctx->q.local_addr,
ctx->q.local_addrlen);
ngtcp2_addr_init(&ctx->connected_path.remote,
- &sockaddr->sa_addr, (socklen_t)sockaddr->addrlen);
+ &sockaddr->sa_addr, sockaddr->addrlen);
rc = ngtcp2_conn_client_new(&ctx->qconn, &ctx->dcid, &ctx->scid,
&ctx->connected_path,
@@ -2266,12 +2544,10 @@ static CURLcode cf_connect_start(struct Curl_cfilter *cf,
if(rc)
return CURLE_QUIC_CONNECT_ERROR;
-#ifdef USE_OPENSSL
- ngtcp2_conn_set_tls_native_handle(ctx->qconn, ctx->tls.ossl.ssl);
-#elif defined(USE_GNUTLS)
- ngtcp2_conn_set_tls_native_handle(ctx->qconn, ctx->tls.gtls.session);
+#ifdef USE_GNUTLS
+ ngtcp2_conn_set_tls_native_handle(ctx->qconn, ctx->gtls->session);
#else
- ngtcp2_conn_set_tls_native_handle(ctx->qconn, ctx->tls.wssl.handle);
+ ngtcp2_conn_set_tls_native_handle(ctx->qconn, ctx->ssl);
#endif
ngtcp2_ccerr_default(&ctx->last_error);
@@ -2310,6 +2586,12 @@ static CURLcode cf_ngtcp2_connect(struct Curl_cfilter *cf,
CF_DATA_SAVE(save, cf, data);
+ if(ctx->reconnect_at.tv_sec && Curl_timediff(now, ctx->reconnect_at) < 0) {
+ /* Not time yet to attempt the next connect */
+ CURL_TRC_CF(data, cf, "waiting for reconnect time");
+ goto out;
+ }
+
if(!ctx->qconn) {
ctx->started_at = now;
result = cf_connect_start(cf, data, &pktx);
@@ -2354,11 +2636,13 @@ out:
#ifndef CURL_DISABLE_VERBOSE_STRINGS
if(result) {
- struct ip_quadruple ip;
+ const char *r_ip = NULL;
+ int r_port = 0;
- Curl_cf_socket_peek(cf->next, data, NULL, NULL, &ip);
+ Curl_cf_socket_peek(cf->next, data, NULL, NULL,
+ &r_ip, &r_port, NULL, NULL);
infof(data, "QUIC connect to %s port %u failed: %s",
- ip.remote_ip, ip.remote_port, curl_easy_strerror(result));
+ r_ip, r_port, curl_easy_strerror(result));
}
#endif
if(!result && ctx->qconn) {
@@ -2379,34 +2663,23 @@ static CURLcode cf_ngtcp2_query(struct Curl_cfilter *cf,
switch(query) {
case CF_QUERY_MAX_CONCURRENT: {
+ const ngtcp2_transport_params *rp;
DEBUGASSERT(pres1);
+
CF_DATA_SAVE(save, cf, data);
- /* Set after transport params arrived and continually updated
- * by callback. QUIC counts the number over the lifetime of the
- * connection, ever increasing.
- * We count the *open* transfers plus the budget for new ones. */
- if(!ctx->qconn || ctx->shutdown_started) {
- *pres1 = 0;
- }
- else if(ctx->max_bidi_streams) {
- uint64_t avail_bidi_streams = 0;
- uint64_t max_streams = CONN_INUSE(cf->conn);
- if(ctx->max_bidi_streams > ctx->used_bidi_streams)
- avail_bidi_streams = ctx->max_bidi_streams - ctx->used_bidi_streams;
- max_streams += avail_bidi_streams;
- *pres1 = (max_streams > INT_MAX)? INT_MAX : (int)max_streams;
- }
- else /* transport params not arrived yet? take our default. */
- *pres1 = (int)Curl_multi_max_concurrent_streams(data->multi);
- CURL_TRC_CF(data, cf, "query conn[%" FMT_OFF_T "]: "
- "MAX_CONCURRENT -> %d (%zu in use)",
- cf->conn->connection_id, *pres1, CONN_INUSE(cf->conn));
+ rp = ngtcp2_conn_get_remote_transport_params(ctx->qconn);
+ if(rp)
+ *pres1 = (rp->initial_max_streams_bidi > INT_MAX)?
+ INT_MAX : (int)rp->initial_max_streams_bidi;
+ else /* not arrived yet? */
+ *pres1 = Curl_multi_max_concurrent_streams(data->multi);
+ CURL_TRC_CF(data, cf, "query max_conncurrent -> %d", *pres1);
CF_DATA_RESTORE(cf, save);
return CURLE_OK;
}
case CF_QUERY_CONNECT_REPLY_MS:
- if(ctx->q.got_first_byte) {
- timediff_t ms = Curl_timediff(ctx->q.first_byte_at, ctx->started_at);
+ if(ctx->got_first_byte) {
+ timediff_t ms = Curl_timediff(ctx->first_byte_at, ctx->started_at);
*pres1 = (ms < INT_MAX)? (int)ms : INT_MAX;
}
else
@@ -2414,8 +2687,8 @@ static CURLcode cf_ngtcp2_query(struct Curl_cfilter *cf,
return CURLE_OK;
case CF_QUERY_TIMER_CONNECT: {
struct curltime *when = pres2;
- if(ctx->q.got_first_byte)
- *when = ctx->q.first_byte_at;
+ if(ctx->got_first_byte)
+ *when = ctx->first_byte_at;
return CURLE_OK;
}
case CF_QUERY_TIMER_APPCONNECT: {
@@ -2441,9 +2714,9 @@ static bool cf_ngtcp2_conn_is_alive(struct Curl_cfilter *cf,
const ngtcp2_transport_params *rp;
struct cf_call_data save;
- CF_DATA_SAVE(save, cf, data);
+ CF_DATA_SAVE(save, cf, data);
*input_pending = FALSE;
- if(!ctx->qconn || ctx->shutdown_started)
+ if(!ctx->qconn)
goto out;
/* Both sides of the QUIC connection announce they max idle times in
@@ -2470,8 +2743,8 @@ static bool cf_ngtcp2_conn_is_alive(struct Curl_cfilter *cf,
alive = TRUE;
if(*input_pending) {
CURLcode result;
- /* This happens before we have sent off a request and the connection is
- not in use by any other transfer, there should not be any data here,
+ /* This happens before we've sent off a request and the connection is
+ not in use by any other transfer, there shouldn't be any data here,
only "protocol frames" */
*input_pending = FALSE;
result = cf_progress_ingress(cf, data, NULL);
@@ -2491,7 +2764,6 @@ struct Curl_cftype Curl_cft_http3 = {
cf_ngtcp2_destroy,
cf_ngtcp2_connect,
cf_ngtcp2_close,
- cf_ngtcp2_shutdown,
Curl_cf_def_get_host,
cf_ngtcp2_adjust_pollset,
cf_ngtcp2_data_pending,
@@ -2518,7 +2790,8 @@ CURLcode Curl_cf_ngtcp2_create(struct Curl_cfilter **pcf,
result = CURLE_OUT_OF_MEMORY;
goto out;
}
- cf_ngtcp2_ctx_init(ctx);
+ ctx->qlogfd = -1;
+ cf_ngtcp2_ctx_clear(ctx);
result = Curl_cf_create(&cf, &Curl_cft_http3, ctx);
if(result)
@@ -2539,7 +2812,7 @@ out:
if(udp_cf)
Curl_conn_cf_discard_sub(cf, udp_cf, data, TRUE);
Curl_safefree(cf);
- cf_ngtcp2_ctx_free(ctx);
+ Curl_safefree(ctx);
}
return result;
}
diff --git a/contrib/libs/curl/lib/vquic/curl_osslq.c b/contrib/libs/curl/lib/vquic/curl_osslq.c
deleted file mode 100644
index 21ba050216..0000000000
--- a/contrib/libs/curl/lib/vquic/curl_osslq.c
+++ /dev/null
@@ -1,2389 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at https://curl.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * SPDX-License-Identifier: curl
- *
- ***************************************************************************/
-
-#include "curl_setup.h"
-
-#if defined(USE_OPENSSL_QUIC) && defined(USE_NGHTTP3)
-
-#include <openssl/ssl.h>
-#include <openssl/bio.h>
-#include <openssl/err.h>
-#error #include <nghttp3/nghttp3.h>
-
-#include "urldata.h"
-#include "hash.h"
-#include "sendf.h"
-#include "strdup.h"
-#include "rand.h"
-#include "multiif.h"
-#include "strcase.h"
-#include "cfilters.h"
-#include "cf-socket.h"
-#include "connect.h"
-#include "progress.h"
-#include "strerror.h"
-#include "dynbuf.h"
-#include "http1.h"
-#include "select.h"
-#include "inet_pton.h"
-#include "vquic.h"
-#include "vquic_int.h"
-#error #include "vquic-tls.h"
-#include "vtls/keylog.h"
-#include "vtls/vtls.h"
-#include "vtls/openssl.h"
-#include "curl_osslq.h"
-
-#include "warnless.h"
-
-/* The last 3 #include files should be in this order */
-#include "curl_printf.h"
-#include "curl_memory.h"
-#include "memdebug.h"
-
-/* A stream window is the maximum amount we need to buffer for
- * each active transfer. We use HTTP/3 flow control and only ACK
- * when we take things out of the buffer.
- * Chunk size is large enough to take a full DATA frame */
-#define H3_STREAM_WINDOW_SIZE (128 * 1024)
-#define H3_STREAM_CHUNK_SIZE (16 * 1024)
-/* The pool keeps spares around and half of a full stream window
- * seems good. More does not seem to improve performance.
- * The benefit of the pool is that stream buffer to not keep
- * spares. Memory consumption goes down when streams run empty,
- * have a large upload done, etc. */
-#define H3_STREAM_POOL_SPARES \
- (H3_STREAM_WINDOW_SIZE / H3_STREAM_CHUNK_SIZE ) / 2
-/* Receive and Send max number of chunks just follows from the
- * chunk size and window size */
-#define H3_STREAM_RECV_CHUNKS \
- (H3_STREAM_WINDOW_SIZE / H3_STREAM_CHUNK_SIZE)
-#define H3_STREAM_SEND_CHUNKS \
- (H3_STREAM_WINDOW_SIZE / H3_STREAM_CHUNK_SIZE)
-
-#ifndef ARRAYSIZE
-#define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
-#endif
-
-#if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC)
-typedef uint32_t sslerr_t;
-#else
-typedef unsigned long sslerr_t;
-#endif
-
-
-/* How to access `call_data` from a cf_osslq filter */
-#undef CF_CTX_CALL_DATA
-#define CF_CTX_CALL_DATA(cf) \
- ((struct cf_osslq_ctx *)(cf)->ctx)->call_data
-
-static CURLcode cf_progress_ingress(struct Curl_cfilter *cf,
- struct Curl_easy *data);
-
-static const char *osslq_SSL_ERROR_to_str(int err)
-{
- switch(err) {
- case SSL_ERROR_NONE:
- return "SSL_ERROR_NONE";
- case SSL_ERROR_SSL:
- return "SSL_ERROR_SSL";
- case SSL_ERROR_WANT_READ:
- return "SSL_ERROR_WANT_READ";
- case SSL_ERROR_WANT_WRITE:
- return "SSL_ERROR_WANT_WRITE";
- case SSL_ERROR_WANT_X509_LOOKUP:
- return "SSL_ERROR_WANT_X509_LOOKUP";
- case SSL_ERROR_SYSCALL:
- return "SSL_ERROR_SYSCALL";
- case SSL_ERROR_ZERO_RETURN:
- return "SSL_ERROR_ZERO_RETURN";
- case SSL_ERROR_WANT_CONNECT:
- return "SSL_ERROR_WANT_CONNECT";
- case SSL_ERROR_WANT_ACCEPT:
- return "SSL_ERROR_WANT_ACCEPT";
-#if defined(SSL_ERROR_WANT_ASYNC)
- case SSL_ERROR_WANT_ASYNC:
- return "SSL_ERROR_WANT_ASYNC";
-#endif
-#if defined(SSL_ERROR_WANT_ASYNC_JOB)
- case SSL_ERROR_WANT_ASYNC_JOB:
- return "SSL_ERROR_WANT_ASYNC_JOB";
-#endif
-#if defined(SSL_ERROR_WANT_EARLY)
- case SSL_ERROR_WANT_EARLY:
- return "SSL_ERROR_WANT_EARLY";
-#endif
- default:
- return "SSL_ERROR unknown";
- }
-}
-
-/* Return error string for last OpenSSL error */
-static char *osslq_strerror(unsigned long error, char *buf, size_t size)
-{
- DEBUGASSERT(size);
- *buf = '\0';
-
-#if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC)
- ERR_error_string_n((uint32_t)error, buf, size);
-#else
- ERR_error_string_n(error, buf, size);
-#endif
-
- if(!*buf) {
- const char *msg = error ? "Unknown error" : "No error";
- if(strlen(msg) < size)
- strcpy(buf, msg);
- }
-
- return buf;
-}
-
-static CURLcode make_bio_addr(BIO_ADDR **pbio_addr,
- const struct Curl_sockaddr_ex *addr)
-{
- BIO_ADDR *ba;
- CURLcode result = CURLE_FAILED_INIT;
-
- ba = BIO_ADDR_new();
- if(!ba) {
- result = CURLE_OUT_OF_MEMORY;
- goto out;
- }
-
- switch(addr->family) {
- case AF_INET: {
- struct sockaddr_in * const sin =
- (struct sockaddr_in * const)(void *)&addr->sa_addr;
- if(!BIO_ADDR_rawmake(ba, AF_INET, &sin->sin_addr,
- sizeof(sin->sin_addr), sin->sin_port)) {
- goto out;
- }
- result = CURLE_OK;
- break;
- }
-#ifdef USE_IPV6
- case AF_INET6: {
- struct sockaddr_in6 * const sin =
- (struct sockaddr_in6 * const)(void *)&addr->sa_addr;
- if(!BIO_ADDR_rawmake(ba, AF_INET6, &sin->sin6_addr,
- sizeof(sin->sin6_addr), sin->sin6_port)) {
- }
- result = CURLE_OK;
- break;
- }
-#endif /* USE_IPV6 */
- default:
- /* sunsupported */
- DEBUGASSERT(0);
- break;
- }
-
-out:
- if(result && ba) {
- BIO_ADDR_free(ba);
- ba = NULL;
- }
- *pbio_addr = ba;
- return result;
-}
-
-/* QUIC stream (not necessarily H3) */
-struct cf_osslq_stream {
- curl_int64_t id;
- SSL *ssl;
- struct bufq recvbuf; /* QUIC war data recv buffer */
- BIT(recvd_eos);
- BIT(closed);
- BIT(reset);
- BIT(send_blocked);
-};
-
-static CURLcode cf_osslq_stream_open(struct cf_osslq_stream *s,
- SSL *conn,
- uint64_t flags,
- struct bufc_pool *bufcp,
- void *user_data)
-{
- DEBUGASSERT(!s->ssl);
- Curl_bufq_initp(&s->recvbuf, bufcp, 1, BUFQ_OPT_NONE);
- s->ssl = SSL_new_stream(conn, flags);
- if(!s->ssl) {
- return CURLE_FAILED_INIT;
- }
- s->id = (curl_int64_t)SSL_get_stream_id(s->ssl);
- SSL_set_app_data(s->ssl, user_data);
- return CURLE_OK;
-}
-
-static void cf_osslq_stream_cleanup(struct cf_osslq_stream *s)
-{
- if(s->ssl) {
- SSL_set_app_data(s->ssl, NULL);
- SSL_free(s->ssl);
- }
- Curl_bufq_free(&s->recvbuf);
- memset(s, 0, sizeof(*s));
-}
-
-static void cf_osslq_stream_close(struct cf_osslq_stream *s)
-{
- if(s->ssl) {
- SSL_free(s->ssl);
- s->ssl = NULL;
- }
-}
-
-struct cf_osslq_h3conn {
- nghttp3_conn *conn;
- nghttp3_settings settings;
- struct cf_osslq_stream s_ctrl;
- struct cf_osslq_stream s_qpack_enc;
- struct cf_osslq_stream s_qpack_dec;
- struct cf_osslq_stream remote_ctrl[3]; /* uni streams opened by the peer */
- size_t remote_ctrl_n; /* number of peer streams opened */
-};
-
-static void cf_osslq_h3conn_cleanup(struct cf_osslq_h3conn *h3)
-{
- size_t i;
-
- if(h3->conn)
- nghttp3_conn_del(h3->conn);
- cf_osslq_stream_cleanup(&h3->s_ctrl);
- cf_osslq_stream_cleanup(&h3->s_qpack_enc);
- cf_osslq_stream_cleanup(&h3->s_qpack_dec);
- for(i = 0; i < h3->remote_ctrl_n; ++i) {
- cf_osslq_stream_cleanup(&h3->remote_ctrl[i]);
- }
-}
-
-struct cf_osslq_ctx {
- struct cf_quic_ctx q;
- struct ssl_peer peer;
- struct curl_tls_ctx tls;
- struct cf_call_data call_data;
- struct cf_osslq_h3conn h3;
- struct curltime started_at; /* time the current attempt started */
- struct curltime handshake_at; /* time connect handshake finished */
- struct curltime first_byte_at; /* when first byte was recvd */
- struct bufc_pool stream_bufcp; /* chunk pool for streams */
- struct Curl_hash streams; /* hash `data->mid` to `h3_stream_ctx` */
- size_t max_stream_window; /* max flow window for one stream */
- uint64_t max_idle_ms; /* max idle time for QUIC connection */
- BIT(initialized);
- BIT(got_first_byte); /* if first byte was received */
- BIT(x509_store_setup); /* if x509 store has been set up */
- BIT(protocol_shutdown); /* QUIC connection is shut down */
- BIT(need_recv); /* QUIC connection needs to receive */
- BIT(need_send); /* QUIC connection needs to send */
-};
-
-static void h3_stream_hash_free(void *stream);
-
-static void cf_osslq_ctx_init(struct cf_osslq_ctx *ctx)
-{
- DEBUGASSERT(!ctx->initialized);
- Curl_bufcp_init(&ctx->stream_bufcp, H3_STREAM_CHUNK_SIZE,
- H3_STREAM_POOL_SPARES);
- Curl_hash_offt_init(&ctx->streams, 63, h3_stream_hash_free);
- ctx->initialized = TRUE;
-}
-
-static void cf_osslq_ctx_free(struct cf_osslq_ctx *ctx)
-{
- if(ctx && ctx->initialized) {
- Curl_bufcp_free(&ctx->stream_bufcp);
- Curl_hash_clean(&ctx->streams);
- Curl_hash_destroy(&ctx->streams);
- Curl_ssl_peer_cleanup(&ctx->peer);
- }
- free(ctx);
-}
-
-static void cf_osslq_ctx_close(struct cf_osslq_ctx *ctx)
-{
- struct cf_call_data save = ctx->call_data;
-
- cf_osslq_h3conn_cleanup(&ctx->h3);
- Curl_vquic_tls_cleanup(&ctx->tls);
- vquic_ctx_free(&ctx->q);
- ctx->call_data = save;
-}
-
-static CURLcode cf_osslq_shutdown(struct Curl_cfilter *cf,
- struct Curl_easy *data, bool *done)
-{
- struct cf_osslq_ctx *ctx = cf->ctx;
- struct cf_call_data save;
- CURLcode result = CURLE_OK;
- int rc;
-
- CF_DATA_SAVE(save, cf, data);
-
- if(cf->shutdown || ctx->protocol_shutdown) {
- *done = TRUE;
- return CURLE_OK;
- }
-
- CF_DATA_SAVE(save, cf, data);
- *done = FALSE;
- ctx->need_send = FALSE;
- ctx->need_recv = FALSE;
-
- rc = SSL_shutdown_ex(ctx->tls.ossl.ssl,
- SSL_SHUTDOWN_FLAG_NO_BLOCK, NULL, 0);
- if(rc == 0) { /* ongoing */
- CURL_TRC_CF(data, cf, "shutdown ongoing");
- ctx->need_recv = TRUE;
- goto out;
- }
- else if(rc == 1) { /* done */
- CURL_TRC_CF(data, cf, "shutdown finished");
- *done = TRUE;
- goto out;
- }
- else {
- long sslerr;
- char err_buffer[256];
- int err = SSL_get_error(ctx->tls.ossl.ssl, rc);
-
- switch(err) {
- case SSL_ERROR_NONE:
- case SSL_ERROR_ZERO_RETURN:
- CURL_TRC_CF(data, cf, "shutdown not received, but closed");
- *done = TRUE;
- goto out;
- case SSL_ERROR_WANT_READ:
- /* SSL has send its notify and now wants to read the reply
- * from the server. We are not really interested in that. */
- CURL_TRC_CF(data, cf, "shutdown sent, want receive");
- ctx->need_recv = TRUE;
- goto out;
- case SSL_ERROR_WANT_WRITE:
- CURL_TRC_CF(data, cf, "shutdown send blocked");
- ctx->need_send = TRUE;
- goto out;
- default:
- /* We give up on this. */
- sslerr = ERR_get_error();
- CURL_TRC_CF(data, cf, "shutdown, ignore recv error: '%s', errno %d",
- (sslerr ?
- osslq_strerror(sslerr, err_buffer, sizeof(err_buffer)) :
- osslq_SSL_ERROR_to_str(err)),
- SOCKERRNO);
- *done = TRUE;
- result = CURLE_OK;
- goto out;
- }
- }
-out:
- CF_DATA_RESTORE(cf, save);
- return result;
-}
-
-static void cf_osslq_close(struct Curl_cfilter *cf, struct Curl_easy *data)
-{
- struct cf_osslq_ctx *ctx = cf->ctx;
- struct cf_call_data save;
-
- CF_DATA_SAVE(save, cf, data);
- if(ctx && ctx->tls.ossl.ssl) {
- CURL_TRC_CF(data, cf, "cf_osslq_close()");
- if(!cf->shutdown && !ctx->protocol_shutdown) {
- /* last best effort, which OpenSSL calls a "rapid" shutdown. */
- SSL_shutdown_ex(ctx->tls.ossl.ssl,
- (SSL_SHUTDOWN_FLAG_NO_BLOCK | SSL_SHUTDOWN_FLAG_RAPID),
- NULL, 0);
- }
- cf_osslq_ctx_close(ctx);
- }
-
- cf->connected = FALSE;
- CF_DATA_RESTORE(cf, save);
-}
-
-static void cf_osslq_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
-{
- struct cf_osslq_ctx *ctx = cf->ctx;
- struct cf_call_data save;
-
- CF_DATA_SAVE(save, cf, data);
- CURL_TRC_CF(data, cf, "destroy");
- if(ctx) {
- CURL_TRC_CF(data, cf, "cf_osslq_destroy()");
- if(ctx->tls.ossl.ssl)
- cf_osslq_ctx_close(ctx);
- cf_osslq_ctx_free(ctx);
- }
- cf->ctx = NULL;
- /* No CF_DATA_RESTORE(cf, save) possible */
- (void)save;
-}
-
-static CURLcode cf_osslq_h3conn_add_stream(struct cf_osslq_h3conn *h3,
- SSL *stream_ssl,
- struct Curl_cfilter *cf,
- struct Curl_easy *data)
-{
- struct cf_osslq_ctx *ctx = cf->ctx;
- curl_int64_t stream_id = (curl_int64_t)SSL_get_stream_id(stream_ssl);
-
- if(h3->remote_ctrl_n >= ARRAYSIZE(h3->remote_ctrl)) {
- /* rejected, we are full */
- CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] rejecting remote stream",
- stream_id);
- SSL_free(stream_ssl);
- return CURLE_FAILED_INIT;
- }
- switch(SSL_get_stream_type(stream_ssl)) {
- case SSL_STREAM_TYPE_READ: {
- struct cf_osslq_stream *nstream = &h3->remote_ctrl[h3->remote_ctrl_n++];
- nstream->id = stream_id;
- nstream->ssl = stream_ssl;
- Curl_bufq_initp(&nstream->recvbuf, &ctx->stream_bufcp, 1, BUFQ_OPT_NONE);
- CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] accepted remote uni stream",
- stream_id);
- break;
- }
- default:
- CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] reject remote non-uni-read"
- " stream", stream_id);
- SSL_free(stream_ssl);
- return CURLE_FAILED_INIT;
- }
- return CURLE_OK;
-
-}
-
-static CURLcode cf_osslq_ssl_err(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- int detail, CURLcode def_result)
-{
- struct cf_osslq_ctx *ctx = cf->ctx;
- CURLcode result = def_result;
- sslerr_t errdetail;
- char ebuf[256] = "unknown";
- const char *err_descr = ebuf;
- long lerr;
- int lib;
- int reason;
- struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
-
- errdetail = ERR_get_error();
- lib = ERR_GET_LIB(errdetail);
- reason = ERR_GET_REASON(errdetail);
-
- if((lib == ERR_LIB_SSL) &&
- ((reason == SSL_R_CERTIFICATE_VERIFY_FAILED) ||
- (reason == SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED))) {
- result = CURLE_PEER_FAILED_VERIFICATION;
-
- lerr = SSL_get_verify_result(ctx->tls.ossl.ssl);
- if(lerr != X509_V_OK) {
- ssl_config->certverifyresult = lerr;
- msnprintf(ebuf, sizeof(ebuf),
- "SSL certificate problem: %s",
- X509_verify_cert_error_string(lerr));
- }
- else
- err_descr = "SSL certificate verification failed";
- }
-#if defined(SSL_R_TLSV13_ALERT_CERTIFICATE_REQUIRED)
- /* SSL_R_TLSV13_ALERT_CERTIFICATE_REQUIRED is only available on
- OpenSSL version above v1.1.1, not LibreSSL, BoringSSL, or AWS-LC */
- else if((lib == ERR_LIB_SSL) &&
- (reason == SSL_R_TLSV13_ALERT_CERTIFICATE_REQUIRED)) {
- /* If client certificate is required, communicate the
- error to client */
- result = CURLE_SSL_CLIENTCERT;
- osslq_strerror(errdetail, ebuf, sizeof(ebuf));
- }
-#endif
- else if((lib == ERR_LIB_SSL) && (reason == SSL_R_PROTOCOL_IS_SHUTDOWN)) {
- ctx->protocol_shutdown = TRUE;
- err_descr = "QUIC connection has been shut down";
- result = def_result;
- }
- else {
- result = def_result;
- osslq_strerror(errdetail, ebuf, sizeof(ebuf));
- }
-
- /* detail is already set to the SSL error above */
-
- /* If we e.g. use SSLv2 request-method and the server does not like us
- * (RST connection, etc.), OpenSSL gives no explanation whatsoever and
- * the SO_ERROR is also lost.
- */
- if(CURLE_SSL_CONNECT_ERROR == result && errdetail == 0) {
- char extramsg[80]="";
- int sockerr = SOCKERRNO;
- struct ip_quadruple ip;
-
- Curl_cf_socket_peek(cf->next, data, NULL, NULL, &ip);
- if(sockerr && detail == SSL_ERROR_SYSCALL)
- Curl_strerror(sockerr, extramsg, sizeof(extramsg));
- failf(data, "QUIC connect: %s in connection to %s:%d (%s)",
- extramsg[0] ? extramsg : osslq_SSL_ERROR_to_str(detail),
- ctx->peer.dispname, ip.remote_port, ip.remote_ip);
- }
- else {
- /* Could be a CERT problem */
- failf(data, "%s", err_descr);
- }
- return result;
-}
-
-static CURLcode cf_osslq_verify_peer(struct Curl_cfilter *cf,
- struct Curl_easy *data)
-{
- struct cf_osslq_ctx *ctx = cf->ctx;
-
- cf->conn->bits.multiplex = TRUE; /* at least potentially multiplexed */
- cf->conn->httpversion = 30;
-
- return Curl_vquic_tls_verify_peer(&ctx->tls, cf, data, &ctx->peer);
-}
-
-/**
- * All about the H3 internals of a stream
- */
-struct h3_stream_ctx {
- struct cf_osslq_stream s;
- struct bufq sendbuf; /* h3 request body */
- struct bufq recvbuf; /* h3 response body */
- struct h1_req_parser h1; /* h1 request parsing */
- size_t sendbuf_len_in_flight; /* sendbuf amount "in flight" */
- size_t recv_buf_nonflow; /* buffered bytes, not counting for flow control */
- curl_uint64_t error3; /* HTTP/3 stream error code */
- curl_off_t upload_left; /* number of request bytes left to upload */
- curl_off_t download_recvd; /* number of response DATA bytes received */
- int status_code; /* HTTP status code */
- bool resp_hds_complete; /* we have a complete, final response */
- bool closed; /* TRUE on stream close */
- bool reset; /* TRUE on stream reset */
- bool send_closed; /* stream is local closed */
- BIT(quic_flow_blocked); /* stream is blocked by QUIC flow control */
-};
-
-#define H3_STREAM_CTX(ctx,data) ((struct h3_stream_ctx *)(\
- data? Curl_hash_offt_get(&(ctx)->streams, (data)->mid) : NULL))
-
-static void h3_stream_ctx_free(struct h3_stream_ctx *stream)
-{
- cf_osslq_stream_cleanup(&stream->s);
- Curl_bufq_free(&stream->sendbuf);
- Curl_bufq_free(&stream->recvbuf);
- Curl_h1_req_parse_free(&stream->h1);
- free(stream);
-}
-
-static void h3_stream_hash_free(void *stream)
-{
- DEBUGASSERT(stream);
- h3_stream_ctx_free((struct h3_stream_ctx *)stream);
-}
-
-static CURLcode h3_data_setup(struct Curl_cfilter *cf,
- struct Curl_easy *data)
-{
- struct cf_osslq_ctx *ctx = cf->ctx;
- struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
-
- if(!data)
- return CURLE_FAILED_INIT;
-
- if(stream)
- return CURLE_OK;
-
- stream = calloc(1, sizeof(*stream));
- if(!stream)
- return CURLE_OUT_OF_MEMORY;
-
- stream->s.id = -1;
- /* on send, we control how much we put into the buffer */
- Curl_bufq_initp(&stream->sendbuf, &ctx->stream_bufcp,
- H3_STREAM_SEND_CHUNKS, BUFQ_OPT_NONE);
- stream->sendbuf_len_in_flight = 0;
- /* on recv, we need a flexible buffer limit since we also write
- * headers to it that are not counted against the nghttp3 flow limits. */
- Curl_bufq_initp(&stream->recvbuf, &ctx->stream_bufcp,
- H3_STREAM_RECV_CHUNKS, BUFQ_OPT_SOFT_LIMIT);
- stream->recv_buf_nonflow = 0;
- Curl_h1_req_parse_init(&stream->h1, H1_PARSE_DEFAULT_MAX_LINE_LEN);
-
- if(!Curl_hash_offt_set(&ctx->streams, data->mid, stream)) {
- h3_stream_ctx_free(stream);
- return CURLE_OUT_OF_MEMORY;
- }
-
- return CURLE_OK;
-}
-
-static void h3_data_done(struct Curl_cfilter *cf, struct Curl_easy *data)
-{
- struct cf_osslq_ctx *ctx = cf->ctx;
- struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
-
- (void)cf;
- if(stream) {
- CURL_TRC_CF(data, cf, "[%"FMT_PRId64"] easy handle is done",
- stream->s.id);
- if(ctx->h3.conn && !stream->closed) {
- nghttp3_conn_shutdown_stream_read(ctx->h3.conn, stream->s.id);
- nghttp3_conn_close_stream(ctx->h3.conn, stream->s.id,
- NGHTTP3_H3_REQUEST_CANCELLED);
- nghttp3_conn_set_stream_user_data(ctx->h3.conn, stream->s.id, NULL);
- stream->closed = TRUE;
- }
-
- Curl_hash_offt_remove(&ctx->streams, data->mid);
- }
-}
-
-static struct cf_osslq_stream *cf_osslq_get_qstream(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- int64_t stream_id)
-{
- struct cf_osslq_ctx *ctx = cf->ctx;
- struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
-
- if(stream && stream->s.id == stream_id) {
- return &stream->s;
- }
- else if(ctx->h3.s_ctrl.id == stream_id) {
- return &ctx->h3.s_ctrl;
- }
- else if(ctx->h3.s_qpack_enc.id == stream_id) {
- return &ctx->h3.s_qpack_enc;
- }
- else if(ctx->h3.s_qpack_dec.id == stream_id) {
- return &ctx->h3.s_qpack_dec;
- }
- else {
- struct Curl_llist_node *e;
- DEBUGASSERT(data->multi);
- for(e = Curl_llist_head(&data->multi->process); e; e = Curl_node_next(e)) {
- struct Curl_easy *sdata = Curl_node_elem(e);
- if(sdata->conn != data->conn)
- continue;
- stream = H3_STREAM_CTX(ctx, sdata);
- if(stream && stream->s.id == stream_id) {
- return &stream->s;
- }
- }
- }
- return NULL;
-}
-
-static void h3_drain_stream(struct Curl_cfilter *cf,
- struct Curl_easy *data)
-{
- struct cf_osslq_ctx *ctx = cf->ctx;
- struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
- unsigned char bits;
-
- (void)cf;
- bits = CURL_CSELECT_IN;
- if(stream && stream->upload_left && !stream->send_closed)
- bits |= CURL_CSELECT_OUT;
- if(data->state.select_bits != bits) {
- data->state.select_bits = bits;
- Curl_expire(data, 0, EXPIRE_RUN_NOW);
- }
-}
-
-static CURLcode h3_data_pause(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- bool pause)
-{
- if(!pause) {
- /* unpaused. make it run again right away */
- h3_drain_stream(cf, data);
- Curl_expire(data, 0, EXPIRE_RUN_NOW);
- }
- return CURLE_OK;
-}
-
-static int cb_h3_stream_close(nghttp3_conn *conn, int64_t stream_id,
- uint64_t app_error_code, void *user_data,
- void *stream_user_data)
-{
- struct Curl_cfilter *cf = user_data;
- struct cf_osslq_ctx *ctx = cf->ctx;
- struct Curl_easy *data = stream_user_data;
- struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
- (void)conn;
- (void)stream_id;
-
- /* we might be called by nghttp3 after we already cleaned up */
- if(!stream)
- return 0;
-
- stream->closed = TRUE;
- stream->error3 = app_error_code;
- if(stream->error3 != NGHTTP3_H3_NO_ERROR) {
- stream->reset = TRUE;
- stream->send_closed = TRUE;
- CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] RESET: error %" FMT_PRIu64,
- stream->s.id, stream->error3);
- }
- else {
- CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] CLOSED", stream->s.id);
- }
- h3_drain_stream(cf, data);
- return 0;
-}
-
-/*
- * write_resp_raw() copies response data in raw format to the `data`'s
- * receive buffer. If not enough space is available, it appends to the
- * `data`'s overflow buffer.
- */
-static CURLcode write_resp_raw(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- const void *mem, size_t memlen,
- bool flow)
-{
- struct cf_osslq_ctx *ctx = cf->ctx;
- struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
- CURLcode result = CURLE_OK;
- ssize_t nwritten;
-
- (void)cf;
- if(!stream) {
- return CURLE_RECV_ERROR;
- }
- nwritten = Curl_bufq_write(&stream->recvbuf, mem, memlen, &result);
- if(nwritten < 0) {
- return result;
- }
-
- if(!flow)
- stream->recv_buf_nonflow += (size_t)nwritten;
-
- if((size_t)nwritten < memlen) {
- /* This MUST not happen. Our recbuf is dimensioned to hold the
- * full max_stream_window and then some for this very reason. */
- DEBUGASSERT(0);
- return CURLE_RECV_ERROR;
- }
- return result;
-}
-
-static int cb_h3_recv_data(nghttp3_conn *conn, int64_t stream3_id,
- const uint8_t *buf, size_t buflen,
- void *user_data, void *stream_user_data)
-{
- struct Curl_cfilter *cf = user_data;
- struct cf_osslq_ctx *ctx = cf->ctx;
- struct Curl_easy *data = stream_user_data;
- struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
- CURLcode result;
-
- (void)conn;
- (void)stream3_id;
-
- if(!stream)
- return NGHTTP3_ERR_CALLBACK_FAILURE;
-
- result = write_resp_raw(cf, data, buf, buflen, TRUE);
- if(result) {
- CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] DATA len=%zu, ERROR %d",
- stream->s.id, buflen, result);
- return NGHTTP3_ERR_CALLBACK_FAILURE;
- }
- stream->download_recvd += (curl_off_t)buflen;
- CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] DATA len=%zu, total=%zd",
- stream->s.id, buflen, stream->download_recvd);
- h3_drain_stream(cf, data);
- return 0;
-}
-
-static int cb_h3_deferred_consume(nghttp3_conn *conn, int64_t stream_id,
- size_t consumed, void *user_data,
- void *stream_user_data)
-{
- struct Curl_cfilter *cf = user_data;
- struct cf_osslq_ctx *ctx = cf->ctx;
- struct Curl_easy *data = stream_user_data;
- struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
-
- (void)conn;
- (void)stream_id;
- if(stream)
- CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] deferred consume %zu bytes",
- stream->s.id, consumed);
- return 0;
-}
-
-static int cb_h3_recv_header(nghttp3_conn *conn, int64_t sid,
- int32_t token, nghttp3_rcbuf *name,
- nghttp3_rcbuf *value, uint8_t flags,
- void *user_data, void *stream_user_data)
-{
- struct Curl_cfilter *cf = user_data;
- curl_int64_t stream_id = sid;
- struct cf_osslq_ctx *ctx = cf->ctx;
- nghttp3_vec h3name = nghttp3_rcbuf_get_buf(name);
- nghttp3_vec h3val = nghttp3_rcbuf_get_buf(value);
- struct Curl_easy *data = stream_user_data;
- struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
- CURLcode result = CURLE_OK;
- (void)conn;
- (void)stream_id;
- (void)token;
- (void)flags;
- (void)cf;
-
- /* we might have cleaned up this transfer already */
- if(!stream)
- return 0;
-
- if(token == NGHTTP3_QPACK_TOKEN__STATUS) {
- char line[14]; /* status line is always 13 characters long */
- size_t ncopy;
-
- result = Curl_http_decode_status(&stream->status_code,
- (const char *)h3val.base, h3val.len);
- if(result)
- return -1;
- ncopy = msnprintf(line, sizeof(line), "HTTP/3 %03d \r\n",
- stream->status_code);
- CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] status: %s", stream_id, line);
- result = write_resp_raw(cf, data, line, ncopy, FALSE);
- if(result) {
- return -1;
- }
- }
- else {
- /* store as an HTTP1-style header */
- CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] header: %.*s: %.*s",
- stream_id, (int)h3name.len, h3name.base,
- (int)h3val.len, h3val.base);
- result = write_resp_raw(cf, data, h3name.base, h3name.len, FALSE);
- if(result) {
- return -1;
- }
- result = write_resp_raw(cf, data, ": ", 2, FALSE);
- if(result) {
- return -1;
- }
- result = write_resp_raw(cf, data, h3val.base, h3val.len, FALSE);
- if(result) {
- return -1;
- }
- result = write_resp_raw(cf, data, "\r\n", 2, FALSE);
- if(result) {
- return -1;
- }
- }
- return 0;
-}
-
-static int cb_h3_end_headers(nghttp3_conn *conn, int64_t sid,
- int fin, void *user_data, void *stream_user_data)
-{
- struct Curl_cfilter *cf = user_data;
- struct cf_osslq_ctx *ctx = cf->ctx;
- struct Curl_easy *data = stream_user_data;
- curl_int64_t stream_id = sid;
- struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
- CURLcode result = CURLE_OK;
- (void)conn;
- (void)stream_id;
- (void)fin;
- (void)cf;
-
- if(!stream)
- return 0;
- /* add a CRLF only if we have received some headers */
- result = write_resp_raw(cf, data, "\r\n", 2, FALSE);
- if(result) {
- return -1;
- }
-
- CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] end_headers, status=%d",
- stream_id, stream->status_code);
- if(stream->status_code / 100 != 1) {
- stream->resp_hds_complete = TRUE;
- }
- h3_drain_stream(cf, data);
- return 0;
-}
-
-static int cb_h3_stop_sending(nghttp3_conn *conn, int64_t sid,
- uint64_t app_error_code, void *user_data,
- void *stream_user_data)
-{
- struct Curl_cfilter *cf = user_data;
- struct cf_osslq_ctx *ctx = cf->ctx;
- struct Curl_easy *data = stream_user_data;
- curl_int64_t stream_id = sid;
- struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
- (void)conn;
- (void)app_error_code;
-
- if(!stream || !stream->s.ssl)
- return 0;
-
- CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] stop_sending", stream_id);
- cf_osslq_stream_close(&stream->s);
- return 0;
-}
-
-static int cb_h3_reset_stream(nghttp3_conn *conn, int64_t sid,
- uint64_t app_error_code, void *user_data,
- void *stream_user_data) {
- struct Curl_cfilter *cf = user_data;
- struct cf_osslq_ctx *ctx = cf->ctx;
- struct Curl_easy *data = stream_user_data;
- curl_int64_t stream_id = sid;
- struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
- int rv;
- (void)conn;
-
- if(stream && stream->s.ssl) {
- SSL_STREAM_RESET_ARGS args = {0};
- args.quic_error_code = app_error_code;
- rv = !SSL_stream_reset(stream->s.ssl, &args, sizeof(args));
- CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] reset -> %d", stream_id, rv);
- if(!rv) {
- return NGHTTP3_ERR_CALLBACK_FAILURE;
- }
- }
- return 0;
-}
-
-static nghttp3_ssize
-cb_h3_read_req_body(nghttp3_conn *conn, int64_t stream_id,
- nghttp3_vec *vec, size_t veccnt,
- uint32_t *pflags, void *user_data,
- void *stream_user_data)
-{
- struct Curl_cfilter *cf = user_data;
- struct cf_osslq_ctx *ctx = cf->ctx;
- struct Curl_easy *data = stream_user_data;
- struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
- ssize_t nwritten = 0;
- size_t nvecs = 0;
- (void)cf;
- (void)conn;
- (void)stream_id;
- (void)user_data;
- (void)veccnt;
-
- if(!stream)
- return NGHTTP3_ERR_CALLBACK_FAILURE;
- /* nghttp3 keeps references to the sendbuf data until it is ACKed
- * by the server (see `cb_h3_acked_req_body()` for updates).
- * `sendbuf_len_in_flight` is the amount of bytes in `sendbuf`
- * that we have already passed to nghttp3, but which have not been
- * ACKed yet.
- * Any amount beyond `sendbuf_len_in_flight` we need still to pass
- * to nghttp3. Do that now, if we can. */
- if(stream->sendbuf_len_in_flight < Curl_bufq_len(&stream->sendbuf)) {
- nvecs = 0;
- while(nvecs < veccnt &&
- Curl_bufq_peek_at(&stream->sendbuf,
- stream->sendbuf_len_in_flight,
- (const unsigned char **)&vec[nvecs].base,
- &vec[nvecs].len)) {
- stream->sendbuf_len_in_flight += vec[nvecs].len;
- nwritten += vec[nvecs].len;
- ++nvecs;
- }
- DEBUGASSERT(nvecs > 0); /* we SHOULD have been be able to peek */
- }
-
- if(nwritten > 0 && stream->upload_left != -1)
- stream->upload_left -= nwritten;
-
- /* When we stopped sending and everything in `sendbuf` is "in flight",
- * we are at the end of the request body. */
- if(stream->upload_left == 0) {
- *pflags = NGHTTP3_DATA_FLAG_EOF;
- stream->send_closed = TRUE;
- }
- else if(!nwritten) {
- /* Not EOF, and nothing to give, we signal WOULDBLOCK. */
- CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] read req body -> AGAIN",
- stream->s.id);
- return NGHTTP3_ERR_WOULDBLOCK;
- }
-
- CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] read req body -> "
- "%d vecs%s with %zu (buffered=%zu, left=%" FMT_OFF_T ")",
- stream->s.id, (int)nvecs,
- *pflags == NGHTTP3_DATA_FLAG_EOF?" EOF":"",
- nwritten, Curl_bufq_len(&stream->sendbuf),
- stream->upload_left);
- return (nghttp3_ssize)nvecs;
-}
-
-static int cb_h3_acked_stream_data(nghttp3_conn *conn, int64_t stream_id,
- uint64_t datalen, void *user_data,
- void *stream_user_data)
-{
- struct Curl_cfilter *cf = user_data;
- struct cf_osslq_ctx *ctx = cf->ctx;
- struct Curl_easy *data = stream_user_data;
- struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
- size_t skiplen;
-
- (void)cf;
- if(!stream)
- return 0;
- /* The server acknowledged `datalen` of bytes from our request body.
- * This is a delta. We have kept this data in `sendbuf` for
- * re-transmissions and can free it now. */
- if(datalen >= (uint64_t)stream->sendbuf_len_in_flight)
- skiplen = stream->sendbuf_len_in_flight;
- else
- skiplen = (size_t)datalen;
- Curl_bufq_skip(&stream->sendbuf, skiplen);
- stream->sendbuf_len_in_flight -= skiplen;
-
- /* Resume upload processing if we have more data to send */
- if(stream->sendbuf_len_in_flight < Curl_bufq_len(&stream->sendbuf)) {
- int rv = nghttp3_conn_resume_stream(conn, stream_id);
- if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) {
- return NGHTTP3_ERR_CALLBACK_FAILURE;
- }
- }
- return 0;
-}
-
-static nghttp3_callbacks ngh3_callbacks = {
- cb_h3_acked_stream_data,
- cb_h3_stream_close,
- cb_h3_recv_data,
- cb_h3_deferred_consume,
- NULL, /* begin_headers */
- cb_h3_recv_header,
- cb_h3_end_headers,
- NULL, /* begin_trailers */
- cb_h3_recv_header,
- NULL, /* end_trailers */
- cb_h3_stop_sending,
- NULL, /* end_stream */
- cb_h3_reset_stream,
- NULL, /* shutdown */
- NULL /* recv_settings */
-};
-
-static CURLcode cf_osslq_h3conn_init(struct cf_osslq_ctx *ctx, SSL *conn,
- void *user_data)
-{
- struct cf_osslq_h3conn *h3 = &ctx->h3;
- CURLcode result;
- int rc;
-
- nghttp3_settings_default(&h3->settings);
- rc = nghttp3_conn_client_new(&h3->conn,
- &ngh3_callbacks,
- &h3->settings,
- nghttp3_mem_default(),
- user_data);
- if(rc) {
- result = CURLE_OUT_OF_MEMORY;
- goto out;
- }
-
- result = cf_osslq_stream_open(&h3->s_ctrl, conn,
- SSL_STREAM_FLAG_ADVANCE|SSL_STREAM_FLAG_UNI,
- &ctx->stream_bufcp, NULL);
- if(result) {
- result = CURLE_QUIC_CONNECT_ERROR;
- goto out;
- }
- result = cf_osslq_stream_open(&h3->s_qpack_enc, conn,
- SSL_STREAM_FLAG_ADVANCE|SSL_STREAM_FLAG_UNI,
- &ctx->stream_bufcp, NULL);
- if(result) {
- result = CURLE_QUIC_CONNECT_ERROR;
- goto out;
- }
- result = cf_osslq_stream_open(&h3->s_qpack_dec, conn,
- SSL_STREAM_FLAG_ADVANCE|SSL_STREAM_FLAG_UNI,
- &ctx->stream_bufcp, NULL);
- if(result) {
- result = CURLE_QUIC_CONNECT_ERROR;
- goto out;
- }
-
- rc = nghttp3_conn_bind_control_stream(h3->conn, h3->s_ctrl.id);
- if(rc) {
- result = CURLE_QUIC_CONNECT_ERROR;
- goto out;
- }
- rc = nghttp3_conn_bind_qpack_streams(h3->conn, h3->s_qpack_enc.id,
- h3->s_qpack_dec.id);
- if(rc) {
- result = CURLE_QUIC_CONNECT_ERROR;
- goto out;
- }
-
- result = CURLE_OK;
-out:
- return result;
-}
-
-static CURLcode cf_osslq_ctx_start(struct Curl_cfilter *cf,
- struct Curl_easy *data)
-{
- struct cf_osslq_ctx *ctx = cf->ctx;
- CURLcode result;
- int rv;
- const struct Curl_sockaddr_ex *peer_addr = NULL;
- BIO *bio = NULL;
- BIO_ADDR *baddr = NULL;
-
- DEBUGASSERT(ctx->initialized);
- result = Curl_ssl_peer_init(&ctx->peer, cf, TRNSPRT_QUIC);
- if(result)
- goto out;
-
-#define H3_ALPN "\x2h3"
- result = Curl_vquic_tls_init(&ctx->tls, cf, data, &ctx->peer,
- H3_ALPN, sizeof(H3_ALPN) - 1,
- NULL, NULL, NULL);
- if(result)
- goto out;
-
- result = vquic_ctx_init(&ctx->q);
- if(result)
- goto out;
-
- result = CURLE_QUIC_CONNECT_ERROR;
- Curl_cf_socket_peek(cf->next, data, &ctx->q.sockfd, &peer_addr, NULL);
- if(!peer_addr)
- goto out;
-
- ctx->q.local_addrlen = sizeof(ctx->q.local_addr);
- rv = getsockname(ctx->q.sockfd, (struct sockaddr *)&ctx->q.local_addr,
- &ctx->q.local_addrlen);
- if(rv == -1)
- goto out;
-
- result = make_bio_addr(&baddr, peer_addr);
- if(result) {
- failf(data, "error creating BIO_ADDR from sockaddr");
- goto out;
- }
-
- /* Type conversions, see #12861: OpenSSL wants an `int`, but on 64-bit
- * Win32 systems, Microsoft defines SOCKET as `unsigned long long`.
- */
-#if defined(_WIN32) && !defined(__LWIP_OPT_H__) && !defined(LWIP_HDR_OPT_H)
- if(ctx->q.sockfd > INT_MAX) {
- failf(data, "Windows socket identifier larger than MAX_INT, "
- "unable to set in OpenSSL dgram API.");
- result = CURLE_QUIC_CONNECT_ERROR;
- goto out;
- }
- bio = BIO_new_dgram((int)ctx->q.sockfd, BIO_NOCLOSE);
-#else
- bio = BIO_new_dgram(ctx->q.sockfd, BIO_NOCLOSE);
-#endif
- if(!bio) {
- result = CURLE_OUT_OF_MEMORY;
- goto out;
- }
-
- if(!SSL_set1_initial_peer_addr(ctx->tls.ossl.ssl, baddr)) {
- failf(data, "failed to set the initial peer address");
- result = CURLE_FAILED_INIT;
- goto out;
- }
- if(!SSL_set_blocking_mode(ctx->tls.ossl.ssl, 0)) {
- failf(data, "failed to turn off blocking mode");
- result = CURLE_FAILED_INIT;
- goto out;
- }
-
-#ifdef SSL_VALUE_QUIC_IDLE_TIMEOUT
- /* Added in OpenSSL v3.3.x */
- if(!SSL_set_feature_request_uint(ctx->tls.ossl.ssl,
- SSL_VALUE_QUIC_IDLE_TIMEOUT,
- CURL_QUIC_MAX_IDLE_MS)) {
- CURL_TRC_CF(data, cf, "error setting idle timeout, ");
- result = CURLE_FAILED_INIT;
- goto out;
- }
-#endif
-
- SSL_set_bio(ctx->tls.ossl.ssl, bio, bio);
- bio = NULL;
- SSL_set_connect_state(ctx->tls.ossl.ssl);
- SSL_set_incoming_stream_policy(ctx->tls.ossl.ssl,
- SSL_INCOMING_STREAM_POLICY_ACCEPT, 0);
- /* setup the H3 things on top of the QUIC connection */
- result = cf_osslq_h3conn_init(ctx, ctx->tls.ossl.ssl, cf);
-
-out:
- if(bio)
- BIO_free(bio);
- if(baddr)
- BIO_ADDR_free(baddr);
- CURL_TRC_CF(data, cf, "QUIC tls init -> %d", result);
- return result;
-}
-
-struct h3_quic_recv_ctx {
- struct Curl_cfilter *cf;
- struct Curl_easy *data;
- struct cf_osslq_stream *s;
-};
-
-static ssize_t h3_quic_recv(void *reader_ctx,
- unsigned char *buf, size_t len,
- CURLcode *err)
-{
- struct h3_quic_recv_ctx *x = reader_ctx;
- size_t nread;
- int rv;
-
- *err = CURLE_OK;
- rv = SSL_read_ex(x->s->ssl, buf, len, &nread);
- if(rv <= 0) {
- int detail = SSL_get_error(x->s->ssl, rv);
- if(detail == SSL_ERROR_WANT_READ || detail == SSL_ERROR_WANT_WRITE) {
- *err = CURLE_AGAIN;
- return -1;
- }
- else if(detail == SSL_ERROR_ZERO_RETURN) {
- CURL_TRC_CF(x->data, x->cf, "[%" FMT_PRId64 "] h3_quic_recv -> EOS",
- x->s->id);
- x->s->recvd_eos = TRUE;
- return 0;
- }
- else if(SSL_get_stream_read_state(x->s->ssl) ==
- SSL_STREAM_STATE_RESET_REMOTE) {
- uint64_t app_error_code = NGHTTP3_H3_NO_ERROR;
- SSL_get_stream_read_error_code(x->s->ssl, &app_error_code);
- CURL_TRC_CF(x->data, x->cf, "[%" FMT_PRId64 "] h3_quic_recv -> RESET, "
- "rv=%d, app_err=%" FMT_PRIu64,
- x->s->id, rv, (curl_uint64_t)app_error_code);
- if(app_error_code != NGHTTP3_H3_NO_ERROR) {
- x->s->reset = TRUE;
- }
- x->s->recvd_eos = TRUE;
- return 0;
- }
- else {
- *err = cf_osslq_ssl_err(x->cf, x->data, detail, CURLE_RECV_ERROR);
- return -1;
- }
- }
- return (ssize_t)nread;
-}
-
-static CURLcode cf_osslq_stream_recv(struct cf_osslq_stream *s,
- struct Curl_cfilter *cf,
- struct Curl_easy *data)
-{
- struct cf_osslq_ctx *ctx = cf->ctx;
- CURLcode result = CURLE_OK;
- ssize_t nread;
- struct h3_quic_recv_ctx x;
- int rv, eagain = FALSE;
- size_t total_recv_len = 0;
-
- DEBUGASSERT(s);
- if(s->closed)
- return CURLE_OK;
-
- x.cf = cf;
- x.data = data;
- x.s = s;
- while(s->ssl && !s->closed && !eagain &&
- (total_recv_len < H3_STREAM_CHUNK_SIZE)) {
- if(Curl_bufq_is_empty(&s->recvbuf) && !s->recvd_eos) {
- while(!eagain && !s->recvd_eos && !Curl_bufq_is_full(&s->recvbuf)) {
- nread = Curl_bufq_sipn(&s->recvbuf, 0, h3_quic_recv, &x, &result);
- if(nread < 0) {
- if(result != CURLE_AGAIN)
- goto out;
- result = CURLE_OK;
- eagain = TRUE;
- }
- }
- }
-
- /* Forward what we have to nghttp3 */
- if(!Curl_bufq_is_empty(&s->recvbuf)) {
- const unsigned char *buf;
- size_t blen;
-
- while(Curl_bufq_peek(&s->recvbuf, &buf, &blen)) {
- nread = nghttp3_conn_read_stream(ctx->h3.conn, s->id,
- buf, blen, 0);
- CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] forward %zu bytes "
- "to nghttp3 -> %zd", s->id, blen, nread);
- if(nread < 0) {
- failf(data, "nghttp3_conn_read_stream(len=%zu) error: %s",
- blen, nghttp3_strerror((int)nread));
- result = CURLE_RECV_ERROR;
- goto out;
- }
- /* success, `nread` is the flow for QUIC to count as "consumed",
- * not sure how that will work with OpenSSL. Anyways, without error,
- * all data that we passed is not owned by nghttp3. */
- Curl_bufq_skip(&s->recvbuf, blen);
- total_recv_len += blen;
- }
- }
-
- /* When we forwarded everything, handle RESET/EOS */
- if(Curl_bufq_is_empty(&s->recvbuf) && !s->closed) {
- result = CURLE_OK;
- if(s->reset) {
- uint64_t app_error;
- if(!SSL_get_stream_read_error_code(s->ssl, &app_error)) {
- failf(data, "SSL_get_stream_read_error_code returned error");
- result = CURLE_RECV_ERROR;
- goto out;
- }
- rv = nghttp3_conn_close_stream(ctx->h3.conn, s->id, app_error);
- s->closed = TRUE;
- if(rv < 0 && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) {
- failf(data, "nghttp3_conn_close_stream returned error: %s",
- nghttp3_strerror(rv));
- result = CURLE_RECV_ERROR;
- goto out;
- }
- }
- else if(s->recvd_eos) {
- rv = nghttp3_conn_close_stream(ctx->h3.conn, s->id,
- NGHTTP3_H3_NO_ERROR);
- s->closed = TRUE;
- CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] close nghttp3 stream -> %d",
- s->id, rv);
- if(rv < 0 && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) {
- failf(data, "nghttp3_conn_close_stream returned error: %s",
- nghttp3_strerror(rv));
- result = CURLE_RECV_ERROR;
- goto out;
- }
- }
- }
- }
-out:
- if(result)
- CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] cf_osslq_stream_recv -> %d",
- s->id, result);
- return result;
-}
-
-static CURLcode cf_progress_ingress(struct Curl_cfilter *cf,
- struct Curl_easy *data)
-{
- struct cf_osslq_ctx *ctx = cf->ctx;
- CURLcode result = CURLE_OK;
-
- if(!ctx->tls.ossl.ssl)
- goto out;
-
- ERR_clear_error();
-
- /* 1. Check for new incoming streams */
- while(1) {
- SSL *snew = SSL_accept_stream(ctx->tls.ossl.ssl,
- SSL_ACCEPT_STREAM_NO_BLOCK);
- if(!snew)
- break;
-
- (void)cf_osslq_h3conn_add_stream(&ctx->h3, snew, cf, data);
- }
-
- if(!SSL_handle_events(ctx->tls.ossl.ssl)) {
- int detail = SSL_get_error(ctx->tls.ossl.ssl, 0);
- result = cf_osslq_ssl_err(cf, data, detail, CURLE_RECV_ERROR);
- }
-
- if(ctx->h3.conn) {
- size_t i;
- for(i = 0; i < ctx->h3.remote_ctrl_n; ++i) {
- result = cf_osslq_stream_recv(&ctx->h3.remote_ctrl[i], cf, data);
- if(result)
- goto out;
- }
- }
-
- if(ctx->h3.conn) {
- struct Curl_llist_node *e;
- struct h3_stream_ctx *stream;
- /* PULL all open streams */
- DEBUGASSERT(data->multi);
- for(e = Curl_llist_head(&data->multi->process); e; e = Curl_node_next(e)) {
- struct Curl_easy *sdata = Curl_node_elem(e);
- if(sdata->conn == data->conn && CURL_WANT_RECV(sdata)) {
- stream = H3_STREAM_CTX(ctx, sdata);
- if(stream && !stream->closed &&
- !Curl_bufq_is_full(&stream->recvbuf)) {
- result = cf_osslq_stream_recv(&stream->s, cf, sdata);
- if(result)
- goto out;
- }
- }
- }
- }
-
-out:
- CURL_TRC_CF(data, cf, "progress_ingress -> %d", result);
- return result;
-}
-
-/* Iterate over all streams and check if blocked can be unblocked */
-static CURLcode cf_osslq_check_and_unblock(struct Curl_cfilter *cf,
- struct Curl_easy *data)
-{
- struct cf_osslq_ctx *ctx = cf->ctx;
- struct h3_stream_ctx *stream;
-
- if(ctx->h3.conn) {
- struct Curl_llist_node *e;
- for(e = Curl_llist_head(&data->multi->process); e; e = Curl_node_next(e)) {
- struct Curl_easy *sdata = Curl_node_elem(e);
- if(sdata->conn == data->conn) {
- stream = H3_STREAM_CTX(ctx, sdata);
- if(stream && stream->s.ssl && stream->s.send_blocked &&
- !SSL_want_write(stream->s.ssl)) {
- nghttp3_conn_unblock_stream(ctx->h3.conn, stream->s.id);
- stream->s.send_blocked = FALSE;
- h3_drain_stream(cf, sdata);
- CURL_TRC_CF(sdata, cf, "unblocked");
- }
- }
- }
- }
- return CURLE_OK;
-}
-
-static CURLcode h3_send_streams(struct Curl_cfilter *cf,
- struct Curl_easy *data)
-{
- struct cf_osslq_ctx *ctx = cf->ctx;
- CURLcode result = CURLE_OK;
-
- if(!ctx->tls.ossl.ssl || !ctx->h3.conn)
- goto out;
-
- for(;;) {
- struct cf_osslq_stream *s = NULL;
- nghttp3_vec vec[16];
- nghttp3_ssize n, i;
- int64_t stream_id;
- size_t written;
- int eos, ok, rv;
- size_t total_len, acked_len = 0;
- bool blocked = FALSE, eos_written = FALSE;
-
- n = nghttp3_conn_writev_stream(ctx->h3.conn, &stream_id, &eos,
- vec, ARRAYSIZE(vec));
- if(n < 0) {
- failf(data, "nghttp3_conn_writev_stream returned error: %s",
- nghttp3_strerror((int)n));
- result = CURLE_SEND_ERROR;
- goto out;
- }
- if(stream_id < 0) {
- result = CURLE_OK;
- goto out;
- }
-
- /* Get the stream for this data */
- s = cf_osslq_get_qstream(cf, data, stream_id);
- if(!s) {
- failf(data, "nghttp3_conn_writev_stream gave unknown stream %"
- FMT_PRId64, (curl_int64_t)stream_id);
- result = CURLE_SEND_ERROR;
- goto out;
- }
- /* Now write the data to the stream's SSL*, it may not all fit! */
- DEBUGASSERT(s->id == stream_id);
- for(i = 0, total_len = 0; i < n; ++i) {
- total_len += vec[i].len;
- }
- for(i = 0; (i < n) && !blocked; ++i) {
- /* Without stream->s.ssl, we closed that already, so
- * pretend the write did succeed. */
- uint64_t flags = (eos && ((i + 1) == n))? SSL_WRITE_FLAG_CONCLUDE : 0;
- written = vec[i].len;
- ok = !s->ssl || SSL_write_ex2(s->ssl, vec[i].base, vec[i].len, flags,
- &written);
- if(ok && flags & SSL_WRITE_FLAG_CONCLUDE)
- eos_written = TRUE;
- if(ok) {
- /* As OpenSSL buffers the data, we count this as acknowledged
- * from nghttp3's point of view */
- CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] send %zu bytes to QUIC ok",
- s->id, vec[i].len);
- acked_len += vec[i].len;
- }
- else {
- int detail = SSL_get_error(s->ssl, 0);
- switch(detail) {
- case SSL_ERROR_WANT_WRITE:
- case SSL_ERROR_WANT_READ:
- /* QUIC blocked us from writing more */
- CURL_TRC_CF(data, cf, "[%"FMT_PRId64 "] send %zu bytes to "
- "QUIC blocked", s->id, vec[i].len);
- written = 0;
- nghttp3_conn_block_stream(ctx->h3.conn, s->id);
- s->send_blocked = blocked = TRUE;
- break;
- default:
- failf(data, "[%"FMT_PRId64 "] send %zu bytes to QUIC, SSL error %d",
- s->id, vec[i].len, detail);
- result = cf_osslq_ssl_err(cf, data, detail, CURLE_HTTP3);
- goto out;
- }
- }
- }
-
- if(acked_len > 0 || (eos && !s->send_blocked)) {
- /* Since QUIC buffers the data written internally, we can tell
- * nghttp3 that it can move forward on it */
- ctx->q.last_io = Curl_now();
- rv = nghttp3_conn_add_write_offset(ctx->h3.conn, s->id, acked_len);
- if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) {
- failf(data, "nghttp3_conn_add_write_offset returned error: %s\n",
- nghttp3_strerror(rv));
- result = CURLE_SEND_ERROR;
- goto out;
- }
- rv = nghttp3_conn_add_ack_offset(ctx->h3.conn, s->id, acked_len);
- if(rv && rv != NGHTTP3_ERR_STREAM_NOT_FOUND) {
- failf(data, "nghttp3_conn_add_ack_offset returned error: %s\n",
- nghttp3_strerror(rv));
- result = CURLE_SEND_ERROR;
- goto out;
- }
- CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] forwarded %zu/%zu h3 bytes "
- "to QUIC, eos=%d", s->id, acked_len, total_len, eos);
- }
-
- if(eos && !s->send_blocked && !eos_written) {
- /* wrote everything and H3 indicates end of stream */
- CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] closing QUIC stream", s->id);
- SSL_stream_conclude(s->ssl, 0);
- }
- }
-
-out:
- CURL_TRC_CF(data, cf, "h3_send_streams -> %d", result);
- return result;
-}
-
-static CURLcode cf_progress_egress(struct Curl_cfilter *cf,
- struct Curl_easy *data)
-{
- struct cf_osslq_ctx *ctx = cf->ctx;
- CURLcode result = CURLE_OK;
-
- if(!ctx->tls.ossl.ssl)
- goto out;
-
- ERR_clear_error();
- result = h3_send_streams(cf, data);
- if(result)
- goto out;
-
- if(!SSL_handle_events(ctx->tls.ossl.ssl)) {
- int detail = SSL_get_error(ctx->tls.ossl.ssl, 0);
- result = cf_osslq_ssl_err(cf, data, detail, CURLE_SEND_ERROR);
- }
-
- result = cf_osslq_check_and_unblock(cf, data);
-
-out:
- CURL_TRC_CF(data, cf, "progress_egress -> %d", result);
- return result;
-}
-
-static CURLcode check_and_set_expiry(struct Curl_cfilter *cf,
- struct Curl_easy *data)
-{
- struct cf_osslq_ctx *ctx = cf->ctx;
- CURLcode result = CURLE_OK;
- struct timeval tv;
- timediff_t timeoutms;
- int is_infinite = TRUE;
-
- if(ctx->tls.ossl.ssl &&
- SSL_get_event_timeout(ctx->tls.ossl.ssl, &tv, &is_infinite) &&
- !is_infinite) {
- timeoutms = curlx_tvtoms(&tv);
- /* QUIC want to be called again latest at the returned timeout */
- if(timeoutms <= 0) {
- result = cf_progress_ingress(cf, data);
- if(result)
- goto out;
- result = cf_progress_egress(cf, data);
- if(result)
- goto out;
- if(SSL_get_event_timeout(ctx->tls.ossl.ssl, &tv, &is_infinite)) {
- timeoutms = curlx_tvtoms(&tv);
- }
- }
- if(!is_infinite) {
- Curl_expire(data, timeoutms, EXPIRE_QUIC);
- CURL_TRC_CF(data, cf, "QUIC expiry in %ldms", (long)timeoutms);
- }
- }
-out:
- return result;
-}
-
-static CURLcode cf_osslq_connect(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- bool blocking, bool *done)
-{
- struct cf_osslq_ctx *ctx = cf->ctx;
- CURLcode result = CURLE_OK;
- struct cf_call_data save;
- struct curltime now;
- int err;
-
- if(cf->connected) {
- *done = TRUE;
- return CURLE_OK;
- }
-
- /* Connect the UDP filter first */
- if(!cf->next->connected) {
- result = Curl_conn_cf_connect(cf->next, data, blocking, done);
- if(result || !*done)
- return result;
- }
-
- *done = FALSE;
- now = Curl_now();
- CF_DATA_SAVE(save, cf, data);
-
- if(!ctx->tls.ossl.ssl) {
- ctx->started_at = now;
- result = cf_osslq_ctx_start(cf, data);
- if(result)
- goto out;
- }
-
- if(!ctx->got_first_byte) {
- int readable = SOCKET_READABLE(ctx->q.sockfd, 0);
- if(readable > 0 && (readable & CURL_CSELECT_IN)) {
- ctx->got_first_byte = TRUE;
- ctx->first_byte_at = Curl_now();
- }
- }
-
- ERR_clear_error();
- err = SSL_do_handshake(ctx->tls.ossl.ssl);
-
- if(err == 1) {
- /* connected */
- ctx->handshake_at = now;
- ctx->q.last_io = now;
- CURL_TRC_CF(data, cf, "handshake complete after %dms",
- (int)Curl_timediff(now, ctx->started_at));
- result = cf_osslq_verify_peer(cf, data);
- if(!result) {
- CURL_TRC_CF(data, cf, "peer verified");
- cf->connected = TRUE;
- cf->conn->alpn = CURL_HTTP_VERSION_3;
- *done = TRUE;
- connkeep(cf->conn, "HTTP/3 default");
- }
- }
- else {
- int detail = SSL_get_error(ctx->tls.ossl.ssl, err);
- switch(detail) {
- case SSL_ERROR_WANT_READ:
- ctx->q.last_io = now;
- CURL_TRC_CF(data, cf, "QUIC SSL_connect() -> WANT_RECV");
- result = Curl_vquic_tls_before_recv(&ctx->tls, cf, data);
- goto out;
- case SSL_ERROR_WANT_WRITE:
- ctx->q.last_io = now;
- CURL_TRC_CF(data, cf, "QUIC SSL_connect() -> WANT_SEND");
- result = CURLE_OK;
- goto out;
-#ifdef SSL_ERROR_WANT_ASYNC
- case SSL_ERROR_WANT_ASYNC:
- ctx->q.last_io = now;
- CURL_TRC_CF(data, cf, "QUIC SSL_connect() -> WANT_ASYNC");
- result = CURLE_OK;
- goto out;
-#endif
-#ifdef SSL_ERROR_WANT_RETRY_VERIFY
- case SSL_ERROR_WANT_RETRY_VERIFY:
- result = CURLE_OK;
- goto out;
-#endif
- default:
- result = cf_osslq_ssl_err(cf, data, detail, CURLE_COULDNT_CONNECT);
- goto out;
- }
- }
-
-out:
- if(result == CURLE_RECV_ERROR && ctx->tls.ossl.ssl &&
- ctx->protocol_shutdown) {
- /* When a QUIC server instance is shutting down, it may send us a
- * CONNECTION_CLOSE right away. Our connection then enters the DRAINING
- * state. The CONNECT may work in the near future again. Indicate
- * that as a "weird" reply. */
- result = CURLE_WEIRD_SERVER_REPLY;
- }
-
-#ifndef CURL_DISABLE_VERBOSE_STRINGS
- if(result) {
- struct ip_quadruple ip;
-
- Curl_cf_socket_peek(cf->next, data, NULL, NULL, &ip);
- infof(data, "QUIC connect to %s port %u failed: %s",
- ip.remote_ip, ip.remote_port, curl_easy_strerror(result));
- }
-#endif
- if(!result)
- result = check_and_set_expiry(cf, data);
- if(result || *done)
- CURL_TRC_CF(data, cf, "connect -> %d, done=%d", result, *done);
- CF_DATA_RESTORE(cf, save);
- return result;
-}
-
-static ssize_t h3_stream_open(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- const void *buf, size_t len,
- CURLcode *err)
-{
- struct cf_osslq_ctx *ctx = cf->ctx;
- struct h3_stream_ctx *stream = NULL;
- struct dynhds h2_headers;
- size_t nheader;
- nghttp3_nv *nva = NULL;
- int rc = 0;
- unsigned int i;
- ssize_t nwritten = -1;
- nghttp3_data_reader reader;
- nghttp3_data_reader *preader = NULL;
-
- Curl_dynhds_init(&h2_headers, 0, DYN_HTTP_REQUEST);
-
- *err = h3_data_setup(cf, data);
- if(*err)
- goto out;
- stream = H3_STREAM_CTX(ctx, data);
- DEBUGASSERT(stream);
- if(!stream) {
- *err = CURLE_FAILED_INIT;
- goto out;
- }
-
- nwritten = Curl_h1_req_parse_read(&stream->h1, buf, len, NULL, 0, err);
- if(nwritten < 0)
- goto out;
- if(!stream->h1.done) {
- /* need more data */
- goto out;
- }
- DEBUGASSERT(stream->h1.req);
-
- *err = Curl_http_req_to_h2(&h2_headers, stream->h1.req, data);
- if(*err) {
- nwritten = -1;
- goto out;
- }
- /* no longer needed */
- Curl_h1_req_parse_free(&stream->h1);
-
- nheader = Curl_dynhds_count(&h2_headers);
- nva = malloc(sizeof(nghttp3_nv) * nheader);
- if(!nva) {
- *err = CURLE_OUT_OF_MEMORY;
- nwritten = -1;
- goto out;
- }
-
- for(i = 0; i < nheader; ++i) {
- struct dynhds_entry *e = Curl_dynhds_getn(&h2_headers, i);
- nva[i].name = (unsigned char *)e->name;
- nva[i].namelen = e->namelen;
- nva[i].value = (unsigned char *)e->value;
- nva[i].valuelen = e->valuelen;
- nva[i].flags = NGHTTP3_NV_FLAG_NONE;
- }
-
- DEBUGASSERT(stream->s.id == -1);
- *err = cf_osslq_stream_open(&stream->s, ctx->tls.ossl.ssl, 0,
- &ctx->stream_bufcp, data);
- if(*err) {
- failf(data, "cannot get bidi streams");
- *err = CURLE_SEND_ERROR;
- goto out;
- }
-
- switch(data->state.httpreq) {
- case HTTPREQ_POST:
- case HTTPREQ_POST_FORM:
- case HTTPREQ_POST_MIME:
- case HTTPREQ_PUT:
- /* known request body size or -1 */
- if(data->state.infilesize != -1)
- stream->upload_left = data->state.infilesize;
- else
- /* data sending without specifying the data amount up front */
- stream->upload_left = -1; /* unknown */
- break;
- default:
- /* there is not request body */
- stream->upload_left = 0; /* no request body */
- break;
- }
-
- stream->send_closed = (stream->upload_left == 0);
- if(!stream->send_closed) {
- reader.read_data = cb_h3_read_req_body;
- preader = &reader;
- }
-
- rc = nghttp3_conn_submit_request(ctx->h3.conn, stream->s.id,
- nva, nheader, preader, data);
- if(rc) {
- switch(rc) {
- case NGHTTP3_ERR_CONN_CLOSING:
- CURL_TRC_CF(data, cf, "h3sid[%"FMT_PRId64"] failed to send, "
- "connection is closing", stream->s.id);
- break;
- default:
- CURL_TRC_CF(data, cf, "h3sid[%"FMT_PRId64 "] failed to send -> %d (%s)",
- stream->s.id, rc, nghttp3_strerror(rc));
- break;
- }
- *err = CURLE_SEND_ERROR;
- nwritten = -1;
- goto out;
- }
-
- if(Curl_trc_is_verbose(data)) {
- infof(data, "[HTTP/3] [%" FMT_PRId64 "] OPENED stream for %s",
- stream->s.id, data->state.url);
- for(i = 0; i < nheader; ++i) {
- infof(data, "[HTTP/3] [%" FMT_PRId64 "] [%.*s: %.*s]",
- stream->s.id,
- (int)nva[i].namelen, nva[i].name,
- (int)nva[i].valuelen, nva[i].value);
- }
- }
-
-out:
- free(nva);
- Curl_dynhds_free(&h2_headers);
- return nwritten;
-}
-
-static ssize_t cf_osslq_send(struct Curl_cfilter *cf, struct Curl_easy *data,
- const void *buf, size_t len, bool eos,
- CURLcode *err)
-{
- struct cf_osslq_ctx *ctx = cf->ctx;
- struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
- struct cf_call_data save;
- ssize_t nwritten;
- CURLcode result;
-
- (void)eos; /* TODO: use to end stream */
- CF_DATA_SAVE(save, cf, data);
- DEBUGASSERT(cf->connected);
- DEBUGASSERT(ctx->tls.ossl.ssl);
- DEBUGASSERT(ctx->h3.conn);
- *err = CURLE_OK;
-
- result = cf_progress_ingress(cf, data);
- if(result) {
- *err = result;
- nwritten = -1;
- goto out;
- }
-
- result = cf_progress_egress(cf, data);
- if(result) {
- *err = result;
- nwritten = -1;
- goto out;
- }
-
- if(!stream || stream->s.id < 0) {
- nwritten = h3_stream_open(cf, data, buf, len, err);
- if(nwritten < 0) {
- CURL_TRC_CF(data, cf, "failed to open stream -> %d", *err);
- goto out;
- }
- stream = H3_STREAM_CTX(ctx, data);
- }
- else if(stream->closed) {
- if(stream->resp_hds_complete) {
- /* Server decided to close the stream after having sent us a final
- * response. This is valid if it is not interested in the request
- * body. This happens on 30x or 40x responses.
- * We silently discard the data sent, since this is not a transport
- * error situation. */
- CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] discarding data"
- "on closed stream with response", stream->s.id);
- *err = CURLE_OK;
- nwritten = (ssize_t)len;
- goto out;
- }
- CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] send_body(len=%zu) "
- "-> stream closed", stream->s.id, len);
- *err = CURLE_HTTP3;
- nwritten = -1;
- goto out;
- }
- else {
- nwritten = Curl_bufq_write(&stream->sendbuf, buf, len, err);
- CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] cf_send, add to "
- "sendbuf(len=%zu) -> %zd, %d",
- stream->s.id, len, nwritten, *err);
- if(nwritten < 0) {
- goto out;
- }
-
- (void)nghttp3_conn_resume_stream(ctx->h3.conn, stream->s.id);
- }
-
- result = cf_progress_egress(cf, data);
- if(result) {
- *err = result;
- nwritten = -1;
- }
-
-out:
- result = check_and_set_expiry(cf, data);
- CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] cf_send(len=%zu) -> %zd, %d",
- stream? stream->s.id : -1, len, nwritten, *err);
- CF_DATA_RESTORE(cf, save);
- return nwritten;
-}
-
-static ssize_t recv_closed_stream(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- struct h3_stream_ctx *stream,
- CURLcode *err)
-{
- ssize_t nread = -1;
-
- (void)cf;
- if(stream->reset) {
- failf(data,
- "HTTP/3 stream %" FMT_PRId64 " reset by server",
- stream->s.id);
- *err = data->req.bytecount? CURLE_PARTIAL_FILE : CURLE_HTTP3;
- goto out;
- }
- else if(!stream->resp_hds_complete) {
- failf(data,
- "HTTP/3 stream %" FMT_PRId64
- " was closed cleanly, but before getting"
- " all response header fields, treated as error",
- stream->s.id);
- *err = CURLE_HTTP3;
- goto out;
- }
- *err = CURLE_OK;
- nread = 0;
-
-out:
- return nread;
-}
-
-static ssize_t cf_osslq_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
- char *buf, size_t len, CURLcode *err)
-{
- struct cf_osslq_ctx *ctx = cf->ctx;
- struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
- ssize_t nread = -1;
- struct cf_call_data save;
- CURLcode result;
-
- (void)ctx;
- CF_DATA_SAVE(save, cf, data);
- DEBUGASSERT(cf->connected);
- DEBUGASSERT(ctx);
- DEBUGASSERT(ctx->tls.ossl.ssl);
- DEBUGASSERT(ctx->h3.conn);
- *err = CURLE_OK;
-
- if(!stream) {
- *err = CURLE_RECV_ERROR;
- goto out;
- }
-
- if(!Curl_bufq_is_empty(&stream->recvbuf)) {
- nread = Curl_bufq_read(&stream->recvbuf,
- (unsigned char *)buf, len, err);
- if(nread < 0) {
- CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] read recvbuf(len=%zu) "
- "-> %zd, %d", stream->s.id, len, nread, *err);
- goto out;
- }
- }
-
- result = cf_progress_ingress(cf, data);
- if(result) {
- *err = result;
- nread = -1;
- goto out;
- }
-
- /* recvbuf had nothing before, maybe after progressing ingress? */
- if(nread < 0 && !Curl_bufq_is_empty(&stream->recvbuf)) {
- nread = Curl_bufq_read(&stream->recvbuf,
- (unsigned char *)buf, len, err);
- if(nread < 0) {
- CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] read recvbuf(len=%zu) "
- "-> %zd, %d", stream->s.id, len, nread, *err);
- goto out;
- }
- }
-
- if(nread > 0) {
- h3_drain_stream(cf, data);
- }
- else {
- if(stream->closed) {
- nread = recv_closed_stream(cf, data, stream, err);
- goto out;
- }
- *err = CURLE_AGAIN;
- nread = -1;
- }
-
-out:
- if(cf_progress_egress(cf, data)) {
- *err = CURLE_SEND_ERROR;
- nread = -1;
- }
- else {
- CURLcode result2 = check_and_set_expiry(cf, data);
- if(result2) {
- *err = result2;
- nread = -1;
- }
- }
- CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] cf_recv(len=%zu) -> %zd, %d",
- stream? stream->s.id : -1, len, nread, *err);
- CF_DATA_RESTORE(cf, save);
- return nread;
-}
-
-/*
- * Called from transfer.c:data_pending to know if we should keep looping
- * to receive more data from the connection.
- */
-static bool cf_osslq_data_pending(struct Curl_cfilter *cf,
- const struct Curl_easy *data)
-{
- struct cf_osslq_ctx *ctx = cf->ctx;
- const struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
- (void)cf;
- return stream && !Curl_bufq_is_empty(&stream->recvbuf);
-}
-
-static CURLcode cf_osslq_data_event(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- int event, int arg1, void *arg2)
-{
- struct cf_osslq_ctx *ctx = cf->ctx;
- CURLcode result = CURLE_OK;
- struct cf_call_data save;
-
- CF_DATA_SAVE(save, cf, data);
- (void)arg1;
- (void)arg2;
- switch(event) {
- case CF_CTRL_DATA_SETUP:
- break;
- case CF_CTRL_DATA_PAUSE:
- result = h3_data_pause(cf, data, (arg1 != 0));
- break;
- case CF_CTRL_DATA_DETACH:
- h3_data_done(cf, data);
- break;
- case CF_CTRL_DATA_DONE:
- h3_data_done(cf, data);
- break;
- case CF_CTRL_DATA_DONE_SEND: {
- struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
- if(stream && !stream->send_closed) {
- stream->send_closed = TRUE;
- stream->upload_left = Curl_bufq_len(&stream->sendbuf) -
- stream->sendbuf_len_in_flight;
- (void)nghttp3_conn_resume_stream(ctx->h3.conn, stream->s.id);
- }
- break;
- }
- case CF_CTRL_DATA_IDLE: {
- struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data);
- CURL_TRC_CF(data, cf, "data idle");
- if(stream && !stream->closed) {
- result = check_and_set_expiry(cf, data);
- }
- break;
- }
- default:
- break;
- }
- CF_DATA_RESTORE(cf, save);
- return result;
-}
-
-static bool cf_osslq_conn_is_alive(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- bool *input_pending)
-{
- struct cf_osslq_ctx *ctx = cf->ctx;
- bool alive = FALSE;
- struct cf_call_data save;
-
- CF_DATA_SAVE(save, cf, data);
- *input_pending = FALSE;
- if(!ctx->tls.ossl.ssl)
- goto out;
-
-#ifdef SSL_VALUE_QUIC_IDLE_TIMEOUT
- /* Added in OpenSSL v3.3.x */
- {
- timediff_t idletime;
- uint64_t idle_ms = ctx->max_idle_ms;
- if(!SSL_get_value_uint(ctx->tls.ossl.ssl,
- SSL_VALUE_CLASS_FEATURE_NEGOTIATED,
- SSL_VALUE_QUIC_IDLE_TIMEOUT, &idle_ms)) {
- CURL_TRC_CF(data, cf, "error getting negotiated idle timeout, "
- "assume connection is dead.");
- goto out;
- }
- CURL_TRC_CF(data, cf, "negotiated idle timeout: %zums", (size_t)idle_ms);
- idletime = Curl_timediff(Curl_now(), ctx->q.last_io);
- if(idletime > 0 && (uint64_t)idletime > idle_ms)
- goto out;
- }
-
-#endif
-
- if(!cf->next || !cf->next->cft->is_alive(cf->next, data, input_pending))
- goto out;
-
- alive = TRUE;
- if(*input_pending) {
- CURLcode result;
- /* This happens before we have sent off a request and the connection is
- not in use by any other transfer, there should not be any data here,
- only "protocol frames" */
- *input_pending = FALSE;
- result = cf_progress_ingress(cf, data);
- CURL_TRC_CF(data, cf, "is_alive, progress ingress -> %d", result);
- alive = result? FALSE : TRUE;
- }
-
-out:
- CF_DATA_RESTORE(cf, save);
- return alive;
-}
-
-static void cf_osslq_adjust_pollset(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- struct easy_pollset *ps)
-{
- struct cf_osslq_ctx *ctx = cf->ctx;
-
- if(!ctx->tls.ossl.ssl) {
- /* NOP */
- }
- else if(!cf->connected) {
- /* during handshake, transfer has not started yet. we always
- * add our socket for polling if SSL wants to send/recv */
- Curl_pollset_set(data, ps, ctx->q.sockfd,
- SSL_net_read_desired(ctx->tls.ossl.ssl),
- SSL_net_write_desired(ctx->tls.ossl.ssl));
- }
- else {
- /* once connected, we only modify the socket if it is present.
- * this avoids adding it for paused transfers. */
- bool want_recv, want_send;
- Curl_pollset_check(data, ps, ctx->q.sockfd, &want_recv, &want_send);
- if(want_recv || want_send) {
- Curl_pollset_set(data, ps, ctx->q.sockfd,
- SSL_net_read_desired(ctx->tls.ossl.ssl),
- SSL_net_write_desired(ctx->tls.ossl.ssl));
- }
- else if(ctx->need_recv || ctx->need_send) {
- Curl_pollset_set(data, ps, ctx->q.sockfd,
- ctx->need_recv, ctx->need_send);
- }
- }
-}
-
-static CURLcode cf_osslq_query(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- int query, int *pres1, void *pres2)
-{
- struct cf_osslq_ctx *ctx = cf->ctx;
-
- switch(query) {
- case CF_QUERY_MAX_CONCURRENT: {
-#ifdef SSL_VALUE_QUIC_STREAM_BIDI_LOCAL_AVAIL
- /* Added in OpenSSL v3.3.x */
- uint64_t v;
- if(!SSL_get_value_uint(ctx->tls.ossl.ssl, SSL_VALUE_CLASS_GENERIC,
- SSL_VALUE_QUIC_STREAM_BIDI_LOCAL_AVAIL, &v)) {
- CURL_TRC_CF(data, cf, "error getting available local bidi streams");
- return CURLE_HTTP3;
- }
- /* we report avail + in_use */
- v += CONN_INUSE(cf->conn);
- *pres1 = (v > INT_MAX)? INT_MAX : (int)v;
-#else
- *pres1 = 100;
-#endif
- CURL_TRC_CF(data, cf, "query max_conncurrent -> %d", *pres1);
- return CURLE_OK;
- }
- case CF_QUERY_CONNECT_REPLY_MS:
- if(ctx->got_first_byte) {
- timediff_t ms = Curl_timediff(ctx->first_byte_at, ctx->started_at);
- *pres1 = (ms < INT_MAX)? (int)ms : INT_MAX;
- }
- else
- *pres1 = -1;
- return CURLE_OK;
- case CF_QUERY_TIMER_CONNECT: {
- struct curltime *when = pres2;
- if(ctx->got_first_byte)
- *when = ctx->first_byte_at;
- return CURLE_OK;
- }
- case CF_QUERY_TIMER_APPCONNECT: {
- struct curltime *when = pres2;
- if(cf->connected)
- *when = ctx->handshake_at;
- return CURLE_OK;
- }
- default:
- break;
- }
- return cf->next?
- cf->next->cft->query(cf->next, data, query, pres1, pres2) :
- CURLE_UNKNOWN_OPTION;
-}
-
-struct Curl_cftype Curl_cft_http3 = {
- "HTTP/3",
- CF_TYPE_IP_CONNECT | CF_TYPE_SSL | CF_TYPE_MULTIPLEX,
- 0,
- cf_osslq_destroy,
- cf_osslq_connect,
- cf_osslq_close,
- cf_osslq_shutdown,
- Curl_cf_def_get_host,
- cf_osslq_adjust_pollset,
- cf_osslq_data_pending,
- cf_osslq_send,
- cf_osslq_recv,
- cf_osslq_data_event,
- cf_osslq_conn_is_alive,
- Curl_cf_def_conn_keep_alive,
- cf_osslq_query,
-};
-
-CURLcode Curl_cf_osslq_create(struct Curl_cfilter **pcf,
- struct Curl_easy *data,
- struct connectdata *conn,
- const struct Curl_addrinfo *ai)
-{
- struct cf_osslq_ctx *ctx = NULL;
- struct Curl_cfilter *cf = NULL, *udp_cf = NULL;
- CURLcode result;
-
- (void)data;
- ctx = calloc(1, sizeof(*ctx));
- if(!ctx) {
- result = CURLE_OUT_OF_MEMORY;
- goto out;
- }
- cf_osslq_ctx_init(ctx);
-
- result = Curl_cf_create(&cf, &Curl_cft_http3, ctx);
- if(result)
- goto out;
-
- result = Curl_cf_udp_create(&udp_cf, data, conn, ai, TRNSPRT_QUIC);
- if(result)
- goto out;
-
- cf->conn = conn;
- udp_cf->conn = cf->conn;
- udp_cf->sockindex = cf->sockindex;
- cf->next = udp_cf;
-
-out:
- *pcf = (!result)? cf : NULL;
- if(result) {
- if(udp_cf)
- Curl_conn_cf_discard_sub(cf, udp_cf, data, TRUE);
- Curl_safefree(cf);
- cf_osslq_ctx_free(ctx);
- }
- return result;
-}
-
-bool Curl_conn_is_osslq(const struct Curl_easy *data,
- const struct connectdata *conn,
- int sockindex)
-{
- struct Curl_cfilter *cf = conn? conn->cfilter[sockindex] : NULL;
-
- (void)data;
- for(; cf; cf = cf->next) {
- if(cf->cft == &Curl_cft_http3)
- return TRUE;
- if(cf->cft->flags & CF_TYPE_IP_CONNECT)
- return FALSE;
- }
- return FALSE;
-}
-
-/*
- * Store ngtcp2 version info in this buffer.
- */
-void Curl_osslq_ver(char *p, size_t len)
-{
- const nghttp3_info *ht3 = nghttp3_version(0);
- (void)msnprintf(p, len, "nghttp3/%s", ht3->version_str);
-}
-
-#endif /* USE_OPENSSL_QUIC && USE_NGHTTP3 */
diff --git a/contrib/libs/curl/lib/vquic/curl_osslq.h b/contrib/libs/curl/lib/vquic/curl_osslq.h
deleted file mode 100644
index 0e12d7023e..0000000000
--- a/contrib/libs/curl/lib/vquic/curl_osslq.h
+++ /dev/null
@@ -1,51 +0,0 @@
-#ifndef HEADER_CURL_VQUIC_CURL_OSSLQ_H
-#define HEADER_CURL_VQUIC_CURL_OSSLQ_H
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at https://curl.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * SPDX-License-Identifier: curl
- *
- ***************************************************************************/
-
-#include "curl_setup.h"
-
-#if defined(USE_OPENSSL_QUIC) && defined(USE_NGHTTP3)
-
-#ifdef HAVE_NETINET_UDP_H
-#include <netinet/udp.h>
-#endif
-
-struct Curl_cfilter;
-
-#include "urldata.h"
-
-void Curl_osslq_ver(char *p, size_t len);
-
-CURLcode Curl_cf_osslq_create(struct Curl_cfilter **pcf,
- struct Curl_easy *data,
- struct connectdata *conn,
- const struct Curl_addrinfo *ai);
-
-bool Curl_conn_is_osslq(const struct Curl_easy *data,
- const struct connectdata *conn,
- int sockindex);
-#endif
-
-#endif /* HEADER_CURL_VQUIC_CURL_OSSLQ_H */
diff --git a/contrib/libs/curl/lib/vquic/curl_quiche.c b/contrib/libs/curl/lib/vquic/curl_quiche.c
index e7b504375e..0f60378776 100644
--- a/contrib/libs/curl/lib/vquic/curl_quiche.c
+++ b/contrib/libs/curl/lib/vquic/curl_quiche.c
@@ -29,7 +29,6 @@
#include <openssl/err.h>
#include <openssl/ssl.h>
#include "bufq.h"
-#include "hash.h"
#include "urldata.h"
#include "cfilters.h"
#include "cf-socket.h"
@@ -44,7 +43,6 @@
#include "http1.h"
#include "vquic.h"
#include "vquic_int.h"
-#error #include "vquic-tls.h"
#include "curl_quiche.h"
#include "transfer.h"
#include "inet_pton.h"
@@ -64,10 +62,11 @@
#define H3_STREAM_WINDOW_SIZE (128 * 1024)
#define H3_STREAM_CHUNK_SIZE (16 * 1024)
-/* The pool keeps spares around and half of a full stream windows seems good.
- * More does not seem to improve performance. The benefit of the pool is that
- * stream buffer to not keep spares. Memory consumption goes down when streams
- * run empty, have a large upload done, etc. */
+/* The pool keeps spares around and half of a full stream windows
+ * seems good. More does not seem to improve performance.
+ * The benefit of the pool is that stream buffer to not keep
+ * spares. So memory consumption goes down when streams run empty,
+ * have a large upload done, etc. */
#define H3_STREAM_POOL_SPARES \
(H3_STREAM_WINDOW_SIZE / H3_STREAM_CHUNK_SIZE ) / 2
/* Receive and Send max number of chunks just follows from the
@@ -85,29 +84,35 @@ void Curl_quiche_ver(char *p, size_t len)
(void)msnprintf(p, len, "quiche/%s", quiche_version());
}
+static void keylog_callback(const SSL *ssl, const char *line)
+{
+ (void)ssl;
+ Curl_tls_keylog_write_line(line);
+}
+
struct cf_quiche_ctx {
struct cf_quic_ctx q;
struct ssl_peer peer;
- struct curl_tls_ctx tls;
quiche_conn *qconn;
quiche_config *cfg;
quiche_h3_conn *h3c;
quiche_h3_config *h3config;
uint8_t scid[QUICHE_MAX_CONN_ID_LEN];
+ SSL_CTX *sslctx;
+ SSL *ssl;
struct curltime started_at; /* time the current attempt started */
struct curltime handshake_at; /* time connect handshake finished */
+ struct curltime first_byte_at; /* when first byte was recvd */
+ struct curltime reconnect_at; /* time the next attempt should start */
struct bufc_pool stream_bufcp; /* chunk pool for streams */
- struct Curl_hash streams; /* hash `data->mid` to `stream_ctx` */
curl_off_t data_recvd;
- BIT(initialized);
+ uint64_t max_idle_ms; /* max idle time for QUIC conn */
BIT(goaway); /* got GOAWAY from server */
+ BIT(got_first_byte); /* if first byte was received */
BIT(x509_store_setup); /* if x509 store has been set up */
- BIT(shutdown_started); /* queued shutdown packets */
};
#ifdef DEBUG_QUICHE
-/* initialize debug log callback only once */
-static int debug_log_init = 0;
static void quiche_debug_log(const char *line, void *argp)
{
(void)argp;
@@ -115,102 +120,162 @@ static void quiche_debug_log(const char *line, void *argp)
}
#endif
-static void h3_stream_hash_free(void *stream);
-
-static void cf_quiche_ctx_init(struct cf_quiche_ctx *ctx)
+static void cf_quiche_ctx_clear(struct cf_quiche_ctx *ctx)
{
- DEBUGASSERT(!ctx->initialized);
-#ifdef DEBUG_QUICHE
- if(!debug_log_init) {
- quiche_enable_debug_logging(quiche_debug_log, NULL);
- debug_log_init = 1;
+ if(ctx) {
+ vquic_ctx_free(&ctx->q);
+ if(ctx->qconn)
+ quiche_conn_free(ctx->qconn);
+ if(ctx->h3config)
+ quiche_h3_config_free(ctx->h3config);
+ if(ctx->h3c)
+ quiche_h3_conn_free(ctx->h3c);
+ if(ctx->cfg)
+ quiche_config_free(ctx->cfg);
+ Curl_bufcp_free(&ctx->stream_bufcp);
+ Curl_ssl_peer_cleanup(&ctx->peer);
+
+ memset(ctx, 0, sizeof(*ctx));
}
-#endif
- Curl_bufcp_init(&ctx->stream_bufcp, H3_STREAM_CHUNK_SIZE,
- H3_STREAM_POOL_SPARES);
- Curl_hash_offt_init(&ctx->streams, 63, h3_stream_hash_free);
- ctx->data_recvd = 0;
- ctx->initialized = TRUE;
}
-static void cf_quiche_ctx_free(struct cf_quiche_ctx *ctx)
+static CURLcode quic_x509_store_setup(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
- if(ctx && ctx->initialized) {
- /* quiche just freed it */
- ctx->tls.ossl.ssl = NULL;
- Curl_vquic_tls_cleanup(&ctx->tls);
- Curl_ssl_peer_cleanup(&ctx->peer);
- vquic_ctx_free(&ctx->q);
- Curl_bufcp_free(&ctx->stream_bufcp);
- Curl_hash_clean(&ctx->streams);
- Curl_hash_destroy(&ctx->streams);
+ struct cf_quiche_ctx *ctx = cf->ctx;
+ struct ssl_primary_config *conn_config;
+
+ conn_config = Curl_ssl_cf_get_primary_config(cf);
+ if(!conn_config)
+ return CURLE_FAILED_INIT;
+
+ if(!ctx->x509_store_setup) {
+ if(conn_config->verifypeer) {
+ const char * const ssl_cafile = conn_config->CAfile;
+ const char * const ssl_capath = conn_config->CApath;
+ if(ssl_cafile || ssl_capath) {
+ SSL_CTX_set_verify(ctx->sslctx, SSL_VERIFY_PEER, NULL);
+ /* tell OpenSSL where to find CA certificates that are used to verify
+ the server's certificate. */
+ if(!SSL_CTX_load_verify_locations(ctx->sslctx, ssl_cafile,
+ ssl_capath)) {
+ /* Fail if we insist on successfully verifying the server. */
+ failf(data, "error setting certificate verify locations:"
+ " CAfile: %s CApath: %s",
+ ssl_cafile ? ssl_cafile : "none",
+ ssl_capath ? ssl_capath : "none");
+ return CURLE_SSL_CACERT_BADFILE;
+ }
+ infof(data, " CAfile: %s", ssl_cafile ? ssl_cafile : "none");
+ infof(data, " CApath: %s", ssl_capath ? ssl_capath : "none");
+ }
+#ifdef CURL_CA_FALLBACK
+ else {
+ /* verifying the peer without any CA certificates won't work so
+ use openssl's built-in default as fallback */
+ SSL_CTX_set_default_verify_paths(ctx->sslctx);
+ }
+#endif
+ }
+ ctx->x509_store_setup = TRUE;
}
- free(ctx);
+ return CURLE_OK;
}
-static void cf_quiche_ctx_close(struct cf_quiche_ctx *ctx)
+static CURLcode quic_ssl_setup(struct Curl_cfilter *cf, struct Curl_easy *data)
{
- if(ctx->h3c)
- quiche_h3_conn_free(ctx->h3c);
- if(ctx->h3config)
- quiche_h3_config_free(ctx->h3config);
- if(ctx->qconn)
- quiche_conn_free(ctx->qconn);
- if(ctx->cfg)
- quiche_config_free(ctx->cfg);
-}
+ struct cf_quiche_ctx *ctx = cf->ctx;
+ struct ssl_primary_config *conn_config;
+ CURLcode result;
-static CURLcode cf_flush_egress(struct Curl_cfilter *cf,
- struct Curl_easy *data);
+ conn_config = Curl_ssl_cf_get_primary_config(cf);
+ if(!conn_config)
+ return CURLE_FAILED_INIT;
+
+ result = Curl_ssl_peer_init(&ctx->peer, cf);
+ if(result)
+ return result;
+
+ DEBUGASSERT(!ctx->sslctx);
+ ctx->sslctx = SSL_CTX_new(TLS_method());
+ if(!ctx->sslctx)
+ return CURLE_OUT_OF_MEMORY;
+
+ SSL_CTX_set_alpn_protos(ctx->sslctx,
+ (const uint8_t *)QUICHE_H3_APPLICATION_PROTOCOL,
+ sizeof(QUICHE_H3_APPLICATION_PROTOCOL) - 1);
+
+ SSL_CTX_set_default_verify_paths(ctx->sslctx);
+
+ /* Open the file if a TLS or QUIC backend has not done this before. */
+ Curl_tls_keylog_open();
+ if(Curl_tls_keylog_enabled()) {
+ SSL_CTX_set_keylog_callback(ctx->sslctx, keylog_callback);
+ }
+
+ if(conn_config->curves &&
+ !SSL_CTX_set1_curves_list(ctx->sslctx, conn_config->curves)) {
+ failf(data, "failed setting curves list for QUIC: '%s'",
+ conn_config->curves);
+ return CURLE_SSL_CIPHER;
+ }
+
+ ctx->ssl = SSL_new(ctx->sslctx);
+ if(!ctx->ssl)
+ return CURLE_QUIC_CONNECT_ERROR;
+
+ SSL_set_app_data(ctx->ssl, cf);
+
+ if(ctx->peer.sni) {
+ if(!SSL_set_tlsext_host_name(ctx->ssl, ctx->peer.sni)) {
+ failf(data, "Failed set SNI");
+ SSL_free(ctx->ssl);
+ ctx->ssl = NULL;
+ return CURLE_QUIC_CONNECT_ERROR;
+ }
+ }
+
+ return CURLE_OK;
+}
/**
* All about the H3 internals of a stream
*/
struct stream_ctx {
- curl_uint64_t id; /* HTTP/3 protocol stream identifier */
+ int64_t id; /* HTTP/3 protocol stream identifier */
struct bufq recvbuf; /* h3 response */
struct h1_req_parser h1; /* h1 request parsing */
- curl_uint64_t error3; /* HTTP/3 stream error code */
- BIT(opened); /* TRUE after stream has been opened */
- BIT(closed); /* TRUE on stream close */
- BIT(reset); /* TRUE on stream reset */
- BIT(send_closed); /* stream is locally closed */
- BIT(resp_hds_complete); /* final response has been received */
- BIT(resp_got_header); /* TRUE when h3 stream has recvd some HEADER */
+ uint64_t error3; /* HTTP/3 stream error code */
+ curl_off_t upload_left; /* number of request bytes left to upload */
+ bool closed; /* TRUE on stream close */
+ bool reset; /* TRUE on stream reset */
+ bool send_closed; /* stream is locally closed */
+ bool resp_hds_complete; /* complete, final response has been received */
+ bool resp_got_header; /* TRUE when h3 stream has recvd some HEADER */
BIT(quic_flow_blocked); /* stream is blocked by QUIC flow control */
};
-#define H3_STREAM_CTX(ctx,data) ((struct stream_ctx *)(\
- data? Curl_hash_offt_get(&(ctx)->streams, (data)->mid) : NULL))
-
-static void h3_stream_ctx_free(struct stream_ctx *stream)
-{
- Curl_bufq_free(&stream->recvbuf);
- Curl_h1_req_parse_free(&stream->h1);
- free(stream);
-}
-
-static void h3_stream_hash_free(void *stream)
-{
- DEBUGASSERT(stream);
- h3_stream_ctx_free((struct stream_ctx *)stream);
-}
+#define H3_STREAM_CTX(d) ((struct stream_ctx *)(((d) && (d)->req.p.http)? \
+ ((struct HTTP *)(d)->req.p.http)->h3_ctx \
+ : NULL))
+#define H3_STREAM_LCTX(d) ((struct HTTP *)(d)->req.p.http)->h3_ctx
+#define H3_STREAM_ID(d) (H3_STREAM_CTX(d)? \
+ H3_STREAM_CTX(d)->id : -2)
static void check_resumes(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
- struct cf_quiche_ctx *ctx = cf->ctx;
- struct Curl_llist_node *e;
+ struct Curl_easy *sdata;
+ struct stream_ctx *stream;
DEBUGASSERT(data->multi);
- for(e = Curl_llist_head(&data->multi->process); e; e = Curl_node_next(e)) {
- struct Curl_easy *sdata = Curl_node_elem(e);
+ for(sdata = data->multi->easyp; sdata; sdata = sdata->next) {
if(sdata->conn == data->conn) {
- struct stream_ctx *stream = H3_STREAM_CTX(ctx, sdata);
+ stream = H3_STREAM_CTX(sdata);
if(stream && stream->quic_flow_blocked) {
stream->quic_flow_blocked = FALSE;
Curl_expire(data, 0, EXPIRE_RUN_NOW);
- CURL_TRC_CF(data, cf, "[%"FMT_PRIu64"] unblock", stream->id);
+ CURL_TRC_CF(data, cf, "[%"PRId64"] unblock", stream->id);
}
}
}
@@ -220,7 +285,7 @@ static CURLcode h3_data_setup(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
struct cf_quiche_ctx *ctx = cf->ctx;
- struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
+ struct stream_ctx *stream = H3_STREAM_CTX(data);
if(stream)
return CURLE_OK;
@@ -229,28 +294,22 @@ static CURLcode h3_data_setup(struct Curl_cfilter *cf,
if(!stream)
return CURLE_OUT_OF_MEMORY;
+ H3_STREAM_LCTX(data) = stream;
stream->id = -1;
Curl_bufq_initp(&stream->recvbuf, &ctx->stream_bufcp,
H3_STREAM_RECV_CHUNKS, BUFQ_OPT_SOFT_LIMIT);
Curl_h1_req_parse_init(&stream->h1, H1_PARSE_DEFAULT_MAX_LINE_LEN);
-
- if(!Curl_hash_offt_set(&ctx->streams, data->mid, stream)) {
- h3_stream_ctx_free(stream);
- return CURLE_OUT_OF_MEMORY;
- }
-
return CURLE_OK;
}
static void h3_data_done(struct Curl_cfilter *cf, struct Curl_easy *data)
{
struct cf_quiche_ctx *ctx = cf->ctx;
- struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
- CURLcode result;
+ struct stream_ctx *stream = H3_STREAM_CTX(data);
(void)cf;
if(stream) {
- CURL_TRC_CF(data, cf, "[%"FMT_PRIu64"] easy handle is done", stream->id);
+ CURL_TRC_CF(data, cf, "[%"PRId64"] easy handle is done", stream->id);
if(ctx->qconn && !stream->closed) {
quiche_conn_stream_shutdown(ctx->qconn, stream->id,
QUICHE_SHUTDOWN_READ, CURL_H3_NO_ERROR);
@@ -260,79 +319,51 @@ static void h3_data_done(struct Curl_cfilter *cf, struct Curl_easy *data)
stream->send_closed = TRUE;
}
stream->closed = TRUE;
- result = cf_flush_egress(cf, data);
- if(result)
- CURL_TRC_CF(data, cf, "data_done, flush egress -> %d", result);
}
- Curl_hash_offt_remove(&ctx->streams, data->mid);
+ Curl_bufq_free(&stream->recvbuf);
+ Curl_h1_req_parse_free(&stream->h1);
+ free(stream);
+ H3_STREAM_LCTX(data) = NULL;
}
}
static void drain_stream(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
- struct cf_quiche_ctx *ctx = cf->ctx;
- struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
+ struct stream_ctx *stream = H3_STREAM_CTX(data);
unsigned char bits;
(void)cf;
bits = CURL_CSELECT_IN;
- if(stream && !stream->send_closed)
+ if(stream && !stream->send_closed && stream->upload_left)
bits |= CURL_CSELECT_OUT;
- if(data->state.select_bits != bits) {
- data->state.select_bits = bits;
+ if(data->state.dselect_bits != bits) {
+ data->state.dselect_bits = bits;
Curl_expire(data, 0, EXPIRE_RUN_NOW);
}
}
static struct Curl_easy *get_stream_easy(struct Curl_cfilter *cf,
struct Curl_easy *data,
- curl_uint64_t stream_id,
- struct stream_ctx **pstream)
+ int64_t stream3_id)
{
- struct cf_quiche_ctx *ctx = cf->ctx;
- struct stream_ctx *stream;
+ struct Curl_easy *sdata;
(void)cf;
- stream = H3_STREAM_CTX(ctx, data);
- if(stream && stream->id == stream_id) {
- *pstream = stream;
+ if(H3_STREAM_ID(data) == stream3_id) {
return data;
}
else {
- struct Curl_llist_node *e;
DEBUGASSERT(data->multi);
- for(e = Curl_llist_head(&data->multi->process); e; e = Curl_node_next(e)) {
- struct Curl_easy *sdata = Curl_node_elem(e);
- if(sdata->conn != data->conn)
- continue;
- stream = H3_STREAM_CTX(ctx, sdata);
- if(stream && stream->id == stream_id) {
- *pstream = stream;
+ for(sdata = data->multi->easyp; sdata; sdata = sdata->next) {
+ if((sdata->conn == data->conn) && H3_STREAM_ID(sdata) == stream3_id) {
return sdata;
}
}
}
- *pstream = NULL;
return NULL;
}
-static void cf_quiche_expire_conn_closed(struct Curl_cfilter *cf,
- struct Curl_easy *data)
-{
- struct Curl_llist_node *e;
-
- DEBUGASSERT(data->multi);
- CURL_TRC_CF(data, cf, "conn closed, expire all transfers");
- for(e = Curl_llist_head(&data->multi->process); e; e = Curl_node_next(e)) {
- struct Curl_easy *sdata = Curl_node_elem(e);
- if(sdata == data || sdata->conn != data->conn)
- continue;
- CURL_TRC_CF(sdata, cf, "conn closed, expire transfer");
- Curl_expire(sdata, 0, EXPIRE_RUN_NOW);
- }
-}
-
/*
* write_resp_raw() copies response data in raw format to the `data`'s
* receive buffer. If not enough space is available, it appends to the
@@ -342,8 +373,7 @@ static CURLcode write_resp_raw(struct Curl_cfilter *cf,
struct Curl_easy *data,
const void *mem, size_t memlen)
{
- struct cf_quiche_ctx *ctx = cf->ctx;
- struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
+ struct stream_ctx *stream = H3_STREAM_CTX(data);
CURLcode result = CURLE_OK;
ssize_t nwritten;
@@ -373,15 +403,14 @@ static int cb_each_header(uint8_t *name, size_t name_len,
void *argp)
{
struct cb_ctx *x = argp;
- struct cf_quiche_ctx *ctx = x->cf->ctx;
- struct stream_ctx *stream = H3_STREAM_CTX(ctx, x->data);
+ struct stream_ctx *stream = H3_STREAM_CTX(x->data);
CURLcode result;
if(!stream)
return CURLE_OK;
if((name_len == 7) && !strncmp(HTTP_PSEUDO_STATUS, (char *)name, 7)) {
- CURL_TRC_CF(x->data, x->cf, "[%" FMT_PRIu64 "] status: %.*s",
+ CURL_TRC_CF(x->data, x->cf, "[%" PRId64 "] status: %.*s",
stream->id, (int)value_len, value);
result = write_resp_raw(x->cf, x->data, "HTTP/3 ", sizeof("HTTP/3 ") - 1);
if(!result)
@@ -390,7 +419,7 @@ static int cb_each_header(uint8_t *name, size_t name_len,
result = write_resp_raw(x->cf, x->data, " \r\n", 3);
}
else {
- CURL_TRC_CF(x->data, x->cf, "[%" FMT_PRIu64 "] header: %.*s: %.*s",
+ CURL_TRC_CF(x->data, x->cf, "[%" PRId64 "] header: %.*s: %.*s",
stream->id, (int)name_len, name,
(int)value_len, value);
result = write_resp_raw(x->cf, x->data, name, name_len);
@@ -402,7 +431,7 @@ static int cb_each_header(uint8_t *name, size_t name_len,
result = write_resp_raw(x->cf, x->data, "\r\n", 2);
}
if(result) {
- CURL_TRC_CF(x->data, x->cf, "[%"FMT_PRIu64"] on header error %d",
+ CURL_TRC_CF(x->data, x->cf, "[%"PRId64"] on header error %d",
stream->id, result);
}
return result;
@@ -414,7 +443,7 @@ static ssize_t stream_resp_read(void *reader_ctx,
{
struct cb_ctx *x = reader_ctx;
struct cf_quiche_ctx *ctx = x->cf->ctx;
- struct stream_ctx *stream = H3_STREAM_CTX(ctx, x->data);
+ struct stream_ctx *stream = H3_STREAM_CTX(x->data);
ssize_t nread;
if(!stream) {
@@ -437,8 +466,7 @@ static ssize_t stream_resp_read(void *reader_ctx,
static CURLcode cf_recv_body(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
- struct cf_quiche_ctx *ctx = cf->ctx;
- struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
+ struct stream_ctx *stream = H3_STREAM_CTX(data);
ssize_t nwritten;
struct cb_ctx cb_ctx;
CURLcode result = CURLE_OK;
@@ -459,9 +487,9 @@ static CURLcode cf_recv_body(struct Curl_cfilter *cf,
stream_resp_read, &cb_ctx, &result);
if(nwritten < 0 && result != CURLE_AGAIN) {
- CURL_TRC_CF(data, cf, "[%"FMT_PRIu64"] recv_body error %zd",
+ CURL_TRC_CF(data, cf, "[%"PRId64"] recv_body error %zd",
stream->id, nwritten);
- failf(data, "Error %d in HTTP/3 response body for stream[%"FMT_PRIu64"]",
+ failf(data, "Error %d in HTTP/3 response body for stream[%"PRId64"]",
result, stream->id);
stream->closed = TRUE;
stream->reset = TRUE;
@@ -496,15 +524,17 @@ static const char *cf_ev_name(quiche_h3_event *ev)
static CURLcode h3_process_event(struct Curl_cfilter *cf,
struct Curl_easy *data,
- struct stream_ctx *stream,
+ int64_t stream3_id,
quiche_h3_event *ev)
{
+ struct stream_ctx *stream = H3_STREAM_CTX(data);
struct cb_ctx cb_ctx;
CURLcode result = CURLE_OK;
int rc;
if(!stream)
return CURLE_OK;
+ DEBUGASSERT(stream3_id == stream->id);
switch(quiche_h3_event_type(ev)) {
case QUICHE_H3_EVENT_HEADERS:
stream->resp_got_header = TRUE;
@@ -512,11 +542,11 @@ static CURLcode h3_process_event(struct Curl_cfilter *cf,
cb_ctx.data = data;
rc = quiche_h3_event_for_each_header(ev, cb_each_header, &cb_ctx);
if(rc) {
- failf(data, "Error %d in HTTP/3 response header for stream[%"
- FMT_PRIu64"]", rc, stream->id);
+ failf(data, "Error %d in HTTP/3 response header for stream[%"PRId64"]",
+ rc, stream3_id);
return CURLE_RECV_ERROR;
}
- CURL_TRC_CF(data, cf, "[%"FMT_PRIu64"] <- [HEADERS]", stream->id);
+ CURL_TRC_CF(data, cf, "[%"PRId64"] <- [HEADERS]", stream3_id);
break;
case QUICHE_H3_EVENT_DATA:
@@ -526,7 +556,7 @@ static CURLcode h3_process_event(struct Curl_cfilter *cf,
break;
case QUICHE_H3_EVENT_RESET:
- CURL_TRC_CF(data, cf, "[%"FMT_PRIu64"] RESET", stream->id);
+ CURL_TRC_CF(data, cf, "[%"PRId64"] RESET", stream3_id);
stream->closed = TRUE;
stream->reset = TRUE;
stream->send_closed = TRUE;
@@ -534,7 +564,7 @@ static CURLcode h3_process_event(struct Curl_cfilter *cf,
break;
case QUICHE_H3_EVENT_FINISHED:
- CURL_TRC_CF(data, cf, "[%"FMT_PRIu64"] CLOSED", stream->id);
+ CURL_TRC_CF(data, cf, "[%"PRId64"] CLOSED", stream3_id);
if(!stream->resp_hds_complete) {
result = write_resp_raw(cf, data, "\r\n", 2);
if(result)
@@ -546,12 +576,12 @@ static CURLcode h3_process_event(struct Curl_cfilter *cf,
break;
case QUICHE_H3_EVENT_GOAWAY:
- CURL_TRC_CF(data, cf, "[%"FMT_PRIu64"] <- [GOAWAY]", stream->id);
+ CURL_TRC_CF(data, cf, "[%"PRId64"] <- [GOAWAY]", stream3_id);
break;
default:
- CURL_TRC_CF(data, cf, "[%"FMT_PRIu64"] recv, unhandled event %d",
- stream->id, quiche_h3_event_type(ev));
+ CURL_TRC_CF(data, cf, "[%"PRId64"] recv, unhandled event %d",
+ stream3_id, quiche_h3_event_type(ev));
break;
}
return result;
@@ -561,33 +591,36 @@ static CURLcode cf_poll_events(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
struct cf_quiche_ctx *ctx = cf->ctx;
- struct stream_ctx *stream = NULL;
+ struct stream_ctx *stream = H3_STREAM_CTX(data);
struct Curl_easy *sdata;
quiche_h3_event *ev;
CURLcode result;
/* Take in the events and distribute them to the transfers. */
while(ctx->h3c) {
- curl_int64_t stream3_id = quiche_h3_conn_poll(ctx->h3c, ctx->qconn, &ev);
+ int64_t stream3_id = quiche_h3_conn_poll(ctx->h3c, ctx->qconn, &ev);
if(stream3_id == QUICHE_H3_ERR_DONE) {
break;
}
else if(stream3_id < 0) {
- CURL_TRC_CF(data, cf, "error poll: %"FMT_PRId64, stream3_id);
+ CURL_TRC_CF(data, cf, "[%"PRId64"] error poll: %"PRId64,
+ stream? stream->id : -1, stream3_id);
return CURLE_HTTP3;
}
- sdata = get_stream_easy(cf, data, stream3_id, &stream);
- if(!sdata || !stream) {
- CURL_TRC_CF(data, cf, "discard event %s for unknown [%"FMT_PRId64"]",
- cf_ev_name(ev), stream3_id);
+ sdata = get_stream_easy(cf, data, stream3_id);
+ if(!sdata) {
+ CURL_TRC_CF(data, cf, "[%"PRId64"] discard event %s for "
+ "unknown [%"PRId64"]",
+ stream? stream->id : -1, cf_ev_name(ev), stream3_id);
}
else {
- result = h3_process_event(cf, sdata, stream, ev);
+ result = h3_process_event(cf, sdata, stream3_id, ev);
drain_stream(cf, sdata);
if(result) {
- CURL_TRC_CF(data, cf, "error processing event %s "
- "for [%"FMT_PRIu64"] -> %d", cf_ev_name(ev),
+ CURL_TRC_CF(data, cf, "[%"PRId64"] error processing event %s "
+ "for [%"PRId64"] -> %d",
+ stream? stream->id : -1, cf_ev_name(ev),
stream3_id, result);
if(data == sdata) {
/* Only report this error to the caller if it is about the
@@ -631,19 +664,11 @@ static CURLcode recv_pkt(const unsigned char *pkt, size_t pktlen,
&recv_info);
if(nread < 0) {
if(QUICHE_ERR_DONE == nread) {
- if(quiche_conn_is_draining(ctx->qconn)) {
- CURL_TRC_CF(r->data, r->cf, "ingress, connection is draining");
- return CURLE_RECV_ERROR;
- }
- if(quiche_conn_is_closed(ctx->qconn)) {
- CURL_TRC_CF(r->data, r->cf, "ingress, connection is closed");
- return CURLE_RECV_ERROR;
- }
CURL_TRC_CF(r->data, r->cf, "ingress, quiche is DONE");
return CURLE_OK;
}
else if(QUICHE_ERR_TLS_FAIL == nread) {
- long verify_ok = SSL_get_verify_result(ctx->tls.ossl.ssl);
+ long verify_ok = SSL_get_verify_result(ctx->ssl);
if(verify_ok != X509_V_OK) {
failf(r->data, "SSL certificate problem: %s",
X509_verify_cert_error_string(verify_ok));
@@ -671,7 +696,7 @@ static CURLcode cf_process_ingress(struct Curl_cfilter *cf,
CURLcode result;
DEBUGASSERT(ctx->qconn);
- result = Curl_vquic_tls_before_recv(&ctx->tls, cf, data);
+ result = quic_x509_store_setup(cf, data);
if(result)
return result;
@@ -730,8 +755,8 @@ static CURLcode cf_flush_egress(struct Curl_cfilter *cf,
struct cf_quiche_ctx *ctx = cf->ctx;
ssize_t nread;
CURLcode result;
- curl_int64_t expiry_ns;
- curl_int64_t timeout_ns;
+ int64_t expiry_ns;
+ int64_t timeout_ns;
struct read_ctx readx;
size_t pkt_count, gsolen;
@@ -739,13 +764,7 @@ static CURLcode cf_flush_egress(struct Curl_cfilter *cf,
if(!expiry_ns) {
quiche_conn_on_timeout(ctx->qconn);
if(quiche_conn_is_closed(ctx->qconn)) {
- if(quiche_conn_is_timed_out(ctx->qconn))
- failf(data, "connection closed by idle timeout");
- else
- failf(data, "connection closed by server");
- /* Connection timed out, expire all transfers belonging to it
- * as will not get any more POLL events here. */
- cf_quiche_expire_conn_closed(cf, data);
+ failf(data, "quiche_conn_on_timeout closed the connection");
return CURLE_SEND_ERROR;
}
}
@@ -810,26 +829,25 @@ static ssize_t recv_closed_stream(struct Curl_cfilter *cf,
struct Curl_easy *data,
CURLcode *err)
{
- struct cf_quiche_ctx *ctx = cf->ctx;
- struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
+ struct stream_ctx *stream = H3_STREAM_CTX(data);
ssize_t nread = -1;
DEBUGASSERT(stream);
if(stream->reset) {
failf(data,
- "HTTP/3 stream %" FMT_PRIu64 " reset by server", stream->id);
- *err = data->req.bytecount? CURLE_PARTIAL_FILE : CURLE_HTTP3;
- CURL_TRC_CF(data, cf, "[%" FMT_PRIu64 "] cf_recv, was reset -> %d",
+ "HTTP/3 stream %" PRId64 " reset by server", stream->id);
+ *err = stream->resp_got_header? CURLE_PARTIAL_FILE : CURLE_RECV_ERROR;
+ CURL_TRC_CF(data, cf, "[%" PRId64 "] cf_recv, was reset -> %d",
stream->id, *err);
}
else if(!stream->resp_got_header) {
failf(data,
- "HTTP/3 stream %" FMT_PRIu64 " was closed cleanly, but before "
- "getting all response header fields, treated as error",
+ "HTTP/3 stream %" PRId64 " was closed cleanly, but before getting"
+ " all response header fields, treated as error",
stream->id);
/* *err = CURLE_PARTIAL_FILE; */
- *err = CURLE_HTTP3;
- CURL_TRC_CF(data, cf, "[%" FMT_PRIu64 "] cf_recv, closed incomplete"
+ *err = CURLE_RECV_ERROR;
+ CURL_TRC_CF(data, cf, "[%" PRId64 "] cf_recv, closed incomplete"
" -> %d", stream->id, *err);
}
else {
@@ -843,7 +861,7 @@ static ssize_t cf_quiche_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
char *buf, size_t len, CURLcode *err)
{
struct cf_quiche_ctx *ctx = cf->ctx;
- struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
+ struct stream_ctx *stream = H3_STREAM_CTX(data);
ssize_t nread = -1;
CURLcode result;
@@ -857,7 +875,7 @@ static ssize_t cf_quiche_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
if(!Curl_bufq_is_empty(&stream->recvbuf)) {
nread = Curl_bufq_read(&stream->recvbuf,
(unsigned char *)buf, len, err);
- CURL_TRC_CF(data, cf, "[%" FMT_PRIu64 "] read recvbuf(len=%zu) "
+ CURL_TRC_CF(data, cf, "[%" PRId64 "] read recvbuf(len=%zu) "
"-> %zd, %d", stream->id, len, nread, *err);
if(nread < 0)
goto out;
@@ -874,7 +892,7 @@ static ssize_t cf_quiche_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
if(nread < 0 && !Curl_bufq_is_empty(&stream->recvbuf)) {
nread = Curl_bufq_read(&stream->recvbuf,
(unsigned char *)buf, len, err);
- CURL_TRC_CF(data, cf, "[%" FMT_PRIu64 "] read recvbuf(len=%zu) "
+ CURL_TRC_CF(data, cf, "[%" PRId64 "] read recvbuf(len=%zu) "
"-> %zd, %d", stream->id, len, nread, *err);
if(nread < 0)
goto out;
@@ -908,76 +926,25 @@ out:
}
if(nread > 0)
ctx->data_recvd += nread;
- CURL_TRC_CF(data, cf, "[%"FMT_PRIu64"] cf_recv(total=%"
- FMT_OFF_T ") -> %zd, %d",
+ CURL_TRC_CF(data, cf, "[%"PRId64"] cf_recv(total=%"
+ CURL_FORMAT_CURL_OFF_T ") -> %zd, %d",
stream->id, ctx->data_recvd, nread, *err);
return nread;
}
-static ssize_t cf_quiche_send_body(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- struct stream_ctx *stream,
- const void *buf, size_t len, bool eos,
- CURLcode *err)
-{
- struct cf_quiche_ctx *ctx = cf->ctx;
- ssize_t nwritten;
-
- nwritten = quiche_h3_send_body(ctx->h3c, ctx->qconn, stream->id,
- (uint8_t *)buf, len, eos);
- if(nwritten == QUICHE_H3_ERR_DONE || (nwritten == 0 && len > 0)) {
- /* TODO: we seem to be blocked on flow control and should HOLD
- * sending. But when do we open again? */
- if(!quiche_conn_stream_writable(ctx->qconn, stream->id, len)) {
- CURL_TRC_CF(data, cf, "[%" FMT_PRIu64 "] send_body(len=%zu) "
- "-> window exhausted", stream->id, len);
- stream->quic_flow_blocked = TRUE;
- }
- *err = CURLE_AGAIN;
- return -1;
- }
- else if(nwritten == QUICHE_H3_TRANSPORT_ERR_INVALID_STREAM_STATE) {
- CURL_TRC_CF(data, cf, "[%" FMT_PRIu64 "] send_body(len=%zu) "
- "-> invalid stream state", stream->id, len);
- *err = CURLE_HTTP3;
- return -1;
- }
- else if(nwritten == QUICHE_H3_TRANSPORT_ERR_FINAL_SIZE) {
- CURL_TRC_CF(data, cf, "[%" FMT_PRIu64 "] send_body(len=%zu) "
- "-> exceeds size", stream->id, len);
- *err = CURLE_SEND_ERROR;
- return -1;
- }
- else if(nwritten < 0) {
- CURL_TRC_CF(data, cf, "[%" FMT_PRIu64 "] send_body(len=%zu) "
- "-> quiche err %zd", stream->id, len, nwritten);
- *err = CURLE_SEND_ERROR;
- return -1;
- }
- else {
- if(eos && (len == (size_t)nwritten))
- stream->send_closed = TRUE;
- CURL_TRC_CF(data, cf, "[%" FMT_PRIu64 "] send body(len=%zu, "
- "eos=%d) -> %zd",
- stream->id, len, stream->send_closed, nwritten);
- *err = CURLE_OK;
- return nwritten;
- }
-}
-
/* Index where :authority header field will appear in request header
field list. */
#define AUTHORITY_DST_IDX 3
static ssize_t h3_open_stream(struct Curl_cfilter *cf,
struct Curl_easy *data,
- const char *buf, size_t len, bool eos,
+ const void *buf, size_t len,
CURLcode *err)
{
struct cf_quiche_ctx *ctx = cf->ctx;
- struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
+ struct stream_ctx *stream = H3_STREAM_CTX(data);
size_t nheader, i;
- curl_int64_t stream3_id;
+ int64_t stream3_id;
struct dynhds h2_headers;
quiche_h3_header *nva = NULL;
ssize_t nwritten;
@@ -987,7 +954,7 @@ static ssize_t h3_open_stream(struct Curl_cfilter *cf,
if(*err) {
return -1;
}
- stream = H3_STREAM_CTX(ctx, data);
+ stream = H3_STREAM_CTX(data);
DEBUGASSERT(stream);
}
@@ -1027,7 +994,23 @@ static ssize_t h3_open_stream(struct Curl_cfilter *cf,
nva[i].value_len = e->valuelen;
}
- if(eos && ((size_t)nwritten == len))
+ switch(data->state.httpreq) {
+ case HTTPREQ_POST:
+ case HTTPREQ_POST_FORM:
+ case HTTPREQ_POST_MIME:
+ case HTTPREQ_PUT:
+ if(data->state.infilesize != -1)
+ stream->upload_left = data->state.infilesize;
+ else
+ /* data sending without specifying the data amount up front */
+ stream->upload_left = -1; /* unknown */
+ break;
+ default:
+ stream->upload_left = 0; /* no request body */
+ break;
+ }
+
+ if(stream->upload_left == 0)
stream->send_closed = TRUE;
stream3_id = quiche_h3_send_request(ctx->h3c, ctx->qconn, nva, nheader,
@@ -1036,14 +1019,14 @@ static ssize_t h3_open_stream(struct Curl_cfilter *cf,
if(QUICHE_H3_ERR_STREAM_BLOCKED == stream3_id) {
/* quiche seems to report this error if the connection window is
* exhausted. Which happens frequently and intermittent. */
- CURL_TRC_CF(data, cf, "[%"FMT_PRIu64"] blocked", stream->id);
+ CURL_TRC_CF(data, cf, "[%"PRId64"] blocked", stream->id);
stream->quic_flow_blocked = TRUE;
*err = CURLE_AGAIN;
nwritten = -1;
goto out;
}
else {
- CURL_TRC_CF(data, cf, "send_request(%s) -> %" FMT_PRIu64,
+ CURL_TRC_CF(data, cf, "send_request(%s) -> %" PRId64,
data->state.url, stream3_id);
}
*err = CURLE_SEND_ERROR;
@@ -1051,39 +1034,22 @@ static ssize_t h3_open_stream(struct Curl_cfilter *cf,
goto out;
}
- DEBUGASSERT(!stream->opened);
+ DEBUGASSERT(stream->id == -1);
*err = CURLE_OK;
stream->id = stream3_id;
- stream->opened = TRUE;
stream->closed = FALSE;
stream->reset = FALSE;
if(Curl_trc_is_verbose(data)) {
- infof(data, "[HTTP/3] [%" FMT_PRIu64 "] OPENED stream for %s",
+ infof(data, "[HTTP/3] [%" PRId64 "] OPENED stream for %s",
stream->id, data->state.url);
for(i = 0; i < nheader; ++i) {
- infof(data, "[HTTP/3] [%" FMT_PRIu64 "] [%.*s: %.*s]", stream->id,
+ infof(data, "[HTTP/3] [%" PRId64 "] [%.*s: %.*s]", stream->id,
(int)nva[i].name_len, nva[i].name,
(int)nva[i].value_len, nva[i].value);
}
}
- if(nwritten > 0 && ((size_t)nwritten < len)) {
- /* after the headers, there was request BODY data */
- size_t hds_len = (size_t)nwritten;
- ssize_t bwritten;
-
- bwritten = cf_quiche_send_body(cf, data, stream,
- buf + hds_len, len - hds_len, eos, err);
- if((bwritten < 0) && (CURLE_AGAIN != *err)) {
- /* real error, fail */
- nwritten = -1;
- }
- else if(bwritten > 0) {
- nwritten += bwritten;
- }
- }
-
out:
free(nva);
Curl_dynhds_free(&h2_headers);
@@ -1091,11 +1057,10 @@ out:
}
static ssize_t cf_quiche_send(struct Curl_cfilter *cf, struct Curl_easy *data,
- const void *buf, size_t len, bool eos,
- CURLcode *err)
+ const void *buf, size_t len, CURLcode *err)
{
struct cf_quiche_ctx *ctx = cf->ctx;
- struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
+ struct stream_ctx *stream = H3_STREAM_CTX(data);
CURLcode result;
ssize_t nwritten;
@@ -1107,14 +1072,31 @@ static ssize_t cf_quiche_send(struct Curl_cfilter *cf, struct Curl_easy *data,
goto out;
}
- if(!stream || !stream->opened) {
- nwritten = h3_open_stream(cf, data, buf, len, eos, err);
+ if(!stream || stream->id < 0) {
+ nwritten = h3_open_stream(cf, data, buf, len, err);
if(nwritten < 0)
goto out;
- stream = H3_STREAM_CTX(ctx, data);
+ stream = H3_STREAM_CTX(data);
}
- else if(stream->closed) {
- if(stream->resp_hds_complete) {
+ else {
+ bool eof = (stream->upload_left >= 0 &&
+ (curl_off_t)len >= stream->upload_left);
+ nwritten = quiche_h3_send_body(ctx->h3c, ctx->qconn, stream->id,
+ (uint8_t *)buf, len, eof);
+ if(nwritten == QUICHE_H3_ERR_DONE || (nwritten == 0 && len > 0)) {
+ /* TODO: we seem to be blocked on flow control and should HOLD
+ * sending. But when do we open again? */
+ if(!quiche_conn_stream_writable(ctx->qconn, stream->id, len)) {
+ CURL_TRC_CF(data, cf, "[%" PRId64 "] send_body(len=%zu) "
+ "-> window exhausted", stream->id, len);
+ stream->quic_flow_blocked = TRUE;
+ }
+ *err = CURLE_AGAIN;
+ nwritten = -1;
+ goto out;
+ }
+ else if(nwritten == QUICHE_H3_TRANSPORT_ERR_INVALID_STREAM_STATE &&
+ stream->closed && stream->resp_hds_complete) {
/* sending request body on a stream that has been closed by the
* server. If the server has send us a final response, we should
* silently discard the send data.
@@ -1123,20 +1105,40 @@ static ssize_t cf_quiche_send(struct Curl_cfilter *cf, struct Curl_easy *data,
* sending the 30x response.
* This is sort of a race: had the transfer loop called recv first,
* it would see the response and stop/discard sending on its own- */
- CURL_TRC_CF(data, cf, "[%" FMT_PRIu64 "] discarding data"
+ CURL_TRC_CF(data, cf, "[%" PRId64 "] discarding data"
"on closed stream with response", stream->id);
*err = CURLE_OK;
nwritten = (ssize_t)len;
goto out;
}
- CURL_TRC_CF(data, cf, "[%" FMT_PRIu64 "] send_body(len=%zu) "
- "-> stream closed", stream->id, len);
- *err = CURLE_HTTP3;
- nwritten = -1;
- goto out;
- }
- else {
- nwritten = cf_quiche_send_body(cf, data, stream, buf, len, eos, err);
+ else if(nwritten == QUICHE_H3_TRANSPORT_ERR_FINAL_SIZE) {
+ CURL_TRC_CF(data, cf, "[%" PRId64 "] send_body(len=%zu) "
+ "-> exceeds size", stream->id, len);
+ *err = CURLE_SEND_ERROR;
+ nwritten = -1;
+ goto out;
+ }
+ else if(nwritten < 0) {
+ CURL_TRC_CF(data, cf, "[%" PRId64 "] send_body(len=%zu) "
+ "-> quiche err %zd", stream->id, len, nwritten);
+ *err = CURLE_SEND_ERROR;
+ nwritten = -1;
+ goto out;
+ }
+ else {
+ /* quiche accepted all or at least a part of the buf */
+ if(stream->upload_left > 0) {
+ stream->upload_left = (nwritten < stream->upload_left)?
+ (stream->upload_left - nwritten) : 0;
+ }
+ if(stream->upload_left == 0)
+ stream->send_closed = TRUE;
+
+ CURL_TRC_CF(data, cf, "[%" PRId64 "] send body(len=%zu, "
+ "left=%" CURL_FORMAT_CURL_OFF_T ") -> %zd",
+ stream->id, len, stream->upload_left, nwritten);
+ *err = CURLE_OK;
+ }
}
out:
@@ -1145,8 +1147,8 @@ out:
*err = result;
nwritten = -1;
}
- CURL_TRC_CF(data, cf, "[%" FMT_PRIu64 "] cf_send(len=%zu) -> %zd, %d",
- stream? stream->id : (curl_uint64_t)~0, len, nwritten, *err);
+ CURL_TRC_CF(data, cf, "[%" PRId64 "] cf_send(len=%zu) -> %zd, %d",
+ stream? stream->id : -1, len, nwritten, *err);
return nwritten;
}
@@ -1154,10 +1156,10 @@ static bool stream_is_writeable(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
struct cf_quiche_ctx *ctx = cf->ctx;
- struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
+ struct stream_ctx *stream = H3_STREAM_CTX(data);
- return stream && (quiche_conn_stream_writable(
- ctx->qconn, (curl_uint64_t)stream->id, 1) > 0);
+ return stream && (quiche_conn_stream_writable(ctx->qconn,
+ (uint64_t)stream->id, 1) > 0);
}
static void cf_quiche_adjust_pollset(struct Curl_cfilter *cf,
@@ -1165,19 +1167,16 @@ static void cf_quiche_adjust_pollset(struct Curl_cfilter *cf,
struct easy_pollset *ps)
{
struct cf_quiche_ctx *ctx = cf->ctx;
- bool want_recv, want_send;
+ bool want_recv = CURL_WANT_RECV(data);
+ bool want_send = CURL_WANT_SEND(data);
- if(!ctx->qconn)
- return;
-
- Curl_pollset_check(data, ps, ctx->q.sockfd, &want_recv, &want_send);
- if(want_recv || want_send) {
- struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
+ if(ctx->qconn && (want_recv || want_send)) {
+ struct stream_ctx *stream = H3_STREAM_CTX(data);
bool c_exhaust, s_exhaust;
c_exhaust = FALSE; /* Have not found any call in quiche that tells
us if the connection itself is blocked */
- s_exhaust = want_send && stream && stream->opened &&
+ s_exhaust = want_send && stream && stream->id >= 0 &&
(stream->quic_flow_blocked || !stream_is_writeable(cf, data));
want_recv = (want_recv || c_exhaust || s_exhaust);
want_send = (!s_exhaust && want_send) ||
@@ -1194,8 +1193,7 @@ static void cf_quiche_adjust_pollset(struct Curl_cfilter *cf,
static bool cf_quiche_data_pending(struct Curl_cfilter *cf,
const struct Curl_easy *data)
{
- struct cf_quiche_ctx *ctx = cf->ctx;
- const struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
+ const struct stream_ctx *stream = H3_STREAM_CTX(data);
(void)cf;
return stream && !Curl_bufq_is_empty(&stream->recvbuf);
}
@@ -1217,7 +1215,6 @@ static CURLcode cf_quiche_data_event(struct Curl_cfilter *cf,
struct Curl_easy *data,
int event, int arg1, void *arg2)
{
- struct cf_quiche_ctx *ctx = cf->ctx;
CURLcode result = CURLE_OK;
(void)arg1;
@@ -1235,21 +1232,22 @@ static CURLcode cf_quiche_data_event(struct Curl_cfilter *cf,
h3_data_done(cf, data);
break;
case CF_CTRL_DATA_DONE_SEND: {
- struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
+ struct stream_ctx *stream = H3_STREAM_CTX(data);
if(stream && !stream->send_closed) {
unsigned char body[1];
ssize_t sent;
stream->send_closed = TRUE;
+ stream->upload_left = 0;
body[0] = 'X';
- sent = cf_quiche_send(cf, data, body, 0, TRUE, &result);
- CURL_TRC_CF(data, cf, "[%"FMT_PRIu64"] DONE_SEND -> %zd, %d",
+ sent = cf_quiche_send(cf, data, body, 0, &result);
+ CURL_TRC_CF(data, cf, "[%"PRId64"] DONE_SEND -> %zd, %d",
stream->id, sent, result);
}
break;
}
case CF_CTRL_DATA_IDLE: {
- struct stream_ctx *stream = H3_STREAM_CTX(ctx, data);
+ struct stream_ctx *stream = H3_STREAM_CTX(data);
if(stream && !stream->closed) {
result = cf_flush_egress(cf, data);
if(result)
@@ -1263,8 +1261,68 @@ static CURLcode cf_quiche_data_event(struct Curl_cfilter *cf,
return result;
}
-static CURLcode cf_quiche_ctx_open(struct Curl_cfilter *cf,
- struct Curl_easy *data)
+static CURLcode cf_verify_peer(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
+{
+ struct cf_quiche_ctx *ctx = cf->ctx;
+ struct ssl_primary_config *conn_config;
+ CURLcode result = CURLE_OK;
+
+ conn_config = Curl_ssl_cf_get_primary_config(cf);
+ if(!conn_config)
+ return CURLE_FAILED_INIT;
+
+ cf->conn->bits.multiplex = TRUE; /* at least potentially multiplexed */
+ cf->conn->httpversion = 30;
+ cf->conn->bundle->multiuse = BUNDLE_MULTIPLEX;
+
+ if(conn_config->verifyhost) {
+ X509 *server_cert;
+ server_cert = SSL_get_peer_certificate(ctx->ssl);
+ if(!server_cert) {
+ result = CURLE_PEER_FAILED_VERIFICATION;
+ goto out;
+ }
+ result = Curl_ossl_verifyhost(data, cf->conn, &ctx->peer, server_cert);
+ X509_free(server_cert);
+ if(result)
+ goto out;
+ }
+ else
+ CURL_TRC_CF(data, cf, "Skipped certificate verification");
+
+ ctx->h3config = quiche_h3_config_new();
+ if(!ctx->h3config) {
+ result = CURLE_OUT_OF_MEMORY;
+ goto out;
+ }
+
+ /* Create a new HTTP/3 connection on the QUIC connection. */
+ ctx->h3c = quiche_h3_conn_new_with_transport(ctx->qconn, ctx->h3config);
+ if(!ctx->h3c) {
+ result = CURLE_OUT_OF_MEMORY;
+ goto out;
+ }
+ if(data->set.ssl.certinfo)
+ /* asked to gather certificate info */
+ (void)Curl_ossl_certchain(data, ctx->ssl);
+
+out:
+ if(result) {
+ if(ctx->h3config) {
+ quiche_h3_config_free(ctx->h3config);
+ ctx->h3config = NULL;
+ }
+ if(ctx->h3c) {
+ quiche_h3_conn_free(ctx->h3c);
+ ctx->h3c = NULL;
+ }
+ }
+ return result;
+}
+
+static CURLcode cf_connect_start(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
struct cf_quiche_ctx *ctx = cf->ctx;
int rv;
@@ -1272,23 +1330,31 @@ static CURLcode cf_quiche_ctx_open(struct Curl_cfilter *cf,
const struct Curl_sockaddr_ex *sockaddr;
DEBUGASSERT(ctx->q.sockfd != CURL_SOCKET_BAD);
- DEBUGASSERT(ctx->initialized);
- result = vquic_ctx_init(&ctx->q);
- if(result)
- return result;
+#ifdef DEBUG_QUICHE
+ /* initialize debug log callback only once */
+ static int debug_log_init = 0;
+ if(!debug_log_init) {
+ quiche_enable_debug_logging(quiche_debug_log, NULL);
+ debug_log_init = 1;
+ }
+#endif
+ ctx->max_idle_ms = CURL_QUIC_MAX_IDLE_MS;
+ Curl_bufcp_init(&ctx->stream_bufcp, H3_STREAM_CHUNK_SIZE,
+ H3_STREAM_POOL_SPARES);
+ ctx->data_recvd = 0;
- result = Curl_ssl_peer_init(&ctx->peer, cf, TRNSPRT_QUIC);
+ result = vquic_ctx_init(&ctx->q);
if(result)
return result;
ctx->cfg = quiche_config_new(QUICHE_PROTOCOL_VERSION);
if(!ctx->cfg) {
- failf(data, "cannot create quiche config");
+ failf(data, "can't create quiche config");
return CURLE_FAILED_INIT;
}
quiche_config_enable_pacing(ctx->cfg, false);
- quiche_config_set_max_idle_timeout(ctx->cfg, CURL_QUIC_MAX_IDLE_MS);
+ quiche_config_set_max_idle_timeout(ctx->cfg, ctx->max_idle_ms * 1000);
quiche_config_set_initial_max_data(ctx->cfg, (1 * 1024 * 1024)
/* (QUIC_MAX_STREAMS/2) * H3_STREAM_WINDOW_SIZE */);
quiche_config_set_initial_max_streams_bidi(ctx->cfg, QUIC_MAX_STREAMS);
@@ -1310,10 +1376,9 @@ static CURLcode cf_quiche_ctx_open(struct Curl_cfilter *cf,
sizeof(QUICHE_H3_APPLICATION_PROTOCOL)
- 1);
- result = Curl_vquic_tls_init(&ctx->tls, cf, data, &ctx->peer,
- QUICHE_H3_APPLICATION_PROTOCOL,
- sizeof(QUICHE_H3_APPLICATION_PROTOCOL) - 1,
- NULL, NULL, cf);
+ DEBUGASSERT(!ctx->ssl);
+ DEBUGASSERT(!ctx->sslctx);
+ result = quic_ssl_setup(cf, data);
if(result)
return result;
@@ -1321,7 +1386,8 @@ static CURLcode cf_quiche_ctx_open(struct Curl_cfilter *cf,
if(result)
return result;
- Curl_cf_socket_peek(cf->next, data, &ctx->q.sockfd, &sockaddr, NULL);
+ Curl_cf_socket_peek(cf->next, data, &ctx->q.sockfd,
+ &sockaddr, NULL, NULL, NULL, NULL);
ctx->q.local_addrlen = sizeof(ctx->q.local_addr);
rv = getsockname(ctx->q.sockfd, (struct sockaddr *)&ctx->q.local_addr,
&ctx->q.local_addrlen);
@@ -1333,9 +1399,9 @@ static CURLcode cf_quiche_ctx_open(struct Curl_cfilter *cf,
(struct sockaddr *)&ctx->q.local_addr,
ctx->q.local_addrlen,
&sockaddr->sa_addr, sockaddr->addrlen,
- ctx->cfg, ctx->tls.ossl.ssl, false);
+ ctx->cfg, ctx->ssl, false);
if(!ctx->qconn) {
- failf(data, "cannot create quiche connection");
+ failf(data, "can't create quiche connection");
return CURLE_OUT_OF_MEMORY;
}
@@ -1372,17 +1438,6 @@ static CURLcode cf_quiche_ctx_open(struct Curl_cfilter *cf,
return CURLE_OK;
}
-static CURLcode cf_quiche_verify_peer(struct Curl_cfilter *cf,
- struct Curl_easy *data)
-{
- struct cf_quiche_ctx *ctx = cf->ctx;
-
- cf->conn->bits.multiplex = TRUE; /* at least potentially multiplexed */
- cf->conn->httpversion = 30;
-
- return Curl_vquic_tls_verify_peer(&ctx->tls, cf, data, &ctx->peer);
-}
-
static CURLcode cf_quiche_connect(struct Curl_cfilter *cf,
struct Curl_easy *data,
bool blocking, bool *done)
@@ -1405,8 +1460,15 @@ static CURLcode cf_quiche_connect(struct Curl_cfilter *cf,
*done = FALSE;
vquic_ctx_update_time(&ctx->q);
+ if(ctx->reconnect_at.tv_sec &&
+ Curl_timediff(ctx->q.last_op, ctx->reconnect_at) < 0) {
+ /* Not time yet to attempt the next connect */
+ CURL_TRC_CF(data, cf, "waiting for reconnect time");
+ goto out;
+ }
+
if(!ctx->qconn) {
- result = cf_quiche_ctx_open(cf, data);
+ result = cf_connect_start(cf, data);
if(result)
goto out;
ctx->started_at = ctx->q.last_op;
@@ -1427,21 +1489,9 @@ static CURLcode cf_quiche_connect(struct Curl_cfilter *cf,
ctx->handshake_at = ctx->q.last_op;
CURL_TRC_CF(data, cf, "handshake complete after %dms",
(int)Curl_timediff(ctx->handshake_at, ctx->started_at));
- result = cf_quiche_verify_peer(cf, data);
+ result = cf_verify_peer(cf, data);
if(!result) {
CURL_TRC_CF(data, cf, "peer verified");
- ctx->h3config = quiche_h3_config_new();
- if(!ctx->h3config) {
- result = CURLE_OUT_OF_MEMORY;
- goto out;
- }
-
- /* Create a new HTTP/3 connection on the QUIC connection. */
- ctx->h3c = quiche_h3_conn_new_with_transport(ctx->qconn, ctx->h3config);
- if(!ctx->h3c) {
- result = CURLE_OUT_OF_MEMORY;
- goto out;
- }
cf->connected = TRUE;
cf->conn->alpn = CURL_HTTP_VERSION_3;
*done = TRUE;
@@ -1459,79 +1509,42 @@ static CURLcode cf_quiche_connect(struct Curl_cfilter *cf,
out:
#ifndef CURL_DISABLE_VERBOSE_STRINGS
if(result && result != CURLE_AGAIN) {
- struct ip_quadruple ip;
+ const char *r_ip;
+ int r_port;
- Curl_cf_socket_peek(cf->next, data, NULL, NULL, &ip);
+ Curl_cf_socket_peek(cf->next, data, NULL, NULL,
+ &r_ip, &r_port, NULL, NULL);
infof(data, "connect to %s port %u failed: %s",
- ip.remote_ip, ip.remote_port, curl_easy_strerror(result));
+ r_ip, r_port, curl_easy_strerror(result));
}
#endif
return result;
}
-static CURLcode cf_quiche_shutdown(struct Curl_cfilter *cf,
- struct Curl_easy *data, bool *done)
+static void cf_quiche_close(struct Curl_cfilter *cf, struct Curl_easy *data)
{
struct cf_quiche_ctx *ctx = cf->ctx;
- CURLcode result = CURLE_OK;
-
- if(cf->shutdown || !ctx || !ctx->qconn) {
- *done = TRUE;
- return CURLE_OK;
- }
- *done = FALSE;
- if(!ctx->shutdown_started) {
- int err;
-
- ctx->shutdown_started = TRUE;
- vquic_ctx_update_time(&ctx->q);
- err = quiche_conn_close(ctx->qconn, TRUE, 0, NULL, 0);
- if(err) {
- CURL_TRC_CF(data, cf, "error %d adding shutdown packet, "
- "aborting shutdown", err);
- result = CURLE_SEND_ERROR;
- goto out;
+ if(ctx) {
+ if(ctx->qconn) {
+ vquic_ctx_update_time(&ctx->q);
+ (void)quiche_conn_close(ctx->qconn, TRUE, 0, NULL, 0);
+ /* flushing the egress is not a failsafe way to deliver all the
+ outstanding packets, but we also don't want to get stuck here... */
+ (void)cf_flush_egress(cf, data);
}
- }
-
- if(!Curl_bufq_is_empty(&ctx->q.sendbuf)) {
- CURL_TRC_CF(data, cf, "shutdown, flushing sendbuf");
- result = cf_flush_egress(cf, data);
- if(result)
- goto out;
- }
-
- if(Curl_bufq_is_empty(&ctx->q.sendbuf)) {
- /* sent everything, quiche does not seem to support a graceful
- * shutdown waiting for a reply, so ware done. */
- CURL_TRC_CF(data, cf, "shutdown completely sent off, done");
- *done = TRUE;
- }
- else {
- CURL_TRC_CF(data, cf, "shutdown sending blocked");
- }
-
-out:
- return result;
-}
-
-static void cf_quiche_close(struct Curl_cfilter *cf, struct Curl_easy *data)
-{
- if(cf->ctx) {
- bool done;
- (void)cf_quiche_shutdown(cf, data, &done);
- cf_quiche_ctx_close(cf->ctx);
+ cf_quiche_ctx_clear(ctx);
}
}
static void cf_quiche_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
{
+ struct cf_quiche_ctx *ctx = cf->ctx;
+
(void)data;
- if(cf->ctx) {
- cf_quiche_ctx_free(cf->ctx);
- cf->ctx = NULL;
- }
+ cf_quiche_ctx_clear(ctx);
+ free(ctx);
+ cf->ctx = NULL;
}
static CURLcode cf_quiche_query(struct Curl_cfilter *cf,
@@ -1542,19 +1555,17 @@ static CURLcode cf_quiche_query(struct Curl_cfilter *cf,
switch(query) {
case CF_QUERY_MAX_CONCURRENT: {
- curl_uint64_t max_streams = CONN_INUSE(cf->conn);
+ uint64_t max_streams = CONN_INUSE(cf->conn);
if(!ctx->goaway) {
max_streams += quiche_conn_peer_streams_left_bidi(ctx->qconn);
}
*pres1 = (max_streams > INT_MAX)? INT_MAX : (int)max_streams;
- CURL_TRC_CF(data, cf, "query conn[%" FMT_OFF_T "]: "
- "MAX_CONCURRENT -> %d (%zu in use)",
- cf->conn->connection_id, *pres1, CONN_INUSE(cf->conn));
+ CURL_TRC_CF(data, cf, "query: MAX_CONCURRENT -> %d", *pres1);
return CURLE_OK;
}
case CF_QUERY_CONNECT_REPLY_MS:
- if(ctx->q.got_first_byte) {
- timediff_t ms = Curl_timediff(ctx->q.first_byte_at, ctx->started_at);
+ if(ctx->got_first_byte) {
+ timediff_t ms = Curl_timediff(ctx->first_byte_at, ctx->started_at);
*pres1 = (ms < INT_MAX)? (int)ms : INT_MAX;
}
else
@@ -1562,8 +1573,8 @@ static CURLcode cf_quiche_query(struct Curl_cfilter *cf,
return CURLE_OK;
case CF_QUERY_TIMER_CONNECT: {
struct curltime *when = pres2;
- if(ctx->q.got_first_byte)
- *when = ctx->q.first_byte_at;
+ if(ctx->got_first_byte)
+ *when = ctx->first_byte_at;
return CURLE_OK;
}
case CF_QUERY_TIMER_APPCONNECT: {
@@ -1591,20 +1602,31 @@ static bool cf_quiche_conn_is_alive(struct Curl_cfilter *cf,
if(!ctx->qconn)
return FALSE;
- if(quiche_conn_is_closed(ctx->qconn)) {
- if(quiche_conn_is_timed_out(ctx->qconn))
- CURL_TRC_CF(data, cf, "connection was closed due to idle timeout");
- else
- CURL_TRC_CF(data, cf, "connection is closed");
- return FALSE;
+ /* Both sides of the QUIC connection announce they max idle times in
+ * the transport parameters. Look at the minimum of both and if
+ * we exceed this, regard the connection as dead. The other side
+ * may have completely purged it and will no longer respond
+ * to any packets from us. */
+ {
+ quiche_transport_params qpeerparams;
+ timediff_t idletime;
+ uint64_t idle_ms = ctx->max_idle_ms;
+
+ if(quiche_conn_peer_transport_params(ctx->qconn, &qpeerparams) &&
+ qpeerparams.peer_max_idle_timeout &&
+ qpeerparams.peer_max_idle_timeout < idle_ms)
+ idle_ms = qpeerparams.peer_max_idle_timeout;
+ idletime = Curl_timediff(Curl_now(), cf->conn->lastused);
+ if(idletime > 0 && (uint64_t)idletime > idle_ms)
+ return FALSE;
}
if(!cf->next || !cf->next->cft->is_alive(cf->next, data, input_pending))
return FALSE;
if(*input_pending) {
- /* This happens before we have sent off a request and the connection is
- not in use by any other transfer, there should not be any data here,
+ /* This happens before we've sent off a request and the connection is
+ not in use by any other transfer, there shouldn't be any data here,
only "protocol frames" */
*input_pending = FALSE;
if(cf_process_ingress(cf, data))
@@ -1624,7 +1646,6 @@ struct Curl_cftype Curl_cft_http3 = {
cf_quiche_destroy,
cf_quiche_connect,
cf_quiche_close,
- cf_quiche_shutdown,
Curl_cf_def_get_host,
cf_quiche_adjust_pollset,
cf_quiche_data_pending,
@@ -1652,7 +1673,6 @@ CURLcode Curl_cf_quiche_create(struct Curl_cfilter **pcf,
result = CURLE_OUT_OF_MEMORY;
goto out;
}
- cf_quiche_ctx_init(ctx);
result = Curl_cf_create(&cf, &Curl_cft_http3, ctx);
if(result)
@@ -1672,7 +1692,7 @@ out:
if(udp_cf)
Curl_conn_cf_discard_sub(cf, udp_cf, data, TRUE);
Curl_safefree(cf);
- cf_quiche_ctx_free(ctx);
+ Curl_safefree(ctx);
}
return result;
diff --git a/contrib/libs/curl/lib/vquic/vquic-tls.c b/contrib/libs/curl/lib/vquic/vquic-tls.c
deleted file mode 100644
index 0361afb7f9..0000000000
--- a/contrib/libs/curl/lib/vquic/vquic-tls.c
+++ /dev/null
@@ -1,347 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at https://curl.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * SPDX-License-Identifier: curl
- *
- ***************************************************************************/
-
-#include "curl_setup.h"
-
-#if defined(USE_HTTP3) && \
- (defined(USE_OPENSSL) || defined(USE_GNUTLS) || defined(USE_WOLFSSL))
-
-#ifdef USE_OPENSSL
-#include <openssl/err.h>
-#include "vtls/openssl.h"
-#elif defined(USE_GNUTLS)
-#error #include <gnutls/abstract.h>
-#error #include <gnutls/gnutls.h>
-#error #include <gnutls/x509.h>
-#error #include <gnutls/crypto.h>
-#error #include <nettle/sha2.h>
-#include "vtls/gtls.h"
-#elif defined(USE_WOLFSSL)
-#error #include <wolfssl/options.h>
-#error #include <wolfssl/ssl.h>
-#error #include <wolfssl/quic.h>
-#include "vtls/wolfssl.h"
-#endif
-
-#include "urldata.h"
-#include "curl_trc.h"
-#include "cfilters.h"
-#include "multiif.h"
-#include "vtls/keylog.h"
-#include "vtls/vtls.h"
-#error #include "vquic-tls.h"
-
-/* The last 3 #include files should be in this order */
-#include "curl_printf.h"
-#include "curl_memory.h"
-#include "memdebug.h"
-
-#ifndef ARRAYSIZE
-#define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
-#endif
-
-#if defined(USE_WOLFSSL)
-
-#define QUIC_CIPHERS \
- "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_" \
- "POLY1305_SHA256:TLS_AES_128_CCM_SHA256"
-#define QUIC_GROUPS "P-256:P-384:P-521"
-
-#if defined(HAVE_SECRET_CALLBACK)
-static void keylog_callback(const WOLFSSL *ssl, const char *line)
-{
- (void)ssl;
- Curl_tls_keylog_write_line(line);
-}
-#endif
-
-static CURLcode Curl_wssl_init_ctx(struct curl_tls_ctx *ctx,
- struct Curl_cfilter *cf,
- struct Curl_easy *data,
- Curl_vquic_tls_ctx_setup *cb_setup,
- void *cb_user_data)
-{
- struct ssl_primary_config *conn_config;
- CURLcode result = CURLE_FAILED_INIT;
-
- conn_config = Curl_ssl_cf_get_primary_config(cf);
- if(!conn_config) {
- result = CURLE_FAILED_INIT;
- goto out;
- }
-
- ctx->wssl.ctx = wolfSSL_CTX_new(wolfTLSv1_3_client_method());
- if(!ctx->wssl.ctx) {
- result = CURLE_OUT_OF_MEMORY;
- goto out;
- }
-
- if(cb_setup) {
- result = cb_setup(cf, data, cb_user_data);
- if(result)
- goto out;
- }
-
- wolfSSL_CTX_set_default_verify_paths(ctx->wssl.ctx);
-
- if(wolfSSL_CTX_set_cipher_list(ctx->wssl.ctx, conn_config->cipher_list13 ?
- conn_config->cipher_list13 :
- QUIC_CIPHERS) != 1) {
- char error_buffer[256];
- ERR_error_string_n(ERR_get_error(), error_buffer, sizeof(error_buffer));
- failf(data, "wolfSSL failed to set ciphers: %s", error_buffer);
- result = CURLE_BAD_FUNCTION_ARGUMENT;
- goto out;
- }
-
- if(wolfSSL_CTX_set1_groups_list(ctx->wssl.ctx, conn_config->curves ?
- conn_config->curves :
- (char *)QUIC_GROUPS) != 1) {
- failf(data, "wolfSSL failed to set curves");
- result = CURLE_BAD_FUNCTION_ARGUMENT;
- goto out;
- }
-
- /* Open the file if a TLS or QUIC backend has not done this before. */
- Curl_tls_keylog_open();
- if(Curl_tls_keylog_enabled()) {
-#if defined(HAVE_SECRET_CALLBACK)
- wolfSSL_CTX_set_keylog_callback(ctx->wssl.ctx, keylog_callback);
-#else
- failf(data, "wolfSSL was built without keylog callback");
- result = CURLE_NOT_BUILT_IN;
- goto out;
-#endif
- }
-
- if(conn_config->verifypeer) {
- const char * const ssl_cafile = conn_config->CAfile;
- const char * const ssl_capath = conn_config->CApath;
-
- wolfSSL_CTX_set_verify(ctx->wssl.ctx, SSL_VERIFY_PEER, NULL);
- if(ssl_cafile || ssl_capath) {
- /* tell wolfSSL where to find CA certificates that are used to verify
- the server's certificate. */
- int rc =
- wolfSSL_CTX_load_verify_locations_ex(ctx->wssl.ctx, ssl_cafile,
- ssl_capath,
- WOLFSSL_LOAD_FLAG_IGNORE_ERR);
- if(SSL_SUCCESS != rc) {
- /* Fail if we insist on successfully verifying the server. */
- failf(data, "error setting certificate verify locations:"
- " CAfile: %s CApath: %s",
- ssl_cafile ? ssl_cafile : "none",
- ssl_capath ? ssl_capath : "none");
- result = CURLE_SSL_CACERT_BADFILE;
- goto out;
- }
- infof(data, " CAfile: %s", ssl_cafile ? ssl_cafile : "none");
- infof(data, " CApath: %s", ssl_capath ? ssl_capath : "none");
- }
-#ifdef CURL_CA_FALLBACK
- else {
- /* verifying the peer without any CA certificates will not work so
- use wolfSSL's built-in default as fallback */
- wolfSSL_CTX_set_default_verify_paths(ctx->wssl.ctx);
- }
-#endif
- }
- else {
- wolfSSL_CTX_set_verify(ctx->wssl.ctx, SSL_VERIFY_NONE, NULL);
- }
-
- /* give application a chance to interfere with SSL set up. */
- if(data->set.ssl.fsslctx) {
- Curl_set_in_callback(data, true);
- result = (*data->set.ssl.fsslctx)(data, ctx->wssl.ctx,
- data->set.ssl.fsslctxp);
- Curl_set_in_callback(data, false);
- if(result) {
- failf(data, "error signaled by ssl ctx callback");
- goto out;
- }
- }
- result = CURLE_OK;
-
-out:
- if(result && ctx->wssl.ctx) {
- SSL_CTX_free(ctx->wssl.ctx);
- ctx->wssl.ctx = NULL;
- }
- return result;
-}
-
-/** SSL callbacks ***/
-
-static CURLcode Curl_wssl_init_ssl(struct curl_tls_ctx *ctx,
- struct Curl_easy *data,
- struct ssl_peer *peer,
- const char *alpn, size_t alpn_len,
- void *user_data)
-{
- (void)data;
- DEBUGASSERT(!ctx->wssl.handle);
- DEBUGASSERT(ctx->wssl.ctx);
- ctx->wssl.handle = wolfSSL_new(ctx->wssl.ctx);
-
- wolfSSL_set_app_data(ctx->wssl.handle, user_data);
- wolfSSL_set_connect_state(ctx->wssl.handle);
- wolfSSL_set_quic_use_legacy_codepoint(ctx->wssl.handle, 0);
-
- if(alpn)
- wolfSSL_set_alpn_protos(ctx->wssl.handle, (const unsigned char *)alpn,
- (unsigned int)alpn_len);
-
- if(peer->sni) {
- wolfSSL_UseSNI(ctx->wssl.handle, WOLFSSL_SNI_HOST_NAME,
- peer->sni, (unsigned short)strlen(peer->sni));
- }
-
- return CURLE_OK;
-}
-#endif /* defined(USE_WOLFSSL) */
-
-CURLcode Curl_vquic_tls_init(struct curl_tls_ctx *ctx,
- struct Curl_cfilter *cf,
- struct Curl_easy *data,
- struct ssl_peer *peer,
- const char *alpn, size_t alpn_len,
- Curl_vquic_tls_ctx_setup *cb_setup,
- void *cb_user_data, void *ssl_user_data)
-{
- CURLcode result;
-
-#ifdef USE_OPENSSL
- (void)result;
- return Curl_ossl_ctx_init(&ctx->ossl, cf, data, peer, TRNSPRT_QUIC,
- (const unsigned char *)alpn, alpn_len,
- cb_setup, cb_user_data, NULL, ssl_user_data);
-#elif defined(USE_GNUTLS)
- (void)result;
- return Curl_gtls_ctx_init(&ctx->gtls, cf, data, peer,
- (const unsigned char *)alpn, alpn_len,
- cb_setup, cb_user_data, ssl_user_data);
-#elif defined(USE_WOLFSSL)
- result = Curl_wssl_init_ctx(ctx, cf, data, cb_setup, cb_user_data);
- if(result)
- return result;
-
- return Curl_wssl_init_ssl(ctx, data, peer, alpn, alpn_len, ssl_user_data);
-#else
-#error "no TLS lib in used, should not happen"
- return CURLE_FAILED_INIT;
-#endif
-}
-
-void Curl_vquic_tls_cleanup(struct curl_tls_ctx *ctx)
-{
-#ifdef USE_OPENSSL
- if(ctx->ossl.ssl)
- SSL_free(ctx->ossl.ssl);
- if(ctx->ossl.ssl_ctx)
- SSL_CTX_free(ctx->ossl.ssl_ctx);
-#elif defined(USE_GNUTLS)
- if(ctx->gtls.session)
- gnutls_deinit(ctx->gtls.session);
- Curl_gtls_shared_creds_free(&ctx->gtls.shared_creds);
-#elif defined(USE_WOLFSSL)
- if(ctx->wssl.handle)
- wolfSSL_free(ctx->wssl.handle);
- if(ctx->wssl.ctx)
- wolfSSL_CTX_free(ctx->wssl.ctx);
-#endif
- memset(ctx, 0, sizeof(*ctx));
-}
-
-CURLcode Curl_vquic_tls_before_recv(struct curl_tls_ctx *ctx,
- struct Curl_cfilter *cf,
- struct Curl_easy *data)
-{
-#ifdef USE_OPENSSL
- if(!ctx->ossl.x509_store_setup) {
- CURLcode result = Curl_ssl_setup_x509_store(cf, data, ctx->ossl.ssl_ctx);
- if(result)
- return result;
- ctx->ossl.x509_store_setup = TRUE;
- }
-#elif defined(USE_WOLFSSL)
- if(!ctx->wssl.x509_store_setup) {
- CURLcode result = Curl_wssl_setup_x509_store(cf, data, &ctx->wssl);
- if(result)
- return result;
- }
-#elif defined(USE_GNUTLS)
- if(!ctx->gtls.shared_creds->trust_setup) {
- CURLcode result = Curl_gtls_client_trust_setup(cf, data, &ctx->gtls);
- if(result)
- return result;
- }
-#else
- (void)ctx; (void)cf; (void)data;
-#endif
- return CURLE_OK;
-}
-
-CURLcode Curl_vquic_tls_verify_peer(struct curl_tls_ctx *ctx,
- struct Curl_cfilter *cf,
- struct Curl_easy *data,
- struct ssl_peer *peer)
-{
- struct ssl_primary_config *conn_config;
- CURLcode result = CURLE_OK;
-
- conn_config = Curl_ssl_cf_get_primary_config(cf);
- if(!conn_config)
- return CURLE_FAILED_INIT;
-
-#ifdef USE_OPENSSL
- (void)conn_config;
- result = Curl_oss_check_peer_cert(cf, data, &ctx->ossl, peer);
-#elif defined(USE_GNUTLS)
- if(conn_config->verifyhost) {
- result = Curl_gtls_verifyserver(data, ctx->gtls.session,
- conn_config, &data->set.ssl, peer,
- data->set.str[STRING_SSL_PINNEDPUBLICKEY]);
- if(result)
- return result;
- }
-#elif defined(USE_WOLFSSL)
- (void)data;
- if(conn_config->verifyhost) {
- if(peer->sni) {
- WOLFSSL_X509* cert = wolfSSL_get_peer_certificate(ctx->wssl.handle);
- if(wolfSSL_X509_check_host(cert, peer->sni, strlen(peer->sni), 0, NULL)
- == WOLFSSL_FAILURE) {
- result = CURLE_PEER_FAILED_VERIFICATION;
- }
- wolfSSL_X509_free(cert);
- }
-
- }
-#endif
- return result;
-}
-
-
-#endif /* !USE_HTTP3 && (USE_OPENSSL || USE_GNUTLS || USE_WOLFSSL) */
diff --git a/contrib/libs/curl/lib/vquic/vquic.c b/contrib/libs/curl/lib/vquic/vquic.c
index 4648b5a072..523b807bcc 100644
--- a/contrib/libs/curl/lib/vquic/vquic.c
+++ b/contrib/libs/curl/lib/vquic/vquic.c
@@ -22,7 +22,7 @@
*
***************************************************************************/
-/* WIP, experimental: use recvmmsg() on Linux
+/* WIP, experimental: use recvmmsg() on linux
* we have no configure check, yet
* and also it is only available for _GNU_SOURCE, which
* we do not use otherwise.
@@ -36,9 +36,6 @@
#include "curl_setup.h"
-#ifdef HAVE_NETINET_UDP_H
-#include <netinet/udp.h>
-#endif
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
@@ -49,7 +46,6 @@
#include "curl_trc.h"
#include "curl_msh3.h"
#include "curl_ngtcp2.h"
-#include "curl_osslq.h"
#include "curl_quiche.h"
#include "rand.h"
#include "vquic.h"
@@ -62,7 +58,7 @@
#include "memdebug.h"
-#ifdef USE_HTTP3
+#ifdef ENABLE_QUIC
#ifdef O_BINARY
#define QLOGMODE O_WRONLY|O_CREAT|O_BINARY
@@ -78,8 +74,6 @@ void Curl_quic_ver(char *p, size_t len)
{
#if defined(USE_NGTCP2) && defined(USE_NGHTTP3)
Curl_ngtcp2_ver(p, len);
-#elif defined(USE_OPENSSL_QUIC) && defined(USE_NGHTTP3)
- Curl_osslq_ver(p, len);
#elif defined(USE_QUICHE)
Curl_quiche_ver(p, len);
#elif defined(USE_MSH3)
@@ -185,7 +179,7 @@ static CURLcode do_sendmsg(struct Curl_cfilter *cf,
qctx->no_gso = TRUE;
return send_packet_no_gso(cf, data, qctx, pkt, pktlen, gsolen, psent);
}
- FALLTHROUGH();
+ /* FALLTHROUGH */
default:
failf(data, "sendmsg() returned %zd (errno %d)", sent, SOCKERRNO);
return CURLE_SEND_ERROR;
@@ -332,36 +326,6 @@ CURLcode vquic_send_tail_split(struct Curl_cfilter *cf, struct Curl_easy *data,
return vquic_flush(cf, data, qctx);
}
-#if defined(HAVE_SENDMMSG) || defined(HAVE_SENDMSG)
-static size_t msghdr_get_udp_gro(struct msghdr *msg)
-{
- int gso_size = 0;
-#if defined(__linux__) && defined(UDP_GRO)
- struct cmsghdr *cmsg;
-
- /* Workaround musl CMSG_NXTHDR issue */
-#ifndef __GLIBC__
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wsign-compare"
-#pragma clang diagnostic ignored "-Wcast-align"
-#endif
- for(cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) {
-#ifndef __GLIBC__
-#pragma clang diagnostic pop
-#endif
- if(cmsg->cmsg_level == SOL_UDP && cmsg->cmsg_type == UDP_GRO) {
- memcpy(&gso_size, CMSG_DATA(cmsg), sizeof(gso_size));
-
- break;
- }
- }
-#endif
- (void)msg;
-
- return (size_t)gso_size;
-}
-#endif
-
#ifdef HAVE_SENDMMSG
static CURLcode recvmmsg_packets(struct Curl_cfilter *cf,
struct Curl_easy *data,
@@ -372,16 +336,12 @@ static CURLcode recvmmsg_packets(struct Curl_cfilter *cf,
#define MMSG_NUM 64
struct iovec msg_iov[MMSG_NUM];
struct mmsghdr mmsg[MMSG_NUM];
- uint8_t msg_ctrl[MMSG_NUM * CMSG_SPACE(sizeof(uint16_t))];
uint8_t bufs[MMSG_NUM][2*1024];
struct sockaddr_storage remote_addr[MMSG_NUM];
size_t total_nread, pkts;
int mcount, i, n;
char errstr[STRERROR_LEN];
CURLcode result = CURLE_OK;
- size_t gso_size;
- size_t pktlen;
- size_t offset, to;
DEBUGASSERT(max_pkts > 0);
pkts = 0;
@@ -396,8 +356,6 @@ static CURLcode recvmmsg_packets(struct Curl_cfilter *cf,
mmsg[i].msg_hdr.msg_iovlen = 1;
mmsg[i].msg_hdr.msg_name = &remote_addr[i];
mmsg[i].msg_hdr.msg_namelen = sizeof(remote_addr[i]);
- mmsg[i].msg_hdr.msg_control = &msg_ctrl[i];
- mmsg[i].msg_hdr.msg_controllen = CMSG_SPACE(sizeof(uint16_t));
}
while((mcount = recvmmsg(qctx->sockfd, mmsg, n, 0, NULL)) == -1 &&
@@ -409,10 +367,12 @@ static CURLcode recvmmsg_packets(struct Curl_cfilter *cf,
goto out;
}
if(!cf->connected && SOCKERRNO == ECONNREFUSED) {
- struct ip_quadruple ip;
- Curl_cf_socket_peek(cf->next, data, NULL, NULL, &ip);
+ const char *r_ip = NULL;
+ int r_port = 0;
+ Curl_cf_socket_peek(cf->next, data, NULL, NULL,
+ &r_ip, &r_port, NULL, NULL);
failf(data, "QUIC: connection to %s port %u refused",
- ip.remote_ip, ip.remote_port);
+ r_ip, r_port);
result = CURLE_COULDNT_CONNECT;
goto out;
}
@@ -424,30 +384,14 @@ static CURLcode recvmmsg_packets(struct Curl_cfilter *cf,
}
CURL_TRC_CF(data, cf, "recvmmsg() -> %d packets", mcount);
+ pkts += mcount;
for(i = 0; i < mcount; ++i) {
total_nread += mmsg[i].msg_len;
-
- gso_size = msghdr_get_udp_gro(&mmsg[i].msg_hdr);
- if(gso_size == 0) {
- gso_size = mmsg[i].msg_len;
- }
-
- for(offset = 0; offset < mmsg[i].msg_len; offset = to) {
- ++pkts;
-
- to = offset + gso_size;
- if(to > mmsg[i].msg_len) {
- pktlen = mmsg[i].msg_len - offset;
- }
- else {
- pktlen = gso_size;
- }
-
- result = recv_cb(bufs[i] + offset, pktlen, mmsg[i].msg_hdr.msg_name,
- mmsg[i].msg_hdr.msg_namelen, 0, userp);
- if(result)
- goto out;
- }
+ result = recv_cb(bufs[i], mmsg[i].msg_len,
+ mmsg[i].msg_hdr.msg_name, mmsg[i].msg_hdr.msg_namelen,
+ 0, userp);
+ if(result)
+ goto out;
}
}
@@ -473,10 +417,6 @@ static CURLcode recvmsg_packets(struct Curl_cfilter *cf,
ssize_t nread;
char errstr[STRERROR_LEN];
CURLcode result = CURLE_OK;
- uint8_t msg_ctrl[CMSG_SPACE(sizeof(uint16_t))];
- size_t gso_size;
- size_t pktlen;
- size_t offset, to;
msg_iov.iov_base = buf;
msg_iov.iov_len = (int)sizeof(buf);
@@ -484,13 +424,11 @@ static CURLcode recvmsg_packets(struct Curl_cfilter *cf,
memset(&msg, 0, sizeof(msg));
msg.msg_iov = &msg_iov;
msg.msg_iovlen = 1;
- msg.msg_control = msg_ctrl;
DEBUGASSERT(max_pkts > 0);
for(pkts = 0, total_nread = 0; pkts < max_pkts;) {
msg.msg_name = &remote_addr;
msg.msg_namelen = sizeof(remote_addr);
- msg.msg_controllen = sizeof(msg_ctrl);
while((nread = recvmsg(qctx->sockfd, &msg, 0)) == -1 &&
SOCKERRNO == EINTR)
;
@@ -499,10 +437,12 @@ static CURLcode recvmsg_packets(struct Curl_cfilter *cf,
goto out;
}
if(!cf->connected && SOCKERRNO == ECONNREFUSED) {
- struct ip_quadruple ip;
- Curl_cf_socket_peek(cf->next, data, NULL, NULL, &ip);
+ const char *r_ip = NULL;
+ int r_port = 0;
+ Curl_cf_socket_peek(cf->next, data, NULL, NULL,
+ &r_ip, &r_port, NULL, NULL);
failf(data, "QUIC: connection to %s port %u refused",
- ip.remote_ip, ip.remote_port);
+ r_ip, r_port);
result = CURLE_COULDNT_CONNECT;
goto out;
}
@@ -513,29 +453,12 @@ static CURLcode recvmsg_packets(struct Curl_cfilter *cf,
goto out;
}
+ ++pkts;
total_nread += (size_t)nread;
-
- gso_size = msghdr_get_udp_gro(&msg);
- if(gso_size == 0) {
- gso_size = (size_t)nread;
- }
-
- for(offset = 0; offset < (size_t)nread; offset = to) {
- ++pkts;
-
- to = offset + gso_size;
- if(to > (size_t)nread) {
- pktlen = (size_t)nread - offset;
- }
- else {
- pktlen = gso_size;
- }
-
- result =
- recv_cb(buf + offset, pktlen, msg.msg_name, msg.msg_namelen, 0, userp);
- if(result)
- goto out;
- }
+ result = recv_cb(buf, (size_t)nread, msg.msg_name, msg.msg_namelen,
+ 0, userp);
+ if(result)
+ goto out;
}
out:
@@ -574,10 +497,12 @@ static CURLcode recvfrom_packets(struct Curl_cfilter *cf,
goto out;
}
if(!cf->connected && SOCKERRNO == ECONNREFUSED) {
- struct ip_quadruple ip;
- Curl_cf_socket_peek(cf->next, data, NULL, NULL, &ip);
+ const char *r_ip = NULL;
+ int r_port = 0;
+ Curl_cf_socket_peek(cf->next, data, NULL, NULL,
+ &r_ip, &r_port, NULL, NULL);
failf(data, "QUIC: connection to %s port %u refused",
- ip.remote_ip, ip.remote_port);
+ r_ip, r_port);
result = CURLE_COULDNT_CONNECT;
goto out;
}
@@ -618,13 +543,8 @@ CURLcode vquic_recv_packets(struct Curl_cfilter *cf,
#else
result = recvfrom_packets(cf, data, qctx, max_pkts, recv_cb, userp);
#endif
- if(!result) {
- if(!qctx->got_first_byte) {
- qctx->got_first_byte = TRUE;
- qctx->first_byte_at = qctx->last_op;
- }
+ if(!result)
qctx->last_io = qctx->last_op;
- }
return result;
}
@@ -683,8 +603,6 @@ CURLcode Curl_cf_quic_create(struct Curl_cfilter **pcf,
DEBUGASSERT(transport == TRNSPRT_QUIC);
#if defined(USE_NGTCP2) && defined(USE_NGHTTP3)
return Curl_cf_ngtcp2_create(pcf, data, conn, ai);
-#elif defined(USE_OPENSSL_QUIC) && defined(USE_NGHTTP3)
- return Curl_cf_osslq_create(pcf, data, conn, ai);
#elif defined(USE_QUICHE)
return Curl_cf_quiche_create(pcf, data, conn, ai);
#elif defined(USE_MSH3)
@@ -704,8 +622,6 @@ bool Curl_conn_is_http3(const struct Curl_easy *data,
{
#if defined(USE_NGTCP2) && defined(USE_NGHTTP3)
return Curl_conn_is_ngtcp2(data, conn, sockindex);
-#elif defined(USE_OPENSSL_QUIC) && defined(USE_NGHTTP3)
- return Curl_conn_is_osslq(data, conn, sockindex);
#elif defined(USE_QUICHE)
return Curl_conn_is_quiche(data, conn, sockindex);
#elif defined(USE_MSH3)
@@ -720,7 +636,7 @@ CURLcode Curl_conn_may_http3(struct Curl_easy *data,
const struct connectdata *conn)
{
if(conn->transport == TRNSPRT_UNIX) {
- /* cannot do QUIC over a Unix domain socket */
+ /* cannot do QUIC over a unix domain socket */
return CURLE_QUIC_CONNECT_ERROR;
}
if(!(conn->handler->flags & PROTOPT_SSL)) {
@@ -733,7 +649,7 @@ CURLcode Curl_conn_may_http3(struct Curl_easy *data,
return CURLE_URL_MALFORMAT;
}
if(conn->bits.httpproxy && conn->bits.tunnel_proxy) {
- failf(data, "HTTP/3 is not supported over an HTTP proxy");
+ failf(data, "HTTP/3 is not supported over a HTTP proxy");
return CURLE_URL_MALFORMAT;
}
#endif
@@ -741,7 +657,7 @@ CURLcode Curl_conn_may_http3(struct Curl_easy *data,
return CURLE_OK;
}
-#else /* USE_HTTP3 */
+#else /* ENABLE_QUIC */
CURLcode Curl_conn_may_http3(struct Curl_easy *data,
const struct connectdata *conn)
@@ -752,4 +668,4 @@ CURLcode Curl_conn_may_http3(struct Curl_easy *data,
return CURLE_NOT_BUILT_IN;
}
-#endif /* !USE_HTTP3 */
+#endif /* !ENABLE_QUIC */
diff --git a/contrib/libs/curl/lib/vquic/vquic.h b/contrib/libs/curl/lib/vquic/vquic.h
index c1ca1df6aa..dc73957aaf 100644
--- a/contrib/libs/curl/lib/vquic/vquic.h
+++ b/contrib/libs/curl/lib/vquic/vquic.h
@@ -26,7 +26,7 @@
#include "curl_setup.h"
-#ifdef USE_HTTP3
+#ifdef ENABLE_QUIC
struct Curl_cfilter;
struct Curl_easy;
struct connectdata;
@@ -52,11 +52,11 @@ bool Curl_conn_is_http3(const struct Curl_easy *data,
extern struct Curl_cftype Curl_cft_http3;
-#else /* USE_HTTP3 */
+#else /* ENABLE_QUIC */
#define Curl_conn_is_http3(a,b,c) FALSE
-#endif /* !USE_HTTP3 */
+#endif /* !ENABLE_QUIC */
CURLcode Curl_conn_may_http3(struct Curl_easy *data,
const struct connectdata *conn);
diff --git a/contrib/libs/curl/lib/vquic/vquic_int.h b/contrib/libs/curl/lib/vquic/vquic_int.h
index 754e1f5910..a820f39aec 100644
--- a/contrib/libs/curl/lib/vquic/vquic_int.h
+++ b/contrib/libs/curl/lib/vquic/vquic_int.h
@@ -27,7 +27,7 @@
#include "curl_setup.h"
#include "bufq.h"
-#ifdef USE_HTTP3
+#ifdef ENABLE_QUIC
#define MAX_PKT_BURST 10
#define MAX_UDP_PAYLOAD_SIZE 1452
@@ -40,7 +40,6 @@ struct cf_quic_ctx {
socklen_t local_addrlen; /* length of local address */
struct bufq sendbuf; /* buffer for sending one or more packets */
- struct curltime first_byte_at; /* when first byte was recvd */
struct curltime last_op; /* last (attempted) send/recv operation */
struct curltime last_io; /* last successful socket IO */
size_t gsolen; /* length of individual packets in send buf */
@@ -49,8 +48,7 @@ struct cf_quic_ctx {
#ifdef DEBUGBUILD
int wblock_percent; /* percent of writes doing EAGAIN */
#endif
- BIT(got_first_byte); /* if first byte was received */
- BIT(no_gso); /* do not use gso on sending */
+ bool no_gso; /* do not use gso on sending */
};
CURLcode vquic_ctx_init(struct cf_quic_ctx *qctx);
@@ -88,6 +86,6 @@ CURLcode vquic_recv_packets(struct Curl_cfilter *cf,
size_t max_pkts,
vquic_recv_pkt_cb *recv_cb, void *userp);
-#endif /* !USE_HTTP3 */
+#endif /* !ENABLE_QUIC */
#endif /* HEADER_CURL_VQUIC_QUIC_INT_H */
diff --git a/contrib/libs/curl/lib/vssh/libssh.c b/contrib/libs/curl/lib/vssh/libssh.c
index 7addb23ea8..88bfd6a409 100644
--- a/contrib/libs/curl/lib/vssh/libssh.c
+++ b/contrib/libs/curl/lib/vssh/libssh.c
@@ -31,6 +31,9 @@
#include <limits.h>
+#error #include <libssh/libssh.h>
+#error #include <libssh/sftp.h>
+
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif
@@ -86,6 +89,14 @@
#include "curl_memory.h"
#include "memdebug.h"
+/* in 0.10.0 or later, ignore deprecated warnings */
+#if defined(__GNUC__) && \
+ (LIBSSH_VERSION_MINOR >= 10) || \
+ (LIBSSH_VERSION_MAJOR > 0)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
+
/* A recent macro provided by libssh. Or make our own. */
#ifndef SSH_STRING_FREE_CHAR
#define SSH_STRING_FREE_CHAR(x) \
@@ -156,8 +167,7 @@ const struct Curl_handler Curl_handler_scp = {
ZERO_NULL, /* domore_getsock */
myssh_getsock, /* perform_getsock */
scp_disconnect, /* disconnect */
- ZERO_NULL, /* write_resp */
- ZERO_NULL, /* write_resp_hd */
+ ZERO_NULL, /* readwrite */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_SSH, /* defport */
@@ -184,8 +194,7 @@ const struct Curl_handler Curl_handler_sftp = {
ZERO_NULL, /* domore_getsock */
myssh_getsock, /* perform_getsock */
sftp_disconnect, /* disconnect */
- ZERO_NULL, /* write_resp */
- ZERO_NULL, /* write_resp_hd */
+ ZERO_NULL, /* readwrite */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_SSH, /* defport */
@@ -383,25 +392,28 @@ static int myssh_is_known(struct Curl_easy *data)
goto cleanup;
}
- if(data->set.str[STRING_SSH_KNOWNHOSTS]) {
+ if(data->set.ssl.primary.verifyhost != TRUE) {
+ rc = SSH_OK;
+ goto cleanup;
+ }
#if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,9,0)
- /* Get the known_key from the known hosts file */
- vstate = ssh_session_get_known_hosts_entry(sshc->ssh_session,
- &knownhostsentry);
-
- /* Case an entry was found in a known hosts file */
- if(knownhostsentry) {
- if(knownhostsentry->publickey) {
- rc = ssh_pki_export_pubkey_base64(knownhostsentry->publickey,
- &known_base64);
- if(rc != SSH_OK) {
- goto cleanup;
- }
- knownkey.key = known_base64;
- knownkey.len = strlen(known_base64);
+ /* Get the known_key from the known hosts file */
+ vstate = ssh_session_get_known_hosts_entry(sshc->ssh_session,
+ &knownhostsentry);
- switch(ssh_key_type(knownhostsentry->publickey)) {
+ /* Case an entry was found in a known hosts file */
+ if(knownhostsentry) {
+ if(knownhostsentry->publickey) {
+ rc = ssh_pki_export_pubkey_base64(knownhostsentry->publickey,
+ &known_base64);
+ if(rc != SSH_OK) {
+ goto cleanup;
+ }
+ knownkey.key = known_base64;
+ knownkey.len = strlen(known_base64);
+
+ switch(ssh_key_type(knownhostsentry->publickey)) {
case SSH_KEYTYPE_RSA:
knownkey.keytype = CURLKHTYPE_RSA;
break;
@@ -423,51 +435,55 @@ static int myssh_is_known(struct Curl_easy *data)
default:
rc = SSH_ERROR;
goto cleanup;
- }
- knownkeyp = &knownkey;
}
+ knownkeyp = &knownkey;
}
+ }
- switch(vstate) {
+ switch(vstate) {
case SSH_KNOWN_HOSTS_OK:
keymatch = CURLKHMATCH_OK;
break;
case SSH_KNOWN_HOSTS_OTHER:
+ /* fallthrough */
case SSH_KNOWN_HOSTS_NOT_FOUND:
+ /* fallthrough */
case SSH_KNOWN_HOSTS_UNKNOWN:
+ /* fallthrough */
case SSH_KNOWN_HOSTS_ERROR:
keymatch = CURLKHMATCH_MISSING;
break;
- default:
+ default:
keymatch = CURLKHMATCH_MISMATCH;
break;
- }
+ }
#else
- vstate = ssh_is_server_known(sshc->ssh_session);
- switch(vstate) {
+ vstate = ssh_is_server_known(sshc->ssh_session);
+ switch(vstate) {
case SSH_SERVER_KNOWN_OK:
keymatch = CURLKHMATCH_OK;
break;
case SSH_SERVER_FILE_NOT_FOUND:
+ /* fallthrough */
case SSH_SERVER_NOT_KNOWN:
keymatch = CURLKHMATCH_MISSING;
break;
- default:
+ default:
keymatch = CURLKHMATCH_MISMATCH;
break;
- }
+ }
#endif
- if(func) { /* use callback to determine action */
- rc = ssh_pki_export_pubkey_base64(pubkey, &found_base64);
- if(rc != SSH_OK)
- goto cleanup;
+ if(func) { /* use callback to determine action */
+ rc = ssh_pki_export_pubkey_base64(pubkey, &found_base64);
+ if(rc != SSH_OK)
+ goto cleanup;
- foundkey.key = found_base64;
- foundkey.len = strlen(found_base64);
+ foundkey.key = found_base64;
+ foundkey.len = strlen(found_base64);
- switch(ssh_key_type(pubkey)) {
+ switch(ssh_key_type(pubkey)) {
case SSH_KEYTYPE_RSA:
foundkey.keytype = CURLKHTYPE_RSA;
break;
@@ -493,15 +509,15 @@ static int myssh_is_known(struct Curl_easy *data)
default:
rc = SSH_ERROR;
goto cleanup;
- }
+ }
- Curl_set_in_callback(data, true);
- rc = func(data, knownkeyp, /* from the knownhosts file */
- &foundkey, /* from the remote host */
- keymatch, data->set.ssh_keyfunc_userp);
- Curl_set_in_callback(data, false);
+ Curl_set_in_callback(data, true);
+ rc = func(data, knownkeyp, /* from the knownhosts file */
+ &foundkey, /* from the remote host */
+ keymatch, data->set.ssh_keyfunc_userp);
+ Curl_set_in_callback(data, false);
- switch(rc) {
+ switch(rc) {
case CURLKHSTAT_FINE_ADD_TO_FILE:
#if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0,8,0)
rc = ssh_session_update_known_hosts(sshc->ssh_session);
@@ -517,13 +533,12 @@ static int myssh_is_known(struct Curl_easy *data)
default: /* REJECT/DEFER */
rc = SSH_ERROR;
goto cleanup;
- }
}
- else {
- if(keymatch != CURLKHMATCH_OK) {
- rc = SSH_ERROR;
- goto cleanup;
- }
+ }
+ else {
+ if(keymatch != CURLKHMATCH_OK) {
+ rc = SSH_ERROR;
+ goto cleanup;
}
}
rc = SSH_OK;
@@ -614,7 +629,7 @@ restart:
if(rc < 0)
return SSH_ERROR;
- FALLTHROUGH();
+ /* FALLTHROUGH */
case 1:
sshc->kbd_state = 1;
@@ -656,7 +671,7 @@ restart:
/*
* ssh_statemach_act() runs the SSH state machine as far as it can without
- * blocking and without reaching the end. The data the pointer 'block' points
+ * blocking and without reaching the end. The data the pointer 'block' points
* to will be set to TRUE if the libssh function returns SSH_AGAIN
* meaning it wants to be called again when the socket is ready
*/
@@ -670,7 +685,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
int rc = SSH_NO_ERROR, err;
int seekerr = CURL_SEEKFUNC_OK;
const char *err_msg;
- *block = 0; /* we are not blocking by default */
+ *block = 0; /* we're not blocking by default */
do {
@@ -689,7 +704,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
ssh_set_blocking(sshc->ssh_session, 0);
state(data, SSH_S_STARTUP);
- FALLTHROUGH();
+ /* FALLTHROUGH */
case SSH_S_STARTUP:
rc = ssh_connect(sshc->ssh_session);
@@ -704,7 +719,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
state(data, SSH_HOSTKEY);
- FALLTHROUGH();
+ /* FALLTHROUGH */
case SSH_HOSTKEY:
rc = myssh_is_known(data);
@@ -714,7 +729,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
}
state(data, SSH_AUTHLIST);
- FALLTHROUGH();
+ /* FALLTHROUGH */
case SSH_AUTHLIST:{
sshc->authed = FALSE;
@@ -735,8 +750,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
break;
}
- sshc->auth_methods =
- (unsigned int)ssh_userauth_list(sshc->ssh_session, NULL);
+ sshc->auth_methods = ssh_userauth_list(sshc->ssh_session, NULL);
if(sshc->auth_methods)
infof(data, "SSH authentication methods available: %s%s%s%s",
sshc->auth_methods & SSH_AUTH_METHOD_PUBLICKEY ?
@@ -896,7 +910,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
break;
}
state(data, SSH_AUTH_PASS);
- FALLTHROUGH();
+ /* FALLTHROUGH */
case SSH_AUTH_PASS:
rc = ssh_userauth_password(sshc->ssh_session, NULL, conn->passwd);
@@ -959,7 +973,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
break;
}
state(data, SSH_SFTP_REALPATH);
- FALLTHROUGH();
+ /* FALLTHROUGH */
case SSH_SFTP_REALPATH:
/*
* Get the "home" directory
@@ -1147,22 +1161,22 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
}
else if(statvfs) {
#ifdef _MSC_VER
- #define CURL_LIBSSH_VFS_SIZE_MASK "I64u"
+ #define LIBSSH_VFS_SIZE_MASK "I64u"
#else
- #define CURL_LIBSSH_VFS_SIZE_MASK PRIu64
+ #define LIBSSH_VFS_SIZE_MASK PRIu64
#endif
char *tmp = aprintf("statvfs:\n"
- "f_bsize: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
- "f_frsize: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
- "f_blocks: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
- "f_bfree: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
- "f_bavail: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
- "f_files: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
- "f_ffree: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
- "f_favail: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
- "f_fsid: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
- "f_flag: %" CURL_LIBSSH_VFS_SIZE_MASK "\n"
- "f_namemax: %" CURL_LIBSSH_VFS_SIZE_MASK "\n",
+ "f_bsize: %" LIBSSH_VFS_SIZE_MASK "\n"
+ "f_frsize: %" LIBSSH_VFS_SIZE_MASK "\n"
+ "f_blocks: %" LIBSSH_VFS_SIZE_MASK "\n"
+ "f_bfree: %" LIBSSH_VFS_SIZE_MASK "\n"
+ "f_bavail: %" LIBSSH_VFS_SIZE_MASK "\n"
+ "f_files: %" LIBSSH_VFS_SIZE_MASK "\n"
+ "f_ffree: %" LIBSSH_VFS_SIZE_MASK "\n"
+ "f_favail: %" LIBSSH_VFS_SIZE_MASK "\n"
+ "f_fsid: %" LIBSSH_VFS_SIZE_MASK "\n"
+ "f_flag: %" LIBSSH_VFS_SIZE_MASK "\n"
+ "f_namemax: %" LIBSSH_VFS_SIZE_MASK "\n",
statvfs->f_bsize, statvfs->f_frsize,
statvfs->f_blocks, statvfs->f_bfree,
statvfs->f_bavail, statvfs->f_files,
@@ -1236,7 +1250,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
if(attrs) {
curl_off_t size = attrs->size;
if(size < 0) {
- failf(data, "Bad file size (%" FMT_OFF_T ")", size);
+ failf(data, "Bad file size (%" CURL_FORMAT_CURL_OFF_T ")", size);
MOVE_TO_ERROR_STATE(CURLE_BAD_DOWNLOAD_RESUME);
break;
}
@@ -1288,10 +1302,10 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
position. */
if(data->state.resume_from > 0) {
/* Let's read off the proper amount of bytes from the input. */
- if(data->set.seek_func) {
+ if(conn->seek_func) {
Curl_set_in_callback(data, true);
- seekerr = data->set.seek_func(data->set.seek_client,
- data->state.resume_from, SEEK_SET);
+ seekerr = conn->seek_func(conn->seek_client, data->state.resume_from,
+ SEEK_SET);
Curl_set_in_callback(data, false);
}
@@ -1302,16 +1316,15 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
failf(data, "Could not seek stream");
return CURLE_FTP_COULDNT_USE_REST;
}
- /* seekerr == CURL_SEEKFUNC_CANTSEEK (cannot seek to offset) */
+ /* seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */
do {
- char scratch[4*1024];
size_t readthisamountnow =
- (data->state.resume_from - passed >
- (curl_off_t)sizeof(scratch)) ?
- sizeof(scratch) : curlx_sotouz(data->state.resume_from - passed);
+ (data->state.resume_from - passed > data->set.buffer_size) ?
+ (size_t)data->set.buffer_size :
+ curlx_sotouz(data->state.resume_from - passed);
size_t actuallyread =
- data->state.fread_func(scratch, 1,
+ data->state.fread_func(data->state.buffer, 1,
readthisamountnow, data->state.in);
passed += actuallyread;
@@ -1345,21 +1358,21 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
Curl_pgrsSetUploadSize(data, data->state.infilesize);
}
/* upload data */
- Curl_xfer_setup1(data, CURL_XFER_SEND, -1, FALSE);
+ Curl_setup_transfer(data, -1, -1, FALSE, FIRSTSOCKET);
- /* not set by Curl_xfer_setup to preserve keepon bits */
+ /* not set by Curl_setup_transfer to preserve keepon bits */
conn->sockfd = conn->writesockfd;
- /* store this original bitmask setup to use later on if we cannot
+ /* store this original bitmask setup to use later on if we can't
figure out a "real" bitmask */
sshc->orig_waitfor = data->req.keepon;
/* we want to use the _sending_ function even when the socket turns
out readable as the underlying libssh sftp send function will deal
with both accordingly */
- data->state.select_bits = CURL_CSELECT_OUT;
+ conn->cselect_bits = CURL_CSELECT_OUT;
- /* since we do not really wait for anything at this point, we want the
+ /* since we don't really wait for anything at this point, we want the
state machine to move on as soon as possible so we set a very short
timeout here */
Curl_expire(data, 0, EXPIRE_RUN_NOW);
@@ -1398,7 +1411,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
++sshc->slash_pos;
if(rc < 0) {
/*
- * Abort if failure was not that the dir already exists or the
+ * Abort if failure wasn't that the dir already exists or the
* permission was denied (creation might succeed further down the
* path) - retry on unspecific FAILURE also
*/
@@ -1547,7 +1560,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
sshc->readdir_longentry = NULL;
state(data, SSH_SFTP_READDIR_BOTTOM);
- FALLTHROUGH();
+ /* FALLTHROUGH */
case SSH_SFTP_READDIR_BOTTOM:
if(Curl_dyn_addn(&sshc->readdir_buf, "\n", 1))
result = CURLE_OUT_OF_MEMORY;
@@ -1571,7 +1584,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
sshc->sftp_dir = NULL;
/* no data to transfer */
- Curl_xfer_setup_nop(data);
+ Curl_setup_transfer(data, -1, -1, FALSE, -1);
state(data, SSH_STOP);
break;
@@ -1605,9 +1618,9 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
!(attrs->flags & SSH_FILEXFER_ATTR_SIZE) ||
(attrs->size == 0)) {
/*
- * sftp_fstat did not return an error, so maybe the server
- * just does not support stat()
- * OR the server does not return a file size with a stat()
+ * sftp_fstat didn't return an error, so maybe the server
+ * just doesn't support stat()
+ * OR the server doesn't return a file size with a stat()
* OR file size is 0
*/
data->req.size = -1;
@@ -1621,7 +1634,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
sftp_attributes_free(attrs);
if(size < 0) {
- failf(data, "Bad file size (%" FMT_OFF_T ")", size);
+ failf(data, "Bad file size (%" CURL_FORMAT_CURL_OFF_T ")", size);
return CURLE_BAD_DOWNLOAD_RESUME;
}
if(data->state.use_range) {
@@ -1651,8 +1664,9 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
to = size - 1;
}
if(from > size) {
- failf(data, "Offset (%" FMT_OFF_T ") was beyond file size (%"
- FMT_OFF_T ")", from, size);
+ failf(data, "Offset (%"
+ CURL_FORMAT_CURL_OFF_T ") was beyond file size (%"
+ CURL_FORMAT_CURL_OFF_T ")", from, size);
return CURLE_BAD_DOWNLOAD_RESUME;
}
if(from > to) {
@@ -1660,8 +1674,6 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
size = 0;
}
else {
- if((to - from) == CURL_OFF_T_MAX)
- return CURLE_RANGE_ERROR;
size = to - from + 1;
}
@@ -1679,10 +1691,12 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
/* We can resume if we can seek to the resume position */
if(data->state.resume_from) {
if(data->state.resume_from < 0) {
- /* We are supposed to download the last abs(from) bytes */
+ /* We're supposed to download the last abs(from) bytes */
if((curl_off_t)size < -data->state.resume_from) {
- failf(data, "Offset (%" FMT_OFF_T ") was beyond file size (%"
- FMT_OFF_T ")", data->state.resume_from, size);
+ failf(data, "Offset (%"
+ CURL_FORMAT_CURL_OFF_T ") was beyond file size (%"
+ CURL_FORMAT_CURL_OFF_T ")",
+ data->state.resume_from, size);
return CURLE_BAD_DOWNLOAD_RESUME;
}
/* download from where? */
@@ -1690,8 +1704,8 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
}
else {
if((curl_off_t)size < data->state.resume_from) {
- failf(data, "Offset (%" FMT_OFF_T
- ") was beyond file size (%" FMT_OFF_T ")",
+ failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T
+ ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")",
data->state.resume_from, size);
return CURLE_BAD_DOWNLOAD_RESUME;
}
@@ -1713,20 +1727,20 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
/* Setup the actual download */
if(data->req.size == 0) {
/* no data to transfer */
- Curl_xfer_setup_nop(data);
+ Curl_setup_transfer(data, -1, -1, FALSE, -1);
infof(data, "File already completely downloaded");
state(data, SSH_STOP);
break;
}
- Curl_xfer_setup1(data, CURL_XFER_RECV, data->req.size, FALSE);
+ Curl_setup_transfer(data, FIRSTSOCKET, data->req.size, FALSE, -1);
- /* not set by Curl_xfer_setup to preserve keepon bits */
+ /* not set by Curl_setup_transfer to preserve keepon bits */
conn->writesockfd = conn->sockfd;
/* we want to use the _receiving_ function even when the socket turns
out writableable as the underlying libssh recv function will deal
with both accordingly */
- data->state.select_bits = CURL_CSELECT_IN;
+ conn->cselect_bits = CURL_CSELECT_IN;
if(result) {
/* this should never occur; the close state should be entered
@@ -1842,19 +1856,19 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
}
/* upload data */
- Curl_xfer_setup1(data, CURL_XFER_SEND, -1, FALSE);
+ Curl_setup_transfer(data, -1, data->req.size, FALSE, FIRSTSOCKET);
- /* not set by Curl_xfer_setup to preserve keepon bits */
+ /* not set by Curl_setup_transfer to preserve keepon bits */
conn->sockfd = conn->writesockfd;
- /* store this original bitmask setup to use later on if we cannot
+ /* store this original bitmask setup to use later on if we can't
figure out a "real" bitmask */
sshc->orig_waitfor = data->req.keepon;
/* we want to use the _sending_ function even when the socket turns
out readable as the underlying libssh scp send function will deal
with both accordingly */
- data->state.select_bits = CURL_CSELECT_OUT;
+ conn->cselect_bits = CURL_CSELECT_OUT;
state(data, SSH_STOP);
@@ -1870,7 +1884,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
break;
}
state(data, SSH_SCP_DOWNLOAD);
- FALLTHROUGH();
+ /* FALLTHROUGH */
case SSH_SCP_DOWNLOAD:{
curl_off_t bytecount;
@@ -1886,15 +1900,15 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
/* download data */
bytecount = ssh_scp_request_get_size(sshc->scp_session);
data->req.maxdownload = (curl_off_t) bytecount;
- Curl_xfer_setup1(data, CURL_XFER_RECV, bytecount, FALSE);
+ Curl_setup_transfer(data, FIRSTSOCKET, bytecount, FALSE, -1);
- /* not set by Curl_xfer_setup to preserve keepon bits */
+ /* not set by Curl_setup_transfer to preserve keepon bits */
conn->writesockfd = conn->sockfd;
/* we want to use the _receiving_ function even when the socket turns
out writableable as the underlying libssh recv function will deal
with both accordingly */
- data->state.select_bits = CURL_CSELECT_IN;
+ conn->cselect_bits = CURL_CSELECT_IN;
state(data, SSH_STOP);
break;
@@ -1934,10 +1948,10 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
ssh_set_blocking(sshc->ssh_session, 0);
state(data, SSH_SESSION_DISCONNECT);
- FALLTHROUGH();
+ /* FALLTHROUGH */
case SSH_SESSION_DISCONNECT:
- /* during weird times when we have been prematurely aborted, the channel
+ /* during weird times when we've been prematurely aborted, the channel
is still alive when we reach this state and we MUST kill the channel
properly first */
if(sshc->scp_session) {
@@ -1957,7 +1971,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
data->state.most_recent_ftp_entrypath = NULL;
state(data, SSH_SESSION_FREE);
- FALLTHROUGH();
+ /* FALLTHROUGH */
case SSH_SESSION_FREE:
if(sshc->ssh_session) {
ssh_free(sshc->ssh_session);
@@ -2008,6 +2022,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
break;
case SSH_QUIT:
+ /* fallthrough, just stop! */
default:
/* internal error */
sshc->nextstate = SSH_NO_STATE;
@@ -2054,7 +2069,7 @@ static void myssh_block2waitfor(struct connectdata *conn, bool block)
{
struct ssh_conn *sshc = &conn->proto.sshc;
- /* If it did not block, or nothing was returned by ssh_get_poll_flags
+ /* If it didn't block, or nothing was returned by ssh_get_poll_flags
* have the original set */
conn->waitfor = sshc->orig_waitfor;
@@ -2349,7 +2364,7 @@ static CURLcode scp_disconnect(struct Curl_easy *data,
(void) dead_connection;
if(ssh->ssh_session) {
- /* only if there is a session still around to use! */
+ /* only if there's a session still around to use! */
state(data, SSH_SESSION_DISCONNECT);
@@ -2396,13 +2411,12 @@ static CURLcode scp_done(struct Curl_easy *data, CURLcode status,
}
static ssize_t scp_send(struct Curl_easy *data, int sockindex,
- const void *mem, size_t len, bool eos, CURLcode *err)
+ const void *mem, size_t len, CURLcode *err)
{
int rc;
struct connectdata *conn = data->conn;
(void) sockindex; /* we only support SCP on the fixed known primary socket */
(void) err;
- (void)eos;
rc = ssh_scp_write(conn->proto.sshc.scp_session, mem, len);
@@ -2515,7 +2529,7 @@ static CURLcode sftp_disconnect(struct Curl_easy *data,
DEBUGF(infof(data, "SSH DISCONNECT starts now"));
if(conn->proto.sshc.ssh_session) {
- /* only if there is a session still around to use! */
+ /* only if there's a session still around to use! */
state(data, SSH_SFTP_SHUTDOWN);
result = myssh_block_statemach(data, TRUE);
}
@@ -2545,13 +2559,11 @@ static CURLcode sftp_done(struct Curl_easy *data, CURLcode status,
/* return number of sent bytes */
static ssize_t sftp_send(struct Curl_easy *data, int sockindex,
- const void *mem, size_t len, bool eos,
- CURLcode *err)
+ const void *mem, size_t len, CURLcode *err)
{
ssize_t nwrite;
struct connectdata *conn = data->conn;
(void)sockindex;
- (void)eos;
/* limit the writes to the maximum specified in Section 3 of
* https://datatracker.ietf.org/doc/html/draft-ietf-secsh-filexfer-02
@@ -2601,13 +2613,13 @@ static ssize_t sftp_recv(struct Curl_easy *data, int sockindex,
return -1;
}
- FALLTHROUGH();
+ /* FALLTHROUGH */
case 1:
conn->proto.sshc.sftp_recv_state = 1;
nread = sftp_async_read(conn->proto.sshc.sftp_file,
mem, (uint32_t)len,
- (uint32_t)conn->proto.sshc.sftp_file_index);
+ conn->proto.sshc.sftp_file_index);
myssh_block2waitfor(conn, (nread == SSH_AGAIN)?TRUE:FALSE);
@@ -2711,7 +2723,7 @@ static void sftp_quote(struct Curl_easy *data)
}
/*
- * SFTP is a binary protocol, so we do not send text commands
+ * SFTP is a binary protocol, so we don't send text commands
* to the server. Instead, we scan for commands used by
* OpenSSH's sftp program and call the appropriate libssh
* functions.
@@ -2945,4 +2957,10 @@ void Curl_ssh_version(char *buffer, size_t buflen)
(void)msnprintf(buffer, buflen, "libssh/%s", ssh_version(0));
}
+#if defined(__GNUC__) && \
+ (LIBSSH_VERSION_MINOR >= 10) || \
+ (LIBSSH_VERSION_MAJOR > 0)
+#pragma GCC diagnostic pop
+#endif
+
#endif /* USE_LIBSSH */
diff --git a/contrib/libs/curl/lib/vssh/libssh2.c b/contrib/libs/curl/lib/vssh/libssh2.c
index b01580c82d..6560dba2ed 100644
--- a/contrib/libs/curl/lib/vssh/libssh2.c
+++ b/contrib/libs/curl/lib/vssh/libssh2.c
@@ -30,6 +30,9 @@
#include <limits.h>
+#error #include <libssh2.h>
+#error #include <libssh2_sftp.h>
+
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
@@ -135,8 +138,7 @@ const struct Curl_handler Curl_handler_scp = {
ZERO_NULL, /* domore_getsock */
ssh_getsock, /* perform_getsock */
scp_disconnect, /* disconnect */
- ZERO_NULL, /* write_resp */
- ZERO_NULL, /* write_resp_hd */
+ ZERO_NULL, /* readwrite */
ZERO_NULL, /* connection_check */
ssh_attach, /* attach */
PORT_SSH, /* defport */
@@ -165,8 +167,7 @@ const struct Curl_handler Curl_handler_sftp = {
ZERO_NULL, /* domore_getsock */
ssh_getsock, /* perform_getsock */
sftp_disconnect, /* disconnect */
- ZERO_NULL, /* write_resp */
- ZERO_NULL, /* write_resp_hd */
+ ZERO_NULL, /* readwrite */
ZERO_NULL, /* connection_check */
ssh_attach, /* attach */
PORT_SSH, /* defport */
@@ -200,8 +201,7 @@ kbd_callback(const char *name, int name_len, const char *instruction,
if(num_prompts == 1) {
struct connectdata *conn = data->conn;
responses[0].text = strdup(conn->passwd);
- responses[0].length =
- responses[0].text == NULL ? 0 : curlx_uztoui(strlen(conn->passwd));
+ responses[0].length = curlx_uztoui(strlen(conn->passwd));
}
(void)prompts;
} /* kbd_callback */
@@ -402,8 +402,8 @@ static int sshkeycallback(struct Curl_easy *easy,
#endif
/*
- * Earlier libssh2 versions did not have the ability to seek to 64-bit
- * positions with 32-bit size_t.
+ * Earlier libssh2 versions didn't have the ability to seek to 64bit positions
+ * with 32bit size_t.
*/
#ifdef HAVE_LIBSSH2_SFTP_SEEK64
#define SFTP_SEEK(x,y) libssh2_sftp_seek64(x, (libssh2_uint64_t)y)
@@ -412,27 +412,27 @@ static int sshkeycallback(struct Curl_easy *easy,
#endif
/*
- * Earlier libssh2 versions did not do SCP properly beyond 32-bit sizes on
- * 32-bit architectures so we check of the necessary function is present.
+ * Earlier libssh2 versions didn't do SCP properly beyond 32bit sizes on 32bit
+ * architectures so we check of the necessary function is present.
*/
#ifndef HAVE_LIBSSH2_SCP_SEND64
#define SCP_SEND(a,b,c,d) libssh2_scp_send_ex(a, b, (int)(c), (size_t)d, 0, 0)
#else
#define SCP_SEND(a,b,c,d) libssh2_scp_send64(a, b, (int)(c), \
- (libssh2_int64_t)d, 0, 0)
+ (libssh2_uint64_t)d, 0, 0)
#endif
/*
- * libssh2 1.2.8 fixed the problem with 32-bit ints used for sockets on win64.
+ * libssh2 1.2.8 fixed the problem with 32bit ints used for sockets on win64.
*/
#ifdef HAVE_LIBSSH2_SESSION_HANDSHAKE
#define session_startup(x,y) libssh2_session_handshake(x, y)
#else
#define session_startup(x,y) libssh2_session_startup(x, (int)y)
#endif
-static enum curl_khtype convert_ssh2_keytype(int sshkeytype)
+static int convert_ssh2_keytype(int sshkeytype)
{
- enum curl_khtype keytype = CURLKHTYPE_UNKNOWN;
+ int keytype = CURLKHTYPE_UNKNOWN;
switch(sshkeytype) {
case LIBSSH2_HOSTKEY_TYPE_RSA:
keytype = CURLKHTYPE_RSA;
@@ -473,7 +473,7 @@ static CURLcode ssh_knownhost(struct Curl_easy *data)
#ifdef HAVE_LIBSSH2_KNOWNHOST_API
if(data->set.str[STRING_SSH_KNOWNHOSTS]) {
- /* we are asked to verify the host against a file */
+ /* we're asked to verify the host against a file */
struct connectdata *conn = data->conn;
struct ssh_conn *sshc = &conn->proto.sshc;
struct libssh2_knownhost *host = NULL;
@@ -484,8 +484,8 @@ static CURLcode ssh_knownhost(struct Curl_easy *data)
if(remotekey) {
/*
- * A subject to figure out is what hostname we need to pass in here.
- * What hostname does OpenSSH store in its file if an IDN name is
+ * A subject to figure out is what host name we need to pass in here.
+ * What host name does OpenSSH store in its file if an IDN name is
* used?
*/
enum curl_khmatch keymatch;
@@ -523,7 +523,7 @@ static CURLcode ssh_knownhost(struct Curl_easy *data)
break;
#endif
default:
- infof(data, "unsupported key type, cannot check knownhosts");
+ infof(data, "unsupported key type, can't check knownhosts");
keybit = 0;
break;
}
@@ -589,23 +589,25 @@ static CURLcode ssh_knownhost(struct Curl_easy *data)
switch(rc) {
default: /* unknown return codes will equal reject */
+ /* FALLTHROUGH */
case CURLKHSTAT_REJECT:
state(data, SSH_SESSION_FREE);
- FALLTHROUGH();
+ /* FALLTHROUGH */
case CURLKHSTAT_DEFER:
/* DEFER means bail out but keep the SSH_HOSTKEY state */
result = sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION;
break;
case CURLKHSTAT_FINE_REPLACE:
- /* remove old host+key that does not match */
+ /* remove old host+key that doesn't match */
if(host)
libssh2_knownhost_del(sshc->kh, host);
- FALLTHROUGH();
+ /* FALLTHROUGH */
case CURLKHSTAT_FINE:
+ /* FALLTHROUGH */
case CURLKHSTAT_FINE_ADD_TO_FILE:
/* proceed */
if(keycheck != LIBSSH2_KNOWNHOST_CHECK_MATCH) {
- /* the found host+key did not match but has been told to be fine
+ /* the found host+key didn't match but has been told to be fine
anyway so we add it in memory */
int addrc = libssh2_knownhost_add(sshc->kh,
conn->host.name, NULL,
@@ -659,7 +661,7 @@ static CURLcode ssh_check_fingerprint(struct Curl_easy *data)
size_t b64_pos = 0;
#ifdef LIBSSH2_HOSTKEY_HASH_SHA256
- /* The fingerprint points to static storage (!), do not free() it. */
+ /* The fingerprint points to static storage (!), don't free() it. */
fingerprint = libssh2_hostkey_hash(sshc->ssh_session,
LIBSSH2_HOSTKEY_HASH_SHA256);
#else
@@ -739,7 +741,7 @@ static CURLcode ssh_check_fingerprint(struct Curl_easy *data)
LIBSSH2_HOSTKEY_HASH_MD5);
if(fingerprint) {
- /* The fingerprint points to static storage (!), do not free() it. */
+ /* The fingerprint points to static storage (!), don't free() it. */
int i;
for(i = 0; i < 16; i++) {
msnprintf(&md5buffer[i*2], 3, "%02x", (unsigned char) fingerprint[i]);
@@ -777,10 +779,10 @@ static CURLcode ssh_check_fingerprint(struct Curl_easy *data)
const char *remotekey = libssh2_session_hostkey(sshc->ssh_session,
&keylen, &sshkeytype);
if(remotekey) {
- enum curl_khtype keytype = convert_ssh2_keytype(sshkeytype);
+ int keytype = convert_ssh2_keytype(sshkeytype);
Curl_set_in_callback(data, true);
rc = data->set.ssh_hostkeyfunc(data->set.ssh_hostkeyfunc_userp,
- (int)keytype, remotekey, keylen);
+ keytype, remotekey, keylen);
Curl_set_in_callback(data, false);
if(rc!= CURLKHMATCH_OK) {
state(data, SSH_SESSION_FREE);
@@ -957,7 +959,7 @@ static CURLcode ssh_force_knownhost_key_type(struct Curl_easy *data)
/*
* ssh_statemach_act() runs the SSH state machine as far as it can without
- * blocking and without reaching the end. The data the pointer 'block' points
+ * blocking and without reaching the end. The data the pointer 'block' points
* to will be set to TRUE if the libssh2 function returns LIBSSH2_ERROR_EAGAIN
* meaning it wants to be called again when the socket is ready
*/
@@ -974,7 +976,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
unsigned long sftperr;
int seekerr = CURL_SEEKFUNC_OK;
size_t readdir_len;
- *block = 0; /* we are not blocking by default */
+ *block = 0; /* we're not blocking by default */
do {
switch(sshc->state) {
@@ -995,7 +997,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
}
state(data, SSH_S_STARTUP);
- FALLTHROUGH();
+ /* FALLTHROUGH */
case SSH_S_STARTUP:
rc = session_startup(sshc->ssh_session, sock);
@@ -1014,7 +1016,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
state(data, SSH_HOSTKEY);
- FALLTHROUGH();
+ /* FALLTHROUGH */
case SSH_HOSTKEY:
/*
* Before we authenticate we should check the hostkey's fingerprint
@@ -1034,7 +1036,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
* must never change it later. Thus, always specify the correct username
* here, even though the libssh2 docs kind of indicate that it should be
* possible to get a 'generic' list (not user-specific) of authentication
- * methods, presumably with a blank username. That will not work in my
+ * methods, presumably with a blank username. That won't work in my
* experience.
* So always specify it here.
*/
@@ -1083,7 +1085,6 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
/* To ponder about: should really the lib be messing about with the
HOME environment variable etc? */
char *home = curl_getenv("HOME");
- struct_stat sbuf;
/* If no private key file is specified, try some common paths. */
if(home) {
@@ -1091,12 +1092,12 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
sshc->rsa = aprintf("%s/.ssh/id_rsa", home);
if(!sshc->rsa)
out_of_memory = TRUE;
- else if(stat(sshc->rsa, &sbuf)) {
+ else if(access(sshc->rsa, R_OK) != 0) {
Curl_safefree(sshc->rsa);
sshc->rsa = aprintf("%s/.ssh/id_dsa", home);
if(!sshc->rsa)
out_of_memory = TRUE;
- else if(stat(sshc->rsa, &sbuf)) {
+ else if(access(sshc->rsa, R_OK) != 0) {
Curl_safefree(sshc->rsa);
}
}
@@ -1105,10 +1106,10 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
if(!out_of_memory && !sshc->rsa) {
/* Nothing found; try the current dir. */
sshc->rsa = strdup("id_rsa");
- if(sshc->rsa && stat(sshc->rsa, &sbuf)) {
+ if(sshc->rsa && access(sshc->rsa, R_OK) != 0) {
Curl_safefree(sshc->rsa);
sshc->rsa = strdup("id_dsa");
- if(sshc->rsa && stat(sshc->rsa, &sbuf)) {
+ if(sshc->rsa && access(sshc->rsa, R_OK) != 0) {
Curl_safefree(sshc->rsa);
/* Out of guesses. Set to the empty string to avoid
* surprising info messages. */
@@ -1437,7 +1438,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
if(sftperr)
result = sftp_libssh2_error_to_CURLE(sftperr);
else
- /* in this case, the error was not in the SFTP level but for example
+ /* in this case, the error wasn't in the SFTP level but for example
a time-out or similar */
result = CURLE_SSH;
sshc->actualcode = result;
@@ -1568,7 +1569,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
}
/*
- * SFTP is a binary protocol, so we do not send text commands
+ * SFTP is a binary protocol, so we don't send text commands
* to the server. Instead, we scan for commands used by
* OpenSSH's sftp program and call the appropriate libssh2
* functions.
@@ -1706,7 +1707,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
if(!strncasecompare(cmd, "chmod", 5)) {
/* Since chown and chgrp only set owner OR group but libssh2 wants to
* set them both at once, we need to obtain the current ownership
- * first. This takes an extra protocol round trip.
+ * first. This takes an extra protocol round trip.
*/
rc = libssh2_sftp_stat_ex(sshc->sftp_session, sshc->quote_path2,
curlx_uztoui(strlen(sshc->quote_path2)),
@@ -1783,7 +1784,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
}
#if SIZEOF_TIME_T > SIZEOF_LONG
if(date > 0xffffffff) {
- /* if 'long' cannot old >32-bit, this date cannot be sent */
+ /* if 'long' can't old >32bit, this date cannot be sent */
failf(data, "date overflow");
fail = TRUE;
}
@@ -1857,7 +1858,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
case SSH_SFTP_QUOTE_MKDIR:
rc = libssh2_sftp_mkdir_ex(sshc->sftp_session, sshc->quote_path1,
curlx_uztoui(strlen(sshc->quote_path1)),
- (long)data->set.new_directory_perms);
+ data->set.new_directory_perms);
if(rc == LIBSSH2_ERROR_EAGAIN) {
break;
}
@@ -1960,22 +1961,22 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
}
else if(rc == 0) {
#ifdef _MSC_VER
- #define CURL_LIBSSH2_VFS_SIZE_MASK "I64u"
+ #define LIBSSH2_VFS_SIZE_MASK "I64u"
#else
- #define CURL_LIBSSH2_VFS_SIZE_MASK "llu"
+ #define LIBSSH2_VFS_SIZE_MASK "llu"
#endif
char *tmp = aprintf("statvfs:\n"
- "f_bsize: %" CURL_LIBSSH2_VFS_SIZE_MASK "\n"
- "f_frsize: %" CURL_LIBSSH2_VFS_SIZE_MASK "\n"
- "f_blocks: %" CURL_LIBSSH2_VFS_SIZE_MASK "\n"
- "f_bfree: %" CURL_LIBSSH2_VFS_SIZE_MASK "\n"
- "f_bavail: %" CURL_LIBSSH2_VFS_SIZE_MASK "\n"
- "f_files: %" CURL_LIBSSH2_VFS_SIZE_MASK "\n"
- "f_ffree: %" CURL_LIBSSH2_VFS_SIZE_MASK "\n"
- "f_favail: %" CURL_LIBSSH2_VFS_SIZE_MASK "\n"
- "f_fsid: %" CURL_LIBSSH2_VFS_SIZE_MASK "\n"
- "f_flag: %" CURL_LIBSSH2_VFS_SIZE_MASK "\n"
- "f_namemax: %" CURL_LIBSSH2_VFS_SIZE_MASK "\n",
+ "f_bsize: %" LIBSSH2_VFS_SIZE_MASK "\n"
+ "f_frsize: %" LIBSSH2_VFS_SIZE_MASK "\n"
+ "f_blocks: %" LIBSSH2_VFS_SIZE_MASK "\n"
+ "f_bfree: %" LIBSSH2_VFS_SIZE_MASK "\n"
+ "f_bavail: %" LIBSSH2_VFS_SIZE_MASK "\n"
+ "f_files: %" LIBSSH2_VFS_SIZE_MASK "\n"
+ "f_ffree: %" LIBSSH2_VFS_SIZE_MASK "\n"
+ "f_favail: %" LIBSSH2_VFS_SIZE_MASK "\n"
+ "f_fsid: %" LIBSSH2_VFS_SIZE_MASK "\n"
+ "f_flag: %" LIBSSH2_VFS_SIZE_MASK "\n"
+ "f_namemax: %" LIBSSH2_VFS_SIZE_MASK "\n",
statvfs.f_bsize, statvfs.f_frsize,
statvfs.f_blocks, statvfs.f_bfree,
statvfs.f_bavail, statvfs.f_files,
@@ -2023,7 +2024,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
break;
}
if(rc == 0) {
- data->info.filetime = (time_t)attrs.mtime;
+ data->info.filetime = attrs.mtime;
}
state(data, SSH_SFTP_TRANS_INIT);
@@ -2066,7 +2067,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
else {
curl_off_t size = attrs.filesize;
if(size < 0) {
- failf(data, "Bad file size (%" FMT_OFF_T ")", size);
+ failf(data, "Bad file size (%" CURL_FORMAT_CURL_OFF_T ")", size);
return CURLE_BAD_DOWNLOAD_RESUME;
}
data->state.resume_from = attrs.filesize;
@@ -2087,7 +2088,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
sshc->sftp_handle =
libssh2_sftp_open_ex(sshc->sftp_session, sshp->path,
curlx_uztoui(strlen(sshp->path)),
- flags, (long)data->set.new_file_perms,
+ flags, data->set.new_file_perms,
LIBSSH2_SFTP_OPENFILE);
if(!sshc->sftp_handle) {
@@ -2143,10 +2144,10 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
position. */
if(data->state.resume_from > 0) {
/* Let's read off the proper amount of bytes from the input. */
- if(data->set.seek_func) {
+ if(conn->seek_func) {
Curl_set_in_callback(data, true);
- seekerr = data->set.seek_func(data->set.seek_client,
- data->state.resume_from, SEEK_SET);
+ seekerr = conn->seek_func(conn->seek_client, data->state.resume_from,
+ SEEK_SET);
Curl_set_in_callback(data, false);
}
@@ -2157,17 +2158,16 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
failf(data, "Could not seek stream");
return CURLE_FTP_COULDNT_USE_REST;
}
- /* seekerr == CURL_SEEKFUNC_CANTSEEK (cannot seek to offset) */
+ /* seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */
do {
- char scratch[4*1024];
size_t readthisamountnow =
- (data->state.resume_from - passed >
- (curl_off_t)sizeof(scratch)) ?
- sizeof(scratch) : curlx_sotouz(data->state.resume_from - passed);
+ (data->state.resume_from - passed > data->set.buffer_size) ?
+ (size_t)data->set.buffer_size :
+ curlx_sotouz(data->state.resume_from - passed);
size_t actuallyread;
Curl_set_in_callback(data, true);
- actuallyread = data->state.fread_func(scratch, 1,
+ actuallyread = data->state.fread_func(data->state.buffer, 1,
readthisamountnow,
data->state.in);
Curl_set_in_callback(data, false);
@@ -2196,9 +2196,9 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
Curl_pgrsSetUploadSize(data, data->state.infilesize);
}
/* upload data */
- Curl_xfer_setup1(data, CURL_XFER_SEND, -1, FALSE);
+ Curl_setup_transfer(data, -1, -1, FALSE, FIRSTSOCKET);
- /* not set by Curl_xfer_setup to preserve keepon bits */
+ /* not set by Curl_setup_transfer to preserve keepon bits */
conn->sockfd = conn->writesockfd;
if(result) {
@@ -2206,16 +2206,16 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
sshc->actualcode = result;
}
else {
- /* store this original bitmask setup to use later on if we cannot
+ /* store this original bitmask setup to use later on if we can't
figure out a "real" bitmask */
sshc->orig_waitfor = data->req.keepon;
/* we want to use the _sending_ function even when the socket turns
out readable as the underlying libssh2 sftp send function will deal
with both accordingly */
- data->state.select_bits = CURL_CSELECT_OUT;
+ conn->cselect_bits = CURL_CSELECT_OUT;
- /* since we do not really wait for anything at this point, we want the
+ /* since we don't really wait for anything at this point, we want the
state machine to move on as soon as possible so we set a very short
timeout here */
Curl_expire(data, 0, EXPIRE_RUN_NOW);
@@ -2251,7 +2251,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
/* 'mode' - parameter is preliminary - default to 0644 */
rc = libssh2_sftp_mkdir_ex(sshc->sftp_session, sshp->path,
curlx_uztoui(strlen(sshp->path)),
- (long)data->set.new_directory_perms);
+ data->set.new_directory_perms);
if(rc == LIBSSH2_ERROR_EAGAIN) {
break;
}
@@ -2259,7 +2259,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
++sshc->slash_pos;
if(rc < 0) {
/*
- * Abort if failure was not that the dir already exists or the
+ * Abort if failure wasn't that the dir already exists or the
* permission was denied (creation might succeed further down the
* path) - retry on unspecific FAILURE also
*/
@@ -2399,8 +2399,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
rc =
libssh2_sftp_symlink_ex(sshc->sftp_session,
Curl_dyn_ptr(&sshp->readdir_link),
- (unsigned int)
- Curl_dyn_len(&sshp->readdir_link),
+ (int)Curl_dyn_len(&sshp->readdir_link),
sshp->readdir_filename,
PATH_MAX, LIBSSH2_SFTP_READLINK);
if(rc == LIBSSH2_ERROR_EAGAIN) {
@@ -2450,7 +2449,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
Curl_safefree(sshp->readdir_longentry);
/* no data to transfer */
- Curl_xfer_setup_nop(data);
+ Curl_setup_transfer(data, -1, -1, FALSE, -1);
state(data, SSH_STOP);
break;
@@ -2461,7 +2460,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
sshc->sftp_handle =
libssh2_sftp_open_ex(sshc->sftp_session, sshp->path,
curlx_uztoui(strlen(sshp->path)),
- LIBSSH2_FXF_READ, (long)data->set.new_file_perms,
+ LIBSSH2_FXF_READ, data->set.new_file_perms,
LIBSSH2_SFTP_OPENFILE);
if(!sshc->sftp_handle) {
if(libssh2_session_last_errno(sshc->ssh_session) ==
@@ -2494,9 +2493,9 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
!(attrs.flags & LIBSSH2_SFTP_ATTR_SIZE) ||
(attrs.filesize == 0)) {
/*
- * libssh2_sftp_open() did not return an error, so maybe the server
- * just does not support stat()
- * OR the server does not return a file size with a stat()
+ * libssh2_sftp_open() didn't return an error, so maybe the server
+ * just doesn't support stat()
+ * OR the server doesn't return a file size with a stat()
* OR file size is 0
*/
data->req.size = -1;
@@ -2507,7 +2506,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
curl_off_t size = attrs.filesize;
if(size < 0) {
- failf(data, "Bad file size (%" FMT_OFF_T ")", size);
+ failf(data, "Bad file size (%" CURL_FORMAT_CURL_OFF_T ")", size);
return CURLE_BAD_DOWNLOAD_RESUME;
}
if(data->state.use_range) {
@@ -2535,8 +2534,10 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
to = size - 1;
}
if(from > size) {
- failf(data, "Offset (%" FMT_OFF_T ") was beyond file size (%"
- FMT_OFF_T ")", from, (curl_off_t)attrs.filesize);
+ failf(data, "Offset (%"
+ CURL_FORMAT_CURL_OFF_T ") was beyond file size (%"
+ CURL_FORMAT_CURL_OFF_T ")", from,
+ (curl_off_t)attrs.filesize);
return CURLE_BAD_DOWNLOAD_RESUME;
}
if(from > to) {
@@ -2544,8 +2545,6 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
size = 0;
}
else {
- if((to - from) == CURL_OFF_T_MAX)
- return CURLE_RANGE_ERROR;
size = to - from + 1;
}
@@ -2559,10 +2558,11 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
/* We can resume if we can seek to the resume position */
if(data->state.resume_from) {
if(data->state.resume_from < 0) {
- /* We are supposed to download the last abs(from) bytes */
+ /* We're supposed to download the last abs(from) bytes */
if((curl_off_t)attrs.filesize < -data->state.resume_from) {
- failf(data, "Offset (%" FMT_OFF_T ") was beyond file size (%"
- FMT_OFF_T ")",
+ failf(data, "Offset (%"
+ CURL_FORMAT_CURL_OFF_T ") was beyond file size (%"
+ CURL_FORMAT_CURL_OFF_T ")",
data->state.resume_from, (curl_off_t)attrs.filesize);
return CURLE_BAD_DOWNLOAD_RESUME;
}
@@ -2571,8 +2571,8 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
}
else {
if((curl_off_t)attrs.filesize < data->state.resume_from) {
- failf(data, "Offset (%" FMT_OFF_T
- ") was beyond file size (%" FMT_OFF_T ")",
+ failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T
+ ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")",
data->state.resume_from, (curl_off_t)attrs.filesize);
return CURLE_BAD_DOWNLOAD_RESUME;
}
@@ -2589,20 +2589,20 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
/* Setup the actual download */
if(data->req.size == 0) {
/* no data to transfer */
- Curl_xfer_setup_nop(data);
+ Curl_setup_transfer(data, -1, -1, FALSE, -1);
infof(data, "File already completely downloaded");
state(data, SSH_STOP);
break;
}
- Curl_xfer_setup1(data, CURL_XFER_RECV, data->req.size, FALSE);
+ Curl_setup_transfer(data, FIRSTSOCKET, data->req.size, FALSE, -1);
- /* not set by Curl_xfer_setup to preserve keepon bits */
+ /* not set by Curl_setup_transfer to preserve keepon bits */
conn->writesockfd = conn->sockfd;
/* we want to use the _receiving_ function even when the socket turns
out writableable as the underlying libssh2 recv function will deal
with both accordingly */
- data->state.select_bits = CURL_CSELECT_IN;
+ conn->cselect_bits = CURL_CSELECT_IN;
if(result) {
/* this should never occur; the close state should be entered
@@ -2708,7 +2708,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
case SSH_SCP_UPLOAD_INIT:
/*
* libssh2 requires that the destination path is a full path that
- * includes the destination file and name OR ends in a "/" . If this is
+ * includes the destination file and name OR ends in a "/" . If this is
* not done the destination file will be named the same name as the last
* directory in the path.
*/
@@ -2740,9 +2740,9 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
/* upload data */
data->req.size = data->state.infilesize;
Curl_pgrsSetUploadSize(data, data->state.infilesize);
- Curl_xfer_setup1(data, CURL_XFER_SEND, -1, FALSE);
+ Curl_setup_transfer(data, -1, -1, FALSE, FIRSTSOCKET);
- /* not set by Curl_xfer_setup to preserve keepon bits */
+ /* not set by Curl_setup_transfer to preserve keepon bits */
conn->sockfd = conn->writesockfd;
if(result) {
@@ -2750,14 +2750,14 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
sshc->actualcode = result;
}
else {
- /* store this original bitmask setup to use later on if we cannot
+ /* store this original bitmask setup to use later on if we can't
figure out a "real" bitmask */
sshc->orig_waitfor = data->req.keepon;
/* we want to use the _sending_ function even when the socket turns
out readable as the underlying libssh2 scp send function will deal
with both accordingly */
- data->state.select_bits = CURL_CSELECT_OUT;
+ conn->cselect_bits = CURL_CSELECT_OUT;
state(data, SSH_STOP);
}
@@ -2811,15 +2811,15 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
/* download data */
bytecount = (curl_off_t)sb.st_size;
data->req.maxdownload = (curl_off_t)sb.st_size;
- Curl_xfer_setup1(data, CURL_XFER_RECV, bytecount, FALSE);
+ Curl_setup_transfer(data, FIRSTSOCKET, bytecount, FALSE, -1);
- /* not set by Curl_xfer_setup to preserve keepon bits */
+ /* not set by Curl_setup_transfer to preserve keepon bits */
conn->writesockfd = conn->sockfd;
/* we want to use the _receiving_ function even when the socket turns
out writableable as the underlying libssh2 recv function will deal
with both accordingly */
- data->state.select_bits = CURL_CSELECT_IN;
+ conn->cselect_bits = CURL_CSELECT_IN;
if(result) {
state(data, SSH_SCP_CHANNEL_FREE);
@@ -2910,7 +2910,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
break;
case SSH_SESSION_DISCONNECT:
- /* during weird times when we have been prematurely aborted, the channel
+ /* during weird times when we've been prematurely aborted, the channel
is still alive when we reach this state and we MUST kill the channel
properly first */
if(sshc->ssh_channel) {
@@ -3024,6 +3024,7 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
break;
case SSH_QUIT:
+ /* fallthrough, just stop! */
default:
/* internal error */
sshc->nextstate = SSH_NO_STATE;
@@ -3066,7 +3067,7 @@ static int ssh_getsock(struct Curl_easy *data,
* When one of the libssh2 functions has returned LIBSSH2_ERROR_EAGAIN this
* function is used to figure out in what direction and stores this info so
* that the multi interface can take advantage of it. Make sure to call this
- * function in all cases so that when it _does not_ return EAGAIN we can
+ * function in all cases so that when it _doesn't_ return EAGAIN we can
* restore the default wait bits.
*/
static void ssh_block2waitfor(struct Curl_easy *data, bool block)
@@ -3083,7 +3084,7 @@ static void ssh_block2waitfor(struct Curl_easy *data, bool block)
}
}
if(!dir)
- /* It did not block or libssh2 did not reveal in which direction, put back
+ /* It didn't block or libssh2 didn't reveal in which direction, put back
the original set */
conn->waitfor = sshc->orig_waitfor;
}
@@ -3099,7 +3100,7 @@ static CURLcode ssh_multi_statemach(struct Curl_easy *data, bool *done)
do {
result = ssh_statemach_act(data, &block);
*done = (sshc->state == SSH_STOP) ? TRUE : FALSE;
- /* if there is no error, it is not done and it did not EWOULDBLOCK, then
+ /* if there's no error, it isn't done and it didn't EWOULDBLOCK, then
try again */
} while(!result && !*done && !block);
ssh_block2waitfor(data, block);
@@ -3192,13 +3193,12 @@ static ssize_t ssh_tls_recv(libssh2_socket_t sock, void *buffer,
struct connectdata *conn = data->conn;
Curl_recv *backup = conn->recv[0];
struct ssh_conn *ssh = &conn->proto.sshc;
- int socknum = Curl_conn_sockindex(data, sock);
(void)flags;
/* swap in the TLS reader function for this call only, and then swap back
the SSH one again */
conn->recv[0] = ssh->tls_recv;
- result = Curl_conn_recv(data, socknum, buffer, length, &nread);
+ result = Curl_read(data, sock, buffer, length, &nread);
conn->recv[0] = backup;
if(result == CURLE_AGAIN)
return -EAGAIN; /* magic return code for libssh2 */
@@ -3212,25 +3212,24 @@ static ssize_t ssh_tls_send(libssh2_socket_t sock, const void *buffer,
size_t length, int flags, void **abstract)
{
struct Curl_easy *data = (struct Curl_easy *)*abstract;
- size_t nwrite;
+ ssize_t nwrite;
CURLcode result;
struct connectdata *conn = data->conn;
Curl_send *backup = conn->send[0];
struct ssh_conn *ssh = &conn->proto.sshc;
- int socknum = Curl_conn_sockindex(data, sock);
(void)flags;
/* swap in the TLS writer function for this call only, and then swap back
the SSH one again */
conn->send[0] = ssh->tls_send;
- result = Curl_conn_send(data, socknum, buffer, length, FALSE, &nwrite);
+ result = Curl_write(data, sock, buffer, length, &nwrite);
conn->send[0] = backup;
if(result == CURLE_AGAIN)
return -EAGAIN; /* magic return code for libssh2 */
else if(result)
return -1; /* error */
- Curl_debug(data, CURLINFO_DATA_OUT, (char *)buffer, nwrite);
- return (ssize_t)nwrite;
+ Curl_debug(data, CURLINFO_DATA_OUT, (char *)buffer, (size_t)nwrite);
+ return nwrite;
}
#endif
@@ -3271,7 +3270,7 @@ static CURLcode ssh_connect(struct Curl_easy *data, bool *done)
#endif /* CURL_LIBSSH2_DEBUG */
/* libcurl MUST to set custom memory functions so that the kbd_callback
- function's memory allocations can be properly freed */
+ funciton's memory allocations can be properled freed */
sshc->ssh_session = libssh2_session_init_ex(my_libssh2_malloc,
my_libssh2_free,
my_libssh2_realloc, data);
@@ -3281,38 +3280,19 @@ static CURLcode ssh_connect(struct Curl_easy *data, bool *done)
return CURLE_FAILED_INIT;
}
+#ifdef HAVE_LIBSSH2_VERSION
/* Set the packet read timeout if the libssh2 version supports it */
#if LIBSSH2_VERSION_NUM >= 0x010B00
if(data->set.server_response_timeout > 0) {
libssh2_session_set_read_timeout(sshc->ssh_session,
- (long)(data->set.server_response_timeout / 1000));
+ data->set.server_response_timeout / 1000);
}
#endif
+#endif
#ifndef CURL_DISABLE_PROXY
if(conn->http_proxy.proxytype == CURLPROXY_HTTPS) {
/*
- Setup libssh2 callbacks to make it read/write TLS from the socket.
-
- ssize_t
- recvcb(libssh2_socket_t sock, void *buffer, size_t length,
- int flags, void **abstract);
-
- ssize_t
- sendcb(libssh2_socket_t sock, const void *buffer, size_t length,
- int flags, void **abstract);
-
- */
-#if LIBSSH2_VERSION_NUM >= 0x010b01
- infof(data, "Uses HTTPS proxy");
- libssh2_session_callback_set2(sshc->ssh_session,
- LIBSSH2_CALLBACK_RECV,
- (libssh2_cb_generic *)ssh_tls_recv);
- libssh2_session_callback_set2(sshc->ssh_session,
- LIBSSH2_CALLBACK_SEND,
- (libssh2_cb_generic *)ssh_tls_send);
-#else
- /*
* This crazy union dance is here to avoid assigning a void pointer a
* function pointer as it is invalid C. The problem is of course that
* libssh2 has such an API...
@@ -3332,11 +3312,22 @@ static CURLcode ssh_connect(struct Curl_easy *data, bool *done)
sshsend.sendptr = ssh_tls_send;
infof(data, "Uses HTTPS proxy");
+ /*
+ Setup libssh2 callbacks to make it read/write TLS from the socket.
+
+ ssize_t
+ recvcb(libssh2_socket_t sock, void *buffer, size_t length,
+ int flags, void **abstract);
+
+ ssize_t
+ sendcb(libssh2_socket_t sock, const void *buffer, size_t length,
+ int flags, void **abstract);
+
+ */
libssh2_session_callback_set(sshc->ssh_session,
LIBSSH2_CALLBACK_RECV, sshrecv.recvp);
libssh2_session_callback_set(sshc->ssh_session,
LIBSSH2_CALLBACK_SEND, sshsend.sendp);
-#endif
/* Store the underlying TLS recv/send function pointers to be used when
reading from the proxy */
@@ -3486,7 +3477,7 @@ static CURLcode scp_disconnect(struct Curl_easy *data,
(void) dead_connection;
if(sshc->ssh_session) {
- /* only if there is a session still around to use! */
+ /* only if there's a session still around to use! */
state(data, SSH_SESSION_DISCONNECT);
result = ssh_block_statemach(data, conn, TRUE);
}
@@ -3534,13 +3525,12 @@ static CURLcode scp_done(struct Curl_easy *data, CURLcode status,
}
static ssize_t scp_send(struct Curl_easy *data, int sockindex,
- const void *mem, size_t len, bool eos, CURLcode *err)
+ const void *mem, size_t len, CURLcode *err)
{
ssize_t nwrite;
struct connectdata *conn = data->conn;
struct ssh_conn *sshc = &conn->proto.sshc;
(void)sockindex; /* we only support SCP on the fixed known primary socket */
- (void)eos;
/* libssh2_channel_write() returns int! */
nwrite = (ssize_t) libssh2_channel_write(sshc->ssh_channel, mem, len);
@@ -3643,7 +3633,7 @@ static CURLcode sftp_disconnect(struct Curl_easy *data,
DEBUGF(infof(data, "SSH DISCONNECT starts now"));
if(sshc->ssh_session) {
- /* only if there is a session still around to use! */
+ /* only if there's a session still around to use! */
state(data, SSH_SFTP_SHUTDOWN);
result = ssh_block_statemach(data, conn, TRUE);
}
@@ -3673,13 +3663,12 @@ static CURLcode sftp_done(struct Curl_easy *data, CURLcode status,
/* return number of sent bytes */
static ssize_t sftp_send(struct Curl_easy *data, int sockindex,
- const void *mem, size_t len, bool eos, CURLcode *err)
+ const void *mem, size_t len, CURLcode *err)
{
ssize_t nwrite;
struct connectdata *conn = data->conn;
struct ssh_conn *sshc = &conn->proto.sshc;
(void)sockindex;
- (void)eos;
nwrite = libssh2_sftp_write(sshc->sftp_handle, mem, len);
diff --git a/contrib/libs/curl/lib/vssh/ssh.h b/contrib/libs/curl/lib/vssh/ssh.h
index 1af514806b..ff1d0a1efe 100644
--- a/contrib/libs/curl/lib/vssh/ssh.h
+++ b/contrib/libs/curl/lib/vssh/ssh.h
@@ -30,8 +30,6 @@
#error #include <libssh2.h>
#error #include <libssh2_sftp.h>
#elif defined(USE_LIBSSH)
-/* in 0.10.0 or later, ignore deprecated warnings */
-#define SSH_SUPPRESS_DEPRECATED
#error #include <libssh/libssh.h>
#error #include <libssh/sftp.h>
#elif defined(USE_WOLFSSH)
@@ -165,7 +163,7 @@ struct ssh_conn {
unsigned kbd_state; /* 0 or 1 */
ssh_key privkey;
ssh_key pubkey;
- unsigned int auth_methods;
+ int auth_methods;
ssh_session ssh_session;
ssh_scp scp_session;
sftp_session sftp_session;
@@ -245,10 +243,10 @@ struct ssh_conn {
#endif
#ifdef HAVE_LIBSSH2_VERSION
-/* get it runtime if possible */
+/* get it run-time if possible */
#define CURL_LIBSSH2_VERSION libssh2_version(0)
#else
-/* use build-time if runtime not possible */
+/* use build-time if run-time not possible */
#define CURL_LIBSSH2_VERSION LIBSSH2_VERSION
#endif
diff --git a/contrib/libs/curl/lib/vssh/wolfssh.c b/contrib/libs/curl/lib/vssh/wolfssh.c
index 91b39a46b0..e32e98cc75 100644
--- a/contrib/libs/curl/lib/vssh/wolfssh.c
+++ b/contrib/libs/curl/lib/vssh/wolfssh.c
@@ -28,6 +28,8 @@
#include <limits.h>
+#error #include <wolfssh/ssh.h>
+#error #include <wolfssh/wolfsftp.h>
#include "urldata.h"
#include "cfilters.h"
#include "connect.h"
@@ -40,7 +42,6 @@
#include "select.h"
#include "multiif.h"
#include "warnless.h"
-#include "strdup.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@@ -91,8 +92,7 @@ const struct Curl_handler Curl_handler_scp = {
ZERO_NULL, /* domore_getsock */
wssh_getsock, /* perform_getsock */
wscp_disconnect, /* disconnect */
- ZERO_NULL, /* write_resp */
- ZERO_NULL, /* write_resp_hd */
+ ZERO_NULL, /* readwrite */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_SSH, /* defport */
@@ -121,8 +121,7 @@ const struct Curl_handler Curl_handler_sftp = {
ZERO_NULL, /* domore_getsock */
wssh_getsock, /* perform_getsock */
wsftp_disconnect, /* disconnect */
- ZERO_NULL, /* write_resp */
- ZERO_NULL, /* write_resp_hd */
+ ZERO_NULL, /* readwrite */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
PORT_SSH, /* defport */
@@ -218,15 +217,13 @@ static void state(struct Curl_easy *data, sshstate nowstate)
}
static ssize_t wscp_send(struct Curl_easy *data, int sockindex,
- const void *mem, size_t len, bool eos,
- CURLcode *err)
+ const void *mem, size_t len, CURLcode *err)
{
ssize_t nwrite = 0;
(void)data;
(void)sockindex; /* we only support SCP on the fixed known primary socket */
(void)mem;
(void)len;
- (void)eos;
(void)err;
return nwrite;
@@ -247,14 +244,13 @@ static ssize_t wscp_recv(struct Curl_easy *data, int sockindex,
/* return number of sent bytes */
static ssize_t wsftp_send(struct Curl_easy *data, int sockindex,
- const void *mem, size_t len, bool eos, CURLcode *err)
+ const void *mem, size_t len, CURLcode *err)
{
struct connectdata *conn = data->conn;
struct ssh_conn *sshc = &conn->proto.sshc;
word32 offset[2];
int rc;
(void)sockindex;
- (void)eos;
offset[0] = (word32)sshc->offset&0xFFFFFFFF;
offset[1] = (word32)(sshc->offset>>32)&0xFFFFFFFF;
@@ -281,7 +277,7 @@ static ssize_t wsftp_send(struct Curl_easy *data, int sockindex,
return -1;
}
DEBUGASSERT(rc == (int)len);
- infof(data, "sent %zu bytes SFTP from offset %" FMT_OFF_T,
+ infof(data, "sent %zu bytes SFTP from offset %" CURL_FORMAT_CURL_OFF_T,
len, sshc->offset);
sshc->offset += len;
return (ssize_t)rc;
@@ -401,7 +397,7 @@ static CURLcode wssh_connect(struct Curl_easy *data, bool *done)
rc = wolfSSH_SetUsername(sshc->ssh_session, conn->user);
if(rc != WS_SUCCESS) {
- failf(data, "wolfSSH failed to set username");
+ failf(data, "wolfSSH failed to set user name");
goto error;
}
@@ -434,7 +430,7 @@ error:
/*
* wssh_statemach_act() runs the SSH state machine as far as it can without
- * blocking and without reaching the end. The data the pointer 'block' points
+ * blocking and without reaching the end. The data the pointer 'block' points
* to will be set to TRUE if the wolfssh function returns EAGAIN meaning it
* wants to be called again when the socket is ready
*/
@@ -447,7 +443,7 @@ static CURLcode wssh_statemach_act(struct Curl_easy *data, bool *block)
struct SSHPROTO *sftp_scp = data->req.p.ssh;
WS_SFTPNAME *name;
int rc = 0;
- *block = FALSE; /* we are not blocking by default */
+ *block = FALSE; /* we're not blocking by default */
do {
switch(sshc->state) {
@@ -516,9 +512,15 @@ static CURLcode wssh_statemach_act(struct Curl_easy *data, bool *block)
return CURLE_OK;
}
else if(name && (rc == WS_SUCCESS)) {
- sshc->homedir = Curl_memdup0(name->fName, name->fSz);
- if(!sshc->homedir)
+ sshc->homedir = malloc(name->fSz + 1);
+ if(!sshc->homedir) {
sshc->actualcode = CURLE_OUT_OF_MEMORY;
+ }
+ else {
+ memcpy(sshc->homedir, name->fName, name->fSz);
+ sshc->homedir[name->fSz] = 0;
+ infof(data, "wolfssh SFTP realpath succeeded");
+ }
wolfSSH_SFTPNAME_list_free(name);
state(data, SSH_STOP);
return CURLE_OK;
@@ -578,7 +580,7 @@ static CURLcode wssh_statemach_act(struct Curl_easy *data, bool *block)
else {
curl_off_t size = ((curl_off_t)attrs.sz[1] << 32) | attrs.sz[0];
if(size < 0) {
- failf(data, "Bad file size (%" FMT_OFF_T ")", size);
+ failf(data, "Bad file size (%" CURL_FORMAT_CURL_OFF_T ")", size);
return CURLE_BAD_DOWNLOAD_RESUME;
}
data->state.resume_from = size;
@@ -628,10 +630,10 @@ static CURLcode wssh_statemach_act(struct Curl_easy *data, bool *block)
if(data->state.resume_from > 0) {
/* Let's read off the proper amount of bytes from the input. */
int seekerr = CURL_SEEKFUNC_OK;
- if(data->set.seek_func) {
+ if(conn->seek_func) {
Curl_set_in_callback(data, true);
- seekerr = data->set.seek_func(data->set.seek_client,
- data->state.resume_from, SEEK_SET);
+ seekerr = conn->seek_func(conn->seek_client, data->state.resume_from,
+ SEEK_SET);
Curl_set_in_callback(data, false);
}
@@ -642,17 +644,16 @@ static CURLcode wssh_statemach_act(struct Curl_easy *data, bool *block)
failf(data, "Could not seek stream");
return CURLE_FTP_COULDNT_USE_REST;
}
- /* seekerr == CURL_SEEKFUNC_CANTSEEK (cannot seek to offset) */
+ /* seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */
do {
- char scratch[4*1024];
size_t readthisamountnow =
- (data->state.resume_from - passed >
- (curl_off_t)sizeof(scratch)) ?
- sizeof(scratch) : curlx_sotouz(data->state.resume_from - passed);
+ (data->state.resume_from - passed > data->set.buffer_size) ?
+ (size_t)data->set.buffer_size :
+ curlx_sotouz(data->state.resume_from - passed);
size_t actuallyread;
Curl_set_in_callback(data, true);
- actuallyread = data->state.fread_func(scratch, 1,
+ actuallyread = data->state.fread_func(data->state.buffer, 1,
readthisamountnow,
data->state.in);
Curl_set_in_callback(data, false);
@@ -681,9 +682,9 @@ static CURLcode wssh_statemach_act(struct Curl_easy *data, bool *block)
Curl_pgrsSetUploadSize(data, data->state.infilesize);
}
/* upload data */
- Curl_xfer_setup1(data, CURL_XFER_SEND, -1, FALSE);
+ Curl_setup_transfer(data, -1, -1, FALSE, FIRSTSOCKET);
- /* not set by Curl_xfer_setup to preserve keepon bits */
+ /* not set by Curl_setup_transfer to preserve keepon bits */
conn->sockfd = conn->writesockfd;
if(result) {
@@ -691,16 +692,16 @@ static CURLcode wssh_statemach_act(struct Curl_easy *data, bool *block)
sshc->actualcode = result;
}
else {
- /* store this original bitmask setup to use later on if we cannot
+ /* store this original bitmask setup to use later on if we can't
figure out a "real" bitmask */
sshc->orig_waitfor = data->req.keepon;
/* we want to use the _sending_ function even when the socket turns
out readable as the underlying libssh2 sftp send function will deal
with both accordingly */
- data->state.select_bits = CURL_CSELECT_OUT;
+ conn->cselect_bits = CURL_CSELECT_OUT;
- /* since we do not really wait for anything at this point, we want the
+ /* since we don't really wait for anything at this point, we want the
state machine to move on as soon as possible so we set a very short
timeout here */
Curl_expire(data, 0, EXPIRE_RUN_NOW);
@@ -769,7 +770,7 @@ static CURLcode wssh_statemach_act(struct Curl_easy *data, bool *block)
data->req.maxdownload = size;
Curl_pgrsSetDownloadSize(data, size);
- infof(data, "SFTP download %" FMT_OFF_T " bytes", size);
+ infof(data, "SFTP download %" CURL_FORMAT_CURL_OFF_T " bytes", size);
/* We cannot seek with wolfSSH so resuming and range requests are not
possible */
@@ -781,20 +782,20 @@ static CURLcode wssh_statemach_act(struct Curl_easy *data, bool *block)
/* Setup the actual download */
if(data->req.size == 0) {
/* no data to transfer */
- Curl_xfer_setup_nop(data);
+ Curl_setup_transfer(data, -1, -1, FALSE, -1);
infof(data, "File already completely downloaded");
state(data, SSH_STOP);
break;
}
- Curl_xfer_setup1(data, CURL_XFER_RECV, data->req.size, FALSE);
+ Curl_setup_transfer(data, FIRSTSOCKET, data->req.size, FALSE, -1);
- /* not set by Curl_xfer_setup to preserve keepon bits */
+ /* not set by Curl_setup_transfer to preserve keepon bits */
conn->writesockfd = conn->sockfd;
/* we want to use the _receiving_ function even when the socket turns
out writableable as the underlying libssh2 recv function will deal
with both accordingly */
- data->state.select_bits = CURL_CSELECT_IN;
+ conn->cselect_bits = CURL_CSELECT_IN;
if(result) {
/* this should never occur; the close state should be entered
@@ -909,7 +910,7 @@ static CURLcode wssh_multi_statemach(struct Curl_easy *data, bool *done)
do {
result = wssh_statemach_act(data, &block);
*done = (sshc->state == SSH_STOP) ? TRUE : FALSE;
- /* if there is no error, it is not done and it did not EWOULDBLOCK, then
+ /* if there's no error, it isn't done and it didn't EWOULDBLOCK, then
try again */
if(*done) {
DEBUGF(infof(data, "wssh_statemach_act says DONE"));
@@ -1122,7 +1123,7 @@ static CURLcode wsftp_disconnect(struct Curl_easy *data,
DEBUGF(infof(data, "SSH DISCONNECT starts now"));
if(conn->proto.sshc.ssh_session) {
- /* only if there is a session still around to use! */
+ /* only if there's a session still around to use! */
state(data, SSH_SFTP_SHUTDOWN);
result = wssh_block_statemach(data, TRUE);
}
diff --git a/contrib/libs/curl/lib/vtls/bearssl.c b/contrib/libs/curl/lib/vtls/bearssl.c
index 224913bd1e..b52fc14262 100644
--- a/contrib/libs/curl/lib/vtls/bearssl.c
+++ b/contrib/libs/curl/lib/vtls/bearssl.c
@@ -28,7 +28,6 @@
#error #include <bearssl.h>
#include "bearssl.h"
-#error #include "cipher_suite.h"
#include "urldata.h"
#include "sendf.h"
#include "inet_pton.h"
@@ -38,6 +37,7 @@
#include "select.h"
#include "multiif.h"
#include "curl_printf.h"
+#include "strcase.h"
/* The last #include files should be: */
#include "curl_memory.h"
@@ -63,7 +63,6 @@ struct bearssl_ssl_backend_data {
bool active;
/* size of pending write, yet to be flushed */
size_t pending_write;
- BIT(sent_shutdown);
};
struct cafile_parser {
@@ -121,9 +120,9 @@ static CURLcode load_cafile(struct cafile_source *source,
br_x509_pkey *pkey;
FILE *fp = 0;
unsigned char buf[BUFSIZ];
- const unsigned char *p = NULL;
+ const unsigned char *p;
const char *name;
- size_t n = 0, i, pushed;
+ size_t n, i, pushed;
DEBUGASSERT(source->type == CAFILE_SOURCE_PATH
|| source->type == CAFILE_SOURCE_BLOB);
@@ -328,7 +327,7 @@ static unsigned x509_end_chain(const br_x509_class **ctx)
struct x509_context *x509 = (struct x509_context *)ctx;
if(!x509->verifypeer) {
- return (unsigned)br_x509_decoder_last_error(&x509->decoder);
+ return br_x509_decoder_last_error(&x509->decoder);
}
return x509->minimal.vtable->end_chain(&x509->minimal.vtable);
@@ -361,171 +360,213 @@ static const br_x509_class x509_vtable = {
x509_get_pkey
};
-static CURLcode
-bearssl_set_ssl_version_min_max(struct Curl_easy *data,
- br_ssl_engine_context *ssl_eng,
- struct ssl_primary_config *conn_config)
-{
- unsigned version_min, version_max;
-
- switch(conn_config->version) {
- case CURL_SSLVERSION_DEFAULT:
- case CURL_SSLVERSION_TLSv1:
- case CURL_SSLVERSION_TLSv1_0:
- version_min = BR_TLS10;
- break;
- case CURL_SSLVERSION_TLSv1_1:
- version_min = BR_TLS11;
- break;
- case CURL_SSLVERSION_TLSv1_2:
- version_min = BR_TLS12;
- break;
- case CURL_SSLVERSION_TLSv1_3:
- failf(data, "BearSSL: does not support TLS 1.3");
- return CURLE_SSL_CONNECT_ERROR;
- default:
- failf(data, "BearSSL: unsupported minimum TLS version value");
- return CURLE_SSL_CONNECT_ERROR;
- }
-
- switch(conn_config->version_max) {
- case CURL_SSLVERSION_MAX_DEFAULT:
- case CURL_SSLVERSION_MAX_NONE:
- case CURL_SSLVERSION_MAX_TLSv1_3:
- case CURL_SSLVERSION_MAX_TLSv1_2:
- version_max = BR_TLS12;
- break;
- case CURL_SSLVERSION_MAX_TLSv1_1:
- version_max = BR_TLS11;
- break;
- case CURL_SSLVERSION_MAX_TLSv1_0:
- version_max = BR_TLS10;
- break;
- default:
- failf(data, "BearSSL: unsupported maximum TLS version value");
- return CURLE_SSL_CONNECT_ERROR;
- }
-
- br_ssl_engine_set_versions(ssl_eng, version_min, version_max);
+struct st_cipher {
+ const char *name; /* Cipher suite IANA name. It starts with "TLS_" prefix */
+ const char *alias_name; /* Alias name is the same as OpenSSL cipher name */
+ uint16_t num; /* BearSSL cipher suite */
+};
- return CURLE_OK;
-}
+/* Macro to initialize st_cipher data structure */
+#define CIPHER_DEF(num, alias) { #num, alias, BR_##num }
-static const uint16_t ciphertable[] = {
+static const struct st_cipher ciphertable[] = {
/* RFC 2246 TLS 1.0 */
- BR_TLS_RSA_WITH_3DES_EDE_CBC_SHA, /* 0x000A */
+ CIPHER_DEF(TLS_RSA_WITH_3DES_EDE_CBC_SHA, /* 0x000A */
+ "DES-CBC3-SHA"),
/* RFC 3268 TLS 1.0 AES */
- BR_TLS_RSA_WITH_AES_128_CBC_SHA, /* 0x002F */
- BR_TLS_RSA_WITH_AES_256_CBC_SHA, /* 0x0035 */
+ CIPHER_DEF(TLS_RSA_WITH_AES_128_CBC_SHA, /* 0x002F */
+ "AES128-SHA"),
+ CIPHER_DEF(TLS_RSA_WITH_AES_256_CBC_SHA, /* 0x0035 */
+ "AES256-SHA"),
/* RFC 5246 TLS 1.2 */
- BR_TLS_RSA_WITH_AES_128_CBC_SHA256, /* 0x003C */
- BR_TLS_RSA_WITH_AES_256_CBC_SHA256, /* 0x003D */
+ CIPHER_DEF(TLS_RSA_WITH_AES_128_CBC_SHA256, /* 0x003C */
+ "AES128-SHA256"),
+ CIPHER_DEF(TLS_RSA_WITH_AES_256_CBC_SHA256, /* 0x003D */
+ "AES256-SHA256"),
/* RFC 5288 TLS 1.2 AES GCM */
- BR_TLS_RSA_WITH_AES_128_GCM_SHA256, /* 0x009C */
- BR_TLS_RSA_WITH_AES_256_GCM_SHA384, /* 0x009D */
+ CIPHER_DEF(TLS_RSA_WITH_AES_128_GCM_SHA256, /* 0x009C */
+ "AES128-GCM-SHA256"),
+ CIPHER_DEF(TLS_RSA_WITH_AES_256_GCM_SHA384, /* 0x009D */
+ "AES256-GCM-SHA384"),
/* RFC 4492 TLS 1.0 ECC */
- BR_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, /* 0xC003 */
- BR_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, /* 0xC004 */
- BR_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, /* 0xC005 */
- BR_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, /* 0xC008 */
- BR_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, /* 0xC009 */
- BR_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, /* 0xC00A */
- BR_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, /* 0xC00D */
- BR_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, /* 0xC00E */
- BR_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, /* 0xC00F */
- BR_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, /* 0xC012 */
- BR_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, /* 0xC013 */
- BR_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, /* 0xC014 */
+ CIPHER_DEF(TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, /* 0xC003 */
+ "ECDH-ECDSA-DES-CBC3-SHA"),
+ CIPHER_DEF(TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, /* 0xC004 */
+ "ECDH-ECDSA-AES128-SHA"),
+ CIPHER_DEF(TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, /* 0xC005 */
+ "ECDH-ECDSA-AES256-SHA"),
+ CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, /* 0xC008 */
+ "ECDHE-ECDSA-DES-CBC3-SHA"),
+ CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, /* 0xC009 */
+ "ECDHE-ECDSA-AES128-SHA"),
+ CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, /* 0xC00A */
+ "ECDHE-ECDSA-AES256-SHA"),
+ CIPHER_DEF(TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, /* 0xC00D */
+ "ECDH-RSA-DES-CBC3-SHA"),
+ CIPHER_DEF(TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, /* 0xC00E */
+ "ECDH-RSA-AES128-SHA"),
+ CIPHER_DEF(TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, /* 0xC00F */
+ "ECDH-RSA-AES256-SHA"),
+ CIPHER_DEF(TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, /* 0xC012 */
+ "ECDHE-RSA-DES-CBC3-SHA"),
+ CIPHER_DEF(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, /* 0xC013 */
+ "ECDHE-RSA-AES128-SHA"),
+ CIPHER_DEF(TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, /* 0xC014 */
+ "ECDHE-RSA-AES256-SHA"),
/* RFC 5289 TLS 1.2 ECC HMAC SHA256/384 */
- BR_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, /* 0xC023 */
- BR_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, /* 0xC024 */
- BR_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256, /* 0xC025 */
- BR_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384, /* 0xC026 */
- BR_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, /* 0xC027 */
- BR_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, /* 0xC028 */
- BR_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256, /* 0xC029 */
- BR_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384, /* 0xC02A */
+ CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, /* 0xC023 */
+ "ECDHE-ECDSA-AES128-SHA256"),
+ CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, /* 0xC024 */
+ "ECDHE-ECDSA-AES256-SHA384"),
+ CIPHER_DEF(TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256, /* 0xC025 */
+ "ECDH-ECDSA-AES128-SHA256"),
+ CIPHER_DEF(TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384, /* 0xC026 */
+ "ECDH-ECDSA-AES256-SHA384"),
+ CIPHER_DEF(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, /* 0xC027 */
+ "ECDHE-RSA-AES128-SHA256"),
+ CIPHER_DEF(TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, /* 0xC028 */
+ "ECDHE-RSA-AES256-SHA384"),
+ CIPHER_DEF(TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256, /* 0xC029 */
+ "ECDH-RSA-AES128-SHA256"),
+ CIPHER_DEF(TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384, /* 0xC02A */
+ "ECDH-RSA-AES256-SHA384"),
/* RFC 5289 TLS 1.2 GCM */
- BR_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, /* 0xC02B */
- BR_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, /* 0xC02C */
- BR_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256, /* 0xC02D */
- BR_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384, /* 0xC02E */
- BR_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, /* 0xC02F */
- BR_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, /* 0xC030 */
- BR_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256, /* 0xC031 */
- BR_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384, /* 0xC032 */
-
+ CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, /* 0xC02B */
+ "ECDHE-ECDSA-AES128-GCM-SHA256"),
+ CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, /* 0xC02C */
+ "ECDHE-ECDSA-AES256-GCM-SHA384"),
+ CIPHER_DEF(TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256, /* 0xC02D */
+ "ECDH-ECDSA-AES128-GCM-SHA256"),
+ CIPHER_DEF(TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384, /* 0xC02E */
+ "ECDH-ECDSA-AES256-GCM-SHA384"),
+ CIPHER_DEF(TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, /* 0xC02F */
+ "ECDHE-RSA-AES128-GCM-SHA256"),
+ CIPHER_DEF(TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, /* 0xC030 */
+ "ECDHE-RSA-AES256-GCM-SHA384"),
+ CIPHER_DEF(TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256, /* 0xC031 */
+ "ECDH-RSA-AES128-GCM-SHA256"),
+ CIPHER_DEF(TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384, /* 0xC032 */
+ "ECDH-RSA-AES256-GCM-SHA384"),
#ifdef BR_TLS_RSA_WITH_AES_128_CCM
+
/* RFC 6655 TLS 1.2 CCM
Supported since BearSSL 0.6 */
- BR_TLS_RSA_WITH_AES_128_CCM, /* 0xC09C */
- BR_TLS_RSA_WITH_AES_256_CCM, /* 0xC09D */
- BR_TLS_RSA_WITH_AES_128_CCM_8, /* 0xC0A0 */
- BR_TLS_RSA_WITH_AES_256_CCM_8, /* 0xC0A1 */
+ CIPHER_DEF(TLS_RSA_WITH_AES_128_CCM, /* 0xC09C */
+ "AES128-CCM"),
+ CIPHER_DEF(TLS_RSA_WITH_AES_256_CCM, /* 0xC09D */
+ "AES256-CCM"),
+ CIPHER_DEF(TLS_RSA_WITH_AES_128_CCM_8, /* 0xC0A0 */
+ "AES128-CCM8"),
+ CIPHER_DEF(TLS_RSA_WITH_AES_256_CCM_8, /* 0xC0A1 */
+ "AES256-CCM8"),
/* RFC 7251 TLS 1.2 ECC CCM
Supported since BearSSL 0.6 */
- BR_TLS_ECDHE_ECDSA_WITH_AES_128_CCM, /* 0xC0AC */
- BR_TLS_ECDHE_ECDSA_WITH_AES_256_CCM, /* 0xC0AD */
- BR_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8, /* 0xC0AE */
- BR_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8, /* 0xC0AF */
+ CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_128_CCM, /* 0xC0AC */
+ "ECDHE-ECDSA-AES128-CCM"),
+ CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_256_CCM, /* 0xC0AD */
+ "ECDHE-ECDSA-AES256-CCM"),
+ CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8, /* 0xC0AE */
+ "ECDHE-ECDSA-AES128-CCM8"),
+ CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8, /* 0xC0AF */
+ "ECDHE-ECDSA-AES256-CCM8"),
#endif
/* RFC 7905 TLS 1.2 ChaCha20-Poly1305
Supported since BearSSL 0.2 */
- BR_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, /* 0xCCA8 */
- BR_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, /* 0xCCA9 */
+ CIPHER_DEF(TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, /* 0xCCA8 */
+ "ECDHE-RSA-CHACHA20-POLY1305"),
+ CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, /* 0xCCA9 */
+ "ECDHE-ECDSA-CHACHA20-POLY1305"),
};
#define NUM_OF_CIPHERS (sizeof(ciphertable) / sizeof(ciphertable[0]))
+#define CIPHER_NAME_BUF_LEN 64
+
+static bool is_separator(char c)
+{
+ /* Return whether character is a cipher list separator. */
+ switch(c) {
+ case ' ':
+ case '\t':
+ case ':':
+ case ',':
+ case ';':
+ return true;
+ }
+ return false;
+}
static CURLcode bearssl_set_selected_ciphers(struct Curl_easy *data,
br_ssl_engine_context *ssl_eng,
const char *ciphers)
{
- uint16_t selected[NUM_OF_CIPHERS];
- size_t count = 0, i;
- const char *ptr, *end;
-
- for(ptr = ciphers; ptr[0] != '\0' && count < NUM_OF_CIPHERS; ptr = end) {
- uint16_t id = Curl_cipher_suite_walk_str(&ptr, &end);
-
- /* Check if cipher is supported */
- if(id) {
- for(i = 0; i < NUM_OF_CIPHERS && ciphertable[i] != id; i++);
- if(i == NUM_OF_CIPHERS)
- id = 0;
+ uint16_t selected_ciphers[NUM_OF_CIPHERS];
+ size_t selected_count = 0;
+ char cipher_name[CIPHER_NAME_BUF_LEN];
+ const char *cipher_start = ciphers;
+ const char *cipher_end;
+ size_t i, j;
+
+ if(!cipher_start)
+ return CURLE_SSL_CIPHER;
+
+ while(true) {
+ /* Extract the next cipher name from the ciphers string */
+ while(is_separator(*cipher_start))
+ ++cipher_start;
+ if(*cipher_start == '\0')
+ break;
+ cipher_end = cipher_start;
+ while(*cipher_end != '\0' && !is_separator(*cipher_end))
+ ++cipher_end;
+ j = cipher_end - cipher_start < CIPHER_NAME_BUF_LEN - 1 ?
+ cipher_end - cipher_start : CIPHER_NAME_BUF_LEN - 1;
+ strncpy(cipher_name, cipher_start, j);
+ cipher_name[j] = '\0';
+ cipher_start = cipher_end;
+
+ /* Lookup the cipher name in the table of available ciphers. If the cipher
+ name starts with "TLS_" we do the lookup by IANA name. Otherwise, we try
+ to match cipher name by an (OpenSSL) alias. */
+ if(strncasecompare(cipher_name, "TLS_", 4)) {
+ for(i = 0; i < NUM_OF_CIPHERS &&
+ !strcasecompare(cipher_name, ciphertable[i].name); ++i);
}
- if(!id) {
- if(ptr[0] != '\0')
- infof(data, "BearSSL: unknown cipher in list: \"%.*s\"",
- (int) (end - ptr), ptr);
+ else {
+ for(i = 0; i < NUM_OF_CIPHERS &&
+ !strcasecompare(cipher_name, ciphertable[i].alias_name); ++i);
+ }
+ if(i == NUM_OF_CIPHERS) {
+ infof(data, "BearSSL: unknown cipher in list: %s", cipher_name);
continue;
}
/* No duplicates allowed */
- for(i = 0; i < count && selected[i] != id; i++);
- if(i < count) {
- infof(data, "BearSSL: duplicate cipher in list: \"%.*s\"",
- (int) (end - ptr), ptr);
+ for(j = 0; j < selected_count &&
+ selected_ciphers[j] != ciphertable[i].num; j++);
+ if(j < selected_count) {
+ infof(data, "BearSSL: duplicate cipher in list: %s", cipher_name);
continue;
}
- selected[count++] = id;
+ DEBUGASSERT(selected_count < NUM_OF_CIPHERS);
+ selected_ciphers[selected_count] = ciphertable[i].num;
+ ++selected_count;
}
- if(count == 0) {
+ if(selected_count == 0) {
failf(data, "BearSSL: no supported cipher in list");
return CURLE_SSL_CIPHER;
}
- br_ssl_engine_set_suites(ssl_eng, selected, count);
+ br_ssl_engine_set_suites(ssl_eng, selected_ciphers, selected_count);
return CURLE_OK;
}
@@ -545,11 +586,41 @@ static CURLcode bearssl_connect_step1(struct Curl_cfilter *cf,
const bool verifypeer = conn_config->verifypeer;
const bool verifyhost = conn_config->verifyhost;
CURLcode ret;
+ unsigned version_min, version_max;
int session_set = 0;
DEBUGASSERT(backend);
CURL_TRC_CF(data, cf, "connect_step1");
+ switch(conn_config->version) {
+ case CURL_SSLVERSION_SSLv2:
+ failf(data, "BearSSL does not support SSLv2");
+ return CURLE_SSL_CONNECT_ERROR;
+ case CURL_SSLVERSION_SSLv3:
+ failf(data, "BearSSL does not support SSLv3");
+ return CURLE_SSL_CONNECT_ERROR;
+ case CURL_SSLVERSION_TLSv1_0:
+ version_min = BR_TLS10;
+ version_max = BR_TLS10;
+ break;
+ case CURL_SSLVERSION_TLSv1_1:
+ version_min = BR_TLS11;
+ version_max = BR_TLS11;
+ break;
+ case CURL_SSLVERSION_TLSv1_2:
+ version_min = BR_TLS12;
+ version_max = BR_TLS12;
+ break;
+ case CURL_SSLVERSION_DEFAULT:
+ case CURL_SSLVERSION_TLSv1:
+ version_min = BR_TLS10;
+ version_max = BR_TLS12;
+ break;
+ default:
+ failf(data, "BearSSL: unknown CURLOPT_SSLVERSION");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
if(verifypeer) {
if(ca_info_blob) {
struct cafile_source source;
@@ -584,11 +655,7 @@ static CURLcode bearssl_connect_step1(struct Curl_cfilter *cf,
/* initialize SSL context */
br_ssl_client_init_full(&backend->ctx, &backend->x509.minimal,
backend->anchors, backend->anchors_len);
-
- ret = bearssl_set_ssl_version_min_max(data, &backend->ctx.eng, conn_config);
- if(ret != CURLE_OK)
- return ret;
-
+ br_ssl_engine_set_versions(&backend->ctx.eng, version_min, version_max);
br_ssl_engine_set_buffer(&backend->ctx.eng, backend->buf,
sizeof(backend->buf), 1);
@@ -608,12 +675,12 @@ static CURLcode bearssl_connect_step1(struct Curl_cfilter *cf,
backend->x509.verifyhost = verifyhost;
br_ssl_engine_set_x509(&backend->ctx.eng, &backend->x509.vtable);
- if(ssl_config->primary.cache_session) {
+ if(ssl_config->primary.sessionid) {
void *session;
CURL_TRC_CF(data, cf, "connect_step1, check session cache");
Curl_ssl_sessionid_lock(data);
- if(!Curl_ssl_getsessionid(cf, data, &connssl->peer, &session, NULL)) {
+ if(!Curl_ssl_getsessionid(cf, data, &session, NULL)) {
br_ssl_engine_set_session_parameters(&backend->ctx.eng, session);
session_set = 1;
infof(data, "BearSSL: reusing session ID");
@@ -634,7 +701,7 @@ static CURLcode bearssl_connect_step1(struct Curl_cfilter *cf,
infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data);
}
- if(connssl->peer.type != CURL_SSL_PEER_DNS) {
+ if(connssl->peer.is_ip_address) {
if(verifyhost) {
failf(data, "BearSSL: "
"host verification of IP address is not supported");
@@ -672,6 +739,28 @@ static CURLcode bearssl_connect_step1(struct Curl_cfilter *cf,
return CURLE_OK;
}
+static void bearssl_adjust_pollset(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ struct easy_pollset *ps)
+{
+ if(!cf->connected) {
+ curl_socket_t sock = Curl_conn_cf_get_socket(cf->next, data);
+ if(sock != CURL_SOCKET_BAD) {
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct bearssl_ssl_backend_data *backend =
+ (struct bearssl_ssl_backend_data *)connssl->backend;
+ unsigned state = br_ssl_engine_current_state(&backend->ctx.eng);
+
+ if(state & BR_SSL_SENDREC) {
+ Curl_pollset_set_out_only(data, ps, sock);
+ }
+ else {
+ Curl_pollset_set_in_only(data, ps, sock);
+ }
+ }
+ }
+}
+
static CURLcode bearssl_run_until(struct Curl_cfilter *cf,
struct Curl_easy *data,
unsigned target)
@@ -688,7 +777,6 @@ static CURLcode bearssl_run_until(struct Curl_cfilter *cf,
DEBUGASSERT(backend);
- connssl->io_need = CURL_SSL_IO_NEED_NONE;
for(;;) {
state = br_ssl_engine_current_state(&backend->ctx.eng);
if(state & BR_SSL_CLOSED) {
@@ -713,9 +801,7 @@ static CURLcode bearssl_run_until(struct Curl_cfilter *cf,
failf(data, "SSL: X.509 verification: "
"chain could not be linked to a trust anchor");
return CURLE_PEER_FAILED_VERIFICATION;
- default:;
}
- failf(data, "BearSSL: connection error 0x%04x", err);
/* X.509 errors are documented to have the range 32..63 */
if(err >= 32 && err < 64)
return CURLE_PEER_FAILED_VERIFICATION;
@@ -725,12 +811,9 @@ static CURLcode bearssl_run_until(struct Curl_cfilter *cf,
return CURLE_OK;
if(state & BR_SSL_SENDREC) {
buf = br_ssl_engine_sendrec_buf(&backend->ctx.eng, &len);
- ret = Curl_conn_cf_send(cf->next, data, (char *)buf, len, FALSE,
- &result);
+ ret = Curl_conn_cf_send(cf->next, data, (char *)buf, len, &result);
CURL_TRC_CF(data, cf, "ssl_send(len=%zu) -> %zd, %d", len, ret, result);
if(ret <= 0) {
- if(result == CURLE_AGAIN)
- connssl->io_need |= CURL_SSL_IO_NEED_SEND;
return result;
}
br_ssl_engine_sendrec_ack(&backend->ctx.eng, ret);
@@ -741,11 +824,9 @@ static CURLcode bearssl_run_until(struct Curl_cfilter *cf,
CURL_TRC_CF(data, cf, "ssl_recv(len=%zu) -> %zd, %d", len, ret, result);
if(ret == 0) {
failf(data, "SSL: EOF without close notify");
- return CURLE_RECV_ERROR;
+ return CURLE_READ_ERROR;
}
if(ret <= 0) {
- if(result == CURLE_AGAIN)
- connssl->io_need |= CURL_SSL_IO_NEED_RECV;
return result;
}
br_ssl_engine_recvrec_ack(&backend->ctx.eng, ret);
@@ -759,9 +840,6 @@ static CURLcode bearssl_connect_step2(struct Curl_cfilter *cf,
struct ssl_connect_data *connssl = cf->ctx;
struct bearssl_ssl_backend_data *backend =
(struct bearssl_ssl_backend_data *)connssl->backend;
- br_ssl_session_parameters session;
- char cipher_str[64];
- char ver_str[16];
CURLcode ret;
DEBUGASSERT(backend);
@@ -772,7 +850,6 @@ static CURLcode bearssl_connect_step2(struct Curl_cfilter *cf,
return CURLE_OK;
if(ret == CURLE_OK) {
unsigned int tver;
-
if(br_ssl_engine_current_state(&backend->ctx.eng) == BR_SSL_CLOSED) {
failf(data, "SSL: connection closed during handshake");
return CURLE_SSL_CONNECT_ERROR;
@@ -780,29 +857,16 @@ static CURLcode bearssl_connect_step2(struct Curl_cfilter *cf,
connssl->connecting_state = ssl_connect_3;
/* Informational message */
tver = br_ssl_engine_get_version(&backend->ctx.eng);
- if(tver == BR_TLS12)
- strcpy(ver_str, "TLSv1.2");
- else if(tver == BR_TLS11)
- strcpy(ver_str, "TLSv1.1");
- else if(tver == BR_TLS10)
- strcpy(ver_str, "TLSv1.0");
- else {
- msnprintf(ver_str, sizeof(ver_str), "TLS 0x%04x", tver);
- }
- br_ssl_engine_get_session_parameters(&backend->ctx.eng, &session);
- Curl_cipher_suite_get_str(session.cipher_suite, cipher_str,
- sizeof(cipher_str), true);
- infof(data, "BearSSL: %s connection using %s", ver_str, cipher_str);
+ if(tver == 0x0303)
+ infof(data, "SSL connection using TLSv1.2");
+ else if(tver == 0x0304)
+ infof(data, "SSL connection using TLSv1.3");
+ else
+ infof(data, "SSL connection using TLS 0x%x", tver);
}
return ret;
}
-static void bearssl_session_free(void *sessionid, size_t idsize)
-{
- (void)idsize;
- free(sessionid);
-}
-
static CURLcode bearssl_connect_step3(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
@@ -824,7 +888,10 @@ static CURLcode bearssl_connect_step3(struct Curl_cfilter *cf,
proto? strlen(proto) : 0);
}
- if(ssl_config->primary.cache_session) {
+ if(ssl_config->primary.sessionid) {
+ bool incache;
+ bool added = FALSE;
+ void *oldsession;
br_ssl_session_parameters *session;
session = malloc(sizeof(*session));
@@ -832,11 +899,16 @@ static CURLcode bearssl_connect_step3(struct Curl_cfilter *cf,
return CURLE_OUT_OF_MEMORY;
br_ssl_engine_get_session_parameters(&backend->ctx.eng, session);
Curl_ssl_sessionid_lock(data);
- ret = Curl_ssl_set_sessionid(cf, data, &connssl->peer, session, 0,
- bearssl_session_free);
+ incache = !(Curl_ssl_getsessionid(cf, data, &oldsession, NULL));
+ if(incache)
+ Curl_ssl_delsessionid(data, oldsession);
+ ret = Curl_ssl_addsessionid(cf, data, session, 0, &added);
Curl_ssl_sessionid_unlock(data);
- if(ret)
- return ret;
+ if(!added)
+ free(session);
+ if(ret) {
+ return CURLE_OUT_OF_MEMORY;
+ }
}
connssl->connecting_state = ssl_connect_done;
@@ -929,7 +1001,9 @@ static CURLcode bearssl_connect_common(struct Curl_cfilter *cf,
return ret;
}
- while(ssl_connect_2 == connssl->connecting_state) {
+ while(ssl_connect_2 == connssl->connecting_state ||
+ ssl_connect_2_reading == connssl->connecting_state ||
+ ssl_connect_2_writing == connssl->connecting_state) {
/* check allowed time left */
timeout_ms = Curl_timeleft(data, NULL, TRUE);
@@ -939,13 +1013,14 @@ static CURLcode bearssl_connect_common(struct Curl_cfilter *cf,
return CURLE_OPERATION_TIMEDOUT;
}
- /* if ssl is expecting something, check if it is available. */
- if(connssl->io_need) {
+ /* if ssl is expecting something, check if it's available. */
+ if(ssl_connect_2_reading == connssl->connecting_state ||
+ ssl_connect_2_writing == connssl->connecting_state) {
- curl_socket_t writefd = (connssl->io_need & CURL_SSL_IO_NEED_SEND)?
- sockfd:CURL_SOCKET_BAD;
- curl_socket_t readfd = (connssl->io_need & CURL_SSL_IO_NEED_RECV)?
- sockfd:CURL_SOCKET_BAD;
+ curl_socket_t writefd = ssl_connect_2_writing ==
+ connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
+ curl_socket_t readfd = ssl_connect_2_reading ==
+ connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
CURL_TRC_CF(data, cf, "connect_common, check socket");
what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
@@ -976,9 +1051,11 @@ static CURLcode bearssl_connect_common(struct Curl_cfilter *cf,
* before step2 has completed while ensuring that a client using select()
* or epoll() will always have a valid fdset to wait on.
*/
- connssl->io_need = CURL_SSL_IO_NEED_NONE;
ret = bearssl_connect_step2(cf, data);
- if(ret || (nonblocking && (ssl_connect_2 == connssl->connecting_state)))
+ if(ret || (nonblocking &&
+ (ssl_connect_2 == connssl->connecting_state ||
+ ssl_connect_2_reading == connssl->connecting_state ||
+ ssl_connect_2_writing == connssl->connecting_state)))
return ret;
}
@@ -1069,43 +1146,6 @@ static void *bearssl_get_internals(struct ssl_connect_data *connssl,
return &backend->ctx;
}
-static CURLcode bearssl_shutdown(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- bool send_shutdown, bool *done)
-{
- struct ssl_connect_data *connssl = cf->ctx;
- struct bearssl_ssl_backend_data *backend =
- (struct bearssl_ssl_backend_data *)connssl->backend;
- CURLcode result;
-
- DEBUGASSERT(backend);
- if(!backend->active || cf->shutdown) {
- *done = TRUE;
- return CURLE_OK;
- }
-
- *done = FALSE;
- if(!backend->sent_shutdown) {
- (void)send_shutdown; /* unknown how to suppress our close notify */
- br_ssl_engine_close(&backend->ctx.eng);
- backend->sent_shutdown = TRUE;
- }
-
- result = bearssl_run_until(cf, data, BR_SSL_CLOSED);
- if(result == CURLE_OK) {
- *done = TRUE;
- }
- else if(result == CURLE_AGAIN) {
- CURL_TRC_CF(data, cf, "shutdown EAGAIN, io_need=%x", connssl->io_need);
- result = CURLE_OK;
- }
- else
- CURL_TRC_CF(data, cf, "shutdown error: %d", result);
-
- cf->shutdown = (result || *done);
- return result;
-}
-
static void bearssl_close(struct Curl_cfilter *cf, struct Curl_easy *data)
{
struct ssl_connect_data *connssl = cf->ctx;
@@ -1113,10 +1153,13 @@ static void bearssl_close(struct Curl_cfilter *cf, struct Curl_easy *data)
(struct bearssl_ssl_backend_data *)connssl->backend;
size_t i;
- (void)data;
DEBUGASSERT(backend);
- backend->active = FALSE;
+ if(backend->active) {
+ backend->active = FALSE;
+ br_ssl_engine_close(&backend->ctx.eng);
+ (void)bearssl_run_until(cf, data, BR_SSL_CLOSED);
+ }
if(backend->anchors) {
for(i = 0; i < backend->anchors_len; ++i)
free(backend->anchors[i].dn.data);
@@ -1124,6 +1167,11 @@ static void bearssl_close(struct Curl_cfilter *cf, struct Curl_easy *data)
}
}
+static void bearssl_session_free(void *ptr)
+{
+ free(ptr);
+}
+
static CURLcode bearssl_sha256sum(const unsigned char *input,
size_t inputlen,
unsigned char *sha256sum,
@@ -1139,28 +1187,24 @@ static CURLcode bearssl_sha256sum(const unsigned char *input,
const struct Curl_ssl Curl_ssl_bearssl = {
{ CURLSSLBACKEND_BEARSSL, "bearssl" }, /* info */
-
- SSLSUPP_CAINFO_BLOB |
- SSLSUPP_SSL_CTX |
- SSLSUPP_HTTPS_PROXY |
- SSLSUPP_CIPHER_LIST,
-
+ SSLSUPP_CAINFO_BLOB | SSLSUPP_SSL_CTX | SSLSUPP_HTTPS_PROXY,
sizeof(struct bearssl_ssl_backend_data),
Curl_none_init, /* init */
Curl_none_cleanup, /* cleanup */
bearssl_version, /* version */
Curl_none_check_cxn, /* check_cxn */
- bearssl_shutdown, /* shutdown */
+ Curl_none_shutdown, /* shutdown */
bearssl_data_pending, /* data_pending */
bearssl_random, /* random */
Curl_none_cert_status_request, /* cert_status_request */
bearssl_connect, /* connect */
bearssl_connect_nonblocking, /* connect_nonblocking */
- Curl_ssl_adjust_pollset, /* adjust_pollset */
+ bearssl_adjust_pollset, /* adjust_pollset */
bearssl_get_internals, /* get_internals */
bearssl_close, /* close_one */
Curl_none_close_all, /* close_all */
+ bearssl_session_free, /* session_free */
Curl_none_set_engine, /* set_engine */
Curl_none_set_engine_default, /* set_engine_default */
Curl_none_engines_list, /* engines_list */
@@ -1168,9 +1212,9 @@ const struct Curl_ssl Curl_ssl_bearssl = {
bearssl_sha256sum, /* sha256sum */
NULL, /* associate_connection */
NULL, /* disassociate_connection */
+ NULL, /* free_multi_ssl_backend_data */
bearssl_recv, /* recv decrypted data */
bearssl_send, /* send data to encrypt */
- NULL, /* get_channel_binding */
};
#endif /* USE_BEARSSL */
diff --git a/contrib/libs/curl/lib/vtls/cipher_suite.c b/contrib/libs/curl/lib/vtls/cipher_suite.c
deleted file mode 100644
index 53333af73a..0000000000
--- a/contrib/libs/curl/lib/vtls/cipher_suite.c
+++ /dev/null
@@ -1,891 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) Jan Venekamp, <jan@venekamp.net>
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at https://curl.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * SPDX-License-Identifier: curl
- *
- ***************************************************************************/
-#include "curl_setup.h"
-
-#if defined(USE_SECTRANSP) || defined(USE_MBEDTLS) || \
- defined(USE_BEARSSL) || defined(USE_RUSTLS)
-#error #include "cipher_suite.h"
-#include "curl_printf.h"
-#include "strcase.h"
-#include <string.h>
-
-/*
- * To support the CURLOPT_SSL_CIPHER_LIST option on SSL backends
- * that do not support it natively, but do support setting a list of
- * IANA ids, we need a list of all supported cipher suite names
- * (OpenSSL and IANA) to be able to look up the IANA ids.
- *
- * To keep the binary size of this list down we compress each entry
- * down to 2 + 6 bytes using the C preprocessor.
- */
-
-/*
- * mbedTLS NOTE: mbedTLS has mbedtls_ssl_get_ciphersuite_id() to
- * convert a string representation to an IANA id, we do not use that
- * because it does not support "standard" OpenSSL cipher suite
- * names, nor IANA names.
- */
-
-/* NOTE: also see tests/unit/unit3205.c */
-
-/* Text for cipher suite parts (max 64 entries),
- keep indexes below in sync with this! */
-static const char *cs_txt =
- "\0"
- "TLS" "\0"
- "WITH" "\0"
- "128" "\0"
- "256" "\0"
- "3DES" "\0"
- "8" "\0"
- "AES" "\0"
- "AES128" "\0"
- "AES256" "\0"
- "CBC" "\0"
- "CBC3" "\0"
- "CCM" "\0"
- "CCM8" "\0"
- "CHACHA20" "\0"
- "DES" "\0"
- "DHE" "\0"
- "ECDH" "\0"
- "ECDHE" "\0"
- "ECDSA" "\0"
- "EDE" "\0"
- "GCM" "\0"
- "MD5" "\0"
- "NULL" "\0"
- "POLY1305" "\0"
- "PSK" "\0"
- "RSA" "\0"
- "SHA" "\0"
- "SHA256" "\0"
- "SHA384" "\0"
-#if defined(USE_MBEDTLS)
- "ARIA" "\0"
- "ARIA128" "\0"
- "ARIA256" "\0"
- "CAMELLIA" "\0"
- "CAMELLIA128" "\0"
- "CAMELLIA256" "\0"
-#endif
-#if defined(USE_SECTRANSP)
- "40" "\0"
- "ADH" "\0"
- "AECDH" "\0"
- "anon" "\0"
- "DES40" "\0"
- "DH" "\0"
- "DSS" "\0"
- "EDH" "\0"
- "EXP" "\0"
- "EXPORT" "\0"
- "IDEA" "\0"
- "RC2" "\0"
- "RC4" "\0"
-#endif
-;
-/* Indexes of above cs_txt */
-enum {
- CS_TXT_IDX_,
- CS_TXT_IDX_TLS,
- CS_TXT_IDX_WITH,
- CS_TXT_IDX_128,
- CS_TXT_IDX_256,
- CS_TXT_IDX_3DES,
- CS_TXT_IDX_8,
- CS_TXT_IDX_AES,
- CS_TXT_IDX_AES128,
- CS_TXT_IDX_AES256,
- CS_TXT_IDX_CBC,
- CS_TXT_IDX_CBC3,
- CS_TXT_IDX_CCM,
- CS_TXT_IDX_CCM8,
- CS_TXT_IDX_CHACHA20,
- CS_TXT_IDX_DES,
- CS_TXT_IDX_DHE,
- CS_TXT_IDX_ECDH,
- CS_TXT_IDX_ECDHE,
- CS_TXT_IDX_ECDSA,
- CS_TXT_IDX_EDE,
- CS_TXT_IDX_GCM,
- CS_TXT_IDX_MD5,
- CS_TXT_IDX_NULL,
- CS_TXT_IDX_POLY1305,
- CS_TXT_IDX_PSK,
- CS_TXT_IDX_RSA,
- CS_TXT_IDX_SHA,
- CS_TXT_IDX_SHA256,
- CS_TXT_IDX_SHA384,
-#if defined(USE_MBEDTLS)
- CS_TXT_IDX_ARIA,
- CS_TXT_IDX_ARIA128,
- CS_TXT_IDX_ARIA256,
- CS_TXT_IDX_CAMELLIA,
- CS_TXT_IDX_CAMELLIA128,
- CS_TXT_IDX_CAMELLIA256,
-#endif
-#if defined(USE_SECTRANSP)
- CS_TXT_IDX_40,
- CS_TXT_IDX_ADH,
- CS_TXT_IDX_AECDH,
- CS_TXT_IDX_anon,
- CS_TXT_IDX_DES40,
- CS_TXT_IDX_DH,
- CS_TXT_IDX_DSS,
- CS_TXT_IDX_EDH,
- CS_TXT_IDX_EXP,
- CS_TXT_IDX_EXPORT,
- CS_TXT_IDX_IDEA,
- CS_TXT_IDX_RC2,
- CS_TXT_IDX_RC4,
-#endif
- CS_TXT_LEN,
-};
-
-#define CS_ZIP_IDX(a, b, c, d, e, f, g, h) \
-{ \
- (uint8_t) ((((a) << 2) & 0xFF) | ((b) & 0x3F) >> 4), \
- (uint8_t) ((((b) << 4) & 0xFF) | ((c) & 0x3F) >> 2), \
- (uint8_t) ((((c) << 6) & 0xFF) | ((d) & 0x3F)), \
- (uint8_t) ((((e) << 2) & 0xFF) | ((f) & 0x3F) >> 4), \
- (uint8_t) ((((f) << 4) & 0xFF) | ((g) & 0x3F) >> 2), \
- (uint8_t) ((((g) << 6) & 0xFF) | ((h) & 0x3F)) \
-}
-#define CS_ENTRY(id, a, b, c, d, e, f, g, h) \
-{ \
- id, \
- CS_ZIP_IDX( \
- CS_TXT_IDX_ ## a, CS_TXT_IDX_ ## b, \
- CS_TXT_IDX_ ## c, CS_TXT_IDX_ ## d, \
- CS_TXT_IDX_ ## e, CS_TXT_IDX_ ## f, \
- CS_TXT_IDX_ ## g, CS_TXT_IDX_ ## h \
- ) \
-}
-
-struct cs_entry {
- uint16_t id;
- uint8_t zip[6];
-};
-
-/* !checksrc! disable COMMANOSPACE all */
-static const struct cs_entry cs_list [] = {
- /* TLS 1.3 ciphers */
-#if defined(USE_SECTRANSP) || defined(USE_MBEDTLS) || defined(USE_RUSTLS)
- CS_ENTRY(0x1301, TLS,AES,128,GCM,SHA256,,,),
- CS_ENTRY(0x1302, TLS,AES,256,GCM,SHA384,,,),
- CS_ENTRY(0x1303, TLS,CHACHA20,POLY1305,SHA256,,,,),
- CS_ENTRY(0x1304, TLS,AES,128,CCM,SHA256,,,),
- CS_ENTRY(0x1305, TLS,AES,128,CCM,8,SHA256,,),
-#endif
- /* TLS 1.2 ciphers */
- CS_ENTRY(0xC02B, TLS,ECDHE,ECDSA,WITH,AES,128,GCM,SHA256),
- CS_ENTRY(0xC02B, ECDHE,ECDSA,AES128,GCM,SHA256,,,),
- CS_ENTRY(0xC02C, TLS,ECDHE,ECDSA,WITH,AES,256,GCM,SHA384),
- CS_ENTRY(0xC02C, ECDHE,ECDSA,AES256,GCM,SHA384,,,),
- CS_ENTRY(0xC02F, TLS,ECDHE,RSA,WITH,AES,128,GCM,SHA256),
- CS_ENTRY(0xC02F, ECDHE,RSA,AES128,GCM,SHA256,,,),
- CS_ENTRY(0xC030, TLS,ECDHE,RSA,WITH,AES,256,GCM,SHA384),
- CS_ENTRY(0xC030, ECDHE,RSA,AES256,GCM,SHA384,,,),
- CS_ENTRY(0xCCA8, TLS,ECDHE,RSA,WITH,CHACHA20,POLY1305,SHA256,),
- CS_ENTRY(0xCCA8, ECDHE,RSA,CHACHA20,POLY1305,,,,),
- CS_ENTRY(0xCCA9, TLS,ECDHE,ECDSA,WITH,CHACHA20,POLY1305,SHA256,),
- CS_ENTRY(0xCCA9, ECDHE,ECDSA,CHACHA20,POLY1305,,,,),
-#if defined(USE_SECTRANSP) || defined(USE_MBEDTLS) || defined(USE_BEARSSL)
- CS_ENTRY(0x002F, TLS,RSA,WITH,AES,128,CBC,SHA,),
- CS_ENTRY(0x002F, AES128,SHA,,,,,,),
- CS_ENTRY(0x0035, TLS,RSA,WITH,AES,256,CBC,SHA,),
- CS_ENTRY(0x0035, AES256,SHA,,,,,,),
- CS_ENTRY(0x003C, TLS,RSA,WITH,AES,128,CBC,SHA256,),
- CS_ENTRY(0x003C, AES128,SHA256,,,,,,),
- CS_ENTRY(0x003D, TLS,RSA,WITH,AES,256,CBC,SHA256,),
- CS_ENTRY(0x003D, AES256,SHA256,,,,,,),
- CS_ENTRY(0x009C, TLS,RSA,WITH,AES,128,GCM,SHA256,),
- CS_ENTRY(0x009C, AES128,GCM,SHA256,,,,,),
- CS_ENTRY(0x009D, TLS,RSA,WITH,AES,256,GCM,SHA384,),
- CS_ENTRY(0x009D, AES256,GCM,SHA384,,,,,),
- CS_ENTRY(0xC004, TLS,ECDH,ECDSA,WITH,AES,128,CBC,SHA),
- CS_ENTRY(0xC004, ECDH,ECDSA,AES128,SHA,,,,),
- CS_ENTRY(0xC005, TLS,ECDH,ECDSA,WITH,AES,256,CBC,SHA),
- CS_ENTRY(0xC005, ECDH,ECDSA,AES256,SHA,,,,),
- CS_ENTRY(0xC009, TLS,ECDHE,ECDSA,WITH,AES,128,CBC,SHA),
- CS_ENTRY(0xC009, ECDHE,ECDSA,AES128,SHA,,,,),
- CS_ENTRY(0xC00A, TLS,ECDHE,ECDSA,WITH,AES,256,CBC,SHA),
- CS_ENTRY(0xC00A, ECDHE,ECDSA,AES256,SHA,,,,),
- CS_ENTRY(0xC00E, TLS,ECDH,RSA,WITH,AES,128,CBC,SHA),
- CS_ENTRY(0xC00E, ECDH,RSA,AES128,SHA,,,,),
- CS_ENTRY(0xC00F, TLS,ECDH,RSA,WITH,AES,256,CBC,SHA),
- CS_ENTRY(0xC00F, ECDH,RSA,AES256,SHA,,,,),
- CS_ENTRY(0xC013, TLS,ECDHE,RSA,WITH,AES,128,CBC,SHA),
- CS_ENTRY(0xC013, ECDHE,RSA,AES128,SHA,,,,),
- CS_ENTRY(0xC014, TLS,ECDHE,RSA,WITH,AES,256,CBC,SHA),
- CS_ENTRY(0xC014, ECDHE,RSA,AES256,SHA,,,,),
- CS_ENTRY(0xC023, TLS,ECDHE,ECDSA,WITH,AES,128,CBC,SHA256),
- CS_ENTRY(0xC023, ECDHE,ECDSA,AES128,SHA256,,,,),
- CS_ENTRY(0xC024, TLS,ECDHE,ECDSA,WITH,AES,256,CBC,SHA384),
- CS_ENTRY(0xC024, ECDHE,ECDSA,AES256,SHA384,,,,),
- CS_ENTRY(0xC025, TLS,ECDH,ECDSA,WITH,AES,128,CBC,SHA256),
- CS_ENTRY(0xC025, ECDH,ECDSA,AES128,SHA256,,,,),
- CS_ENTRY(0xC026, TLS,ECDH,ECDSA,WITH,AES,256,CBC,SHA384),
- CS_ENTRY(0xC026, ECDH,ECDSA,AES256,SHA384,,,,),
- CS_ENTRY(0xC027, TLS,ECDHE,RSA,WITH,AES,128,CBC,SHA256),
- CS_ENTRY(0xC027, ECDHE,RSA,AES128,SHA256,,,,),
- CS_ENTRY(0xC028, TLS,ECDHE,RSA,WITH,AES,256,CBC,SHA384),
- CS_ENTRY(0xC028, ECDHE,RSA,AES256,SHA384,,,,),
- CS_ENTRY(0xC029, TLS,ECDH,RSA,WITH,AES,128,CBC,SHA256),
- CS_ENTRY(0xC029, ECDH,RSA,AES128,SHA256,,,,),
- CS_ENTRY(0xC02A, TLS,ECDH,RSA,WITH,AES,256,CBC,SHA384),
- CS_ENTRY(0xC02A, ECDH,RSA,AES256,SHA384,,,,),
- CS_ENTRY(0xC02D, TLS,ECDH,ECDSA,WITH,AES,128,GCM,SHA256),
- CS_ENTRY(0xC02D, ECDH,ECDSA,AES128,GCM,SHA256,,,),
- CS_ENTRY(0xC02E, TLS,ECDH,ECDSA,WITH,AES,256,GCM,SHA384),
- CS_ENTRY(0xC02E, ECDH,ECDSA,AES256,GCM,SHA384,,,),
- CS_ENTRY(0xC031, TLS,ECDH,RSA,WITH,AES,128,GCM,SHA256),
- CS_ENTRY(0xC031, ECDH,RSA,AES128,GCM,SHA256,,,),
- CS_ENTRY(0xC032, TLS,ECDH,RSA,WITH,AES,256,GCM,SHA384),
- CS_ENTRY(0xC032, ECDH,RSA,AES256,GCM,SHA384,,,),
-#endif
-#if defined(USE_SECTRANSP) || defined(USE_MBEDTLS)
- CS_ENTRY(0x0001, TLS,RSA,WITH,NULL,MD5,,,),
- CS_ENTRY(0x0001, NULL,MD5,,,,,,),
- CS_ENTRY(0x0002, TLS,RSA,WITH,NULL,SHA,,,),
- CS_ENTRY(0x0002, NULL,SHA,,,,,,),
- CS_ENTRY(0x002C, TLS,PSK,WITH,NULL,SHA,,,),
- CS_ENTRY(0x002C, PSK,NULL,SHA,,,,,),
- CS_ENTRY(0x002D, TLS,DHE,PSK,WITH,NULL,SHA,,),
- CS_ENTRY(0x002D, DHE,PSK,NULL,SHA,,,,),
- CS_ENTRY(0x002E, TLS,RSA,PSK,WITH,NULL,SHA,,),
- CS_ENTRY(0x002E, RSA,PSK,NULL,SHA,,,,),
- CS_ENTRY(0x0033, TLS,DHE,RSA,WITH,AES,128,CBC,SHA),
- CS_ENTRY(0x0033, DHE,RSA,AES128,SHA,,,,),
- CS_ENTRY(0x0039, TLS,DHE,RSA,WITH,AES,256,CBC,SHA),
- CS_ENTRY(0x0039, DHE,RSA,AES256,SHA,,,,),
- CS_ENTRY(0x003B, TLS,RSA,WITH,NULL,SHA256,,,),
- CS_ENTRY(0x003B, NULL,SHA256,,,,,,),
- CS_ENTRY(0x0067, TLS,DHE,RSA,WITH,AES,128,CBC,SHA256),
- CS_ENTRY(0x0067, DHE,RSA,AES128,SHA256,,,,),
- CS_ENTRY(0x006B, TLS,DHE,RSA,WITH,AES,256,CBC,SHA256),
- CS_ENTRY(0x006B, DHE,RSA,AES256,SHA256,,,,),
- CS_ENTRY(0x008C, TLS,PSK,WITH,AES,128,CBC,SHA,),
- CS_ENTRY(0x008C, PSK,AES128,CBC,SHA,,,,),
- CS_ENTRY(0x008D, TLS,PSK,WITH,AES,256,CBC,SHA,),
- CS_ENTRY(0x008D, PSK,AES256,CBC,SHA,,,,),
- CS_ENTRY(0x0090, TLS,DHE,PSK,WITH,AES,128,CBC,SHA),
- CS_ENTRY(0x0090, DHE,PSK,AES128,CBC,SHA,,,),
- CS_ENTRY(0x0091, TLS,DHE,PSK,WITH,AES,256,CBC,SHA),
- CS_ENTRY(0x0091, DHE,PSK,AES256,CBC,SHA,,,),
- CS_ENTRY(0x0094, TLS,RSA,PSK,WITH,AES,128,CBC,SHA),
- CS_ENTRY(0x0094, RSA,PSK,AES128,CBC,SHA,,,),
- CS_ENTRY(0x0095, TLS,RSA,PSK,WITH,AES,256,CBC,SHA),
- CS_ENTRY(0x0095, RSA,PSK,AES256,CBC,SHA,,,),
- CS_ENTRY(0x009E, TLS,DHE,RSA,WITH,AES,128,GCM,SHA256),
- CS_ENTRY(0x009E, DHE,RSA,AES128,GCM,SHA256,,,),
- CS_ENTRY(0x009F, TLS,DHE,RSA,WITH,AES,256,GCM,SHA384),
- CS_ENTRY(0x009F, DHE,RSA,AES256,GCM,SHA384,,,),
- CS_ENTRY(0x00A8, TLS,PSK,WITH,AES,128,GCM,SHA256,),
- CS_ENTRY(0x00A8, PSK,AES128,GCM,SHA256,,,,),
- CS_ENTRY(0x00A9, TLS,PSK,WITH,AES,256,GCM,SHA384,),
- CS_ENTRY(0x00A9, PSK,AES256,GCM,SHA384,,,,),
- CS_ENTRY(0x00AA, TLS,DHE,PSK,WITH,AES,128,GCM,SHA256),
- CS_ENTRY(0x00AA, DHE,PSK,AES128,GCM,SHA256,,,),
- CS_ENTRY(0x00AB, TLS,DHE,PSK,WITH,AES,256,GCM,SHA384),
- CS_ENTRY(0x00AB, DHE,PSK,AES256,GCM,SHA384,,,),
- CS_ENTRY(0x00AC, TLS,RSA,PSK,WITH,AES,128,GCM,SHA256),
- CS_ENTRY(0x00AC, RSA,PSK,AES128,GCM,SHA256,,,),
- CS_ENTRY(0x00AD, TLS,RSA,PSK,WITH,AES,256,GCM,SHA384),
- CS_ENTRY(0x00AD, RSA,PSK,AES256,GCM,SHA384,,,),
- CS_ENTRY(0x00AE, TLS,PSK,WITH,AES,128,CBC,SHA256,),
- CS_ENTRY(0x00AE, PSK,AES128,CBC,SHA256,,,,),
- CS_ENTRY(0x00AF, TLS,PSK,WITH,AES,256,CBC,SHA384,),
- CS_ENTRY(0x00AF, PSK,AES256,CBC,SHA384,,,,),
- CS_ENTRY(0x00B0, TLS,PSK,WITH,NULL,SHA256,,,),
- CS_ENTRY(0x00B0, PSK,NULL,SHA256,,,,,),
- CS_ENTRY(0x00B1, TLS,PSK,WITH,NULL,SHA384,,,),
- CS_ENTRY(0x00B1, PSK,NULL,SHA384,,,,,),
- CS_ENTRY(0x00B2, TLS,DHE,PSK,WITH,AES,128,CBC,SHA256),
- CS_ENTRY(0x00B2, DHE,PSK,AES128,CBC,SHA256,,,),
- CS_ENTRY(0x00B3, TLS,DHE,PSK,WITH,AES,256,CBC,SHA384),
- CS_ENTRY(0x00B3, DHE,PSK,AES256,CBC,SHA384,,,),
- CS_ENTRY(0x00B4, TLS,DHE,PSK,WITH,NULL,SHA256,,),
- CS_ENTRY(0x00B4, DHE,PSK,NULL,SHA256,,,,),
- CS_ENTRY(0x00B5, TLS,DHE,PSK,WITH,NULL,SHA384,,),
- CS_ENTRY(0x00B5, DHE,PSK,NULL,SHA384,,,,),
- CS_ENTRY(0x00B6, TLS,RSA,PSK,WITH,AES,128,CBC,SHA256),
- CS_ENTRY(0x00B6, RSA,PSK,AES128,CBC,SHA256,,,),
- CS_ENTRY(0x00B7, TLS,RSA,PSK,WITH,AES,256,CBC,SHA384),
- CS_ENTRY(0x00B7, RSA,PSK,AES256,CBC,SHA384,,,),
- CS_ENTRY(0x00B8, TLS,RSA,PSK,WITH,NULL,SHA256,,),
- CS_ENTRY(0x00B8, RSA,PSK,NULL,SHA256,,,,),
- CS_ENTRY(0x00B9, TLS,RSA,PSK,WITH,NULL,SHA384,,),
- CS_ENTRY(0x00B9, RSA,PSK,NULL,SHA384,,,,),
- CS_ENTRY(0xC001, TLS,ECDH,ECDSA,WITH,NULL,SHA,,),
- CS_ENTRY(0xC001, ECDH,ECDSA,NULL,SHA,,,,),
- CS_ENTRY(0xC006, TLS,ECDHE,ECDSA,WITH,NULL,SHA,,),
- CS_ENTRY(0xC006, ECDHE,ECDSA,NULL,SHA,,,,),
- CS_ENTRY(0xC00B, TLS,ECDH,RSA,WITH,NULL,SHA,,),
- CS_ENTRY(0xC00B, ECDH,RSA,NULL,SHA,,,,),
- CS_ENTRY(0xC010, TLS,ECDHE,RSA,WITH,NULL,SHA,,),
- CS_ENTRY(0xC010, ECDHE,RSA,NULL,SHA,,,,),
- CS_ENTRY(0xC035, TLS,ECDHE,PSK,WITH,AES,128,CBC,SHA),
- CS_ENTRY(0xC035, ECDHE,PSK,AES128,CBC,SHA,,,),
- CS_ENTRY(0xC036, TLS,ECDHE,PSK,WITH,AES,256,CBC,SHA),
- CS_ENTRY(0xC036, ECDHE,PSK,AES256,CBC,SHA,,,),
- CS_ENTRY(0xCCAB, TLS,PSK,WITH,CHACHA20,POLY1305,SHA256,,),
- CS_ENTRY(0xCCAB, PSK,CHACHA20,POLY1305,,,,,),
-#endif
-#if defined(USE_SECTRANSP) || defined(USE_BEARSSL)
- CS_ENTRY(0x000A, TLS,RSA,WITH,3DES,EDE,CBC,SHA,),
- CS_ENTRY(0x000A, DES,CBC3,SHA,,,,,),
- CS_ENTRY(0xC003, TLS,ECDH,ECDSA,WITH,3DES,EDE,CBC,SHA),
- CS_ENTRY(0xC003, ECDH,ECDSA,DES,CBC3,SHA,,,),
- CS_ENTRY(0xC008, TLS,ECDHE,ECDSA,WITH,3DES,EDE,CBC,SHA),
- CS_ENTRY(0xC008, ECDHE,ECDSA,DES,CBC3,SHA,,,),
- CS_ENTRY(0xC00D, TLS,ECDH,RSA,WITH,3DES,EDE,CBC,SHA),
- CS_ENTRY(0xC00D, ECDH,RSA,DES,CBC3,SHA,,,),
- CS_ENTRY(0xC012, TLS,ECDHE,RSA,WITH,3DES,EDE,CBC,SHA),
- CS_ENTRY(0xC012, ECDHE,RSA,DES,CBC3,SHA,,,),
-#endif
-#if defined(USE_MBEDTLS) || defined(USE_BEARSSL)
- CS_ENTRY(0xC09C, TLS,RSA,WITH,AES,128,CCM,,),
- CS_ENTRY(0xC09C, AES128,CCM,,,,,,),
- CS_ENTRY(0xC09D, TLS,RSA,WITH,AES,256,CCM,,),
- CS_ENTRY(0xC09D, AES256,CCM,,,,,,),
- CS_ENTRY(0xC0A0, TLS,RSA,WITH,AES,128,CCM,8,),
- CS_ENTRY(0xC0A0, AES128,CCM8,,,,,,),
- CS_ENTRY(0xC0A1, TLS,RSA,WITH,AES,256,CCM,8,),
- CS_ENTRY(0xC0A1, AES256,CCM8,,,,,,),
- CS_ENTRY(0xC0AC, TLS,ECDHE,ECDSA,WITH,AES,128,CCM,),
- CS_ENTRY(0xC0AC, ECDHE,ECDSA,AES128,CCM,,,,),
- CS_ENTRY(0xC0AD, TLS,ECDHE,ECDSA,WITH,AES,256,CCM,),
- CS_ENTRY(0xC0AD, ECDHE,ECDSA,AES256,CCM,,,,),
- CS_ENTRY(0xC0AE, TLS,ECDHE,ECDSA,WITH,AES,128,CCM,8),
- CS_ENTRY(0xC0AE, ECDHE,ECDSA,AES128,CCM8,,,,),
- CS_ENTRY(0xC0AF, TLS,ECDHE,ECDSA,WITH,AES,256,CCM,8),
- CS_ENTRY(0xC0AF, ECDHE,ECDSA,AES256,CCM8,,,,),
-#endif
-#if defined(USE_SECTRANSP)
- /* entries marked bc are backward compatible aliases for old OpenSSL names */
- CS_ENTRY(0x0003, TLS,RSA,EXPORT,WITH,RC4,40,MD5,),
- CS_ENTRY(0x0003, EXP,RC4,MD5,,,,,),
- CS_ENTRY(0x0004, TLS,RSA,WITH,RC4,128,MD5,,),
- CS_ENTRY(0x0004, RC4,MD5,,,,,,),
- CS_ENTRY(0x0005, TLS,RSA,WITH,RC4,128,SHA,,),
- CS_ENTRY(0x0005, RC4,SHA,,,,,,),
- CS_ENTRY(0x0006, TLS,RSA,EXPORT,WITH,RC2,CBC,40,MD5),
- CS_ENTRY(0x0006, EXP,RC2,CBC,MD5,,,,),
- CS_ENTRY(0x0007, TLS,RSA,WITH,IDEA,CBC,SHA,,),
- CS_ENTRY(0x0007, IDEA,CBC,SHA,,,,,),
- CS_ENTRY(0x0008, TLS,RSA,EXPORT,WITH,DES40,CBC,SHA,),
- CS_ENTRY(0x0008, EXP,DES,CBC,SHA,,,,),
- CS_ENTRY(0x0009, TLS,RSA,WITH,DES,CBC,SHA,,),
- CS_ENTRY(0x0009, DES,CBC,SHA,,,,,),
- CS_ENTRY(0x000B, TLS,DH,DSS,EXPORT,WITH,DES40,CBC,SHA),
- CS_ENTRY(0x000B, EXP,DH,DSS,DES,CBC,SHA,,),
- CS_ENTRY(0x000C, TLS,DH,DSS,WITH,DES,CBC,SHA,),
- CS_ENTRY(0x000C, DH,DSS,DES,CBC,SHA,,,),
- CS_ENTRY(0x000D, TLS,DH,DSS,WITH,3DES,EDE,CBC,SHA),
- CS_ENTRY(0x000D, DH,DSS,DES,CBC3,SHA,,,),
- CS_ENTRY(0x000E, TLS,DH,RSA,EXPORT,WITH,DES40,CBC,SHA),
- CS_ENTRY(0x000E, EXP,DH,RSA,DES,CBC,SHA,,),
- CS_ENTRY(0x000F, TLS,DH,RSA,WITH,DES,CBC,SHA,),
- CS_ENTRY(0x000F, DH,RSA,DES,CBC,SHA,,,),
- CS_ENTRY(0x0010, TLS,DH,RSA,WITH,3DES,EDE,CBC,SHA),
- CS_ENTRY(0x0010, DH,RSA,DES,CBC3,SHA,,,),
- CS_ENTRY(0x0011, TLS,DHE,DSS,EXPORT,WITH,DES40,CBC,SHA),
- CS_ENTRY(0x0011, EXP,DHE,DSS,DES,CBC,SHA,,),
- CS_ENTRY(0x0011, EXP,EDH,DSS,DES,CBC,SHA,,), /* bc */
- CS_ENTRY(0x0012, TLS,DHE,DSS,WITH,DES,CBC,SHA,),
- CS_ENTRY(0x0012, DHE,DSS,DES,CBC,SHA,,,),
- CS_ENTRY(0x0012, EDH,DSS,DES,CBC,SHA,,,), /* bc */
- CS_ENTRY(0x0013, TLS,DHE,DSS,WITH,3DES,EDE,CBC,SHA),
- CS_ENTRY(0x0013, DHE,DSS,DES,CBC3,SHA,,,),
- CS_ENTRY(0x0013, EDH,DSS,DES,CBC3,SHA,,,), /* bc */
- CS_ENTRY(0x0014, TLS,DHE,RSA,EXPORT,WITH,DES40,CBC,SHA),
- CS_ENTRY(0x0014, EXP,DHE,RSA,DES,CBC,SHA,,),
- CS_ENTRY(0x0014, EXP,EDH,RSA,DES,CBC,SHA,,), /* bc */
- CS_ENTRY(0x0015, TLS,DHE,RSA,WITH,DES,CBC,SHA,),
- CS_ENTRY(0x0015, DHE,RSA,DES,CBC,SHA,,,),
- CS_ENTRY(0x0015, EDH,RSA,DES,CBC,SHA,,,), /* bc */
- CS_ENTRY(0x0016, TLS,DHE,RSA,WITH,3DES,EDE,CBC,SHA),
- CS_ENTRY(0x0016, DHE,RSA,DES,CBC3,SHA,,,),
- CS_ENTRY(0x0016, EDH,RSA,DES,CBC3,SHA,,,), /* bc */
- CS_ENTRY(0x0017, TLS,DH,anon,EXPORT,WITH,RC4,40,MD5),
- CS_ENTRY(0x0017, EXP,ADH,RC4,MD5,,,,),
- CS_ENTRY(0x0018, TLS,DH,anon,WITH,RC4,128,MD5,),
- CS_ENTRY(0x0018, ADH,RC4,MD5,,,,,),
- CS_ENTRY(0x0019, TLS,DH,anon,EXPORT,WITH,DES40,CBC,SHA),
- CS_ENTRY(0x0019, EXP,ADH,DES,CBC,SHA,,,),
- CS_ENTRY(0x001A, TLS,DH,anon,WITH,DES,CBC,SHA,),
- CS_ENTRY(0x001A, ADH,DES,CBC,SHA,,,,),
- CS_ENTRY(0x001B, TLS,DH,anon,WITH,3DES,EDE,CBC,SHA),
- CS_ENTRY(0x001B, ADH,DES,CBC3,SHA,,,,),
- CS_ENTRY(0x0030, TLS,DH,DSS,WITH,AES,128,CBC,SHA),
- CS_ENTRY(0x0030, DH,DSS,AES128,SHA,,,,),
- CS_ENTRY(0x0031, TLS,DH,RSA,WITH,AES,128,CBC,SHA),
- CS_ENTRY(0x0031, DH,RSA,AES128,SHA,,,,),
- CS_ENTRY(0x0032, TLS,DHE,DSS,WITH,AES,128,CBC,SHA),
- CS_ENTRY(0x0032, DHE,DSS,AES128,SHA,,,,),
- CS_ENTRY(0x0034, TLS,DH,anon,WITH,AES,128,CBC,SHA),
- CS_ENTRY(0x0034, ADH,AES128,SHA,,,,,),
- CS_ENTRY(0x0036, TLS,DH,DSS,WITH,AES,256,CBC,SHA),
- CS_ENTRY(0x0036, DH,DSS,AES256,SHA,,,,),
- CS_ENTRY(0x0037, TLS,DH,RSA,WITH,AES,256,CBC,SHA),
- CS_ENTRY(0x0037, DH,RSA,AES256,SHA,,,,),
- CS_ENTRY(0x0038, TLS,DHE,DSS,WITH,AES,256,CBC,SHA),
- CS_ENTRY(0x0038, DHE,DSS,AES256,SHA,,,,),
- CS_ENTRY(0x003A, TLS,DH,anon,WITH,AES,256,CBC,SHA),
- CS_ENTRY(0x003A, ADH,AES256,SHA,,,,,),
- CS_ENTRY(0x003E, TLS,DH,DSS,WITH,AES,128,CBC,SHA256),
- CS_ENTRY(0x003E, DH,DSS,AES128,SHA256,,,,),
- CS_ENTRY(0x003F, TLS,DH,RSA,WITH,AES,128,CBC,SHA256),
- CS_ENTRY(0x003F, DH,RSA,AES128,SHA256,,,,),
- CS_ENTRY(0x0040, TLS,DHE,DSS,WITH,AES,128,CBC,SHA256),
- CS_ENTRY(0x0040, DHE,DSS,AES128,SHA256,,,,),
- CS_ENTRY(0x0068, TLS,DH,DSS,WITH,AES,256,CBC,SHA256),
- CS_ENTRY(0x0068, DH,DSS,AES256,SHA256,,,,),
- CS_ENTRY(0x0069, TLS,DH,RSA,WITH,AES,256,CBC,SHA256),
- CS_ENTRY(0x0069, DH,RSA,AES256,SHA256,,,,),
- CS_ENTRY(0x006A, TLS,DHE,DSS,WITH,AES,256,CBC,SHA256),
- CS_ENTRY(0x006A, DHE,DSS,AES256,SHA256,,,,),
- CS_ENTRY(0x006C, TLS,DH,anon,WITH,AES,128,CBC,SHA256),
- CS_ENTRY(0x006C, ADH,AES128,SHA256,,,,,),
- CS_ENTRY(0x006D, TLS,DH,anon,WITH,AES,256,CBC,SHA256),
- CS_ENTRY(0x006D, ADH,AES256,SHA256,,,,,),
- CS_ENTRY(0x008A, TLS,PSK,WITH,RC4,128,SHA,,),
- CS_ENTRY(0x008A, PSK,RC4,SHA,,,,,),
- CS_ENTRY(0x008B, TLS,PSK,WITH,3DES,EDE,CBC,SHA,),
- CS_ENTRY(0x008B, PSK,3DES,EDE,CBC,SHA,,,),
- CS_ENTRY(0x008E, TLS,DHE,PSK,WITH,RC4,128,SHA,),
- CS_ENTRY(0x008E, DHE,PSK,RC4,SHA,,,,),
- CS_ENTRY(0x008F, TLS,DHE,PSK,WITH,3DES,EDE,CBC,SHA),
- CS_ENTRY(0x008F, DHE,PSK,3DES,EDE,CBC,SHA,,),
- CS_ENTRY(0x0092, TLS,RSA,PSK,WITH,RC4,128,SHA,),
- CS_ENTRY(0x0092, RSA,PSK,RC4,SHA,,,,),
- CS_ENTRY(0x0093, TLS,RSA,PSK,WITH,3DES,EDE,CBC,SHA),
- CS_ENTRY(0x0093, RSA,PSK,3DES,EDE,CBC,SHA,,),
- CS_ENTRY(0x00A0, TLS,DH,RSA,WITH,AES,128,GCM,SHA256),
- CS_ENTRY(0x00A0, DH,RSA,AES128,GCM,SHA256,,,),
- CS_ENTRY(0x00A1, TLS,DH,RSA,WITH,AES,256,GCM,SHA384),
- CS_ENTRY(0x00A1, DH,RSA,AES256,GCM,SHA384,,,),
- CS_ENTRY(0x00A2, TLS,DHE,DSS,WITH,AES,128,GCM,SHA256),
- CS_ENTRY(0x00A2, DHE,DSS,AES128,GCM,SHA256,,,),
- CS_ENTRY(0x00A3, TLS,DHE,DSS,WITH,AES,256,GCM,SHA384),
- CS_ENTRY(0x00A3, DHE,DSS,AES256,GCM,SHA384,,,),
- CS_ENTRY(0x00A4, TLS,DH,DSS,WITH,AES,128,GCM,SHA256),
- CS_ENTRY(0x00A4, DH,DSS,AES128,GCM,SHA256,,,),
- CS_ENTRY(0x00A5, TLS,DH,DSS,WITH,AES,256,GCM,SHA384),
- CS_ENTRY(0x00A5, DH,DSS,AES256,GCM,SHA384,,,),
- CS_ENTRY(0x00A6, TLS,DH,anon,WITH,AES,128,GCM,SHA256),
- CS_ENTRY(0x00A6, ADH,AES128,GCM,SHA256,,,,),
- CS_ENTRY(0x00A7, TLS,DH,anon,WITH,AES,256,GCM,SHA384),
- CS_ENTRY(0x00A7, ADH,AES256,GCM,SHA384,,,,),
- CS_ENTRY(0xC002, TLS,ECDH,ECDSA,WITH,RC4,128,SHA,),
- CS_ENTRY(0xC002, ECDH,ECDSA,RC4,SHA,,,,),
- CS_ENTRY(0xC007, TLS,ECDHE,ECDSA,WITH,RC4,128,SHA,),
- CS_ENTRY(0xC007, ECDHE,ECDSA,RC4,SHA,,,,),
- CS_ENTRY(0xC00C, TLS,ECDH,RSA,WITH,RC4,128,SHA,),
- CS_ENTRY(0xC00C, ECDH,RSA,RC4,SHA,,,,),
- CS_ENTRY(0xC011, TLS,ECDHE,RSA,WITH,RC4,128,SHA,),
- CS_ENTRY(0xC011, ECDHE,RSA,RC4,SHA,,,,),
- CS_ENTRY(0xC015, TLS,ECDH,anon,WITH,NULL,SHA,,),
- CS_ENTRY(0xC015, AECDH,NULL,SHA,,,,,),
- CS_ENTRY(0xC016, TLS,ECDH,anon,WITH,RC4,128,SHA,),
- CS_ENTRY(0xC016, AECDH,RC4,SHA,,,,,),
- CS_ENTRY(0xC017, TLS,ECDH,anon,WITH,3DES,EDE,CBC,SHA),
- CS_ENTRY(0xC017, AECDH,DES,CBC3,SHA,,,,),
- CS_ENTRY(0xC018, TLS,ECDH,anon,WITH,AES,128,CBC,SHA),
- CS_ENTRY(0xC018, AECDH,AES128,SHA,,,,,),
- CS_ENTRY(0xC019, TLS,ECDH,anon,WITH,AES,256,CBC,SHA),
- CS_ENTRY(0xC019, AECDH,AES256,SHA,,,,,),
-#endif
-#if defined(USE_MBEDTLS)
- /* entries marked ns are "non-standard", they are not in OpenSSL */
- CS_ENTRY(0x0041, TLS,RSA,WITH,CAMELLIA,128,CBC,SHA,),
- CS_ENTRY(0x0041, CAMELLIA128,SHA,,,,,,),
- CS_ENTRY(0x0045, TLS,DHE,RSA,WITH,CAMELLIA,128,CBC,SHA),
- CS_ENTRY(0x0045, DHE,RSA,CAMELLIA128,SHA,,,,),
- CS_ENTRY(0x0084, TLS,RSA,WITH,CAMELLIA,256,CBC,SHA,),
- CS_ENTRY(0x0084, CAMELLIA256,SHA,,,,,,),
- CS_ENTRY(0x0088, TLS,DHE,RSA,WITH,CAMELLIA,256,CBC,SHA),
- CS_ENTRY(0x0088, DHE,RSA,CAMELLIA256,SHA,,,,),
- CS_ENTRY(0x00BA, TLS,RSA,WITH,CAMELLIA,128,CBC,SHA256,),
- CS_ENTRY(0x00BA, CAMELLIA128,SHA256,,,,,,),
- CS_ENTRY(0x00BE, TLS,DHE,RSA,WITH,CAMELLIA,128,CBC,SHA256),
- CS_ENTRY(0x00BE, DHE,RSA,CAMELLIA128,SHA256,,,,),
- CS_ENTRY(0x00C0, TLS,RSA,WITH,CAMELLIA,256,CBC,SHA256,),
- CS_ENTRY(0x00C0, CAMELLIA256,SHA256,,,,,,),
- CS_ENTRY(0x00C4, TLS,DHE,RSA,WITH,CAMELLIA,256,CBC,SHA256),
- CS_ENTRY(0x00C4, DHE,RSA,CAMELLIA256,SHA256,,,,),
- CS_ENTRY(0xC037, TLS,ECDHE,PSK,WITH,AES,128,CBC,SHA256),
- CS_ENTRY(0xC037, ECDHE,PSK,AES128,CBC,SHA256,,,),
- CS_ENTRY(0xC038, TLS,ECDHE,PSK,WITH,AES,256,CBC,SHA384),
- CS_ENTRY(0xC038, ECDHE,PSK,AES256,CBC,SHA384,,,),
- CS_ENTRY(0xC039, TLS,ECDHE,PSK,WITH,NULL,SHA,,),
- CS_ENTRY(0xC039, ECDHE,PSK,NULL,SHA,,,,),
- CS_ENTRY(0xC03A, TLS,ECDHE,PSK,WITH,NULL,SHA256,,),
- CS_ENTRY(0xC03A, ECDHE,PSK,NULL,SHA256,,,,),
- CS_ENTRY(0xC03B, TLS,ECDHE,PSK,WITH,NULL,SHA384,,),
- CS_ENTRY(0xC03B, ECDHE,PSK,NULL,SHA384,,,,),
- CS_ENTRY(0xC03C, TLS,RSA,WITH,ARIA,128,CBC,SHA256,),
- CS_ENTRY(0xC03C, ARIA128,SHA256,,,,,,), /* ns */
- CS_ENTRY(0xC03D, TLS,RSA,WITH,ARIA,256,CBC,SHA384,),
- CS_ENTRY(0xC03D, ARIA256,SHA384,,,,,,), /* ns */
- CS_ENTRY(0xC044, TLS,DHE,RSA,WITH,ARIA,128,CBC,SHA256),
- CS_ENTRY(0xC044, DHE,RSA,ARIA128,SHA256,,,,), /* ns */
- CS_ENTRY(0xC045, TLS,DHE,RSA,WITH,ARIA,256,CBC,SHA384),
- CS_ENTRY(0xC045, DHE,RSA,ARIA256,SHA384,,,,), /* ns */
- CS_ENTRY(0xC048, TLS,ECDHE,ECDSA,WITH,ARIA,128,CBC,SHA256),
- CS_ENTRY(0xC048, ECDHE,ECDSA,ARIA128,SHA256,,,,), /* ns */
- CS_ENTRY(0xC049, TLS,ECDHE,ECDSA,WITH,ARIA,256,CBC,SHA384),
- CS_ENTRY(0xC049, ECDHE,ECDSA,ARIA256,SHA384,,,,), /* ns */
- CS_ENTRY(0xC04A, TLS,ECDH,ECDSA,WITH,ARIA,128,CBC,SHA256),
- CS_ENTRY(0xC04A, ECDH,ECDSA,ARIA128,SHA256,,,,), /* ns */
- CS_ENTRY(0xC04B, TLS,ECDH,ECDSA,WITH,ARIA,256,CBC,SHA384),
- CS_ENTRY(0xC04B, ECDH,ECDSA,ARIA256,SHA384,,,,), /* ns */
- CS_ENTRY(0xC04C, TLS,ECDHE,RSA,WITH,ARIA,128,CBC,SHA256),
- CS_ENTRY(0xC04C, ECDHE,ARIA128,SHA256,,,,,), /* ns */
- CS_ENTRY(0xC04D, TLS,ECDHE,RSA,WITH,ARIA,256,CBC,SHA384),
- CS_ENTRY(0xC04D, ECDHE,ARIA256,SHA384,,,,,), /* ns */
- CS_ENTRY(0xC04E, TLS,ECDH,RSA,WITH,ARIA,128,CBC,SHA256),
- CS_ENTRY(0xC04E, ECDH,ARIA128,SHA256,,,,,), /* ns */
- CS_ENTRY(0xC04F, TLS,ECDH,RSA,WITH,ARIA,256,CBC,SHA384),
- CS_ENTRY(0xC04F, ECDH,ARIA256,SHA384,,,,,), /* ns */
- CS_ENTRY(0xC050, TLS,RSA,WITH,ARIA,128,GCM,SHA256,),
- CS_ENTRY(0xC050, ARIA128,GCM,SHA256,,,,,),
- CS_ENTRY(0xC051, TLS,RSA,WITH,ARIA,256,GCM,SHA384,),
- CS_ENTRY(0xC051, ARIA256,GCM,SHA384,,,,,),
- CS_ENTRY(0xC052, TLS,DHE,RSA,WITH,ARIA,128,GCM,SHA256),
- CS_ENTRY(0xC052, DHE,RSA,ARIA128,GCM,SHA256,,,),
- CS_ENTRY(0xC053, TLS,DHE,RSA,WITH,ARIA,256,GCM,SHA384),
- CS_ENTRY(0xC053, DHE,RSA,ARIA256,GCM,SHA384,,,),
- CS_ENTRY(0xC05C, TLS,ECDHE,ECDSA,WITH,ARIA,128,GCM,SHA256),
- CS_ENTRY(0xC05C, ECDHE,ECDSA,ARIA128,GCM,SHA256,,,),
- CS_ENTRY(0xC05D, TLS,ECDHE,ECDSA,WITH,ARIA,256,GCM,SHA384),
- CS_ENTRY(0xC05D, ECDHE,ECDSA,ARIA256,GCM,SHA384,,,),
- CS_ENTRY(0xC05E, TLS,ECDH,ECDSA,WITH,ARIA,128,GCM,SHA256),
- CS_ENTRY(0xC05E, ECDH,ECDSA,ARIA128,GCM,SHA256,,,), /* ns */
- CS_ENTRY(0xC05F, TLS,ECDH,ECDSA,WITH,ARIA,256,GCM,SHA384),
- CS_ENTRY(0xC05F, ECDH,ECDSA,ARIA256,GCM,SHA384,,,), /* ns */
- CS_ENTRY(0xC060, TLS,ECDHE,RSA,WITH,ARIA,128,GCM,SHA256),
- CS_ENTRY(0xC060, ECDHE,ARIA128,GCM,SHA256,,,,),
- CS_ENTRY(0xC061, TLS,ECDHE,RSA,WITH,ARIA,256,GCM,SHA384),
- CS_ENTRY(0xC061, ECDHE,ARIA256,GCM,SHA384,,,,),
- CS_ENTRY(0xC062, TLS,ECDH,RSA,WITH,ARIA,128,GCM,SHA256),
- CS_ENTRY(0xC062, ECDH,ARIA128,GCM,SHA256,,,,), /* ns */
- CS_ENTRY(0xC063, TLS,ECDH,RSA,WITH,ARIA,256,GCM,SHA384),
- CS_ENTRY(0xC063, ECDH,ARIA256,GCM,SHA384,,,,), /* ns */
- CS_ENTRY(0xC064, TLS,PSK,WITH,ARIA,128,CBC,SHA256,),
- CS_ENTRY(0xC064, PSK,ARIA128,SHA256,,,,,), /* ns */
- CS_ENTRY(0xC065, TLS,PSK,WITH,ARIA,256,CBC,SHA384,),
- CS_ENTRY(0xC065, PSK,ARIA256,SHA384,,,,,), /* ns */
- CS_ENTRY(0xC066, TLS,DHE,PSK,WITH,ARIA,128,CBC,SHA256),
- CS_ENTRY(0xC066, DHE,PSK,ARIA128,SHA256,,,,), /* ns */
- CS_ENTRY(0xC067, TLS,DHE,PSK,WITH,ARIA,256,CBC,SHA384),
- CS_ENTRY(0xC067, DHE,PSK,ARIA256,SHA384,,,,), /* ns */
- CS_ENTRY(0xC068, TLS,RSA,PSK,WITH,ARIA,128,CBC,SHA256),
- CS_ENTRY(0xC068, RSA,PSK,ARIA128,SHA256,,,,), /* ns */
- CS_ENTRY(0xC069, TLS,RSA,PSK,WITH,ARIA,256,CBC,SHA384),
- CS_ENTRY(0xC069, RSA,PSK,ARIA256,SHA384,,,,), /* ns */
- CS_ENTRY(0xC06A, TLS,PSK,WITH,ARIA,128,GCM,SHA256,),
- CS_ENTRY(0xC06A, PSK,ARIA128,GCM,SHA256,,,,),
- CS_ENTRY(0xC06B, TLS,PSK,WITH,ARIA,256,GCM,SHA384,),
- CS_ENTRY(0xC06B, PSK,ARIA256,GCM,SHA384,,,,),
- CS_ENTRY(0xC06C, TLS,DHE,PSK,WITH,ARIA,128,GCM,SHA256),
- CS_ENTRY(0xC06C, DHE,PSK,ARIA128,GCM,SHA256,,,),
- CS_ENTRY(0xC06D, TLS,DHE,PSK,WITH,ARIA,256,GCM,SHA384),
- CS_ENTRY(0xC06D, DHE,PSK,ARIA256,GCM,SHA384,,,),
- CS_ENTRY(0xC06E, TLS,RSA,PSK,WITH,ARIA,128,GCM,SHA256),
- CS_ENTRY(0xC06E, RSA,PSK,ARIA128,GCM,SHA256,,,),
- CS_ENTRY(0xC06F, TLS,RSA,PSK,WITH,ARIA,256,GCM,SHA384),
- CS_ENTRY(0xC06F, RSA,PSK,ARIA256,GCM,SHA384,,,),
- CS_ENTRY(0xC070, TLS,ECDHE,PSK,WITH,ARIA,128,CBC,SHA256),
- CS_ENTRY(0xC070, ECDHE,PSK,ARIA128,SHA256,,,,), /* ns */
- CS_ENTRY(0xC071, TLS,ECDHE,PSK,WITH,ARIA,256,CBC,SHA384),
- CS_ENTRY(0xC071, ECDHE,PSK,ARIA256,SHA384,,,,), /* ns */
- CS_ENTRY(0xC072, TLS,ECDHE,ECDSA,WITH,CAMELLIA,128,CBC,SHA256),
- CS_ENTRY(0xC072, ECDHE,ECDSA,CAMELLIA128,SHA256,,,,),
- CS_ENTRY(0xC073, TLS,ECDHE,ECDSA,WITH,CAMELLIA,256,CBC,SHA384),
- CS_ENTRY(0xC073, ECDHE,ECDSA,CAMELLIA256,SHA384,,,,),
- CS_ENTRY(0xC074, TLS,ECDH,ECDSA,WITH,CAMELLIA,128,CBC,SHA256),
- CS_ENTRY(0xC074, ECDH,ECDSA,CAMELLIA128,SHA256,,,,), /* ns */
- CS_ENTRY(0xC075, TLS,ECDH,ECDSA,WITH,CAMELLIA,256,CBC,SHA384),
- CS_ENTRY(0xC075, ECDH,ECDSA,CAMELLIA256,SHA384,,,,), /* ns */
- CS_ENTRY(0xC076, TLS,ECDHE,RSA,WITH,CAMELLIA,128,CBC,SHA256),
- CS_ENTRY(0xC076, ECDHE,RSA,CAMELLIA128,SHA256,,,,),
- CS_ENTRY(0xC077, TLS,ECDHE,RSA,WITH,CAMELLIA,256,CBC,SHA384),
- CS_ENTRY(0xC077, ECDHE,RSA,CAMELLIA256,SHA384,,,,),
- CS_ENTRY(0xC078, TLS,ECDH,RSA,WITH,CAMELLIA,128,CBC,SHA256),
- CS_ENTRY(0xC078, ECDH,CAMELLIA128,SHA256,,,,,), /* ns */
- CS_ENTRY(0xC079, TLS,ECDH,RSA,WITH,CAMELLIA,256,CBC,SHA384),
- CS_ENTRY(0xC079, ECDH,CAMELLIA256,SHA384,,,,,), /* ns */
- CS_ENTRY(0xC07A, TLS,RSA,WITH,CAMELLIA,128,GCM,SHA256,),
- CS_ENTRY(0xC07A, CAMELLIA128,GCM,SHA256,,,,,), /* ns */
- CS_ENTRY(0xC07B, TLS,RSA,WITH,CAMELLIA,256,GCM,SHA384,),
- CS_ENTRY(0xC07B, CAMELLIA256,GCM,SHA384,,,,,), /* ns */
- CS_ENTRY(0xC07C, TLS,DHE,RSA,WITH,CAMELLIA,128,GCM,SHA256),
- CS_ENTRY(0xC07C, DHE,RSA,CAMELLIA128,GCM,SHA256,,,), /* ns */
- CS_ENTRY(0xC07D, TLS,DHE,RSA,WITH,CAMELLIA,256,GCM,SHA384),
- CS_ENTRY(0xC07D, DHE,RSA,CAMELLIA256,GCM,SHA384,,,), /* ns */
- CS_ENTRY(0xC086, TLS,ECDHE,ECDSA,WITH,CAMELLIA,128,GCM,SHA256),
- CS_ENTRY(0xC086, ECDHE,ECDSA,CAMELLIA128,GCM,SHA256,,,), /* ns */
- CS_ENTRY(0xC087, TLS,ECDHE,ECDSA,WITH,CAMELLIA,256,GCM,SHA384),
- CS_ENTRY(0xC087, ECDHE,ECDSA,CAMELLIA256,GCM,SHA384,,,), /* ns */
- CS_ENTRY(0xC088, TLS,ECDH,ECDSA,WITH,CAMELLIA,128,GCM,SHA256),
- CS_ENTRY(0xC088, ECDH,ECDSA,CAMELLIA128,GCM,SHA256,,,), /* ns */
- CS_ENTRY(0xC089, TLS,ECDH,ECDSA,WITH,CAMELLIA,256,GCM,SHA384),
- CS_ENTRY(0xC089, ECDH,ECDSA,CAMELLIA256,GCM,SHA384,,,), /* ns */
- CS_ENTRY(0xC08A, TLS,ECDHE,RSA,WITH,CAMELLIA,128,GCM,SHA256),
- CS_ENTRY(0xC08A, ECDHE,CAMELLIA128,GCM,SHA256,,,,), /* ns */
- CS_ENTRY(0xC08B, TLS,ECDHE,RSA,WITH,CAMELLIA,256,GCM,SHA384),
- CS_ENTRY(0xC08B, ECDHE,CAMELLIA256,GCM,SHA384,,,,), /* ns */
- CS_ENTRY(0xC08C, TLS,ECDH,RSA,WITH,CAMELLIA,128,GCM,SHA256),
- CS_ENTRY(0xC08C, ECDH,CAMELLIA128,GCM,SHA256,,,,), /* ns */
- CS_ENTRY(0xC08D, TLS,ECDH,RSA,WITH,CAMELLIA,256,GCM,SHA384),
- CS_ENTRY(0xC08D, ECDH,CAMELLIA256,GCM,SHA384,,,,), /* ns */
- CS_ENTRY(0xC08E, TLS,PSK,WITH,CAMELLIA,128,GCM,SHA256,),
- CS_ENTRY(0xC08E, PSK,CAMELLIA128,GCM,SHA256,,,,), /* ns */
- CS_ENTRY(0xC08F, TLS,PSK,WITH,CAMELLIA,256,GCM,SHA384,),
- CS_ENTRY(0xC08F, PSK,CAMELLIA256,GCM,SHA384,,,,), /* ns */
- CS_ENTRY(0xC090, TLS,DHE,PSK,WITH,CAMELLIA,128,GCM,SHA256),
- CS_ENTRY(0xC090, DHE,PSK,CAMELLIA128,GCM,SHA256,,,), /* ns */
- CS_ENTRY(0xC091, TLS,DHE,PSK,WITH,CAMELLIA,256,GCM,SHA384),
- CS_ENTRY(0xC091, DHE,PSK,CAMELLIA256,GCM,SHA384,,,), /* ns */
- CS_ENTRY(0xC092, TLS,RSA,PSK,WITH,CAMELLIA,128,GCM,SHA256),
- CS_ENTRY(0xC092, RSA,PSK,CAMELLIA128,GCM,SHA256,,,), /* ns */
- CS_ENTRY(0xC093, TLS,RSA,PSK,WITH,CAMELLIA,256,GCM,SHA384),
- CS_ENTRY(0xC093, RSA,PSK,CAMELLIA256,GCM,SHA384,,,), /* ns */
- CS_ENTRY(0xC094, TLS,PSK,WITH,CAMELLIA,128,CBC,SHA256,),
- CS_ENTRY(0xC094, PSK,CAMELLIA128,SHA256,,,,,),
- CS_ENTRY(0xC095, TLS,PSK,WITH,CAMELLIA,256,CBC,SHA384,),
- CS_ENTRY(0xC095, PSK,CAMELLIA256,SHA384,,,,,),
- CS_ENTRY(0xC096, TLS,DHE,PSK,WITH,CAMELLIA,128,CBC,SHA256),
- CS_ENTRY(0xC096, DHE,PSK,CAMELLIA128,SHA256,,,,),
- CS_ENTRY(0xC097, TLS,DHE,PSK,WITH,CAMELLIA,256,CBC,SHA384),
- CS_ENTRY(0xC097, DHE,PSK,CAMELLIA256,SHA384,,,,),
- CS_ENTRY(0xC098, TLS,RSA,PSK,WITH,CAMELLIA,128,CBC,SHA256),
- CS_ENTRY(0xC098, RSA,PSK,CAMELLIA128,SHA256,,,,),
- CS_ENTRY(0xC099, TLS,RSA,PSK,WITH,CAMELLIA,256,CBC,SHA384),
- CS_ENTRY(0xC099, RSA,PSK,CAMELLIA256,SHA384,,,,),
- CS_ENTRY(0xC09A, TLS,ECDHE,PSK,WITH,CAMELLIA,128,CBC,SHA256),
- CS_ENTRY(0xC09A, ECDHE,PSK,CAMELLIA128,SHA256,,,,),
- CS_ENTRY(0xC09B, TLS,ECDHE,PSK,WITH,CAMELLIA,256,CBC,SHA384),
- CS_ENTRY(0xC09B, ECDHE,PSK,CAMELLIA256,SHA384,,,,),
- CS_ENTRY(0xC09E, TLS,DHE,RSA,WITH,AES,128,CCM,),
- CS_ENTRY(0xC09E, DHE,RSA,AES128,CCM,,,,),
- CS_ENTRY(0xC09F, TLS,DHE,RSA,WITH,AES,256,CCM,),
- CS_ENTRY(0xC09F, DHE,RSA,AES256,CCM,,,,),
- CS_ENTRY(0xC0A2, TLS,DHE,RSA,WITH,AES,128,CCM,8),
- CS_ENTRY(0xC0A2, DHE,RSA,AES128,CCM8,,,,),
- CS_ENTRY(0xC0A3, TLS,DHE,RSA,WITH,AES,256,CCM,8),
- CS_ENTRY(0xC0A3, DHE,RSA,AES256,CCM8,,,,),
- CS_ENTRY(0xC0A4, TLS,PSK,WITH,AES,128,CCM,,),
- CS_ENTRY(0xC0A4, PSK,AES128,CCM,,,,,),
- CS_ENTRY(0xC0A5, TLS,PSK,WITH,AES,256,CCM,,),
- CS_ENTRY(0xC0A5, PSK,AES256,CCM,,,,,),
- CS_ENTRY(0xC0A6, TLS,DHE,PSK,WITH,AES,128,CCM,),
- CS_ENTRY(0xC0A6, DHE,PSK,AES128,CCM,,,,),
- CS_ENTRY(0xC0A7, TLS,DHE,PSK,WITH,AES,256,CCM,),
- CS_ENTRY(0xC0A7, DHE,PSK,AES256,CCM,,,,),
- CS_ENTRY(0xC0A8, TLS,PSK,WITH,AES,128,CCM,8,),
- CS_ENTRY(0xC0A8, PSK,AES128,CCM8,,,,,),
- CS_ENTRY(0xC0A9, TLS,PSK,WITH,AES,256,CCM,8,),
- CS_ENTRY(0xC0A9, PSK,AES256,CCM8,,,,,),
- CS_ENTRY(0xC0AA, TLS,PSK,DHE,WITH,AES,128,CCM,8),
- CS_ENTRY(0xC0AA, DHE,PSK,AES128,CCM8,,,,),
- CS_ENTRY(0xC0AB, TLS,PSK,DHE,WITH,AES,256,CCM,8),
- CS_ENTRY(0xC0AB, DHE,PSK,AES256,CCM8,,,,),
- CS_ENTRY(0xCCAA, TLS,DHE,RSA,WITH,CHACHA20,POLY1305,SHA256,),
- CS_ENTRY(0xCCAA, DHE,RSA,CHACHA20,POLY1305,,,,),
- CS_ENTRY(0xCCAC, TLS,ECDHE,PSK,WITH,CHACHA20,POLY1305,SHA256,),
- CS_ENTRY(0xCCAC, ECDHE,PSK,CHACHA20,POLY1305,,,,),
- CS_ENTRY(0xCCAD, TLS,DHE,PSK,WITH,CHACHA20,POLY1305,SHA256,),
- CS_ENTRY(0xCCAD, DHE,PSK,CHACHA20,POLY1305,,,,),
- CS_ENTRY(0xCCAE, TLS,RSA,PSK,WITH,CHACHA20,POLY1305,SHA256,),
- CS_ENTRY(0xCCAE, RSA,PSK,CHACHA20,POLY1305,,,,),
-#endif
-};
-#define CS_LIST_LEN (sizeof(cs_list) / sizeof(cs_list[0]))
-
-static int cs_str_to_zip(const char *cs_str, size_t cs_len,
- uint8_t zip[6])
-{
- uint8_t indexes[8] = {0};
- const char *entry, *cur;
- const char *nxt = cs_str;
- const char *end = cs_str + cs_len;
- char separator = '-';
- int idx, i = 0;
- size_t len;
-
- /* split the cipher string by '-' or '_' */
- if(strncasecompare(cs_str, "TLS", 3))
- separator = '_';
-
- do {
- if(i == 8)
- return -1;
-
- /* determine the length of the part */
- cur = nxt;
- for(; nxt < end && *nxt != '\0' && *nxt != separator; nxt++);
- len = nxt - cur;
-
- /* lookup index for the part (skip empty string at 0) */
- for(idx = 1, entry = cs_txt + 1; idx < CS_TXT_LEN; idx++) {
- size_t elen = strlen(entry);
- if(elen == len && strncasecompare(entry, cur, len))
- break;
- entry += elen + 1;
- }
- if(idx == CS_TXT_LEN)
- return -1;
-
- indexes[i++] = (uint8_t) idx;
- } while(nxt < end && *(nxt++) != '\0');
-
- /* zip the 8 indexes into 48 bits */
- zip[0] = (uint8_t) (indexes[0] << 2 | (indexes[1] & 0x3F) >> 4);
- zip[1] = (uint8_t) (indexes[1] << 4 | (indexes[2] & 0x3F) >> 2);
- zip[2] = (uint8_t) (indexes[2] << 6 | (indexes[3] & 0x3F));
- zip[3] = (uint8_t) (indexes[4] << 2 | (indexes[5] & 0x3F) >> 4);
- zip[4] = (uint8_t) (indexes[5] << 4 | (indexes[6] & 0x3F) >> 2);
- zip[5] = (uint8_t) (indexes[6] << 6 | (indexes[7] & 0x3F));
-
- return 0;
-}
-
-static int cs_zip_to_str(const uint8_t zip[6],
- char *buf, size_t buf_size)
-{
- uint8_t indexes[8] = {0};
- const char *entry;
- char separator = '-';
- int idx, i, r;
- size_t len = 0;
-
- /* unzip the 8 indexes */
- indexes[0] = zip[0] >> 2;
- indexes[1] = ((zip[0] << 4) & 0x3F) | zip[1] >> 4;
- indexes[2] = ((zip[1] << 2) & 0x3F) | zip[2] >> 6;
- indexes[3] = ((zip[2] << 0) & 0x3F);
- indexes[4] = zip[3] >> 2;
- indexes[5] = ((zip[3] << 4) & 0x3F) | zip[4] >> 4;
- indexes[6] = ((zip[4] << 2) & 0x3F) | zip[5] >> 6;
- indexes[7] = ((zip[5] << 0) & 0x3F);
-
- if(indexes[0] == CS_TXT_IDX_TLS)
- separator = '_';
-
- for(i = 0; i < 8 && indexes[i] != 0 && len < buf_size; i++) {
- if(indexes[i] >= CS_TXT_LEN)
- return -1;
-
- /* lookup the part string for the index (skip empty string at 0) */
- for(idx = 1, entry = cs_txt + 1; idx < indexes[i]; idx++) {
- size_t elen = strlen(entry);
- entry += elen + 1;
- }
-
- /* append the part string to the buffer */
- if(i > 0)
- r = msnprintf(&buf[len], buf_size - len, "%c%s", separator, entry);
- else
- r = msnprintf(&buf[len], buf_size - len, "%s", entry);
-
- if(r < 0)
- return -1;
- len += r;
- }
-
- return 0;
-}
-
-uint16_t Curl_cipher_suite_lookup_id(const char *cs_str, size_t cs_len)
-{
- size_t i;
- uint8_t zip[6];
-
- if(cs_len > 0 && cs_str_to_zip(cs_str, cs_len, zip) == 0) {
- for(i = 0; i < CS_LIST_LEN; i++) {
- if(memcmp(cs_list[i].zip, zip, sizeof(zip)) == 0)
- return cs_list[i].id;
- }
- }
-
- return 0;
-}
-
-static bool cs_is_separator(char c)
-{
- switch(c) {
- case ' ':
- case '\t':
- case ':':
- case ',':
- case ';':
- return true;
- default:;
- }
- return false;
-}
-
-uint16_t Curl_cipher_suite_walk_str(const char **str, const char **end)
-{
- /* move string pointer to first non-separator or end of string */
- for(; cs_is_separator(*str[0]); (*str)++);
-
- /* move end pointer to next separator or end of string */
- for(*end = *str; *end[0] != '\0' && !cs_is_separator(*end[0]); (*end)++);
-
- return Curl_cipher_suite_lookup_id(*str, *end - *str);
-}
-
-int Curl_cipher_suite_get_str(uint16_t id, char *buf, size_t buf_size,
- bool prefer_rfc)
-{
- size_t i, j = CS_LIST_LEN;
- int r = -1;
-
- for(i = 0; i < CS_LIST_LEN; i++) {
- if(cs_list[i].id != id)
- continue;
- if((cs_list[i].zip[0] >> 2 != CS_TXT_IDX_TLS) == !prefer_rfc) {
- j = i;
- break;
- }
- if(j == CS_LIST_LEN)
- j = i;
- }
-
- if(j < CS_LIST_LEN)
- r = cs_zip_to_str(cs_list[j].zip, buf, buf_size);
-
- if(r < 0)
- msnprintf(buf, buf_size, "TLS_UNKNOWN_0x%04x", id);
-
- return r;
-}
-
-#endif /* defined(USE_SECTRANSP) || defined(USE_MBEDTLS) || \
- defined(USE_BEARSSL) || defined(USE_RUSTLS) */
diff --git a/contrib/libs/curl/lib/vtls/gtls.c b/contrib/libs/curl/lib/vtls/gtls.c
index 568378cc6b..553309d86f 100644
--- a/contrib/libs/curl/lib/vtls/gtls.c
+++ b/contrib/libs/curl/lib/vtls/gtls.c
@@ -26,7 +26,7 @@
* Source file for all GnuTLS-specific code for the TLS/SSL layer. No code
* but vtls.c should ever call or use these functions.
*
- * Note: do not use the GnuTLS' *_t variable type names in this source code,
+ * Note: don't use the GnuTLS' *_t variable type names in this source code,
* since they were not present in 1.0.X.
*/
@@ -43,7 +43,6 @@
#include "urldata.h"
#include "sendf.h"
#include "inet_pton.h"
-#include "keylog.h"
#include "gtls.h"
#include "vtls.h"
#include "vtls_int.h"
@@ -53,23 +52,13 @@
#include "select.h"
#include "strcase.h"
#include "warnless.h"
-#error #include "x509asn1.h"
+#include "x509asn1.h"
#include "multiif.h"
#include "curl_printf.h"
#include "curl_memory.h"
/* The last #include file should be: */
#include "memdebug.h"
-#ifndef ARRAYSIZE
-#define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
-#endif
-
-#define QUIC_PRIORITY \
- "NORMAL:-VERS-ALL:+VERS-TLS1.3:-CIPHER-ALL:+AES-128-GCM:+AES-256-GCM:" \
- "+CHACHA20-POLY1305:+AES-128-CCM:-GROUP-ALL:+GROUP-SECP256R1:" \
- "+GROUP-X25519:+GROUP-SECP384R1:+GROUP-SECP521R1:" \
- "%DISABLE_TLS13_COMPAT_MODE"
-
/* Enable GnuTLS debugging by defining GTLSDEBUG */
/*#define GTLSDEBUG */
@@ -88,25 +77,22 @@ static bool gtls_inited = FALSE;
# error #include <gnutls/ocsp.h>
struct gtls_ssl_backend_data {
- struct gtls_ctx gtls;
+ struct gtls_instance gtls;
};
static ssize_t gtls_push(void *s, const void *buf, size_t blen)
{
struct Curl_cfilter *cf = s;
struct ssl_connect_data *connssl = cf->ctx;
- struct gtls_ssl_backend_data *backend =
- (struct gtls_ssl_backend_data *)connssl->backend;
struct Curl_easy *data = CF_DATA_CURRENT(cf);
ssize_t nwritten;
CURLcode result;
DEBUGASSERT(data);
- nwritten = Curl_conn_cf_send(cf->next, data, buf, blen, FALSE, &result);
- CURL_TRC_CF(data, cf, "gtls_push(len=%zu) -> %zd, err=%d",
- blen, nwritten, result);
- backend->gtls.io_result = result;
+ nwritten = Curl_conn_cf_send(cf->next, data, buf, blen, &result);
if(nwritten < 0) {
+ struct gtls_ssl_backend_data *backend =
+ (struct gtls_ssl_backend_data *)connssl->backend;
gnutls_transport_set_errno(backend->gtls.session,
(CURLE_AGAIN == result)? EAGAIN : EINVAL);
nwritten = -1;
@@ -118,33 +104,19 @@ static ssize_t gtls_pull(void *s, void *buf, size_t blen)
{
struct Curl_cfilter *cf = s;
struct ssl_connect_data *connssl = cf->ctx;
- struct gtls_ssl_backend_data *backend =
- (struct gtls_ssl_backend_data *)connssl->backend;
struct Curl_easy *data = CF_DATA_CURRENT(cf);
ssize_t nread;
CURLcode result;
DEBUGASSERT(data);
- if(!backend->gtls.shared_creds->trust_setup) {
- result = Curl_gtls_client_trust_setup(cf, data, &backend->gtls);
- if(result) {
- gnutls_transport_set_errno(backend->gtls.session, EINVAL);
- backend->gtls.io_result = result;
- return -1;
- }
- }
-
nread = Curl_conn_cf_recv(cf->next, data, buf, blen, &result);
- CURL_TRC_CF(data, cf, "glts_pull(len=%zu) -> %zd, err=%d",
- blen, nread, result);
- backend->gtls.io_result = result;
if(nread < 0) {
+ struct gtls_ssl_backend_data *backend =
+ (struct gtls_ssl_backend_data *)connssl->backend;
gnutls_transport_set_errno(backend->gtls.session,
(CURLE_AGAIN == result)? EAGAIN : EINVAL);
nread = -1;
}
- else if(nread == 0)
- connssl->peer_closed = TRUE;
return nread;
}
@@ -251,7 +223,6 @@ static CURLcode handshake(struct Curl_cfilter *cf,
DEBUGASSERT(backend);
session = backend->gtls.session;
- connssl->connecting_state = ssl_connect_2;
for(;;) {
timediff_t timeout_ms;
@@ -266,13 +237,14 @@ static CURLcode handshake(struct Curl_cfilter *cf,
return CURLE_OPERATION_TIMEDOUT;
}
- /* if ssl is expecting something, check if it is available. */
- if(connssl->io_need) {
+ /* if ssl is expecting something, check if it's available. */
+ if(connssl->connecting_state == ssl_connect_2_reading
+ || connssl->connecting_state == ssl_connect_2_writing) {
int what;
- curl_socket_t writefd = (connssl->io_need & CURL_SSL_IO_NEED_SEND)?
- sockfd:CURL_SOCKET_BAD;
- curl_socket_t readfd = (connssl->io_need & CURL_SSL_IO_NEED_RECV)?
- sockfd:CURL_SOCKET_BAD;
+ curl_socket_t writefd = ssl_connect_2_writing ==
+ connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
+ curl_socket_t readfd = ssl_connect_2_reading ==
+ connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
nonblocking?0:
@@ -294,29 +266,19 @@ static CURLcode handshake(struct Curl_cfilter *cf,
/* socket is readable or writable */
}
- connssl->io_need = CURL_SSL_IO_NEED_NONE;
- backend->gtls.io_result = CURLE_OK;
rc = gnutls_handshake(session);
- if(!backend->gtls.shared_creds->trust_setup) {
- /* After having send off the ClientHello, we prepare the trust
- * store to verify the coming certificate from the server */
- CURLcode result = Curl_gtls_client_trust_setup(cf, data, &backend->gtls);
- if(result)
- return result;
- }
-
if((rc == GNUTLS_E_AGAIN) || (rc == GNUTLS_E_INTERRUPTED)) {
- connssl->io_need =
+ connssl->connecting_state =
gnutls_record_get_direction(session)?
- CURL_SSL_IO_NEED_SEND:CURL_SSL_IO_NEED_RECV;
+ ssl_connect_2_writing:ssl_connect_2_reading;
continue;
}
else if((rc < 0) && !gnutls_error_is_fatal(rc)) {
const char *strerr = NULL;
if(rc == GNUTLS_E_WARNING_ALERT_RECEIVED) {
- gnutls_alert_description_t alert = gnutls_alert_get(session);
+ int alert = gnutls_alert_get(session);
strerr = gnutls_alert_get_name(alert);
}
@@ -326,21 +288,18 @@ static CURLcode handshake(struct Curl_cfilter *cf,
infof(data, "gnutls_handshake() warning: %s", strerr);
continue;
}
- else if((rc < 0) && backend->gtls.io_result) {
- return backend->gtls.io_result;
- }
else if(rc < 0) {
const char *strerr = NULL;
if(rc == GNUTLS_E_FATAL_ALERT_RECEIVED) {
- gnutls_alert_description_t alert = gnutls_alert_get(session);
+ int alert = gnutls_alert_get(session);
strerr = gnutls_alert_get_name(alert);
}
if(!strerr)
strerr = gnutls_strerror(rc);
- failf(data, "GnuTLS, handshake failed: %s", strerr);
+ failf(data, "gnutls_handshake() failed: %s", strerr);
return CURLE_SSL_CONNECT_ERROR;
}
@@ -350,7 +309,7 @@ static CURLcode handshake(struct Curl_cfilter *cf,
}
}
-static gnutls_x509_crt_fmt_t gnutls_do_file_type(const char *type)
+static gnutls_x509_crt_fmt_t do_file_type(const char *type)
{
if(!type || !type[0])
return GNUTLS_X509_FMT_PEM;
@@ -368,11 +327,10 @@ static gnutls_x509_crt_fmt_t gnutls_do_file_type(const char *type)
#define GNUTLS_SRP "+SRP"
static CURLcode
-gnutls_set_ssl_version_min_max(struct Curl_easy *data,
- struct ssl_peer *peer,
- struct ssl_primary_config *conn_config,
- const char **prioritylist,
- const char *tls13support)
+set_ssl_version_min_max(struct Curl_easy *data,
+ struct ssl_primary_config *conn_config,
+ const char **prioritylist,
+ const char *tls13support)
{
long ssl_version = conn_config->version;
long ssl_version_max = conn_config->version_max;
@@ -382,19 +340,8 @@ gnutls_set_ssl_version_min_max(struct Curl_easy *data,
ssl_version = CURL_SSLVERSION_TLSv1_0;
if(ssl_version_max == CURL_SSLVERSION_MAX_NONE)
ssl_version_max = CURL_SSLVERSION_MAX_DEFAULT;
-
- if(peer->transport == TRNSPRT_QUIC) {
- if((ssl_version_max != CURL_SSLVERSION_MAX_DEFAULT) &&
- (ssl_version_max < CURL_SSLVERSION_MAX_TLSv1_3)) {
- failf(data, "QUIC needs at least TLS version 1.3");
- return CURLE_SSL_CONNECT_ERROR;
- }
- *prioritylist = QUIC_PRIORITY;
- return CURLE_OK;
- }
-
if(!tls13support) {
- /* If the running GnuTLS does not support TLS 1.3, we must not specify a
+ /* If the running GnuTLS doesn't support TLS 1.3, we must not specify a
prioritylist involving that since it will make GnuTLS return an en
error back at us */
if((ssl_version_max == CURL_SSLVERSION_MAX_TLSv1_3) ||
@@ -452,67 +399,67 @@ gnutls_set_ssl_version_min_max(struct Curl_easy *data,
return CURLE_SSL_CONNECT_ERROR;
}
-CURLcode Curl_gtls_shared_creds_create(struct Curl_easy *data,
- struct gtls_shared_creds **pcreds)
+CURLcode gtls_client_init(struct Curl_easy *data,
+ struct ssl_primary_config *config,
+ struct ssl_config_data *ssl_config,
+ struct ssl_peer *peer,
+ struct gtls_instance *gtls,
+ long *pverifyresult)
{
- struct gtls_shared_creds *shared;
+ unsigned int init_flags;
int rc;
+ bool sni = TRUE; /* default is SNI enabled */
+ const char *prioritylist;
+ const char *err = NULL;
+ const char *tls13support;
+ CURLcode result;
+
+ if(!gtls_inited)
+ gtls_init();
- *pcreds = NULL;
- shared = calloc(1, sizeof(*shared));
- if(!shared)
- return CURLE_OUT_OF_MEMORY;
+ *pverifyresult = 0;
- rc = gnutls_certificate_allocate_credentials(&shared->creds);
+ if(config->version == CURL_SSLVERSION_SSLv2) {
+ failf(data, "GnuTLS does not support SSLv2");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ else if(config->version == CURL_SSLVERSION_SSLv3)
+ sni = FALSE; /* SSLv3 has no SNI */
+
+ /* allocate a cred struct */
+ rc = gnutls_certificate_allocate_credentials(&gtls->cred);
if(rc != GNUTLS_E_SUCCESS) {
failf(data, "gnutls_cert_all_cred() failed: %s", gnutls_strerror(rc));
- free(shared);
return CURLE_SSL_CONNECT_ERROR;
}
- shared->refcount = 1;
- shared->time = Curl_now();
- *pcreds = shared;
- return CURLE_OK;
-}
+#ifdef USE_GNUTLS_SRP
+ if(config->username && Curl_auth_allowed_to_host(data)) {
+ infof(data, "Using TLS-SRP username: %s", config->username);
-CURLcode Curl_gtls_shared_creds_up_ref(struct gtls_shared_creds *creds)
-{
- DEBUGASSERT(creds);
- if(creds->refcount < SIZE_T_MAX) {
- ++creds->refcount;
- return CURLE_OK;
- }
- return CURLE_BAD_FUNCTION_ARGUMENT;
-}
+ rc = gnutls_srp_allocate_client_credentials(&gtls->srp_client_cred);
+ if(rc != GNUTLS_E_SUCCESS) {
+ failf(data, "gnutls_srp_allocate_client_cred() failed: %s",
+ gnutls_strerror(rc));
+ return CURLE_OUT_OF_MEMORY;
+ }
-void Curl_gtls_shared_creds_free(struct gtls_shared_creds **pcreds)
-{
- struct gtls_shared_creds *shared = *pcreds;
- *pcreds = NULL;
- if(shared) {
- --shared->refcount;
- if(!shared->refcount) {
- gnutls_certificate_free_credentials(shared->creds);
- free(shared->CAfile);
- free(shared);
+ rc = gnutls_srp_set_client_credentials(gtls->srp_client_cred,
+ config->username,
+ config->password);
+ if(rc != GNUTLS_E_SUCCESS) {
+ failf(data, "gnutls_srp_set_client_cred() failed: %s",
+ gnutls_strerror(rc));
+ return CURLE_BAD_FUNCTION_ARGUMENT;
}
}
-}
-
-static CURLcode gtls_populate_creds(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- gnutls_certificate_credentials_t creds)
-{
- struct ssl_primary_config *config = Curl_ssl_cf_get_primary_config(cf);
- struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
- int rc;
+#endif
if(config->verifypeer) {
bool imported_native_ca = false;
if(ssl_config->native_ca_store) {
- rc = gnutls_certificate_set_x509_system_trust(creds);
+ rc = gnutls_certificate_set_x509_system_trust(gtls->cred);
if(rc < 0)
infof(data, "error reading native ca store (%s), continuing anyway",
gnutls_strerror(rc));
@@ -525,10 +472,10 @@ static CURLcode gtls_populate_creds(struct Curl_cfilter *cf,
if(config->CAfile) {
/* set the trusted CA cert bundle file */
- gnutls_certificate_set_verify_flags(creds,
+ gnutls_certificate_set_verify_flags(gtls->cred,
GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT);
- rc = gnutls_certificate_set_x509_trust_file(creds,
+ rc = gnutls_certificate_set_x509_trust_file(gtls->cred,
config->CAfile,
GNUTLS_X509_FMT_PEM);
if(rc < 0) {
@@ -536,7 +483,7 @@ static CURLcode gtls_populate_creds(struct Curl_cfilter *cf,
config->CAfile, gnutls_strerror(rc),
(imported_native_ca ? ", continuing anyway" : ""));
if(!imported_native_ca) {
- ssl_config->certverifyresult = rc;
+ *pverifyresult = rc;
return CURLE_SSL_CACERT_BADFILE;
}
}
@@ -546,14 +493,15 @@ static CURLcode gtls_populate_creds(struct Curl_cfilter *cf,
if(config->CApath) {
/* set the trusted CA cert directory */
- rc = gnutls_certificate_set_x509_trust_dir(creds, config->CApath,
+ rc = gnutls_certificate_set_x509_trust_dir(gtls->cred,
+ config->CApath,
GNUTLS_X509_FMT_PEM);
if(rc < 0) {
infof(data, "error reading ca cert file %s (%s)%s",
config->CApath, gnutls_strerror(rc),
(imported_native_ca ? ", continuing anyway" : ""));
if(!imported_native_ca) {
- ssl_config->certverifyresult = rc;
+ *pverifyresult = rc;
return CURLE_SSL_CACERT_BADFILE;
}
}
@@ -564,7 +512,8 @@ static CURLcode gtls_populate_creds(struct Curl_cfilter *cf,
if(config->CRLfile) {
/* set the CRL list file */
- rc = gnutls_certificate_set_x509_crl_file(creds, config->CRLfile,
+ rc = gnutls_certificate_set_x509_crl_file(gtls->cred,
+ config->CRLfile,
GNUTLS_X509_FMT_PEM);
if(rc < 0) {
failf(data, "error reading crl file %s (%s)",
@@ -575,269 +524,6 @@ static CURLcode gtls_populate_creds(struct Curl_cfilter *cf,
infof(data, "found %d CRL in %s", rc, config->CRLfile);
}
- return CURLE_OK;
-}
-
-/* key to use at `multi->proto_hash` */
-#define MPROTO_GTLS_X509_KEY "tls:gtls:x509:share"
-
-static bool gtls_shared_creds_expired(const struct Curl_easy *data,
- const struct gtls_shared_creds *sc)
-{
- const struct ssl_general_config *cfg = &data->set.general_ssl;
- struct curltime now = Curl_now();
- timediff_t elapsed_ms = Curl_timediff(now, sc->time);
- timediff_t timeout_ms = cfg->ca_cache_timeout * (timediff_t)1000;
-
- if(timeout_ms < 0)
- return false;
-
- return elapsed_ms >= timeout_ms;
-}
-
-static bool gtls_shared_creds_different(struct Curl_cfilter *cf,
- const struct gtls_shared_creds *sc)
-{
- struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
- if(!sc->CAfile || !conn_config->CAfile)
- return sc->CAfile != conn_config->CAfile;
-
- return strcmp(sc->CAfile, conn_config->CAfile);
-}
-
-static struct gtls_shared_creds*
-gtls_get_cached_creds(struct Curl_cfilter *cf, struct Curl_easy *data)
-{
- struct gtls_shared_creds *shared_creds;
-
- if(data->multi) {
- shared_creds = Curl_hash_pick(&data->multi->proto_hash,
- (void *)MPROTO_GTLS_X509_KEY,
- sizeof(MPROTO_GTLS_X509_KEY)-1);
- if(shared_creds && shared_creds->creds &&
- !gtls_shared_creds_expired(data, shared_creds) &&
- !gtls_shared_creds_different(cf, shared_creds)) {
- return shared_creds;
- }
- }
- return NULL;
-}
-
-static void gtls_shared_creds_hash_free(void *key, size_t key_len, void *p)
-{
- struct gtls_shared_creds *sc = p;
- DEBUGASSERT(key_len == (sizeof(MPROTO_GTLS_X509_KEY)-1));
- DEBUGASSERT(!memcmp(MPROTO_GTLS_X509_KEY, key, key_len));
- (void)key;
- (void)key_len;
- Curl_gtls_shared_creds_free(&sc); /* down reference */
-}
-
-static void gtls_set_cached_creds(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- struct gtls_shared_creds *sc)
-{
- struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
-
- DEBUGASSERT(sc);
- DEBUGASSERT(sc->creds);
- DEBUGASSERT(!sc->CAfile);
- DEBUGASSERT(sc->refcount == 1);
- if(!data->multi)
- return;
-
- if(conn_config->CAfile) {
- sc->CAfile = strdup(conn_config->CAfile);
- if(!sc->CAfile)
- return;
- }
-
- if(Curl_gtls_shared_creds_up_ref(sc))
- return;
-
- if(!Curl_hash_add2(&data->multi->proto_hash,
- (void *)MPROTO_GTLS_X509_KEY,
- sizeof(MPROTO_GTLS_X509_KEY)-1,
- sc, gtls_shared_creds_hash_free)) {
- Curl_gtls_shared_creds_free(&sc); /* down reference again */
- return;
- }
-}
-
-CURLcode Curl_gtls_client_trust_setup(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- struct gtls_ctx *gtls)
-{
- struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
- struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
- struct gtls_shared_creds *cached_creds = NULL;
- bool cache_criteria_met;
- CURLcode result;
- int rc;
-
-
- /* Consider the X509 store cacheable if it comes exclusively from a CAfile,
- or no source is provided and we are falling back to OpenSSL's built-in
- default. */
- cache_criteria_met = (data->set.general_ssl.ca_cache_timeout != 0) &&
- conn_config->verifypeer &&
- !conn_config->CApath &&
- !conn_config->ca_info_blob &&
- !ssl_config->primary.CRLfile &&
- !ssl_config->native_ca_store &&
- !conn_config->clientcert; /* GnuTLS adds client cert to its credentials! */
-
- if(cache_criteria_met)
- cached_creds = gtls_get_cached_creds(cf, data);
-
- if(cached_creds && !Curl_gtls_shared_creds_up_ref(cached_creds)) {
- CURL_TRC_CF(data, cf, "using shared trust anchors and CRLs");
- Curl_gtls_shared_creds_free(&gtls->shared_creds);
- gtls->shared_creds = cached_creds;
- rc = gnutls_credentials_set(gtls->session, GNUTLS_CRD_CERTIFICATE,
- gtls->shared_creds->creds);
- if(rc != GNUTLS_E_SUCCESS) {
- failf(data, "gnutls_credentials_set() failed: %s", gnutls_strerror(rc));
- return CURLE_SSL_CONNECT_ERROR;
- }
- }
- else {
- CURL_TRC_CF(data, cf, "loading trust anchors and CRLs");
- result = gtls_populate_creds(cf, data, gtls->shared_creds->creds);
- if(result)
- return result;
- gtls->shared_creds->trust_setup = TRUE;
- if(cache_criteria_met)
- gtls_set_cached_creds(cf, data, gtls->shared_creds);
- }
- return CURLE_OK;
-}
-
-static void gtls_sessionid_free(void *sessionid, size_t idsize)
-{
- (void)idsize;
- free(sessionid);
-}
-
-static CURLcode gtls_update_session_id(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- gnutls_session_t session)
-{
- struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
- struct ssl_connect_data *connssl = cf->ctx;
- CURLcode result = CURLE_OK;
-
- if(ssl_config->primary.cache_session) {
- /* we always unconditionally get the session id here, as even if we
- already got it from the cache and asked to use it in the connection, it
- might've been rejected and then a new one is in use now and we need to
- detect that. */
- void *connect_sessionid;
- size_t connect_idsize = 0;
-
- /* get the session ID data size */
- gnutls_session_get_data(session, NULL, &connect_idsize);
- connect_sessionid = malloc(connect_idsize); /* get a buffer for it */
- if(!connect_sessionid) {
- return CURLE_OUT_OF_MEMORY;
- }
- else {
- /* extract session ID to the allocated buffer */
- gnutls_session_get_data(session, connect_sessionid, &connect_idsize);
-
- CURL_TRC_CF(data, cf, "get session id (len=%zu) and store in cache",
- connect_idsize);
- Curl_ssl_sessionid_lock(data);
- /* store this session id, takes ownership */
- result = Curl_ssl_set_sessionid(cf, data, &connssl->peer,
- connect_sessionid, connect_idsize,
- gtls_sessionid_free);
- Curl_ssl_sessionid_unlock(data);
- }
- }
- return result;
-}
-
-static int gtls_handshake_cb(gnutls_session_t session, unsigned int htype,
- unsigned when, unsigned int incoming,
- const gnutls_datum_t *msg)
-{
- struct Curl_cfilter *cf = gnutls_session_get_ptr(session);
-
- (void)msg;
- (void)incoming;
- if(when) { /* after message has been processed */
- struct Curl_easy *data = CF_DATA_CURRENT(cf);
- if(data) {
- CURL_TRC_CF(data, cf, "handshake: %s message type %d",
- incoming? "incoming" : "outgoing", htype);
- switch(htype) {
- case GNUTLS_HANDSHAKE_NEW_SESSION_TICKET: {
- gtls_update_session_id(cf, data, session);
- break;
- }
- default:
- break;
- }
- }
- }
- return 0;
-}
-
-static CURLcode gtls_client_init(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- struct ssl_peer *peer,
- struct gtls_ctx *gtls)
-{
- struct ssl_primary_config *config = Curl_ssl_cf_get_primary_config(cf);
- struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
- unsigned int init_flags;
- int rc;
- bool sni = TRUE; /* default is SNI enabled */
- const char *prioritylist;
- const char *err = NULL;
- const char *tls13support;
- CURLcode result;
-
- if(!gtls_inited)
- gtls_init();
-
- if(config->version == CURL_SSLVERSION_SSLv2) {
- failf(data, "GnuTLS does not support SSLv2");
- return CURLE_SSL_CONNECT_ERROR;
- }
- else if(config->version == CURL_SSLVERSION_SSLv3)
- sni = FALSE; /* SSLv3 has no SNI */
-
- /* allocate a shared creds struct */
- result = Curl_gtls_shared_creds_create(data, &gtls->shared_creds);
- if(result)
- return result;
-
-#ifdef USE_GNUTLS_SRP
- if(config->username && Curl_auth_allowed_to_host(data)) {
- infof(data, "Using TLS-SRP username: %s", config->username);
-
- rc = gnutls_srp_allocate_client_credentials(&gtls->srp_client_cred);
- if(rc != GNUTLS_E_SUCCESS) {
- failf(data, "gnutls_srp_allocate_client_cred() failed: %s",
- gnutls_strerror(rc));
- return CURLE_OUT_OF_MEMORY;
- }
-
- rc = gnutls_srp_set_client_credentials(gtls->srp_client_cred,
- config->username,
- config->password);
- if(rc != GNUTLS_E_SUCCESS) {
- failf(data, "gnutls_srp_set_client_cred() failed: %s",
- gnutls_strerror(rc));
- return CURLE_BAD_FUNCTION_ARGUMENT;
- }
- }
-#endif
-
- ssl_config->certverifyresult = 0;
-
/* Initialize TLS session as a client */
init_flags = GNUTLS_CLIENT;
@@ -850,13 +536,6 @@ static CURLcode gtls_client_init(struct Curl_cfilter *cf,
init_flags |= GNUTLS_NO_TICKETS;
#endif
-#if defined(GNUTLS_NO_STATUS_REQUEST)
- if(!config->verifystatus)
- /* Disable the "status_request" TLS extension, enabled by default since
- GnuTLS 3.8.0. */
- init_flags |= GNUTLS_NO_STATUS_REQUEST;
-#endif
-
rc = gnutls_init(&gtls->session, init_flags);
if(rc != GNUTLS_E_SUCCESS) {
failf(data, "gnutls_init() failed: %d", rc);
@@ -880,7 +559,7 @@ static CURLcode gtls_client_init(struct Curl_cfilter *cf,
tls13support = gnutls_check_version("3.6.5");
/* Ensure +SRP comes at the *end* of all relevant strings so that it can be
- * removed if a runtime error indicates that SRP is not supported by this
+ * removed if a run-time error indicates that SRP is not supported by this
* GnuTLS version */
if(config->version == CURL_SSLVERSION_SSLv2 ||
@@ -897,8 +576,7 @@ static CURLcode gtls_client_init(struct Curl_cfilter *cf,
}
/* At this point we know we have a supported TLS version, so set it */
- result = gnutls_set_ssl_version_min_max(data, peer,
- config, &prioritylist, tls13support);
+ result = set_ssl_version_min_max(data, config, &prioritylist, tls13support);
if(result)
return result;
@@ -906,9 +584,13 @@ static CURLcode gtls_client_init(struct Curl_cfilter *cf,
/* Only add SRP to the cipher list if SRP is requested. Otherwise
* GnuTLS will disable TLS 1.3 support. */
if(config->username) {
- char *prioritysrp = aprintf("%s:" GNUTLS_SRP, prioritylist);
+ size_t len = strlen(prioritylist);
+
+ char *prioritysrp = malloc(len + sizeof(GNUTLS_SRP) + 1);
if(!prioritysrp)
return CURLE_OUT_OF_MEMORY;
+ strcpy(prioritysrp, prioritylist);
+ strcpy(prioritysrp + len, ":" GNUTLS_SRP);
rc = gnutls_priority_set_direct(gtls->session, prioritysrp, &err);
free(prioritysrp);
@@ -931,11 +613,6 @@ static CURLcode gtls_client_init(struct Curl_cfilter *cf,
}
if(config->clientcert) {
- if(!gtls->shared_creds->trust_setup) {
- result = Curl_gtls_client_trust_setup(cf, data, gtls);
- if(result)
- return result;
- }
if(ssl_config->key_passwd) {
const unsigned int supported_key_encryption_algorithms =
GNUTLS_PKCS_USE_PKCS12_3DES | GNUTLS_PKCS_USE_PKCS12_ARCFOUR |
@@ -943,10 +620,10 @@ static CURLcode gtls_client_init(struct Curl_cfilter *cf,
GNUTLS_PKCS_USE_PBES2_AES_128 | GNUTLS_PKCS_USE_PBES2_AES_192 |
GNUTLS_PKCS_USE_PBES2_AES_256;
rc = gnutls_certificate_set_x509_key_file2(
- gtls->shared_creds->creds,
+ gtls->cred,
config->clientcert,
ssl_config->key ? ssl_config->key : config->clientcert,
- gnutls_do_file_type(ssl_config->cert_type),
+ do_file_type(ssl_config->cert_type),
ssl_config->key_passwd,
supported_key_encryption_algorithms);
if(rc != GNUTLS_E_SUCCESS) {
@@ -958,10 +635,10 @@ static CURLcode gtls_client_init(struct Curl_cfilter *cf,
}
else {
if(gnutls_certificate_set_x509_key_file(
- gtls->shared_creds->creds,
+ gtls->cred,
config->clientcert,
ssl_config->key ? ssl_config->key : config->clientcert,
- gnutls_do_file_type(ssl_config->cert_type) ) !=
+ do_file_type(ssl_config->cert_type) ) !=
GNUTLS_E_SUCCESS) {
failf(data, "error reading X.509 key or certificate file");
return CURLE_SSL_CONNECT_ERROR;
@@ -983,7 +660,7 @@ static CURLcode gtls_client_init(struct Curl_cfilter *cf,
#endif
{
rc = gnutls_credentials_set(gtls->session, GNUTLS_CRD_CERTIFICATE,
- gtls->shared_creds->creds);
+ gtls->cred);
if(rc != GNUTLS_E_SUCCESS) {
failf(data, "gnutls_credentials_set() failed: %s", gnutls_strerror(rc));
return CURLE_SSL_CONNECT_ERROR;
@@ -1002,136 +679,65 @@ static CURLcode gtls_client_init(struct Curl_cfilter *cf,
return CURLE_OK;
}
-static int keylog_callback(gnutls_session_t session, const char *label,
- const gnutls_datum_t *secret)
-{
- gnutls_datum_t crandom;
- gnutls_datum_t srandom;
-
- gnutls_session_get_random(session, &crandom, &srandom);
- if(crandom.size != 32) {
- return -1;
- }
-
- Curl_tls_keylog_write(label, crandom.data, secret->data, secret->size);
- return 0;
-}
-
-CURLcode Curl_gtls_ctx_init(struct gtls_ctx *gctx,
- struct Curl_cfilter *cf,
- struct Curl_easy *data,
- struct ssl_peer *peer,
- const unsigned char *alpn, size_t alpn_len,
- Curl_gtls_ctx_setup_cb *cb_setup,
- void *cb_user_data,
- void *ssl_user_data)
+static CURLcode
+gtls_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
{
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct gtls_ssl_backend_data *backend =
+ (struct gtls_ssl_backend_data *)connssl->backend;
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+ struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
+ long * const pverifyresult = &ssl_config->certverifyresult;
CURLcode result;
- DEBUGASSERT(gctx);
+ DEBUGASSERT(backend);
+
+ if(connssl->state == ssl_connection_complete)
+ /* to make us tolerant against being called more than once for the
+ same connection */
+ return CURLE_OK;
- result = gtls_client_init(cf, data, peer, gctx);
+ result = gtls_client_init(data, conn_config, ssl_config,
+ &connssl->peer,
+ &backend->gtls, pverifyresult);
if(result)
return result;
- gnutls_session_set_ptr(gctx->session, ssl_user_data);
-
- if(cb_setup) {
- result = cb_setup(cf, data, cb_user_data);
- if(result)
- return result;
- }
-
- /* Open the file if a TLS or QUIC backend has not done this before. */
- Curl_tls_keylog_open();
- if(Curl_tls_keylog_enabled()) {
- gnutls_session_set_keylog_function(gctx->session, keylog_callback);
- }
+ if(connssl->alpn) {
+ struct alpn_proto_buf proto;
+ gnutls_datum_t alpn[ALPN_ENTRIES_MAX];
+ size_t i;
- /* convert the ALPN string from our arguments to a list of strings
- * that gnutls wants and will convert internally back to this very
- * string for sending to the server. nice. */
- if(alpn && alpn_len) {
- gnutls_datum_t alpns[5];
- size_t i, alen = alpn_len;
- unsigned char *s = (unsigned char *)alpn;
- unsigned char slen;
- for(i = 0; (i < ARRAYSIZE(alpns)) && alen; ++i) {
- slen = s[0];
- if(slen >= alen)
- return CURLE_FAILED_INIT;
- alpns[i].data = s + 1;
- alpns[i].size = slen;
- s += slen + 1;
- alen -= (size_t)slen + 1;
+ for(i = 0; i < connssl->alpn->count; ++i) {
+ alpn[i].data = (unsigned char *)connssl->alpn->entries[i];
+ alpn[i].size = (unsigned)strlen(connssl->alpn->entries[i]);
}
- if(alen) /* not all alpn chars used, wrong format or too many */
- return CURLE_FAILED_INIT;
- if(i && gnutls_alpn_set_protocols(gctx->session,
- alpns, (unsigned int)i,
- GNUTLS_ALPN_MANDATORY)) {
+ if(gnutls_alpn_set_protocols(backend->gtls.session, alpn,
+ (unsigned)connssl->alpn->count, 0)) {
failf(data, "failed setting ALPN");
return CURLE_SSL_CONNECT_ERROR;
}
+ Curl_alpn_to_proto_str(&proto, connssl->alpn);
+ infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data);
}
/* This might be a reconnect, so we check for a session ID in the cache
to speed up things */
- if(conn_config->cache_session) {
+ if(conn_config->sessionid) {
void *ssl_sessionid;
size_t ssl_idsize;
Curl_ssl_sessionid_lock(data);
- if(!Curl_ssl_getsessionid(cf, data, peer, &ssl_sessionid, &ssl_idsize)) {
+ if(!Curl_ssl_getsessionid(cf, data, &ssl_sessionid, &ssl_idsize)) {
/* we got a session id, use it! */
- int rc;
+ gnutls_session_set_data(backend->gtls.session,
+ ssl_sessionid, ssl_idsize);
- rc = gnutls_session_set_data(gctx->session, ssl_sessionid, ssl_idsize);
- if(rc < 0)
- infof(data, "SSL failed to set session ID");
- else
- infof(data, "SSL reusing session ID (size=%zu)", ssl_idsize);
+ /* Informational message */
+ infof(data, "SSL reusing session ID");
}
Curl_ssl_sessionid_unlock(data);
}
- return CURLE_OK;
-}
-
-static CURLcode
-gtls_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
-{
- struct ssl_connect_data *connssl = cf->ctx;
- struct gtls_ssl_backend_data *backend =
- (struct gtls_ssl_backend_data *)connssl->backend;
- struct alpn_proto_buf proto;
- CURLcode result;
-
- DEBUGASSERT(backend);
- DEBUGASSERT(ssl_connect_1 == connssl->connecting_state);
-
- if(connssl->state == ssl_connection_complete)
- /* to make us tolerant against being called more than once for the
- same connection */
- return CURLE_OK;
-
- memset(&proto, 0, sizeof(proto));
- if(connssl->alpn) {
- result = Curl_alpn_to_proto_buf(&proto, connssl->alpn);
- if(result) {
- failf(data, "Error determining ALPN");
- return CURLE_SSL_CONNECT_ERROR;
- }
- }
-
- result = Curl_gtls_ctx_init(&backend->gtls, cf, data, &connssl->peer,
- proto.data, proto.len, NULL, NULL, cf);
- if(result)
- return result;
-
- gnutls_handshake_set_hook_function(backend->gtls.session,
- GNUTLS_HANDSHAKE_ANY, GNUTLS_HOOK_POST,
- gtls_handshake_cb);
/* register callback functions and handle to send and receive data. */
gnutls_transport_set_ptr(backend->gtls.session, cf);
@@ -1154,7 +760,7 @@ static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data,
/* Result is returned to caller */
CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
- /* if a path was not specified, do not pin */
+ /* if a path wasn't specified, don't pin */
if(!pinnedpubkey)
return CURLE_OK;
@@ -1216,17 +822,16 @@ Curl_gtls_verifyserver(struct Curl_easy *data,
char certname[65] = ""; /* limited to 64 chars by ASN.1 */
size_t size;
time_t certclock;
+ const char *ptr;
int rc;
CURLcode result = CURLE_OK;
#ifndef CURL_DISABLE_VERBOSE_STRINGS
- const char *ptr;
- int algo;
+ unsigned int algo;
unsigned int bits;
gnutls_protocol_t version = gnutls_protocol_get_version(session);
#endif
long * const certverifyresult = &ssl_config->certverifyresult;
-#ifndef CURL_DISABLE_VERBOSE_STRINGS
/* the name of the cipher suite used, e.g. ECDHE_RSA_AES_256_GCM_SHA384. */
ptr = gnutls_cipher_suite_get_name(gnutls_kx_get(session),
gnutls_cipher_get(session),
@@ -1234,7 +839,6 @@ Curl_gtls_verifyserver(struct Curl_easy *data,
infof(data, "SSL connection using %s / %s",
gnutls_protocol_get_name(version), ptr);
-#endif
/* This function will return the peer's raw certificate (chain) as sent by
the peer. These certificates are in raw format (DER encoded for
@@ -1262,13 +866,13 @@ Curl_gtls_verifyserver(struct Curl_easy *data,
}
#endif
}
- infof(data, " common name: WARNING could not obtain");
+ infof(data, " common name: WARNING couldn't obtain");
}
if(data->set.ssl.certinfo && chainp) {
unsigned int i;
- result = Curl_ssl_init_certinfo(data, (int)cert_list_size);
+ result = Curl_ssl_init_certinfo(data, cert_list_size);
if(result)
return result;
@@ -1276,7 +880,7 @@ Curl_gtls_verifyserver(struct Curl_easy *data,
const char *beg = (const char *) chainp[i].data;
const char *end = beg + chainp[i].size;
- result = Curl_extract_certinfo(data, (int)i, beg, end);
+ result = Curl_extract_certinfo(data, i, beg, end);
if(result)
return result;
}
@@ -1302,18 +906,9 @@ Curl_gtls_verifyserver(struct Curl_easy *data,
/* verify_status is a bitmask of gnutls_certificate_status bits */
if(verify_status & GNUTLS_CERT_INVALID) {
if(config->verifypeer) {
- const char *cause = "certificate error, no details available";
- if(verify_status & GNUTLS_CERT_EXPIRED)
- cause = "certificate has expired";
- else if(verify_status & GNUTLS_CERT_SIGNER_NOT_FOUND)
- cause = "certificate signer not trusted";
- else if(verify_status & GNUTLS_CERT_INSECURE_ALGORITHM)
- cause = "certificate uses insecure algorithm";
- else if(verify_status & GNUTLS_CERT_INVALID_OCSP_STATUS)
- cause = "attached OCSP status response is invalid";
- failf(data, "server verification failed: %s. (CAfile: %s "
- "CRLfile: %s)", cause,
- config->CAfile ? config->CAfile: "none",
+ failf(data, "server certificate verification failed. CAfile: %s "
+ "CRLfile: %s", config->CAfile ? config->CAfile:
+ "none",
ssl_config->primary.CRLfile ?
ssl_config->primary.CRLfile : "none");
return CURLE_PEER_FAILED_VERIFICATION;
@@ -1328,97 +923,104 @@ Curl_gtls_verifyserver(struct Curl_easy *data,
infof(data, " server certificate verification SKIPPED");
if(config->verifystatus) {
- gnutls_datum_t status_request;
- gnutls_ocsp_resp_t ocsp_resp;
- gnutls_ocsp_cert_status_t status;
- gnutls_x509_crl_reason_t reason;
+ if(gnutls_ocsp_status_request_is_checked(session, 0) == 0) {
+ gnutls_datum_t status_request;
+ gnutls_ocsp_resp_t ocsp_resp;
- rc = gnutls_ocsp_status_request_get(session, &status_request);
+ gnutls_ocsp_cert_status_t status;
+ gnutls_x509_crl_reason_t reason;
- if(rc == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
- failf(data, "No OCSP response received");
- return CURLE_SSL_INVALIDCERTSTATUS;
- }
+ rc = gnutls_ocsp_status_request_get(session, &status_request);
- if(rc < 0) {
- failf(data, "Invalid OCSP response received");
- return CURLE_SSL_INVALIDCERTSTATUS;
- }
+ infof(data, " server certificate status verification FAILED");
- gnutls_ocsp_resp_init(&ocsp_resp);
+ if(rc == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
+ failf(data, "No OCSP response received");
+ return CURLE_SSL_INVALIDCERTSTATUS;
+ }
- rc = gnutls_ocsp_resp_import(ocsp_resp, &status_request);
- if(rc < 0) {
- failf(data, "Invalid OCSP response received");
- return CURLE_SSL_INVALIDCERTSTATUS;
- }
+ if(rc < 0) {
+ failf(data, "Invalid OCSP response received");
+ return CURLE_SSL_INVALIDCERTSTATUS;
+ }
- (void)gnutls_ocsp_resp_get_single(ocsp_resp, 0, NULL, NULL, NULL, NULL,
- &status, NULL, NULL, NULL, &reason);
+ gnutls_ocsp_resp_init(&ocsp_resp);
- switch(status) {
- case GNUTLS_OCSP_CERT_GOOD:
- break;
+ rc = gnutls_ocsp_resp_import(ocsp_resp, &status_request);
+ if(rc < 0) {
+ failf(data, "Invalid OCSP response received");
+ return CURLE_SSL_INVALIDCERTSTATUS;
+ }
- case GNUTLS_OCSP_CERT_REVOKED: {
- const char *crl_reason;
+ (void)gnutls_ocsp_resp_get_single(ocsp_resp, 0, NULL, NULL, NULL, NULL,
+ &status, NULL, NULL, NULL, &reason);
- switch(reason) {
- default:
- case GNUTLS_X509_CRLREASON_UNSPECIFIED:
- crl_reason = "unspecified reason";
+ switch(status) {
+ case GNUTLS_OCSP_CERT_GOOD:
break;
- case GNUTLS_X509_CRLREASON_KEYCOMPROMISE:
- crl_reason = "private key compromised";
- break;
+ case GNUTLS_OCSP_CERT_REVOKED: {
+ const char *crl_reason;
- case GNUTLS_X509_CRLREASON_CACOMPROMISE:
- crl_reason = "CA compromised";
- break;
+ switch(reason) {
+ default:
+ case GNUTLS_X509_CRLREASON_UNSPECIFIED:
+ crl_reason = "unspecified reason";
+ break;
- case GNUTLS_X509_CRLREASON_AFFILIATIONCHANGED:
- crl_reason = "affiliation has changed";
- break;
+ case GNUTLS_X509_CRLREASON_KEYCOMPROMISE:
+ crl_reason = "private key compromised";
+ break;
- case GNUTLS_X509_CRLREASON_SUPERSEDED:
- crl_reason = "certificate superseded";
- break;
+ case GNUTLS_X509_CRLREASON_CACOMPROMISE:
+ crl_reason = "CA compromised";
+ break;
- case GNUTLS_X509_CRLREASON_CESSATIONOFOPERATION:
- crl_reason = "operation has ceased";
- break;
+ case GNUTLS_X509_CRLREASON_AFFILIATIONCHANGED:
+ crl_reason = "affiliation has changed";
+ break;
- case GNUTLS_X509_CRLREASON_CERTIFICATEHOLD:
- crl_reason = "certificate is on hold";
- break;
+ case GNUTLS_X509_CRLREASON_SUPERSEDED:
+ crl_reason = "certificate superseded";
+ break;
- case GNUTLS_X509_CRLREASON_REMOVEFROMCRL:
- crl_reason = "will be removed from delta CRL";
- break;
+ case GNUTLS_X509_CRLREASON_CESSATIONOFOPERATION:
+ crl_reason = "operation has ceased";
+ break;
- case GNUTLS_X509_CRLREASON_PRIVILEGEWITHDRAWN:
- crl_reason = "privilege withdrawn";
- break;
+ case GNUTLS_X509_CRLREASON_CERTIFICATEHOLD:
+ crl_reason = "certificate is on hold";
+ break;
+
+ case GNUTLS_X509_CRLREASON_REMOVEFROMCRL:
+ crl_reason = "will be removed from delta CRL";
+ break;
- case GNUTLS_X509_CRLREASON_AACOMPROMISE:
- crl_reason = "AA compromised";
+ case GNUTLS_X509_CRLREASON_PRIVILEGEWITHDRAWN:
+ crl_reason = "privilege withdrawn";
+ break;
+
+ case GNUTLS_X509_CRLREASON_AACOMPROMISE:
+ crl_reason = "AA compromised";
+ break;
+ }
+
+ failf(data, "Server certificate was revoked: %s", crl_reason);
break;
}
- failf(data, "Server certificate was revoked: %s", crl_reason);
- break;
- }
+ default:
+ case GNUTLS_OCSP_CERT_UNKNOWN:
+ failf(data, "Server certificate status is unknown");
+ break;
+ }
- default:
- case GNUTLS_OCSP_CERT_UNKNOWN:
- failf(data, "Server certificate status is unknown");
- break;
- }
+ gnutls_ocsp_resp_deinit(ocsp_resp);
- gnutls_ocsp_resp_deinit(ocsp_resp);
- if(status != GNUTLS_OCSP_CERT_GOOD)
return CURLE_SSL_INVALIDCERTSTATUS;
+ }
+ else
+ infof(data, " server certificate status verification OK");
}
else
infof(data, " server certificate status verification SKIPPED");
@@ -1435,7 +1037,7 @@ Curl_gtls_verifyserver(struct Curl_easy *data,
gnutls_x509_crt_init(&x509_issuer);
issuerp = load_file(config->issuercert);
gnutls_x509_crt_import(x509_issuer, &issuerp, GNUTLS_X509_FMT_PEM);
- rc = (int)gnutls_x509_crt_check_issuer(x509_cert, x509_issuer);
+ rc = gnutls_x509_crt_check_issuer(x509_cert, x509_issuer);
gnutls_x509_crt_deinit(x509_issuer);
unload_file(issuerp);
if(rc <= 0) {
@@ -1464,18 +1066,12 @@ Curl_gtls_verifyserver(struct Curl_easy *data,
in RFC2818 (HTTPS), which takes into account wildcards, and the subject
alternative name PKIX extension. Returns non zero on success, and zero on
failure. */
-
- /* This function does not handle trailing dots, so if we have an SNI name
- use that and fallback to the hostname only if there is no SNI (like for
- IP addresses) */
- rc = (int)gnutls_x509_crt_check_hostname(x509_cert,
- peer->sni ? peer->sni :
- peer->hostname);
+ rc = gnutls_x509_crt_check_hostname(x509_cert, peer->hostname);
#if GNUTLS_VERSION_NUMBER < 0x030306
- /* Before 3.3.6, gnutls_x509_crt_check_hostname() did not check IP
+ /* Before 3.3.6, gnutls_x509_crt_check_hostname() didn't check IP
addresses. */
if(!rc) {
-#ifdef USE_IPV6
+#ifdef ENABLE_IPV6
#define use_addr in6_addr
#else
#define use_addr in_addr
@@ -1485,7 +1081,7 @@ Curl_gtls_verifyserver(struct Curl_easy *data,
if(Curl_inet_pton(AF_INET, peer->hostname, addrbuf) > 0)
addrlen = 4;
-#ifdef USE_IPV6
+#ifdef ENABLE_IPV6
else if(Curl_inet_pton(AF_INET6, peer->hostname, addrbuf) > 0)
addrlen = 16;
#endif
@@ -1498,7 +1094,7 @@ Curl_gtls_verifyserver(struct Curl_easy *data,
size_t certaddrlen = sizeof(certaddr);
int ret = gnutls_x509_crt_get_subject_alt_name(x509_cert, i, certaddr,
&certaddrlen, NULL);
- /* If this happens, it was not an IP address. */
+ /* If this happens, it wasn't an IP address. */
if(ret == GNUTLS_E_SHORT_MEMORY_BUFFER)
continue;
if(ret < 0)
@@ -1516,7 +1112,7 @@ Curl_gtls_verifyserver(struct Curl_easy *data,
if(!rc) {
if(config->verifyhost) {
failf(data, "SSL: certificate subject name (%s) does not match "
- "target hostname '%s'", certname, peer->dispname);
+ "target host name '%s'", certname, peer->dispname);
gnutls_x509_crt_deinit(x509_cert);
return CURLE_PEER_FAILED_VERIFICATION;
}
@@ -1605,7 +1201,7 @@ Curl_gtls_verifyserver(struct Curl_easy *data,
/* public key algorithm's parameters */
algo = gnutls_x509_crt_get_pk_algorithm(x509_cert, &bits);
infof(data, " certificate public key: %s",
- gnutls_pk_algorithm_get_name((gnutls_pk_algorithm_t)algo));
+ gnutls_pk_algorithm_get_name(algo));
/* version of the X.509 certificate. */
infof(data, " certificate version: #%d",
@@ -1649,13 +1245,9 @@ static CURLcode gtls_verifyserver(struct Curl_cfilter *cf,
struct ssl_connect_data *connssl = cf->ctx;
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
-#ifndef CURL_DISABLE_PROXY
const char *pinned_key = Curl_ssl_cf_is_proxy(cf)?
data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]:
data->set.str[STRING_SSL_PINNEDPUBLICKEY];
-#else
- const char *pinned_key = data->set.str[STRING_SSL_PINNEDPUBLICKEY];
-#endif
CURLcode result;
result = Curl_gtls_verifyserver(data, session, conn_config, ssl_config,
@@ -1674,10 +1266,47 @@ static CURLcode gtls_verifyserver(struct Curl_cfilter *cf,
Curl_alpn_set_negotiated(cf, data, NULL, 0);
}
- /* Only on TLSv1.2 or lower do we have the session id now. For
- * TLSv1.3 we get it via a SESSION_TICKET message that arrives later. */
- if(gnutls_protocol_get_version(session) < GNUTLS_TLS1_3)
- result = gtls_update_session_id(cf, data, session);
+ if(ssl_config->primary.sessionid) {
+ /* we always unconditionally get the session id here, as even if we
+ already got it from the cache and asked to use it in the connection, it
+ might've been rejected and then a new one is in use now and we need to
+ detect that. */
+ void *connect_sessionid;
+ size_t connect_idsize = 0;
+
+ /* get the session ID data size */
+ gnutls_session_get_data(session, NULL, &connect_idsize);
+ connect_sessionid = malloc(connect_idsize); /* get a buffer for it */
+
+ if(connect_sessionid) {
+ bool incache;
+ bool added = FALSE;
+ void *ssl_sessionid;
+
+ /* extract session ID to the allocated buffer */
+ gnutls_session_get_data(session, connect_sessionid, &connect_idsize);
+
+ Curl_ssl_sessionid_lock(data);
+ incache = !(Curl_ssl_getsessionid(cf, data, &ssl_sessionid, NULL));
+ if(incache) {
+ /* there was one before in the cache, so instead of risking that the
+ previous one was rejected, we just kill that and store the new */
+ Curl_ssl_delsessionid(data, ssl_sessionid);
+ }
+
+ /* store this session id */
+ result = Curl_ssl_addsessionid(cf, data, connect_sessionid,
+ connect_idsize, &added);
+ Curl_ssl_sessionid_unlock(data);
+ if(!added)
+ free(connect_sessionid);
+ if(result) {
+ result = CURLE_OUT_OF_MEMORY;
+ }
+ }
+ else
+ result = CURLE_OUT_OF_MEMORY;
+ }
out:
return result;
@@ -1689,8 +1318,8 @@ out:
*/
/* We use connssl->connecting_state to keep track of the connection status;
there are three states: 'ssl_connect_1' (not started yet or complete),
- 'ssl_connect_2' (doing handshake with the server), and
- 'ssl_connect_3' (verifying and getting stats).
+ 'ssl_connect_2_reading' (waiting for data from server), and
+ 'ssl_connect_2_writing' (waiting to be able to write).
*/
static CURLcode
gtls_connect_common(struct Curl_cfilter *cf,
@@ -1699,7 +1328,7 @@ gtls_connect_common(struct Curl_cfilter *cf,
bool *done)
{
struct ssl_connect_data *connssl = cf->ctx;
- CURLcode rc;
+ int rc;
CURLcode result = CURLE_OK;
/* Initiate the connection, if not already done */
@@ -1778,146 +1407,142 @@ static bool gtls_data_pending(struct Curl_cfilter *cf,
static ssize_t gtls_send(struct Curl_cfilter *cf,
struct Curl_easy *data,
- const void *buf,
- size_t blen,
+ const void *mem,
+ size_t len,
CURLcode *curlcode)
{
struct ssl_connect_data *connssl = cf->ctx;
struct gtls_ssl_backend_data *backend =
(struct gtls_ssl_backend_data *)connssl->backend;
ssize_t rc;
- size_t nwritten, total_written = 0;
(void)data;
DEBUGASSERT(backend);
- while(blen) {
- backend->gtls.io_result = CURLE_OK;
- rc = gnutls_record_send(backend->gtls.session, buf, blen);
+ rc = gnutls_record_send(backend->gtls.session, mem, len);
- if(rc < 0) {
- if(total_written && (rc == GNUTLS_E_AGAIN)) {
- *curlcode = CURLE_OK;
- rc = (ssize_t)total_written;
- goto out;
- }
- *curlcode = (rc == GNUTLS_E_AGAIN)?
- CURLE_AGAIN :
- (backend->gtls.io_result? backend->gtls.io_result : CURLE_SEND_ERROR);
+ if(rc < 0) {
+ *curlcode = (rc == GNUTLS_E_AGAIN)
+ ? CURLE_AGAIN
+ : CURLE_SEND_ERROR;
- rc = -1;
- goto out;
- }
- nwritten = (size_t)rc;
- total_written += nwritten;
- DEBUGASSERT(nwritten <= blen);
- buf = (char *)buf + nwritten;
- blen -= nwritten;
+ rc = -1;
}
- rc = total_written;
-out:
return rc;
}
-/*
- * This function is called to shut down the SSL layer but keep the
- * socket open (CCC - Clear Command Channel)
- */
-static CURLcode gtls_shutdown(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- bool send_shutdown, bool *done)
+static void gtls_close(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
struct ssl_connect_data *connssl = cf->ctx;
struct gtls_ssl_backend_data *backend =
(struct gtls_ssl_backend_data *)connssl->backend;
- char buf[1024];
- CURLcode result = CURLE_OK;
- ssize_t nread;
- size_t i;
+ (void) data;
DEBUGASSERT(backend);
- if(!backend->gtls.session || cf->shutdown) {
- *done = TRUE;
- goto out;
- }
-
- connssl->io_need = CURL_SSL_IO_NEED_NONE;
- *done = FALSE;
-
- if(!backend->gtls.sent_shutdown) {
- /* do this only once */
- backend->gtls.sent_shutdown = TRUE;
- if(send_shutdown) {
- int ret = gnutls_bye(backend->gtls.session, GNUTLS_SHUT_RDWR);
- if((ret == GNUTLS_E_AGAIN) || (ret == GNUTLS_E_INTERRUPTED)) {
- CURL_TRC_CF(data, cf, "SSL shutdown, gnutls_bye EAGAIN");
- connssl->io_need = gnutls_record_get_direction(backend->gtls.session)?
- CURL_SSL_IO_NEED_SEND : CURL_SSL_IO_NEED_RECV;
- backend->gtls.sent_shutdown = FALSE;
- result = CURLE_OK;
- goto out;
- }
- if(ret != GNUTLS_E_SUCCESS) {
- CURL_TRC_CF(data, cf, "SSL shutdown, gnutls_bye error: '%s'(%d)",
- gnutls_strerror((int)ret), (int)ret);
- result = CURLE_RECV_ERROR;
- goto out;
- }
- }
- }
- /* SSL should now have started the shutdown from our side. Since it
- * was not complete, we are lacking the close notify from the server. */
- for(i = 0; i < 10; ++i) {
- nread = gnutls_record_recv(backend->gtls.session, buf, sizeof(buf));
- if(nread <= 0)
- break;
- }
- if(nread > 0) {
- /* still data coming in? */
- }
- else if(nread == 0) {
- /* We got the close notify alert and are done. */
- *done = TRUE;
+ if(backend->gtls.session) {
+ char buf[32];
+ /* Maybe the server has already sent a close notify alert.
+ Read it to avoid an RST on the TCP connection. */
+ (void)gnutls_record_recv(backend->gtls.session, buf, sizeof(buf));
+ gnutls_bye(backend->gtls.session, GNUTLS_SHUT_WR);
+ gnutls_deinit(backend->gtls.session);
+ backend->gtls.session = NULL;
}
- else if((nread == GNUTLS_E_AGAIN) || (nread == GNUTLS_E_INTERRUPTED)) {
- connssl->io_need = gnutls_record_get_direction(backend->gtls.session)?
- CURL_SSL_IO_NEED_SEND : CURL_SSL_IO_NEED_RECV;
+ if(backend->gtls.cred) {
+ gnutls_certificate_free_credentials(backend->gtls.cred);
+ backend->gtls.cred = NULL;
}
- else {
- CURL_TRC_CF(data, cf, "SSL shutdown, error: '%s'(%d)",
- gnutls_strerror((int)nread), (int)nread);
- result = CURLE_RECV_ERROR;
+#ifdef USE_GNUTLS_SRP
+ if(backend->gtls.srp_client_cred) {
+ gnutls_srp_free_client_credentials(backend->gtls.srp_client_cred);
+ backend->gtls.srp_client_cred = NULL;
}
-
-out:
- cf->shutdown = (result || *done);
- return result;
+#endif
}
-static void gtls_close(struct Curl_cfilter *cf,
- struct Curl_easy *data)
+/*
+ * This function is called to shut down the SSL layer but keep the
+ * socket open (CCC - Clear Command Channel)
+ */
+static int gtls_shutdown(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
struct ssl_connect_data *connssl = cf->ctx;
struct gtls_ssl_backend_data *backend =
(struct gtls_ssl_backend_data *)connssl->backend;
+ int retval = 0;
- (void) data;
DEBUGASSERT(backend);
- CURL_TRC_CF(data, cf, "close");
+
+#ifndef CURL_DISABLE_FTP
+ /* This has only been tested on the proftpd server, and the mod_tls code
+ sends a close notify alert without waiting for a close notify alert in
+ response. Thus we wait for a close notify alert from the server, but
+ we do not send one. Let's hope other servers do the same... */
+
+ if(data->set.ftp_ccc == CURLFTPSSL_CCC_ACTIVE)
+ gnutls_bye(backend->gtls.session, GNUTLS_SHUT_WR);
+#endif
+
if(backend->gtls.session) {
+ ssize_t result;
+ bool done = FALSE;
+ char buf[120];
+
+ while(!done) {
+ int what = SOCKET_READABLE(Curl_conn_cf_get_socket(cf, data),
+ SSL_SHUTDOWN_TIMEOUT);
+ if(what > 0) {
+ /* Something to read, let's do it and hope that it is the close
+ notify alert from the server */
+ result = gnutls_record_recv(backend->gtls.session,
+ buf, sizeof(buf));
+ switch(result) {
+ case 0:
+ /* This is the expected response. There was no data but only
+ the close notify alert */
+ done = TRUE;
+ break;
+ case GNUTLS_E_AGAIN:
+ case GNUTLS_E_INTERRUPTED:
+ infof(data, "GNUTLS_E_AGAIN || GNUTLS_E_INTERRUPTED");
+ break;
+ default:
+ retval = -1;
+ done = TRUE;
+ break;
+ }
+ }
+ else if(0 == what) {
+ /* timeout */
+ failf(data, "SSL shutdown timeout");
+ done = TRUE;
+ }
+ else {
+ /* anything that gets here is fatally bad */
+ failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
+ retval = -1;
+ done = TRUE;
+ }
+ }
gnutls_deinit(backend->gtls.session);
- backend->gtls.session = NULL;
- }
- if(backend->gtls.shared_creds) {
- Curl_gtls_shared_creds_free(&backend->gtls.shared_creds);
}
+ gnutls_certificate_free_credentials(backend->gtls.cred);
+
#ifdef USE_GNUTLS_SRP
- if(backend->gtls.srp_client_cred) {
- gnutls_srp_free_client_credentials(backend->gtls.srp_client_cred);
- backend->gtls.srp_client_cred = NULL;
+ {
+ struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
+ if(ssl_config->primary.username)
+ gnutls_srp_free_client_credentials(backend->gtls.srp_client_cred);
}
#endif
+
+ backend->gtls.cred = NULL;
+ backend->gtls.session = NULL;
+
+ return retval;
}
static ssize_t gtls_recv(struct Curl_cfilter *cf,
@@ -1934,7 +1559,6 @@ static ssize_t gtls_recv(struct Curl_cfilter *cf,
(void)data;
DEBUGASSERT(backend);
- backend->gtls.io_result = CURLE_OK;
ret = gnutls_record_recv(backend->gtls.session, buf, buffersize);
if((ret == GNUTLS_E_AGAIN) || (ret == GNUTLS_E_INTERRUPTED)) {
*curlcode = CURLE_AGAIN;
@@ -1959,8 +1583,7 @@ static ssize_t gtls_recv(struct Curl_cfilter *cf,
failf(data, "GnuTLS recv error (%d): %s",
(int)ret, gnutls_strerror((int)ret));
- *curlcode = backend->gtls.io_result?
- backend->gtls.io_result : CURLE_RECV_ERROR;
+ *curlcode = CURLE_RECV_ERROR;
ret = -1;
goto out;
}
@@ -1969,6 +1592,11 @@ out:
return ret;
}
+static void gtls_session_free(void *ptr)
+{
+ free(ptr);
+}
+
static size_t gtls_version(char *buffer, size_t size)
{
return msnprintf(buffer, size, "GnuTLS/%s", gnutls_check_version(NULL));
@@ -2017,8 +1645,7 @@ const struct Curl_ssl Curl_ssl_gnutls = {
SSLSUPP_CA_PATH |
SSLSUPP_CERTINFO |
SSLSUPP_PINNEDPUBKEY |
- SSLSUPP_HTTPS_PROXY |
- SSLSUPP_CA_CACHE,
+ SSLSUPP_HTTPS_PROXY,
sizeof(struct gtls_ssl_backend_data),
@@ -2036,6 +1663,7 @@ const struct Curl_ssl Curl_ssl_gnutls = {
gtls_get_internals, /* get_internals */
gtls_close, /* close_one */
Curl_none_close_all, /* close_all */
+ gtls_session_free, /* session_free */
Curl_none_set_engine, /* set_engine */
Curl_none_set_engine_default, /* set_engine_default */
Curl_none_engines_list, /* engines_list */
@@ -2043,9 +1671,9 @@ const struct Curl_ssl Curl_ssl_gnutls = {
gtls_sha256sum, /* sha256sum */
NULL, /* associate_connection */
NULL, /* disassociate_connection */
+ NULL, /* free_multi_ssl_backend_data */
gtls_recv, /* recv decrypted data */
gtls_send, /* send data to encrypt */
- NULL, /* get_channel_binding */
};
#endif /* USE_GNUTLS */
diff --git a/contrib/libs/curl/lib/vtls/gtls.h b/contrib/libs/curl/lib/vtls/gtls.h
index 659c41e860..a1e1729060 100644
--- a/contrib/libs/curl/lib/vtls/gtls.h
+++ b/contrib/libs/curl/lib/vtls/gtls.h
@@ -30,7 +30,6 @@
#ifdef USE_GNUTLS
#error #include <gnutls/gnutls.h>
-#include "timeval.h"
#ifdef HAVE_GNUTLS_SRP
/* the function exists */
@@ -46,52 +45,29 @@ struct ssl_primary_config;
struct ssl_config_data;
struct ssl_peer;
-struct gtls_shared_creds {
- gnutls_certificate_credentials_t creds;
- char *CAfile; /* CAfile path used to generate X509 store */
- struct curltime time; /* when the shared creds was created */
- size_t refcount;
- BIT(trust_setup); /* x509 anchors + CRLs have been set up */
-};
-
-CURLcode Curl_gtls_shared_creds_create(struct Curl_easy *data,
- struct gtls_shared_creds **pcreds);
-CURLcode Curl_gtls_shared_creds_up_ref(struct gtls_shared_creds *creds);
-void Curl_gtls_shared_creds_free(struct gtls_shared_creds **pcreds);
-
-struct gtls_ctx {
+struct gtls_instance {
gnutls_session_t session;
- struct gtls_shared_creds *shared_creds;
+ gnutls_certificate_credentials_t cred;
#ifdef USE_GNUTLS_SRP
gnutls_srp_client_credentials_t srp_client_cred;
#endif
- CURLcode io_result; /* result of last IO cfilter operation */
- BIT(sent_shutdown);
};
-typedef CURLcode Curl_gtls_ctx_setup_cb(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- void *user_data);
-
-CURLcode Curl_gtls_ctx_init(struct gtls_ctx *gctx,
- struct Curl_cfilter *cf,
- struct Curl_easy *data,
- struct ssl_peer *peer,
- const unsigned char *alpn, size_t alpn_len,
- Curl_gtls_ctx_setup_cb *cb_setup,
- void *cb_user_data,
- void *ssl_user_data);
-
-CURLcode Curl_gtls_client_trust_setup(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- struct gtls_ctx *gtls);
+CURLcode
+gtls_client_init(struct Curl_easy *data,
+ struct ssl_primary_config *config,
+ struct ssl_config_data *ssl_config,
+ struct ssl_peer *peer,
+ struct gtls_instance *gtls,
+ long *pverifyresult);
-CURLcode Curl_gtls_verifyserver(struct Curl_easy *data,
- gnutls_session_t session,
- struct ssl_primary_config *config,
- struct ssl_config_data *ssl_config,
- struct ssl_peer *peer,
- const char *pinned_key);
+CURLcode
+Curl_gtls_verifyserver(struct Curl_easy *data,
+ gnutls_session_t session,
+ struct ssl_primary_config *config,
+ struct ssl_config_data *ssl_config,
+ struct ssl_peer *peer,
+ const char *pinned_key);
extern const struct Curl_ssl Curl_ssl_gnutls;
diff --git a/contrib/libs/curl/lib/vtls/hostcheck.c b/contrib/libs/curl/lib/vtls/hostcheck.c
index ba2569d5c0..64f120f944 100644
--- a/contrib/libs/curl/lib/vtls/hostcheck.c
+++ b/contrib/libs/curl/lib/vtls/hostcheck.c
@@ -62,7 +62,7 @@ static bool pmatch(const char *hostname, size_t hostlen,
* We use the matching rule described in RFC6125, section 6.4.3.
* https://datatracker.ietf.org/doc/html/rfc6125#section-6.4.3
*
- * In addition: ignore trailing dots in the hostnames and wildcards, so that
+ * In addition: ignore trailing dots in the host names and wildcards, so that
* the names are used normalized. This is what the browsers do.
*
* Do not allow wildcard matching on IP numbers. There are apparently
diff --git a/contrib/libs/curl/lib/vtls/hostcheck.h b/contrib/libs/curl/lib/vtls/hostcheck.h
index 6b4e379644..22a1ac2e56 100644
--- a/contrib/libs/curl/lib/vtls/hostcheck.h
+++ b/contrib/libs/curl/lib/vtls/hostcheck.h
@@ -26,7 +26,7 @@
#include <curl/curl.h>
-/* returns TRUE if there is a match */
+/* returns TRUE if there's a match */
bool Curl_cert_hostcheck(const char *match_pattern, size_t matchlen,
const char *hostname, size_t hostlen);
diff --git a/contrib/libs/curl/lib/vtls/keylog.c b/contrib/libs/curl/lib/vtls/keylog.c
index ab7baaaeca..fbcb25cfb6 100644
--- a/contrib/libs/curl/lib/vtls/keylog.c
+++ b/contrib/libs/curl/lib/vtls/keylog.c
@@ -24,7 +24,6 @@
#include "curl_setup.h"
#if defined(USE_OPENSSL) || \
- defined(USE_GNUTLS) || \
defined(USE_WOLFSSL) || \
(defined(USE_NGTCP2) && defined(USE_NGHTTP3)) || \
defined(USE_QUICHE)
diff --git a/contrib/libs/curl/lib/vtls/mbedtls.c b/contrib/libs/curl/lib/vtls/mbedtls.c
index cc3fc1708c..fabf6a8d21 100644
--- a/contrib/libs/curl/lib/vtls/mbedtls.c
+++ b/contrib/libs/curl/lib/vtls/mbedtls.c
@@ -36,13 +36,6 @@
/* Define this to enable lots of debugging for mbedTLS */
/* #define MBEDTLS_DEBUG */
-#ifdef __GNUC__
-#pragma GCC diagnostic push
-/* mbedTLS (as of v3.5.1) has a duplicate function declaration
- in its public headers. Disable the warning that detects it. */
-#pragma GCC diagnostic ignored "-Wredundant-decls"
-#endif
-
#error #include <mbedtls/version.h>
#if MBEDTLS_VERSION_NUMBER >= 0x02040000
#error #include <mbedtls/net_sockets.h>
@@ -63,25 +56,17 @@
# endif
#endif
-#ifdef __GNUC__
-#pragma GCC diagnostic pop
-#endif
-
-#error #include "cipher_suite.h"
-#include "strcase.h"
#include "urldata.h"
#include "sendf.h"
#include "inet_pton.h"
#include "mbedtls.h"
#include "vtls.h"
#include "vtls_int.h"
-#error #include "x509asn1.h"
#include "parsedate.h"
#include "connect.h" /* for the connect timeout */
#include "select.h"
#include "multiif.h"
#error #include "mbedtls_threadlock.h"
-#include "strdup.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@@ -110,14 +95,10 @@ struct mbed_ssl_backend_data {
#ifdef HAS_ALPN
const char *protocols[3];
#endif
- int *ciphersuites;
- BIT(initialized); /* mbedtls_ssl_context is initialized */
- BIT(sent_shutdown);
};
/* apply threading? */
-#if (defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H)) || \
- defined(_WIN32)
+#if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32)
#define THREADING_SUPPORT
#endif
@@ -125,15 +106,12 @@ struct mbed_ssl_backend_data {
#define mbedtls_strerror(a,b,c) b[0] = 0
#endif
-#if defined(MBEDTLS_SSL_PROTO_TLS1_3) && MBEDTLS_VERSION_NUMBER >= 0x03060000
-#define TLS13_SUPPORT
-#endif
-
#if defined(THREADING_SUPPORT)
static mbedtls_entropy_context ts_entropy;
static int entropy_init_initialized = 0;
+/* start of entropy_init_mutex() */
static void entropy_init_mutex(mbedtls_entropy_context *ctx)
{
/* lock 0 = entropy_init_mutex() */
@@ -144,18 +122,9 @@ static void entropy_init_mutex(mbedtls_entropy_context *ctx)
}
Curl_mbedtlsthreadlock_unlock_function(0);
}
+/* end of entropy_init_mutex() */
-static void entropy_cleanup_mutex(mbedtls_entropy_context *ctx)
-{
- /* lock 0 = use same lock as init */
- Curl_mbedtlsthreadlock_lock_function(0);
- if(entropy_init_initialized == 1) {
- mbedtls_entropy_free(ctx);
- entropy_init_initialized = 0;
- }
- Curl_mbedtlsthreadlock_unlock_function(0);
-}
-
+/* start of entropy_func_mutex() */
static int entropy_func_mutex(void *data, unsigned char *output, size_t len)
{
int ret;
@@ -166,6 +135,7 @@ static int entropy_func_mutex(void *data, unsigned char *output, size_t len)
return ret;
}
+/* end of entropy_func_mutex() */
#endif /* THREADING_SUPPORT */
@@ -173,19 +143,17 @@ static int entropy_func_mutex(void *data, unsigned char *output, size_t len)
static void mbed_debug(void *context, int level, const char *f_name,
int line_nb, const char *line)
{
- struct Curl_easy *data = (struct Curl_easy *)context;
+ struct Curl_easy *data = NULL;
+
+ if(!context)
+ return;
+
+ data = (struct Curl_easy *)context;
+
+ infof(data, "%s", line);
(void) level;
- (void) line_nb;
- (void) f_name;
-
- if(data) {
- size_t len = strlen(line);
- if(len && (line[len - 1] == '\n'))
- /* discount any trailing newline */
- len--;
- infof(data, "%.*s", (int)len, line);
- }
}
+#else
#endif
static int mbedtls_bio_cf_write(void *bio,
@@ -197,11 +165,7 @@ static int mbedtls_bio_cf_write(void *bio,
CURLcode result;
DEBUGASSERT(data);
- if(!data)
- return 0;
-
- nwritten = Curl_conn_cf_send(cf->next, data, (char *)buf, blen, FALSE,
- &result);
+ nwritten = Curl_conn_cf_send(cf->next, data, (char *)buf, blen, &result);
CURL_TRC_CF(data, cf, "mbedtls_bio_cf_out_write(len=%zu) -> %zd, err=%d",
blen, nwritten, result);
if(nwritten < 0 && CURLE_AGAIN == result) {
@@ -218,8 +182,6 @@ static int mbedtls_bio_cf_read(void *bio, unsigned char *buf, size_t blen)
CURLcode result;
DEBUGASSERT(data);
- if(!data)
- return 0;
/* OpenSSL catches this case, so should we. */
if(!buf)
return 0;
@@ -250,8 +212,8 @@ static const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_fr =
1024, /* RSA min key len */
};
-/* See https://web.archive.org/web/20200921194007/tls.mbed.org/discussions/
- generic/howto-determine-exact-buffer-len-for-mbedtls_pk_write_pubkey_der
+/* See https://tls.mbed.org/discussions/generic/
+ howto-determine-exact-buffer-len-for-mbedtls_pk_write_pubkey_der
*/
#define RSA_PUB_DER_MAX_BYTES (38 + 2 * MBEDTLS_MPI_MAX_SIZE)
#define ECP_PUB_DER_MAX_BYTES (30 + 2 * MBEDTLS_ECP_MAX_BYTES)
@@ -259,304 +221,88 @@ static const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_fr =
#define PUB_DER_MAX_BYTES (RSA_PUB_DER_MAX_BYTES > ECP_PUB_DER_MAX_BYTES ? \
RSA_PUB_DER_MAX_BYTES : ECP_PUB_DER_MAX_BYTES)
-static CURLcode
-mbed_set_ssl_version_min_max(struct Curl_easy *data,
- struct mbed_ssl_backend_data *backend,
- struct ssl_primary_config *conn_config)
+static CURLcode mbedtls_version_from_curl(int *mbedver, long version)
{
- /* TLS 1.0 and TLS 1.1 were dropped with mbedTLS 3.0.0 (2021). So, since
- * then, and before the introduction of TLS 1.3 in 3.6.0 (2024), this
- * function basically always sets TLS 1.2 as min/max, unless given
- * unsupported option values. */
-
-#if MBEDTLS_VERSION_NUMBER < 0x03020000
- int ver_min = MBEDTLS_SSL_MINOR_VERSION_3; /* TLS 1.2 */
- int ver_max = MBEDTLS_SSL_MINOR_VERSION_3; /* TLS 1.2 */
-#else
- /* mbedTLS 3.2.0 (2022) introduced new methods for setting TLS version */
- mbedtls_ssl_protocol_version ver_min = MBEDTLS_SSL_VERSION_TLS1_2;
- mbedtls_ssl_protocol_version ver_max = MBEDTLS_SSL_VERSION_TLS1_2;
-#endif
-
- switch(conn_config->version) {
- case CURL_SSLVERSION_DEFAULT:
-#if MBEDTLS_VERSION_NUMBER < 0x03000000
- case CURL_SSLVERSION_TLSv1:
- case CURL_SSLVERSION_TLSv1_0:
- ver_min = MBEDTLS_SSL_MINOR_VERSION_1;
- break;
- case CURL_SSLVERSION_TLSv1_1:
- ver_min = MBEDTLS_SSL_MINOR_VERSION_2;
- break;
-#else
- case CURL_SSLVERSION_TLSv1:
- case CURL_SSLVERSION_TLSv1_0:
- case CURL_SSLVERSION_TLSv1_1:
-#endif
- case CURL_SSLVERSION_TLSv1_2:
- /* ver_min = MBEDTLS_SSL_VERSION_TLS1_2; */
- break;
- case CURL_SSLVERSION_TLSv1_3:
-#ifdef TLS13_SUPPORT
- ver_min = MBEDTLS_SSL_VERSION_TLS1_3;
- break;
-#endif
- default:
- failf(data, "mbedTLS: unsupported minimum TLS version value");
- return CURLE_SSL_CONNECT_ERROR;
+#if MBEDTLS_VERSION_NUMBER >= 0x03000000
+ switch(version) {
+ case CURL_SSLVERSION_TLSv1_0:
+ case CURL_SSLVERSION_TLSv1_1:
+ case CURL_SSLVERSION_TLSv1_2:
+ *mbedver = MBEDTLS_SSL_MINOR_VERSION_3;
+ return CURLE_OK;
+ case CURL_SSLVERSION_TLSv1_3:
+ break;
}
-
- switch(conn_config->version_max) {
- case CURL_SSLVERSION_MAX_DEFAULT:
- case CURL_SSLVERSION_MAX_NONE:
- case CURL_SSLVERSION_MAX_TLSv1_3:
-#ifdef TLS13_SUPPORT
- ver_max = MBEDTLS_SSL_VERSION_TLS1_3;
- break;
-#endif
- case CURL_SSLVERSION_MAX_TLSv1_2:
- /* ver_max = MBEDTLS_SSL_VERSION_TLS1_2; */
- break;
-#if MBEDTLS_VERSION_NUMBER < 0x03000000
- case CURL_SSLVERSION_MAX_TLSv1_1:
- ver_max = MBEDTLS_SSL_MINOR_VERSION_2;
- break;
- case CURL_SSLVERSION_MAX_TLSv1_0:
- ver_max = MBEDTLS_SSL_MINOR_VERSION_1;
- break;
#else
- case CURL_SSLVERSION_MAX_TLSv1_1:
- case CURL_SSLVERSION_MAX_TLSv1_0:
-#endif
- default:
- failf(data, "mbedTLS: unsupported maximum TLS version value");
- return CURLE_SSL_CONNECT_ERROR;
+ switch(version) {
+ case CURL_SSLVERSION_TLSv1_0:
+ *mbedver = MBEDTLS_SSL_MINOR_VERSION_1;
+ return CURLE_OK;
+ case CURL_SSLVERSION_TLSv1_1:
+ *mbedver = MBEDTLS_SSL_MINOR_VERSION_2;
+ return CURLE_OK;
+ case CURL_SSLVERSION_TLSv1_2:
+ *mbedver = MBEDTLS_SSL_MINOR_VERSION_3;
+ return CURLE_OK;
+ case CURL_SSLVERSION_TLSv1_3:
+ break;
}
-
-#if MBEDTLS_VERSION_NUMBER < 0x03020000
- mbedtls_ssl_conf_min_version(&backend->config, MBEDTLS_SSL_MAJOR_VERSION_3,
- ver_min);
- mbedtls_ssl_conf_max_version(&backend->config, MBEDTLS_SSL_MAJOR_VERSION_3,
- ver_max);
-#else
- mbedtls_ssl_conf_min_tls_version(&backend->config, ver_min);
- mbedtls_ssl_conf_max_tls_version(&backend->config, ver_max);
#endif
- return CURLE_OK;
+ return CURLE_SSL_CONNECT_ERROR;
}
-/* TLS_ECJPAKE_WITH_AES_128_CCM_8 (0xC0FF) is marked experimental
- in mbedTLS. The number is not reserved by IANA nor is the
- cipher suite present in other SSL implementations. Provide
- provisional support for specifying the cipher suite here. */
-#ifdef MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8
-static int
-mbed_cipher_suite_get_str(uint16_t id, char *buf, size_t buf_size,
- bool prefer_rfc)
-{
- if(id == MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8)
- msnprintf(buf, buf_size, "%s", "TLS_ECJPAKE_WITH_AES_128_CCM_8");
- else
- return Curl_cipher_suite_get_str(id, buf, buf_size, prefer_rfc);
- return 0;
-}
-
-static uint16_t
-mbed_cipher_suite_walk_str(const char **str, const char **end)
-{
- uint16_t id = Curl_cipher_suite_walk_str(str, end);
- size_t len = *end - *str;
-
- if(!id) {
- if(strncasecompare("TLS_ECJPAKE_WITH_AES_128_CCM_8", *str, len))
- id = MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8;
- }
- return id;
-}
-#else
-#define mbed_cipher_suite_get_str Curl_cipher_suite_get_str
-#define mbed_cipher_suite_walk_str Curl_cipher_suite_walk_str
-#endif
-
static CURLcode
-mbed_set_selected_ciphers(struct Curl_easy *data,
- struct mbed_ssl_backend_data *backend,
- const char *ciphers12,
- const char *ciphers13)
+set_ssl_version_min_max(struct Curl_cfilter *cf, struct Curl_easy *data)
{
- const char *ciphers = ciphers12;
- const int *supported;
- int *selected;
- size_t supported_len, count = 0, default13_count = 0, i, j;
- const char *ptr, *end;
-
- supported = mbedtls_ssl_list_ciphersuites();
- for(i = 0; supported[i] != 0; i++);
- supported_len = i;
-
- selected = malloc(sizeof(int) * (supported_len + 1));
- if(!selected)
- return CURLE_OUT_OF_MEMORY;
-
-#ifndef TLS13_SUPPORT
- (void) ciphers13, (void) j;
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct mbed_ssl_backend_data *backend =
+ (struct mbed_ssl_backend_data *)connssl->backend;
+ struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+#if MBEDTLS_VERSION_NUMBER >= 0x03000000
+ int mbedtls_ver_min = MBEDTLS_SSL_MINOR_VERSION_3;
+ int mbedtls_ver_max = MBEDTLS_SSL_MINOR_VERSION_3;
#else
- if(!ciphers13) {
- /* Add default TLSv1.3 ciphers to selection */
- for(j = 0; j < supported_len; j++) {
- uint16_t id = (uint16_t) supported[j];
- if(strncmp(mbedtls_ssl_get_ciphersuite_name(id), "TLS1-3", 6) != 0)
- continue;
-
- selected[count++] = id;
- }
-
- default13_count = count;
- }
- else
- ciphers = ciphers13;
-
-add_ciphers:
-#endif
- for(ptr = ciphers; ptr[0] != '\0' && count < supported_len; ptr = end) {
- uint16_t id = mbed_cipher_suite_walk_str(&ptr, &end);
-
- /* Check if cipher is supported */
- if(id) {
- for(i = 0; i < supported_len && supported[i] != id; i++);
- if(i == supported_len)
- id = 0;
- }
- if(!id) {
- if(ptr[0] != '\0')
- infof(data, "mbedTLS: unknown cipher in list: \"%.*s\"",
- (int) (end - ptr), ptr);
- continue;
- }
-
- /* No duplicates allowed (so selected cannot overflow) */
- for(i = 0; i < count && selected[i] != id; i++);
- if(i < count) {
- if(i >= default13_count)
- infof(data, "mbedTLS: duplicate cipher in list: \"%.*s\"",
- (int) (end - ptr), ptr);
- continue;
- }
-
- selected[count++] = id;
- }
-
-#ifdef TLS13_SUPPORT
- if(ciphers == ciphers13 && ciphers12) {
- ciphers = ciphers12;
- goto add_ciphers;
- }
-
- if(!ciphers12) {
- /* Add default TLSv1.2 ciphers to selection */
- for(j = 0; j < supported_len; j++) {
- uint16_t id = (uint16_t) supported[j];
- if(strncmp(mbedtls_ssl_get_ciphersuite_name(id), "TLS1-3", 6) == 0)
- continue;
-
- /* No duplicates allowed (so selected cannot overflow) */
- for(i = 0; i < count && selected[i] != id; i++);
- if(i < count)
- continue;
-
- selected[count++] = id;
- }
- }
+ int mbedtls_ver_min = MBEDTLS_SSL_MINOR_VERSION_1;
+ int mbedtls_ver_max = MBEDTLS_SSL_MINOR_VERSION_1;
#endif
+ long ssl_version = conn_config->version;
+ long ssl_version_max = conn_config->version_max;
+ CURLcode result = CURLE_OK;
- selected[count] = 0;
+ DEBUGASSERT(backend);
- if(count == 0) {
- free(selected);
- failf(data, "mbedTLS: no supported cipher in list");
- return CURLE_SSL_CIPHER;
+ switch(ssl_version) {
+ case CURL_SSLVERSION_DEFAULT:
+ case CURL_SSLVERSION_TLSv1:
+ ssl_version = CURL_SSLVERSION_TLSv1_0;
+ break;
}
- /* mbedtls_ssl_conf_ciphersuites(): The ciphersuites array is not copied.
- It must remain valid for the lifetime of the SSL configuration */
- backend->ciphersuites = selected;
- mbedtls_ssl_conf_ciphersuites(&backend->config, backend->ciphersuites);
- return CURLE_OK;
-}
-
-static void
-mbed_dump_cert_info(struct Curl_easy *data, const mbedtls_x509_crt *crt)
-{
-#if defined(CURL_DISABLE_VERBOSE_STRINGS) || \
- (MBEDTLS_VERSION_NUMBER >= 0x03000000 && defined(MBEDTLS_X509_REMOVE_INFO))
- (void) data, (void) crt;
-#else
- const size_t bufsize = 16384;
- char *p, *buffer = malloc(bufsize);
-
- if(buffer && mbedtls_x509_crt_info(buffer, bufsize, " ", crt) > 0) {
- infof(data, "Server certificate:");
- for(p = buffer; *p; p += *p != '\0') {
- size_t s = strcspn(p, "\n");
- infof(data, "%.*s", (int) s, p);
- p += s;
- }
+ switch(ssl_version_max) {
+ case CURL_SSLVERSION_MAX_NONE:
+ case CURL_SSLVERSION_MAX_DEFAULT:
+ ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2;
+ break;
}
- else
- infof(data, "Unable to dump certificate information");
-
- free(buffer);
-#endif
-}
-
-static void
-mbed_extract_certinfo(struct Curl_easy *data, const mbedtls_x509_crt *crt)
-{
- CURLcode result;
- const mbedtls_x509_crt *cur;
- int i;
-
- for(i = 0, cur = crt; cur; ++i, cur = cur->next);
- result = Curl_ssl_init_certinfo(data, i);
- for(i = 0, cur = crt; result == CURLE_OK && cur; ++i, cur = cur->next) {
- const char *beg = (const char *) cur->raw.p;
- const char *end = beg + cur->raw.len;
- result = Curl_extract_certinfo(data, i, beg, end);
+ result = mbedtls_version_from_curl(&mbedtls_ver_min, ssl_version);
+ if(result) {
+ failf(data, "unsupported min version passed via CURLOPT_SSLVERSION");
+ return result;
}
-}
-
-static int mbed_verify_cb(void *ptr, mbedtls_x509_crt *crt,
- int depth, uint32_t *flags)
-{
- struct Curl_cfilter *cf = (struct Curl_cfilter *) ptr;
- struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
- struct Curl_easy *data = CF_DATA_CURRENT(cf);
-
- if(depth == 0) {
- if(data->set.verbose)
- mbed_dump_cert_info(data, crt);
- if(data->set.ssl.certinfo)
- mbed_extract_certinfo(data, crt);
+ result = mbedtls_version_from_curl(&mbedtls_ver_max, ssl_version_max >> 16);
+ if(result) {
+ failf(data, "unsupported max version passed via CURLOPT_SSLVERSION");
+ return result;
}
- if(!conn_config->verifypeer)
- *flags = 0;
- else if(!conn_config->verifyhost)
- *flags &= ~MBEDTLS_X509_BADCERT_CN_MISMATCH;
-
- if(*flags) {
-#if MBEDTLS_VERSION_NUMBER < 0x03000000 || !defined(MBEDTLS_X509_REMOVE_INFO)
- char buf[128];
- mbedtls_x509_crt_verify_info(buf, sizeof(buf), "", *flags);
- failf(data, "mbedTLS: %s", buf);
-#else
- failf(data, "mbedTLS: cerificate verification error 0x%08x", *flags);
-#endif
- }
+ mbedtls_ssl_conf_min_version(&backend->config, MBEDTLS_SSL_MAJOR_VERSION_3,
+ mbedtls_ver_min);
+ mbedtls_ssl_conf_max_version(&backend->config, MBEDTLS_SSL_MAJOR_VERSION_3,
+ mbedtls_ver_max);
- return 0;
+ return result;
}
static CURLcode
@@ -581,7 +327,6 @@ mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
char errorbuf[128];
DEBUGASSERT(backend);
- DEBUGASSERT(!backend->initialized);
if((conn_config->version == CURL_SSLVERSION_SSLv2) ||
(conn_config->version == CURL_SSLVERSION_SSLv3)) {
@@ -589,17 +334,8 @@ mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
return CURLE_NOT_BUILT_IN;
}
-#ifdef TLS13_SUPPORT
- ret = psa_crypto_init();
- if(ret != PSA_SUCCESS) {
- mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
- failf(data, "mbedTLS psa_crypto_init returned (-0x%04X) %s",
- -ret, errorbuf);
- return CURLE_SSL_CONNECT_ERROR;
- }
-#endif /* TLS13_SUPPORT */
-
#ifdef THREADING_SUPPORT
+ entropy_init_mutex(&ts_entropy);
mbedtls_ctr_drbg_init(&backend->ctr_drbg);
ret = mbedtls_ctr_drbg_seed(&backend->ctr_drbg, entropy_func_mutex,
@@ -631,10 +367,11 @@ mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
/* Unfortunately, mbedtls_x509_crt_parse() requires the data to be null
terminated even when provided the exact length, forcing us to waste
extra memory here. */
- unsigned char *newblob = Curl_memdup0(ca_info_blob->data,
- ca_info_blob->len);
+ unsigned char *newblob = malloc(ca_info_blob->len + 1);
if(!newblob)
return CURLE_OUT_OF_MEMORY;
+ memcpy(newblob, ca_info_blob->data, ca_info_blob->len);
+ newblob[ca_info_blob->len] = 0; /* null terminate */
ret = mbedtls_x509_crt_parse(&backend->cacert, newblob,
ca_info_blob->len + 1);
free(newblob);
@@ -704,17 +441,18 @@ mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
/* Unfortunately, mbedtls_x509_crt_parse() requires the data to be null
terminated even when provided the exact length, forcing us to waste
extra memory here. */
- unsigned char *newblob = Curl_memdup0(ssl_cert_blob->data,
- ssl_cert_blob->len);
+ unsigned char *newblob = malloc(ssl_cert_blob->len + 1);
if(!newblob)
return CURLE_OUT_OF_MEMORY;
+ memcpy(newblob, ssl_cert_blob->data, ssl_cert_blob->len);
+ newblob[ssl_cert_blob->len] = 0; /* null terminate */
ret = mbedtls_x509_crt_parse(&backend->clicert, newblob,
ssl_cert_blob->len + 1);
free(newblob);
if(ret) {
mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
- failf(data, "Error reading client cert data %s - mbedTLS: (-0x%04X) %s",
+ failf(data, "Error reading private key %s - mbedTLS: (-0x%04X) %s",
ssl_config->key, -ret, errorbuf);
return CURLE_SSL_CERTPROBLEM;
}
@@ -804,7 +542,7 @@ mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
}
#endif
- infof(data, "mbedTLS: Connecting to %s:%d", hostname, connssl->peer.port);
+ infof(data, "mbedTLS: Connecting to %s:%d", hostname, connssl->port);
mbedtls_ssl_config_init(&backend->config);
ret = mbedtls_ssl_config_defaults(&backend->config,
@@ -816,60 +554,51 @@ mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
return CURLE_SSL_CONNECT_ERROR;
}
- /* Always let mbedTLS verify certificates, if verifypeer or verifyhost are
- * disabled we clear the corresponding error flags in the verify callback
- * function. That is also where we log verification errors. */
- mbedtls_ssl_conf_verify(&backend->config, mbed_verify_cb, cf);
- mbedtls_ssl_conf_authmode(&backend->config, MBEDTLS_SSL_VERIFY_REQUIRED);
-
mbedtls_ssl_init(&backend->ssl);
- backend->initialized = TRUE;
+ if(mbedtls_ssl_setup(&backend->ssl, &backend->config)) {
+ failf(data, "mbedTLS: ssl_init failed");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
/* new profile with RSA min key len = 1024 ... */
mbedtls_ssl_conf_cert_profile(&backend->config,
&mbedtls_x509_crt_profile_fr);
- ret = mbed_set_ssl_version_min_max(data, backend, conn_config);
- if(ret != CURLE_OK)
- return ret;
-
- mbedtls_ssl_conf_rng(&backend->config, mbedtls_ctr_drbg_random,
- &backend->ctr_drbg);
-
- ret = mbedtls_ssl_setup(&backend->ssl, &backend->config);
- if(ret) {
- mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
- failf(data, "ssl_setup failed - mbedTLS: (-0x%04X) %s",
- -ret, errorbuf);
+ switch(conn_config->version) {
+ case CURL_SSLVERSION_DEFAULT:
+ case CURL_SSLVERSION_TLSv1:
+#if MBEDTLS_VERSION_NUMBER < 0x03000000
+ mbedtls_ssl_conf_min_version(&backend->config, MBEDTLS_SSL_MAJOR_VERSION_3,
+ MBEDTLS_SSL_MINOR_VERSION_1);
+ infof(data, "mbedTLS: Set min SSL version to TLS 1.0");
+ break;
+#endif
+ case CURL_SSLVERSION_TLSv1_0:
+ case CURL_SSLVERSION_TLSv1_1:
+ case CURL_SSLVERSION_TLSv1_2:
+ case CURL_SSLVERSION_TLSv1_3:
+ {
+ CURLcode result = set_ssl_version_min_max(cf, data);
+ if(result != CURLE_OK)
+ return result;
+ break;
+ }
+ default:
+ failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
return CURLE_SSL_CONNECT_ERROR;
}
+ mbedtls_ssl_conf_authmode(&backend->config, MBEDTLS_SSL_VERIFY_OPTIONAL);
+
+ mbedtls_ssl_conf_rng(&backend->config, mbedtls_ctr_drbg_random,
+ &backend->ctr_drbg);
mbedtls_ssl_set_bio(&backend->ssl, cf,
mbedtls_bio_cf_write,
mbedtls_bio_cf_read,
NULL /* rev_timeout() */);
-#ifndef TLS13_SUPPORT
- if(conn_config->cipher_list) {
- CURLcode result = mbed_set_selected_ciphers(data, backend,
- conn_config->cipher_list,
- NULL);
-#else
- if(conn_config->cipher_list || conn_config->cipher_list13) {
- CURLcode result = mbed_set_selected_ciphers(data, backend,
- conn_config->cipher_list,
- conn_config->cipher_list13);
-#endif
- if(result != CURLE_OK) {
- failf(data, "mbedTLS: failed to set cipher suites");
- return result;
- }
- }
- else {
- mbedtls_ssl_conf_ciphersuites(&backend->config,
- mbedtls_ssl_list_ciphersuites());
- }
-
+ mbedtls_ssl_conf_ciphersuites(&backend->config,
+ mbedtls_ssl_list_ciphersuites());
#if defined(MBEDTLS_SSL_RENEGOTIATION)
mbedtls_ssl_conf_renegotiation(&backend->config,
@@ -881,12 +610,12 @@ mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
MBEDTLS_SSL_SESSION_TICKETS_DISABLED);
#endif
- /* Check if there is a cached ID we can/should use here! */
- if(ssl_config->primary.cache_session) {
+ /* Check if there's a cached ID we can/should use here! */
+ if(ssl_config->primary.sessionid) {
void *old_session = NULL;
Curl_ssl_sessionid_lock(data);
- if(!Curl_ssl_getsessionid(cf, data, &connssl->peer, &old_session, NULL)) {
+ if(!Curl_ssl_getsessionid(cf, data, &old_session, NULL)) {
ret = mbedtls_ssl_set_session(&backend->ssl, old_session);
if(ret) {
Curl_ssl_sessionid_unlock(data);
@@ -911,13 +640,14 @@ mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
&backend->clicert, &backend->pk);
}
- if(mbedtls_ssl_set_hostname(&backend->ssl, connssl->peer.sni?
- connssl->peer.sni : connssl->peer.hostname)) {
- /* mbedtls_ssl_set_hostname() sets the name to use in CN/SAN checks and
- the name to set in the SNI extension. So even if curl connects to a
- host specified as an IP address, this function must be used. */
- failf(data, "Failed to set SNI");
- return CURLE_SSL_CONNECT_ERROR;
+ if(connssl->peer.sni) {
+ if(mbedtls_ssl_set_hostname(&backend->ssl, connssl->peer.sni)) {
+ /* mbedtls_ssl_set_hostname() sets the name to use in CN/SAN checks and
+ the name to set in the SNI extension. So even if curl connects to a
+ host specified as an IP address, this function must be used. */
+ failf(data, "Failed to set SNI");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
}
#ifdef HAS_ALPN
@@ -928,7 +658,7 @@ mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
for(i = 0; i < connssl->alpn->count; ++i) {
backend->protocols[i] = connssl->alpn->entries[i];
}
- /* this function does not clone the protocols array, which is why we need
+ /* this function doesn't clone the protocols array, which is why we need
to keep it around */
if(mbedtls_ssl_conf_alpn_protocols(&backend->config,
&backend->protocols[0])) {
@@ -954,11 +684,11 @@ mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
/* give application a chance to interfere with mbedTLS set up. */
if(data->set.ssl.fsslctx) {
- CURLcode result = (*data->set.ssl.fsslctx)(data, &backend->config,
- data->set.ssl.fsslctxp);
- if(result != CURLE_OK) {
+ ret = (*data->set.ssl.fsslctx)(data, &backend->config,
+ data->set.ssl.fsslctxp);
+ if(ret) {
failf(data, "error signaled by ssl ctx callback");
- return result;
+ return ret;
}
}
@@ -974,65 +704,83 @@ mbed_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
struct ssl_connect_data *connssl = cf->ctx;
struct mbed_ssl_backend_data *backend =
(struct mbed_ssl_backend_data *)connssl->backend;
-#ifndef CURL_DISABLE_PROXY
+ struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+ const mbedtls_x509_crt *peercert;
const char * const pinnedpubkey = Curl_ssl_cf_is_proxy(cf)?
data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]:
data->set.str[STRING_SSL_PINNEDPUBLICKEY];
-#else
- const char * const pinnedpubkey = data->set.str[STRING_SSL_PINNEDPUBLICKEY];
-#endif
DEBUGASSERT(backend);
ret = mbedtls_ssl_handshake(&backend->ssl);
if(ret == MBEDTLS_ERR_SSL_WANT_READ) {
- connssl->io_need = CURL_SSL_IO_NEED_RECV;
+ connssl->connecting_state = ssl_connect_2_reading;
return CURLE_OK;
}
else if(ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
- connssl->io_need = CURL_SSL_IO_NEED_SEND;
+ connssl->connecting_state = ssl_connect_2_writing;
return CURLE_OK;
}
- else if(ret == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED) {
- failf(data, "peer certificate could not be verified");
- return CURLE_PEER_FAILED_VERIFICATION;
- }
else if(ret) {
char errorbuf[128];
-#if MBEDTLS_VERSION_NUMBER >= 0x03020000
- CURL_TRC_CF(data, cf, "TLS version %04X",
- mbedtls_ssl_get_version_number(&backend->ssl));
-#endif
mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
- failf(data, "ssl_handshake returned: (-0x%04X) %s",
+ failf(data, "ssl_handshake returned - mbedTLS: (-0x%04X) %s",
-ret, errorbuf);
return CURLE_SSL_CONNECT_ERROR;
}
-#if MBEDTLS_VERSION_NUMBER >= 0x03020000
- {
- char cipher_str[64];
- uint16_t cipher_id;
- cipher_id = (uint16_t)
- mbedtls_ssl_get_ciphersuite_id_from_ssl(&backend->ssl);
- mbed_cipher_suite_get_str(cipher_id, cipher_str, sizeof(cipher_str), true);
- infof(data, "mbedTLS: %s Handshake complete, cipher is %s",
- mbedtls_ssl_get_version(&backend->ssl), cipher_str);
+ infof(data, "mbedTLS: Handshake complete, cipher is %s",
+ mbedtls_ssl_get_ciphersuite(&backend->ssl));
+
+ ret = mbedtls_ssl_get_verify_result(&backend->ssl);
+
+ if(!conn_config->verifyhost)
+ /* Ignore hostname errors if verifyhost is disabled */
+ ret &= ~MBEDTLS_X509_BADCERT_CN_MISMATCH;
+
+ if(ret && conn_config->verifypeer) {
+ if(ret & MBEDTLS_X509_BADCERT_EXPIRED)
+ failf(data, "Cert verify failed: BADCERT_EXPIRED");
+
+ else if(ret & MBEDTLS_X509_BADCERT_REVOKED)
+ failf(data, "Cert verify failed: BADCERT_REVOKED");
+
+ else if(ret & MBEDTLS_X509_BADCERT_CN_MISMATCH)
+ failf(data, "Cert verify failed: BADCERT_CN_MISMATCH");
+
+ else if(ret & MBEDTLS_X509_BADCERT_NOT_TRUSTED)
+ failf(data, "Cert verify failed: BADCERT_NOT_TRUSTED");
+
+ else if(ret & MBEDTLS_X509_BADCERT_FUTURE)
+ failf(data, "Cert verify failed: BADCERT_FUTURE");
+
+ return CURLE_PEER_FAILED_VERIFICATION;
+ }
+
+ peercert = mbedtls_ssl_get_peer_cert(&backend->ssl);
+
+ if(peercert && data->set.verbose) {
+ const size_t bufsize = 16384;
+ char *buffer = malloc(bufsize);
+
+ if(!buffer)
+ return CURLE_OUT_OF_MEMORY;
+
+ if(mbedtls_x509_crt_info(buffer, bufsize, "* ", peercert) > 0)
+ infof(data, "Dumping cert info: %s", buffer);
+ else
+ infof(data, "Unable to dump certificate information");
+
+ free(buffer);
}
-#else
- infof(data, "mbedTLS: %s Handshake complete",
- mbedtls_ssl_get_version(&backend->ssl));
-#endif
if(pinnedpubkey) {
int size;
CURLcode result;
- const mbedtls_x509_crt *peercert;
mbedtls_x509_crt *p = NULL;
unsigned char *pubkey = NULL;
- peercert = mbedtls_ssl_get_peer_cert(&backend->ssl);
#if MBEDTLS_VERSION_NUMBER == 0x03000000
if(!peercert || !peercert->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(p) ||
!peercert->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(len)) {
@@ -1113,13 +861,6 @@ pinnedpubkey_error:
return CURLE_OK;
}
-static void mbedtls_session_free(void *sessionid, size_t idsize)
-{
- (void)idsize;
- mbedtls_ssl_session_free(sessionid);
- free(sessionid);
-}
-
static CURLcode
mbed_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data)
{
@@ -1132,9 +873,11 @@ mbed_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data)
DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
DEBUGASSERT(backend);
- if(ssl_config->primary.cache_session) {
+ if(ssl_config->primary.sessionid) {
int ret;
mbedtls_ssl_session *our_ssl_sessionid;
+ void *old_ssl_sessionid = NULL;
+ bool added = FALSE;
our_ssl_sessionid = malloc(sizeof(mbedtls_ssl_session));
if(!our_ssl_sessionid)
@@ -1151,14 +894,22 @@ mbed_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data)
return CURLE_SSL_CONNECT_ERROR;
}
- /* If there is already a matching session in the cache, delete it */
+ /* If there's already a matching session in the cache, delete it */
Curl_ssl_sessionid_lock(data);
- retcode = Curl_ssl_set_sessionid(cf, data, &connssl->peer,
- our_ssl_sessionid, 0,
- mbedtls_session_free);
+ if(!Curl_ssl_getsessionid(cf, data, &old_ssl_sessionid, NULL))
+ Curl_ssl_delsessionid(data, old_ssl_sessionid);
+
+ retcode = Curl_ssl_addsessionid(cf, data, our_ssl_sessionid,
+ 0, &added);
Curl_ssl_sessionid_unlock(data);
- if(retcode)
+ if(!added) {
+ mbedtls_ssl_session_free(our_ssl_sessionid);
+ free(our_ssl_sessionid);
+ }
+ if(retcode) {
+ failf(data, "failed to store ssl session");
return retcode;
+ }
}
connssl->connecting_state = ssl_connect_done;
@@ -1180,13 +931,8 @@ static ssize_t mbed_send(struct Curl_cfilter *cf, struct Curl_easy *data,
ret = mbedtls_ssl_write(&backend->ssl, (unsigned char *)mem, len);
if(ret < 0) {
- CURL_TRC_CF(data, cf, "mbedtls_ssl_write(len=%zu) -> -0x%04X",
- len, -ret);
- *curlcode = ((ret == MBEDTLS_ERR_SSL_WANT_WRITE)
-#ifdef TLS13_SUPPORT
- || (ret == MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET)
-#endif
- )? CURLE_AGAIN : CURLE_SEND_ERROR;
+ *curlcode = (ret == MBEDTLS_ERR_SSL_WANT_WRITE) ?
+ CURLE_AGAIN : CURLE_SEND_ERROR;
ret = -1;
}
@@ -1198,120 +944,32 @@ static void mbedtls_close_all(struct Curl_easy *data)
(void)data;
}
-static CURLcode mbedtls_shutdown(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- bool send_shutdown, bool *done)
-{
- struct ssl_connect_data *connssl = cf->ctx;
- struct mbed_ssl_backend_data *backend =
- (struct mbed_ssl_backend_data *)connssl->backend;
- unsigned char buf[1024];
- CURLcode result = CURLE_OK;
- int ret;
- size_t i;
-
- DEBUGASSERT(backend);
-
- if(!backend->initialized || cf->shutdown) {
- *done = TRUE;
- return CURLE_OK;
- }
-
- connssl->io_need = CURL_SSL_IO_NEED_NONE;
- *done = FALSE;
-
- if(!backend->sent_shutdown) {
- /* do this only once */
- backend->sent_shutdown = TRUE;
- if(send_shutdown) {
- ret = mbedtls_ssl_close_notify(&backend->ssl);
- switch(ret) {
- case 0: /* we sent it, receive from the server */
- break;
- case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY: /* server also closed */
- *done = TRUE;
- goto out;
- case MBEDTLS_ERR_SSL_WANT_READ:
- connssl->io_need = CURL_SSL_IO_NEED_RECV;
- goto out;
- case MBEDTLS_ERR_SSL_WANT_WRITE:
- connssl->io_need = CURL_SSL_IO_NEED_SEND;
- goto out;
- default:
- CURL_TRC_CF(data, cf, "mbedtls_shutdown error -0x%04X", -ret);
- result = CURLE_RECV_ERROR;
- goto out;
- }
- }
- }
-
- /* SSL should now have started the shutdown from our side. Since it
- * was not complete, we are lacking the close notify from the server. */
- for(i = 0; i < 10; ++i) {
- ret = mbedtls_ssl_read(&backend->ssl, buf, sizeof(buf));
- /* This seems to be a bug in mbedTLS TLSv1.3 where it reports
- * WANT_READ, but has not encountered an EAGAIN. */
- if(ret == MBEDTLS_ERR_SSL_WANT_READ)
- ret = mbedtls_ssl_read(&backend->ssl, buf, sizeof(buf));
-#ifdef TLS13_SUPPORT
- if(ret == MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET)
- continue;
-#endif
- if(ret <= 0)
- break;
- }
-
- if(ret > 0) {
- /* still data coming in? */
- CURL_TRC_CF(data, cf, "mbedtls_shutdown, still getting data");
- }
- else if(ret == 0 || (ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY)) {
- /* We got the close notify alert and are done. */
- CURL_TRC_CF(data, cf, "mbedtls_shutdown done");
- *done = TRUE;
- }
- else if(ret == MBEDTLS_ERR_SSL_WANT_READ) {
- CURL_TRC_CF(data, cf, "mbedtls_shutdown, need RECV");
- connssl->io_need = CURL_SSL_IO_NEED_RECV;
- }
- else if(ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
- CURL_TRC_CF(data, cf, "mbedtls_shutdown, need SEND");
- connssl->io_need = CURL_SSL_IO_NEED_SEND;
- }
- else {
- CURL_TRC_CF(data, cf, "mbedtls_shutdown error -0x%04X", -ret);
- result = CURLE_RECV_ERROR;
- }
-
-out:
- cf->shutdown = (result || *done);
- return result;
-}
-
static void mbedtls_close(struct Curl_cfilter *cf, struct Curl_easy *data)
{
struct ssl_connect_data *connssl = cf->ctx;
struct mbed_ssl_backend_data *backend =
(struct mbed_ssl_backend_data *)connssl->backend;
+ char buf[32];
(void)data;
DEBUGASSERT(backend);
- if(backend->initialized) {
- mbedtls_pk_free(&backend->pk);
- mbedtls_x509_crt_free(&backend->clicert);
- mbedtls_x509_crt_free(&backend->cacert);
+
+ /* Maybe the server has already sent a close notify alert.
+ Read it to avoid an RST on the TCP connection. */
+ (void)mbedtls_ssl_read(&backend->ssl, (unsigned char *)buf, sizeof(buf));
+
+ mbedtls_pk_free(&backend->pk);
+ mbedtls_x509_crt_free(&backend->clicert);
+ mbedtls_x509_crt_free(&backend->cacert);
#ifdef MBEDTLS_X509_CRL_PARSE_C
- mbedtls_x509_crl_free(&backend->crl);
+ mbedtls_x509_crl_free(&backend->crl);
#endif
- Curl_safefree(backend->ciphersuites);
- mbedtls_ssl_config_free(&backend->config);
- mbedtls_ssl_free(&backend->ssl);
- mbedtls_ctr_drbg_free(&backend->ctr_drbg);
+ mbedtls_ssl_config_free(&backend->config);
+ mbedtls_ssl_free(&backend->ssl);
+ mbedtls_ctr_drbg_free(&backend->ctr_drbg);
#ifndef THREADING_SUPPORT
- mbedtls_entropy_free(&backend->entropy);
+ mbedtls_entropy_free(&backend->entropy);
#endif /* THREADING_SUPPORT */
- backend->initialized = FALSE;
- }
}
static ssize_t mbed_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
@@ -1329,21 +987,13 @@ static ssize_t mbed_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
ret = mbedtls_ssl_read(&backend->ssl, (unsigned char *)buf,
buffersize);
+
if(ret <= 0) {
- CURL_TRC_CF(data, cf, "mbedtls_ssl_read(len=%zu) -> -0x%04X",
- buffersize, -ret);
if(ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY)
return 0;
- *curlcode = ((ret == MBEDTLS_ERR_SSL_WANT_READ)
-#ifdef TLS13_SUPPORT
- || (ret == MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET)
-#endif
- ) ? CURLE_AGAIN : CURLE_RECV_ERROR;
- if(*curlcode != CURLE_AGAIN) {
- char errorbuf[128];
- mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
- failf(data, "ssl_read returned: (-0x%04X) %s", -ret, errorbuf);
- }
+
+ *curlcode = (ret == MBEDTLS_ERR_SSL_WANT_READ) ?
+ CURLE_AGAIN : CURLE_RECV_ERROR;
return -1;
}
@@ -1352,6 +1002,12 @@ static ssize_t mbed_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
return len;
}
+static void mbedtls_session_free(void *ptr)
+{
+ mbedtls_ssl_session_free(ptr);
+ free(ptr);
+}
+
static size_t mbedtls_version(char *buffer, size_t size)
{
#ifdef MBEDTLS_VERSION_C
@@ -1426,7 +1082,7 @@ mbed_connect_common(struct Curl_cfilter *cf, struct Curl_easy *data,
}
if(ssl_connect_1 == connssl->connecting_state) {
- /* Find out how much more time we are allowed */
+ /* Find out how much more time we're allowed */
timeout_ms = Curl_timeleft(data, NULL, TRUE);
if(timeout_ms < 0) {
@@ -1439,7 +1095,9 @@ mbed_connect_common(struct Curl_cfilter *cf, struct Curl_easy *data,
return retcode;
}
- while(ssl_connect_2 == connssl->connecting_state) {
+ while(ssl_connect_2 == connssl->connecting_state ||
+ ssl_connect_2_reading == connssl->connecting_state ||
+ ssl_connect_2_writing == connssl->connecting_state) {
/* check allowed time left */
timeout_ms = Curl_timeleft(data, NULL, TRUE);
@@ -1450,13 +1108,14 @@ mbed_connect_common(struct Curl_cfilter *cf, struct Curl_easy *data,
return CURLE_OPERATION_TIMEDOUT;
}
- /* if ssl is expecting something, check if it is available. */
- if(connssl->io_need) {
+ /* if ssl is expecting something, check if it's available. */
+ if(connssl->connecting_state == ssl_connect_2_reading
+ || connssl->connecting_state == ssl_connect_2_writing) {
- curl_socket_t writefd = (connssl->io_need & CURL_SSL_IO_NEED_SEND)?
- sockfd:CURL_SOCKET_BAD;
- curl_socket_t readfd = (connssl->io_need & CURL_SSL_IO_NEED_RECV)?
- sockfd:CURL_SOCKET_BAD;
+ curl_socket_t writefd = ssl_connect_2_writing ==
+ connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
+ curl_socket_t readfd = ssl_connect_2_reading ==
+ connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
nonblocking ? 0 : timeout_ms);
@@ -1486,10 +1145,11 @@ mbed_connect_common(struct Curl_cfilter *cf, struct Curl_easy *data,
* ensuring that a client using select() or epoll() will always
* have a valid fdset to wait on.
*/
- connssl->io_need = CURL_SSL_IO_NEED_NONE;
retcode = mbed_connect_step2(cf, data);
- if(retcode ||
- (nonblocking && (ssl_connect_2 == connssl->connecting_state)))
+ if(retcode || (nonblocking &&
+ (ssl_connect_2 == connssl->connecting_state ||
+ ssl_connect_2_reading == connssl->connecting_state ||
+ ssl_connect_2_writing == connssl->connecting_state)))
return retcode;
} /* repeat step2 until all transactions are done. */
@@ -1542,19 +1202,11 @@ static CURLcode mbedtls_connect(struct Curl_cfilter *cf,
*/
static int mbedtls_init(void)
{
- if(!Curl_mbedtlsthreadlock_thread_setup())
- return 0;
-#ifdef THREADING_SUPPORT
- entropy_init_mutex(&ts_entropy);
-#endif
- return 1;
+ return Curl_mbedtlsthreadlock_thread_setup();
}
static void mbedtls_cleanup(void)
{
-#ifdef THREADING_SUPPORT
- entropy_cleanup_mutex(&ts_entropy);
-#endif
(void)Curl_mbedtlsthreadlock_thread_cleanup();
}
@@ -1606,14 +1258,9 @@ const struct Curl_ssl Curl_ssl_mbedtls = {
SSLSUPP_CA_PATH |
SSLSUPP_CAINFO_BLOB |
- SSLSUPP_CERTINFO |
SSLSUPP_PINNEDPUBKEY |
SSLSUPP_SSL_CTX |
-#ifdef TLS13_SUPPORT
- SSLSUPP_TLS13_CIPHERSUITES |
-#endif
- SSLSUPP_HTTPS_PROXY |
- SSLSUPP_CIPHER_LIST,
+ SSLSUPP_HTTPS_PROXY,
sizeof(struct mbed_ssl_backend_data),
@@ -1621,7 +1268,7 @@ const struct Curl_ssl Curl_ssl_mbedtls = {
mbedtls_cleanup, /* cleanup */
mbedtls_version, /* version */
Curl_none_check_cxn, /* check_cxn */
- mbedtls_shutdown, /* shutdown */
+ Curl_none_shutdown, /* shutdown */
mbedtls_data_pending, /* data_pending */
mbedtls_random, /* random */
Curl_none_cert_status_request, /* cert_status_request */
@@ -1631,6 +1278,7 @@ const struct Curl_ssl Curl_ssl_mbedtls = {
mbedtls_get_internals, /* get_internals */
mbedtls_close, /* close_one */
mbedtls_close_all, /* close_all */
+ mbedtls_session_free, /* session_free */
Curl_none_set_engine, /* set_engine */
Curl_none_set_engine_default, /* set_engine_default */
Curl_none_engines_list, /* engines_list */
@@ -1638,9 +1286,9 @@ const struct Curl_ssl Curl_ssl_mbedtls = {
mbedtls_sha256sum, /* sha256sum */
NULL, /* associate_connection */
NULL, /* disassociate_connection */
+ NULL, /* free_multi_ssl_backend_data */
mbed_recv, /* recv decrypted data */
mbed_send, /* send data to encrypt */
- NULL, /* get_channel_binding */
};
#endif /* USE_MBEDTLS */
diff --git a/contrib/libs/curl/lib/vtls/mbedtls_threadlock.c b/contrib/libs/curl/lib/vtls/mbedtls_threadlock.c
index 1fcd35ab51..47ac729502 100644
--- a/contrib/libs/curl/lib/vtls/mbedtls_threadlock.c
+++ b/contrib/libs/curl/lib/vtls/mbedtls_threadlock.c
@@ -26,12 +26,12 @@
#if defined(USE_MBEDTLS) && \
((defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H)) || \
- defined(_WIN32))
+ defined(USE_THREADS_WIN32))
#if defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H)
# include <pthread.h>
# define MBEDTLS_MUTEX_T pthread_mutex_t
-#elif defined(_WIN32)
+#elif defined(USE_THREADS_WIN32)
# define MBEDTLS_MUTEX_T HANDLE
#endif
@@ -59,7 +59,7 @@ int Curl_mbedtlsthreadlock_thread_setup(void)
#if defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H)
if(pthread_mutex_init(&mutex_buf[i], NULL))
return 0; /* pthread_mutex_init failed */
-#elif defined(_WIN32)
+#elif defined(USE_THREADS_WIN32)
mutex_buf[i] = CreateMutex(0, FALSE, 0);
if(mutex_buf[i] == 0)
return 0; /* CreateMutex failed */
@@ -80,7 +80,7 @@ int Curl_mbedtlsthreadlock_thread_cleanup(void)
#if defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H)
if(pthread_mutex_destroy(&mutex_buf[i]))
return 0; /* pthread_mutex_destroy failed */
-#elif defined(_WIN32)
+#elif defined(USE_THREADS_WIN32)
if(!CloseHandle(mutex_buf[i]))
return 0; /* CloseHandle failed */
#endif /* USE_THREADS_POSIX && HAVE_PTHREAD_H */
@@ -100,7 +100,7 @@ int Curl_mbedtlsthreadlock_lock_function(int n)
"Error: mbedtlsthreadlock_lock_function failed\n"));
return 0; /* pthread_mutex_lock failed */
}
-#elif defined(_WIN32)
+#elif defined(USE_THREADS_WIN32)
if(WaitForSingleObject(mutex_buf[n], INFINITE) == WAIT_FAILED) {
DEBUGF(fprintf(stderr,
"Error: mbedtlsthreadlock_lock_function failed\n"));
@@ -120,7 +120,7 @@ int Curl_mbedtlsthreadlock_unlock_function(int n)
"Error: mbedtlsthreadlock_unlock_function failed\n"));
return 0; /* pthread_mutex_unlock failed */
}
-#elif defined(_WIN32)
+#elif defined(USE_THREADS_WIN32)
if(!ReleaseMutex(mutex_buf[n])) {
DEBUGF(fprintf(stderr,
"Error: mbedtlsthreadlock_unlock_function failed\n"));
diff --git a/contrib/libs/curl/lib/vtls/openssl.c b/contrib/libs/curl/lib/vtls/openssl.c
index 865f4237eb..f3d89b0d78 100644
--- a/contrib/libs/curl/lib/vtls/openssl.c
+++ b/contrib/libs/curl/lib/vtls/openssl.c
@@ -82,17 +82,6 @@
#include <openssl/tls1.h>
#include <openssl/evp.h>
-#ifdef USE_ECH
-# ifndef OPENSSL_IS_BORINGSSL
-# error #include <openssl/ech.h>
-# endif
-# include "curl_base64.h"
-# define ECH_ENABLED(__data__) \
- (__data__->set.tls_ech && \
- !(__data__->set.tls_ech & CURLECH_DISABLE)\
- )
-#endif /* USE_ECH */
-
#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_OCSP)
#include <openssl/ocsp.h>
#endif
@@ -204,10 +193,12 @@
* Whether SSL_CTX_set_keylog_callback is available.
* OpenSSL: supported since 1.1.1 https://github.com/openssl/openssl/pull/2287
* BoringSSL: supported since d28f59c27bac (committed 2015-11-19)
- * LibreSSL: not supported. 3.5.0+ has a stub function that does nothing.
+ * LibreSSL: supported since 3.5.0 (released 2022-02-24)
*/
#if (OPENSSL_VERSION_NUMBER >= 0x10101000L && \
!defined(LIBRESSL_VERSION_NUMBER)) || \
+ (defined(LIBRESSL_VERSION_NUMBER) && \
+ LIBRESSL_VERSION_NUMBER >= 0x3050000fL) || \
defined(OPENSSL_IS_BORINGSSL)
#define HAVE_KEYLOG_CALLBACK
#endif
@@ -231,7 +222,7 @@
/*
* Whether SSL_CTX_set1_curves_list is available.
* OpenSSL: supported since 1.0.2, see
- * https://docs.openssl.org/master/man3/SSL_CTX_set1_curves/
+ * https://www.openssl.org/docs/manmaster/man3/SSL_CTX_set1_groups.html
* BoringSSL: supported since 5fd1807d95f7 (committed 2016-09-30)
* LibreSSL: since 2.5.3 (April 12, 2017)
*/
@@ -254,20 +245,13 @@
#endif
#endif
-#if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC)
-typedef size_t numcert_t;
-#else
-typedef int numcert_t;
-#endif
-#define ossl_valsize_t numcert_t
-
#if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
/* up2date versions of OpenSSL maintain reasonably secure defaults without
* breaking compatibility, so it is better not to override the defaults in curl
*/
#define DEFAULT_CIPHER_SELECTION NULL
#else
-/* not the case with old versions of OpenSSL */
+/* ... but it is not the case with old versions of OpenSSL */
#define DEFAULT_CIPHER_SELECTION \
"ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH"
#endif
@@ -314,36 +298,51 @@ typedef unsigned long sslerr_t;
#define USE_PRE_1_1_API (OPENSSL_VERSION_NUMBER < 0x10100000L)
#endif /* !LIBRESSL_VERSION_NUMBER */
-static CURLcode ossl_certchain(struct Curl_easy *data, SSL *ssl);
+struct ossl_ssl_backend_data {
+ /* these ones requires specific SSL-types */
+ SSL_CTX* ctx;
+ SSL* handle;
+ X509* server_cert;
+ BIO_METHOD *bio_method;
+ CURLcode io_result; /* result of last BIO cfilter operation */
+#ifndef HAVE_KEYLOG_CALLBACK
+ /* Set to true once a valid keylog entry has been created to avoid dupes. */
+ bool keylog_done;
+#endif
+ bool x509_store_setup; /* x509 store has been set up */
+};
-static CURLcode push_certinfo(struct Curl_easy *data,
- BIO *mem, const char *label, int num)
- WARN_UNUSED_RESULT;
+#if defined(HAVE_SSL_X509_STORE_SHARE)
+struct multi_ssl_backend_data {
+ char *CAfile; /* CAfile path used to generate X509 store */
+ X509_STORE *store; /* cached X509 store or NULL if none */
+ struct curltime time; /* when the cached store was created */
+};
+#endif /* HAVE_SSL_X509_STORE_SHARE */
-static CURLcode push_certinfo(struct Curl_easy *data,
- BIO *mem, const char *label, int num)
-{
- char *ptr;
- long len = BIO_get_mem_data(mem, &ptr);
- CURLcode result = Curl_ssl_push_certinfo_len(data, num, label, ptr, len);
- (void)BIO_reset(mem);
- return result;
-}
+#define push_certinfo(_label, _num) \
+do { \
+ long info_len = BIO_get_mem_data(mem, &ptr); \
+ Curl_ssl_push_certinfo_len(data, _num, _label, ptr, info_len); \
+ if(1 != BIO_reset(mem)) \
+ break; \
+} while(0)
-static CURLcode pubkey_show(struct Curl_easy *data,
- BIO *mem,
- int num,
- const char *type,
- const char *name,
- const BIGNUM *bn)
+static void pubkey_show(struct Curl_easy *data,
+ BIO *mem,
+ int num,
+ const char *type,
+ const char *name,
+ const BIGNUM *bn)
{
+ char *ptr;
char namebuf[32];
msnprintf(namebuf, sizeof(namebuf), "%s(%s)", type, name);
if(bn)
BN_print(mem, bn);
- return push_certinfo(data, mem, namebuf, num);
+ push_certinfo(namebuf, num);
}
#ifdef HAVE_OPAQUE_RSA_DSA_DH
@@ -375,26 +374,25 @@ static int asn1_object_dump(ASN1_OBJECT *a, char *buf, size_t len)
return 0;
}
-static CURLcode X509V3_ext(struct Curl_easy *data,
- int certnum,
- CONST_EXTS STACK_OF(X509_EXTENSION) *exts)
+static void X509V3_ext(struct Curl_easy *data,
+ int certnum,
+ CONST_EXTS STACK_OF(X509_EXTENSION) *exts)
{
int i;
- CURLcode result = CURLE_OK;
if((int)sk_X509_EXTENSION_num(exts) <= 0)
/* no extensions, bail out */
- return result;
+ return;
for(i = 0; i < (int)sk_X509_EXTENSION_num(exts); i++) {
ASN1_OBJECT *obj;
- X509_EXTENSION *ext = sk_X509_EXTENSION_value(exts, (ossl_valsize_t)i);
+ X509_EXTENSION *ext = sk_X509_EXTENSION_value(exts, i);
BUF_MEM *biomem;
char namebuf[128];
BIO *bio_out = BIO_new(BIO_s_mem());
if(!bio_out)
- return result;
+ return;
obj = X509_EXTENSION_get_object(ext);
@@ -404,16 +402,19 @@ static CURLcode X509V3_ext(struct Curl_easy *data,
ASN1_STRING_print(bio_out, (ASN1_STRING *)X509_EXTENSION_get_data(ext));
BIO_get_mem_ptr(bio_out, &biomem);
- result = Curl_ssl_push_certinfo_len(data, certnum, namebuf, biomem->data,
- biomem->length);
+ Curl_ssl_push_certinfo_len(data, certnum, namebuf, biomem->data,
+ biomem->length);
BIO_free(bio_out);
- if(result)
- break;
}
- return result;
}
-static CURLcode ossl_certchain(struct Curl_easy *data, SSL *ssl)
+#if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC)
+typedef size_t numcert_t;
+#else
+typedef int numcert_t;
+#endif
+
+CURLcode Curl_ossl_certchain(struct Curl_easy *data, SSL *ssl)
{
CURLcode result;
STACK_OF(X509) *sk;
@@ -431,43 +432,38 @@ static CURLcode ossl_certchain(struct Curl_easy *data, SSL *ssl)
numcerts = sk_X509_num(sk);
result = Curl_ssl_init_certinfo(data, (int)numcerts);
- if(result)
+ if(result) {
return result;
+ }
mem = BIO_new(BIO_s_mem());
- if(!mem)
- result = CURLE_OUT_OF_MEMORY;
+ if(!mem) {
+ return CURLE_OUT_OF_MEMORY;
+ }
- for(i = 0; !result && (i < (int)numcerts); i++) {
+ for(i = 0; i < (int)numcerts; i++) {
ASN1_INTEGER *num;
- X509 *x = sk_X509_value(sk, (ossl_valsize_t)i);
+ X509 *x = sk_X509_value(sk, i);
EVP_PKEY *pubkey = NULL;
int j;
+ char *ptr;
const ASN1_BIT_STRING *psig = NULL;
X509_NAME_print_ex(mem, X509_get_subject_name(x), 0, XN_FLAG_ONELINE);
- result = push_certinfo(data, mem, "Subject", i);
- if(result)
- break;
+ push_certinfo("Subject", i);
X509_NAME_print_ex(mem, X509_get_issuer_name(x), 0, XN_FLAG_ONELINE);
- result = push_certinfo(data, mem, "Issuer", i);
- if(result)
- break;
+ push_certinfo("Issuer", i);
BIO_printf(mem, "%lx", X509_get_version(x));
- result = push_certinfo(data, mem, "Version", i);
- if(result)
- break;
+ push_certinfo("Version", i);
num = X509_get_serialNumber(x);
if(num->type == V_ASN1_NEG_INTEGER)
BIO_puts(mem, "-");
for(j = 0; j < num->length; j++)
BIO_printf(mem, "%02x", num->data[j]);
- result = push_certinfo(data, mem, "Serial Number", i);
- if(result)
- break;
+ push_certinfo("Serial Number", i);
#if defined(HAVE_X509_GET0_SIGNATURE) && defined(HAVE_X509_GET0_EXTENSIONS)
{
@@ -480,9 +476,7 @@ static CURLcode ossl_certchain(struct Curl_easy *data, SSL *ssl)
const ASN1_OBJECT *sigalgoid = NULL;
X509_ALGOR_get0(&sigalgoid, NULL, NULL, sigalg);
i2a_ASN1_OBJECT(mem, sigalgoid);
- result = push_certinfo(data, mem, "Signature Algorithm", i);
- if(result)
- break;
+ push_certinfo("Signature Algorithm", i);
}
xpubkey = X509_get_X509_PUBKEY(x);
@@ -490,15 +484,11 @@ static CURLcode ossl_certchain(struct Curl_easy *data, SSL *ssl)
X509_PUBKEY_get0_param(&pubkeyoid, NULL, NULL, NULL, xpubkey);
if(pubkeyoid) {
i2a_ASN1_OBJECT(mem, pubkeyoid);
- result = push_certinfo(data, mem, "Public Key Algorithm", i);
- if(result)
- break;
+ push_certinfo("Public Key Algorithm", i);
}
}
- result = X509V3_ext(data, i, X509_get0_extensions(x));
- if(result)
- break;
+ X509V3_ext(data, i, X509_get0_extensions(x));
}
#else
{
@@ -506,32 +496,22 @@ static CURLcode ossl_certchain(struct Curl_easy *data, SSL *ssl)
X509_CINF *cinf = x->cert_info;
i2a_ASN1_OBJECT(mem, cinf->signature->algorithm);
- result = push_certinfo(data, mem, "Signature Algorithm", i);
+ push_certinfo("Signature Algorithm", i);
- if(!result) {
- i2a_ASN1_OBJECT(mem, cinf->key->algor->algorithm);
- result = push_certinfo(data, mem, "Public Key Algorithm", i);
- }
-
- if(!result)
- result = X509V3_ext(data, i, cinf->extensions);
+ i2a_ASN1_OBJECT(mem, cinf->key->algor->algorithm);
+ push_certinfo("Public Key Algorithm", i);
- if(result)
- break;
+ X509V3_ext(data, i, cinf->extensions);
psig = x->signature;
}
#endif
ASN1_TIME_print(mem, X509_get0_notBefore(x));
- result = push_certinfo(data, mem, "Start date", i);
- if(result)
- break;
+ push_certinfo("Start date", i);
ASN1_TIME_print(mem, X509_get0_notAfter(x));
- result = push_certinfo(data, mem, "Expire date", i);
- if(result)
- break;
+ push_certinfo("Expire date", i);
pubkey = X509_get_pubkey(x);
if(!pubkey)
@@ -544,7 +524,8 @@ static CURLcode ossl_certchain(struct Curl_easy *data, SSL *ssl)
pktype = pubkey->type;
#endif
switch(pktype) {
- case EVP_PKEY_RSA: {
+ case EVP_PKEY_RSA:
+ {
#ifndef HAVE_EVP_PKEY_GET_PARAMS
RSA *rsa;
#ifdef HAVE_OPAQUE_EVP_PKEY
@@ -568,9 +549,7 @@ static CURLcode ossl_certchain(struct Curl_easy *data, SSL *ssl)
#else
BIO_printf(mem, "%d", rsa->n ? BN_num_bits(rsa->n) : 0);
#endif /* HAVE_OPAQUE_RSA_DSA_DH */
- result = push_certinfo(data, mem, "RSA Public Key", i);
- if(result)
- break;
+ push_certinfo("RSA Public Key", i);
print_pubkey_BN(rsa, n, i);
print_pubkey_BN(rsa, e, i);
FREE_PKEY_PARAM_BIGNUM(n);
@@ -618,7 +597,8 @@ static CURLcode ossl_certchain(struct Curl_easy *data, SSL *ssl)
#endif /* !OPENSSL_NO_DSA */
break;
}
- case EVP_PKEY_DH: {
+ case EVP_PKEY_DH:
+ {
#ifndef HAVE_EVP_PKEY_GET_PARAMS
DH *dh;
#ifdef HAVE_OPAQUE_EVP_PKEY
@@ -661,25 +641,19 @@ static CURLcode ossl_certchain(struct Curl_easy *data, SSL *ssl)
EVP_PKEY_free(pubkey);
}
- if(!result && psig) {
+ if(psig) {
for(j = 0; j < psig->length; j++)
BIO_printf(mem, "%02x:", psig->data[j]);
- result = push_certinfo(data, mem, "Signature", i);
+ push_certinfo("Signature", i);
}
- if(!result) {
- PEM_write_bio_X509(mem, x);
- result = push_certinfo(data, mem, "Cert", i);
- }
+ PEM_write_bio_X509(mem, x);
+ push_certinfo("Cert", i);
}
BIO_free(mem);
- if(result)
- /* cleanup all leftovers */
- Curl_ssl_free_certinfo(data);
-
- return result;
+ return CURLE_OK;
}
#endif /* quiche or OpenSSL */
@@ -752,21 +726,18 @@ static int ossl_bio_cf_out_write(BIO *bio, const char *buf, int blen)
{
struct Curl_cfilter *cf = BIO_get_data(bio);
struct ssl_connect_data *connssl = cf->ctx;
- struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend;
+ struct ossl_ssl_backend_data *backend =
+ (struct ossl_ssl_backend_data *)connssl->backend;
struct Curl_easy *data = CF_DATA_CURRENT(cf);
ssize_t nwritten;
CURLcode result = CURLE_SEND_ERROR;
DEBUGASSERT(data);
- if(blen < 0)
- return 0;
-
- nwritten = Curl_conn_cf_send(cf->next, data, buf, (size_t)blen, FALSE,
- &result);
+ nwritten = Curl_conn_cf_send(cf->next, data, buf, blen, &result);
CURL_TRC_CF(data, cf, "ossl_bio_cf_out_write(len=%d) -> %d, err=%d",
blen, (int)nwritten, result);
BIO_clear_retry_flags(bio);
- octx->io_result = result;
+ backend->io_result = result;
if(nwritten < 0) {
if(CURLE_AGAIN == result)
BIO_set_retry_write(bio);
@@ -778,7 +749,8 @@ static int ossl_bio_cf_in_read(BIO *bio, char *buf, int blen)
{
struct Curl_cfilter *cf = BIO_get_data(bio);
struct ssl_connect_data *connssl = cf->ctx;
- struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend;
+ struct ossl_ssl_backend_data *backend =
+ (struct ossl_ssl_backend_data *)connssl->backend;
struct Curl_easy *data = CF_DATA_CURRENT(cf);
ssize_t nread;
CURLcode result = CURLE_RECV_ERROR;
@@ -787,31 +759,26 @@ static int ossl_bio_cf_in_read(BIO *bio, char *buf, int blen)
/* OpenSSL catches this case, so should we. */
if(!buf)
return 0;
- if(blen < 0)
- return 0;
- nread = Curl_conn_cf_recv(cf->next, data, buf, (size_t)blen, &result);
+ nread = Curl_conn_cf_recv(cf->next, data, buf, blen, &result);
CURL_TRC_CF(data, cf, "ossl_bio_cf_in_read(len=%d) -> %d, err=%d",
blen, (int)nread, result);
BIO_clear_retry_flags(bio);
- octx->io_result = result;
+ backend->io_result = result;
if(nread < 0) {
if(CURLE_AGAIN == result)
BIO_set_retry_read(bio);
}
- else if(nread == 0) {
- connssl->peer_closed = TRUE;
- }
/* Before returning server replies to the SSL instance, we need
* to have setup the x509 store or verification will fail. */
- if(!octx->x509_store_setup) {
- result = Curl_ssl_setup_x509_store(cf, data, octx->ssl_ctx);
+ if(!backend->x509_store_setup) {
+ result = Curl_ssl_setup_x509_store(cf, data, backend->ctx);
if(result) {
- octx->io_result = result;
+ backend->io_result = result;
return -1;
}
- octx->x509_store_setup = TRUE;
+ backend->x509_store_setup = TRUE;
}
return (int)nread;
@@ -881,7 +848,7 @@ static void ossl_keylog_callback(const SSL *ssl, const char *line)
#else
/*
* ossl_log_tls12_secret is called by libcurl to make the CLIENT_RANDOMs if the
- * OpenSSL being used does not have native support for doing that.
+ * OpenSSL being used doesn't have native support for doing that.
*/
static void
ossl_log_tls12_secret(const SSL *ssl, bool *keylog_done)
@@ -897,7 +864,7 @@ ossl_log_tls12_secret(const SSL *ssl, bool *keylog_done)
#if OPENSSL_VERSION_NUMBER >= 0x10100000L && \
!(defined(LIBRESSL_VERSION_NUMBER) && \
LIBRESSL_VERSION_NUMBER < 0x20700000L)
- /* ssl->s3 is not checked in OpenSSL 1.1.0-pre6, but let's assume that
+ /* ssl->s3 is not checked in openssl 1.1.0-pre6, but let's assume that
* we have a valid SSL context if we have a non-NULL session. */
SSL_get_client_random(ssl, client_random, SSL3_RANDOM_SIZE);
master_key_length = (int)
@@ -987,9 +954,8 @@ static char *ossl_strerror(unsigned long error, char *buf, size_t size)
#endif
if(!*buf) {
- const char *msg = error ? "Unknown error" : "No error";
- if(strlen(msg) < size)
- strcpy(buf, msg);
+ strncpy(buf, (error ? "Unknown error" : "No error"), size);
+ buf[size - 1] = '\0';
}
return buf;
@@ -1000,7 +966,7 @@ static int passwd_callback(char *buf, int num, int encrypting,
{
DEBUGASSERT(0 == encrypting);
- if(!encrypting && num >= 0) {
+ if(!encrypting) {
int klen = curlx_uztosi(strlen((char *)global_passwd));
if(num > klen) {
memcpy(buf, global_passwd, klen + 1);
@@ -1036,6 +1002,12 @@ static CURLcode ossl_seed(struct Curl_easy *data)
return CURLE_SSL_CONNECT_ERROR;
#else
+#ifdef RANDOM_FILE
+ RAND_load_file(RANDOM_FILE, RAND_LOAD_LENGTH);
+ if(rand_enough())
+ return CURLE_OK;
+#endif
+
/* fallback to a custom seeding of the PRNG using a hash based on a current
time */
do {
@@ -1045,12 +1017,13 @@ static CURLcode ossl_seed(struct Curl_easy *data)
for(i = 0, i_max = len / sizeof(struct curltime); i < i_max; ++i) {
struct curltime tv = Curl_now();
Curl_wait_ms(1);
- tv.tv_sec *= (time_t)i + 1;
- tv.tv_usec *= (int)i + 2;
- tv.tv_sec ^= ((Curl_now().tv_sec + (time_t)Curl_now().tv_usec) *
- (time_t)(i + 3)) << 8;
- tv.tv_usec ^= (int) ((Curl_now().tv_sec + (time_t)Curl_now().tv_usec) *
- (time_t)(i + 4)) << 16;
+ tv.tv_sec *= i + 1;
+ tv.tv_usec *= (unsigned int)i + 2;
+ tv.tv_sec ^= ((Curl_now().tv_sec + Curl_now().tv_usec) *
+ (i + 3)) << 8;
+ tv.tv_usec ^= (unsigned int) ((Curl_now().tv_sec +
+ Curl_now().tv_usec) *
+ (i + 4)) << 16;
memcpy(&randb[i * sizeof(struct curltime)], &tv,
sizeof(struct curltime));
}
@@ -1063,7 +1036,7 @@ static CURLcode ossl_seed(struct Curl_easy *data)
fname[0] = 0; /* blank it first */
RAND_file_name(fname, sizeof(fname));
if(fname[0]) {
- /* we got a filename to try */
+ /* we got a file name to try */
RAND_load_file(fname, RAND_LOAD_LENGTH);
if(rand_enough())
return CURLE_OK;
@@ -1082,7 +1055,7 @@ static CURLcode ossl_seed(struct Curl_easy *data)
#ifndef SSL_FILETYPE_PKCS12
#define SSL_FILETYPE_PKCS12 43
#endif
-static int ossl_do_file_type(const char *type)
+static int do_file_type(const char *type)
{
if(!type || !type[0])
return SSL_FILETYPE_PEM;
@@ -1114,7 +1087,6 @@ static int ssl_ui_reader(UI *ui, UI_STRING *uis)
UI_set_result(ui, uis, password);
return 1;
}
- FALLTHROUGH();
default:
break;
}
@@ -1133,7 +1105,6 @@ static int ssl_ui_writer(UI *ui, UI_STRING *uis)
(UI_get_input_flags(uis) & UI_INPUT_FLAG_DEFAULT_PWD)) {
return 1;
}
- FALLTHROUGH();
default:
break;
}
@@ -1304,7 +1275,7 @@ int cert_stuff(struct Curl_easy *data,
char error_buffer[256];
bool check_privkey = TRUE;
- int file_type = ossl_do_file_type(cert_type);
+ int file_type = do_file_type(cert_type);
if(cert_file || cert_blob || (file_type == SSL_FILETYPE_ENGINE)) {
SSL *ssl;
@@ -1399,7 +1370,7 @@ int cert_stuff(struct Curl_easy *data,
}
if(!params.cert) {
- failf(data, "ssl engine did not initialized the certificate "
+ failf(data, "ssl engine didn't initialized the certificate "
"properly.");
return 0;
}
@@ -1410,10 +1381,10 @@ int cert_stuff(struct Curl_easy *data,
sizeof(error_buffer)));
return 0;
}
- X509_free(params.cert); /* we do not need the handle any more... */
+ X509_free(params.cert); /* we don't need the handle any more... */
}
else {
- failf(data, "crypto engine not set, cannot load certificate");
+ failf(data, "crypto engine not set, can't load certificate");
return 0;
}
}
@@ -1509,7 +1480,7 @@ int cert_stuff(struct Curl_easy *data,
* Note that sk_X509_pop() is used below to make sure the cert is
* removed from the stack properly before getting passed to
* SSL_CTX_add_extra_chain_cert(), which takes ownership. Previously
- * we used sk_X509_value() instead, but then we would clean it in the
+ * we used sk_X509_value() instead, but then we'd clean it in the
* subsequent sk_X509_pop_free() call.
*/
X509 *x = sk_X509_pop(ca);
@@ -1545,13 +1516,13 @@ fail:
key_blob = cert_blob;
}
else
- file_type = ossl_do_file_type(key_type);
+ file_type = do_file_type(key_type);
switch(file_type) {
case SSL_FILETYPE_PEM:
if(cert_done)
break;
- FALLTHROUGH();
+ /* FALLTHROUGH */
case SSL_FILETYPE_ASN1:
cert_use_result = key_blob ?
SSL_CTX_use_PrivateKey_blob(ctx, key_blob, file_type, key_passwd) :
@@ -1602,10 +1573,10 @@ fail:
EVP_PKEY_free(priv_key);
return 0;
}
- EVP_PKEY_free(priv_key); /* we do not need the handle any more... */
+ EVP_PKEY_free(priv_key); /* we don't need the handle any more... */
}
else {
- failf(data, "crypto engine not set, cannot load private key");
+ failf(data, "crypto engine not set, can't load private key");
return 0;
}
}
@@ -1644,8 +1615,8 @@ fail:
#if !defined(OPENSSL_NO_RSA) && !defined(OPENSSL_IS_BORINGSSL) && \
!defined(OPENSSL_NO_DEPRECATED_3_0)
{
- /* If RSA is used, do not check the private key if its flags indicate
- * it does not support it. */
+ /* If RSA is used, don't check the private key if its flags indicate
+ * it doesn't support it. */
EVP_PKEY *priv_key = SSL_get_privatekey(ssl);
int pktype;
#ifdef HAVE_OPAQUE_EVP_PKEY
@@ -1679,6 +1650,22 @@ fail:
return 1;
}
+CURLcode Curl_ossl_set_client_cert(struct Curl_easy *data, SSL_CTX *ctx,
+ char *cert_file,
+ const struct curl_blob *cert_blob,
+ const char *cert_type, char *key_file,
+ const struct curl_blob *key_blob,
+ const char *key_type, char *key_passwd)
+{
+ int rv = cert_stuff(data, ctx, cert_file, cert_blob, cert_type, key_file,
+ key_blob, key_type, key_passwd);
+ if(rv != 1) {
+ return CURLE_SSL_CERTPROBLEM;
+ }
+
+ return CURLE_OK;
+}
+
/* returns non-zero on failure */
static int x509_name_oneline(X509_NAME *a, char *buf, size_t size)
{
@@ -1695,7 +1682,7 @@ static int x509_name_oneline(X509_NAME *a, char *buf, size_t size)
if((size_t)biomem->length < size)
size = biomem->length;
else
- size--; /* do not overwrite the buffer end */
+ size--; /* don't overwrite the buffer end */
memcpy(buf, biomem->data, size);
buf[size] = 0;
@@ -1765,7 +1752,7 @@ static int ossl_init(void)
static void ossl_cleanup(void)
{
#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && \
- (!defined(LIBRESSL_VERSION_NUMBER) || LIBRESSL_VERSION_NUMBER >= 0x2070000fL)
+ !defined(LIBRESSL_VERSION_NUMBER)
/* OpenSSL 1.1 deprecates all these cleanup functions and
turns them into no-ops in OpenSSL 1.0 compatibility mode */
#else
@@ -1887,146 +1874,186 @@ static struct curl_slist *ossl_engines_list(struct Curl_easy *data)
return list;
}
-static CURLcode ossl_shutdown(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- bool send_shutdown, bool *done)
+static void ossl_close(struct Curl_cfilter *cf, struct Curl_easy *data)
{
struct ssl_connect_data *connssl = cf->ctx;
- struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend;
- CURLcode result = CURLE_OK;
- char buf[1024];
- int nread = -1, err;
- unsigned long sslerr;
- size_t i;
+ struct ossl_ssl_backend_data *backend =
+ (struct ossl_ssl_backend_data *)connssl->backend;
- DEBUGASSERT(octx);
- if(!octx->ssl || cf->shutdown) {
- *done = TRUE;
- goto out;
- }
+ (void)data;
+ DEBUGASSERT(backend);
- connssl->io_need = CURL_SSL_IO_NEED_NONE;
- *done = FALSE;
- if(!(SSL_get_shutdown(octx->ssl) & SSL_SENT_SHUTDOWN)) {
- /* We have not started the shutdown from our side yet. Check
- * if the server already sent us one. */
- ERR_clear_error();
- for(i = 0; i < 10; ++i) {
- nread = SSL_read(octx->ssl, buf, (int)sizeof(buf));
- CURL_TRC_CF(data, cf, "SSL shutdown not sent, read -> %d", nread);
- if(nread <= 0)
- break;
- }
- err = SSL_get_error(octx->ssl, nread);
- if(!nread && err == SSL_ERROR_ZERO_RETURN) {
- bool input_pending;
- /* Yes, it did. */
- if(!send_shutdown) {
- CURL_TRC_CF(data, cf, "SSL shutdown received, not sending");
- *done = TRUE;
- goto out;
+ if(backend->handle) {
+ if(cf->next && cf->next->connected) {
+ char buf[1024];
+ int nread, err;
+ long sslerr;
+
+ /* Maybe the server has already sent a close notify alert.
+ Read it to avoid an RST on the TCP connection. */
+ (void)SSL_read(backend->handle, buf, (int)sizeof(buf));
+ ERR_clear_error();
+ if(SSL_shutdown(backend->handle) == 1) {
+ CURL_TRC_CF(data, cf, "SSL shutdown finished");
}
- else if(!cf->next->cft->is_alive(cf->next, data, &input_pending)) {
- /* Server closed the connection after its closy notify. It
- * seems not interested to see our close notify, so do not
- * send it. We are done. */
- connssl->peer_closed = TRUE;
- CURL_TRC_CF(data, cf, "peer closed connection");
- *done = TRUE;
- goto out;
+ else {
+ nread = SSL_read(backend->handle, buf, (int)sizeof(buf));
+ err = SSL_get_error(backend->handle, nread);
+ switch(err) {
+ case SSL_ERROR_NONE: /* this is not an error */
+ case SSL_ERROR_ZERO_RETURN: /* no more data */
+ CURL_TRC_CF(data, cf, "SSL shutdown, EOF from server");
+ break;
+ case SSL_ERROR_WANT_READ:
+ /* SSL has send its notify and now wants to read the reply
+ * from the server. We are not really interested in that. */
+ CURL_TRC_CF(data, cf, "SSL shutdown sent");
+ break;
+ case SSL_ERROR_WANT_WRITE:
+ CURL_TRC_CF(data, cf, "SSL shutdown send blocked");
+ break;
+ default:
+ sslerr = ERR_get_error();
+ CURL_TRC_CF(data, cf, "SSL shutdown, error: '%s', errno %d",
+ (sslerr ?
+ ossl_strerror(sslerr, buf, sizeof(buf)) :
+ SSL_ERROR_to_str(err)),
+ SOCKERRNO);
+ break;
+ }
}
- }
- }
- /* SSL should now have started the shutdown from our side. Since it
- * was not complete, we are lacking the close notify from the server. */
- if(send_shutdown) {
- ERR_clear_error();
- if(SSL_shutdown(octx->ssl) == 1) {
- CURL_TRC_CF(data, cf, "SSL shutdown finished");
- *done = TRUE;
- goto out;
- }
- if(SSL_ERROR_WANT_WRITE == SSL_get_error(octx->ssl, nread)) {
- CURL_TRC_CF(data, cf, "SSL shutdown still wants to send");
- connssl->io_need = CURL_SSL_IO_NEED_SEND;
- goto out;
+ ERR_clear_error();
+ SSL_set_connect_state(backend->handle);
}
- /* Having sent the close notify, we use SSL_read() to get the
- * missing close notify from the server. */
- }
- for(i = 0; i < 10; ++i) {
- ERR_clear_error();
- nread = SSL_read(octx->ssl, buf, (int)sizeof(buf));
- CURL_TRC_CF(data, cf, "SSL shutdown read -> %d", nread);
- if(nread <= 0)
- break;
+ SSL_free(backend->handle);
+ backend->handle = NULL;
}
- err = SSL_get_error(octx->ssl, nread);
- switch(err) {
- case SSL_ERROR_ZERO_RETURN: /* no more data */
- CURL_TRC_CF(data, cf, "SSL shutdown not received, but closed");
- *done = TRUE;
- break;
- case SSL_ERROR_NONE: /* just did not get anything */
- case SSL_ERROR_WANT_READ:
- /* SSL has send its notify and now wants to read the reply
- * from the server. We are not really interested in that. */
- CURL_TRC_CF(data, cf, "SSL shutdown sent, want receive");
- connssl->io_need = CURL_SSL_IO_NEED_RECV;
- break;
- case SSL_ERROR_WANT_WRITE:
- CURL_TRC_CF(data, cf, "SSL shutdown send blocked");
- connssl->io_need = CURL_SSL_IO_NEED_SEND;
- break;
- default:
- /* Server seems to have closed the connection without sending us
- * a close notify. */
- sslerr = ERR_get_error();
- CURL_TRC_CF(data, cf, "SSL shutdown, ignore recv error: '%s', errno %d",
- (sslerr ?
- ossl_strerror(sslerr, buf, sizeof(buf)) :
- SSL_ERROR_to_str(err)),
- SOCKERRNO);
- *done = TRUE;
- result = CURLE_OK;
- break;
+ if(backend->ctx) {
+ SSL_CTX_free(backend->ctx);
+ backend->ctx = NULL;
+ backend->x509_store_setup = FALSE;
+ }
+ if(backend->bio_method) {
+ ossl_bio_cf_method_free(backend->bio_method);
+ backend->bio_method = NULL;
}
-
-out:
- cf->shutdown = (result || *done);
- return result;
}
-static void ossl_close(struct Curl_cfilter *cf, struct Curl_easy *data)
+/*
+ * This function is called to shut down the SSL layer but keep the
+ * socket open (CCC - Clear Command Channel)
+ */
+static int ossl_shutdown(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
+ int retval = 0;
struct ssl_connect_data *connssl = cf->ctx;
- struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend;
+ char buf[256]; /* We will use this for the OpenSSL error buffer, so it has
+ to be at least 256 bytes long. */
+ unsigned long sslerror;
+ int nread;
+ int buffsize;
+ int err;
+ bool done = FALSE;
+ struct ossl_ssl_backend_data *backend =
+ (struct ossl_ssl_backend_data *)connssl->backend;
+ int loop = 10;
+
+ DEBUGASSERT(backend);
+
+#ifndef CURL_DISABLE_FTP
+ /* This has only been tested on the proftpd server, and the mod_tls code
+ sends a close notify alert without waiting for a close notify alert in
+ response. Thus we wait for a close notify alert from the server, but
+ we do not send one. Let's hope other servers do the same... */
+
+ if(data->set.ftp_ccc == CURLFTPSSL_CCC_ACTIVE)
+ (void)SSL_shutdown(backend->handle);
+#endif
+
+ if(backend->handle) {
+ buffsize = (int)sizeof(buf);
+ while(!done && loop--) {
+ int what = SOCKET_READABLE(Curl_conn_cf_get_socket(cf, data),
+ SSL_SHUTDOWN_TIMEOUT);
+ if(what > 0) {
+ ERR_clear_error();
+
+ /* Something to read, let's do it and hope that it is the close
+ notify alert from the server */
+ nread = SSL_read(backend->handle, buf, buffsize);
+ err = SSL_get_error(backend->handle, nread);
+
+ switch(err) {
+ case SSL_ERROR_NONE: /* this is not an error */
+ case SSL_ERROR_ZERO_RETURN: /* no more data */
+ /* This is the expected response. There was no data but only
+ the close notify alert */
+ done = TRUE;
+ break;
+ case SSL_ERROR_WANT_READ:
+ /* there's data pending, re-invoke SSL_read() */
+ infof(data, "SSL_ERROR_WANT_READ");
+ break;
+ case SSL_ERROR_WANT_WRITE:
+ /* SSL wants a write. Really odd. Let's bail out. */
+ infof(data, "SSL_ERROR_WANT_WRITE");
+ done = TRUE;
+ break;
+ default:
+ /* openssl/ssl.h says "look at error stack/return value/errno" */
+ sslerror = ERR_get_error();
+ failf(data, OSSL_PACKAGE " SSL_read on shutdown: %s, errno %d",
+ (sslerror ?
+ ossl_strerror(sslerror, buf, sizeof(buf)) :
+ SSL_ERROR_to_str(err)),
+ SOCKERRNO);
+ done = TRUE;
+ break;
+ }
+ }
+ else if(0 == what) {
+ /* timeout */
+ failf(data, "SSL shutdown timeout");
+ done = TRUE;
+ }
+ else {
+ /* anything that gets here is fatally bad */
+ failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
+ retval = -1;
+ done = TRUE;
+ }
+ } /* while()-loop for the select() */
- (void)data;
- DEBUGASSERT(octx);
+ if(data->set.verbose) {
+#ifdef HAVE_SSL_GET_SHUTDOWN
+ switch(SSL_get_shutdown(backend->handle)) {
+ case SSL_SENT_SHUTDOWN:
+ infof(data, "SSL_get_shutdown() returned SSL_SENT_SHUTDOWN");
+ break;
+ case SSL_RECEIVED_SHUTDOWN:
+ infof(data, "SSL_get_shutdown() returned SSL_RECEIVED_SHUTDOWN");
+ break;
+ case SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN:
+ infof(data, "SSL_get_shutdown() returned SSL_SENT_SHUTDOWN|"
+ "SSL_RECEIVED__SHUTDOWN");
+ break;
+ }
+#endif
+ }
- if(octx->ssl) {
- SSL_free(octx->ssl);
- octx->ssl = NULL;
- }
- if(octx->ssl_ctx) {
- SSL_CTX_free(octx->ssl_ctx);
- octx->ssl_ctx = NULL;
- octx->x509_store_setup = FALSE;
- }
- if(octx->bio_method) {
- ossl_bio_cf_method_free(octx->bio_method);
- octx->bio_method = NULL;
+ SSL_free(backend->handle);
+ backend->handle = NULL;
}
+ return retval;
}
-static void ossl_session_free(void *sessionid, size_t idsize)
+static void ossl_session_free(void *ptr)
{
/* free the ID */
- (void)idsize;
- free(sessionid);
+ SSL_SESSION_free(ptr);
}
/*
@@ -2057,7 +2084,7 @@ static void ossl_close_all(struct Curl_easy *data)
/* ====================================================== */
/*
- * Match subjectAltName against the hostname.
+ * Match subjectAltName against the host name.
*/
static bool subj_alt_hostcheck(struct Curl_easy *data,
const char *match_pattern,
@@ -2087,7 +2114,7 @@ static bool subj_alt_hostcheck(struct Curl_easy *data,
Certification Authorities are encouraged to use the dNSName instead.
Matching is performed using the matching rules specified by
- [RFC2459]. If more than one identity of a given type is present in
+ [RFC2459]. If more than one identity of a given type is present in
the certificate (e.g., more than one dNSName name, a match in any one
of the set is considered acceptable.) Names may contain the wildcard
character * which is considered to match any single domain name
@@ -2100,48 +2127,38 @@ static bool subj_alt_hostcheck(struct Curl_easy *data,
This function is now used from ngtcp2 (QUIC) as well.
*/
-static CURLcode ossl_verifyhost(struct Curl_easy *data,
- struct connectdata *conn,
- struct ssl_peer *peer, X509 *server_cert)
+CURLcode Curl_ossl_verifyhost(struct Curl_easy *data, struct connectdata *conn,
+ struct ssl_peer *peer, X509 *server_cert)
{
bool matched = FALSE;
- int target; /* target type, GEN_DNS or GEN_IPADD */
+ int target = GEN_DNS; /* target type, GEN_DNS or GEN_IPADD */
size_t addrlen = 0;
STACK_OF(GENERAL_NAME) *altnames;
-#ifdef USE_IPV6
+#ifdef ENABLE_IPV6
struct in6_addr addr;
#else
struct in_addr addr;
#endif
CURLcode result = CURLE_OK;
bool dNSName = FALSE; /* if a dNSName field exists in the cert */
- bool iPAddress = FALSE; /* if an iPAddress field exists in the cert */
+ bool iPAddress = FALSE; /* if a iPAddress field exists in the cert */
size_t hostlen;
(void)conn;
hostlen = strlen(peer->hostname);
- switch(peer->type) {
- case CURL_SSL_PEER_IPV4:
- if(!Curl_inet_pton(AF_INET, peer->hostname, &addr))
- return CURLE_PEER_FAILED_VERIFICATION;
- target = GEN_IPADD;
- addrlen = sizeof(struct in_addr);
- break;
-#ifdef USE_IPV6
- case CURL_SSL_PEER_IPV6:
- if(!Curl_inet_pton(AF_INET6, peer->hostname, &addr))
- return CURLE_PEER_FAILED_VERIFICATION;
- target = GEN_IPADD;
- addrlen = sizeof(struct in6_addr);
- break;
+ if(peer->is_ip_address) {
+#ifdef ENABLE_IPV6
+ if(conn->bits.ipv6_ip &&
+ Curl_inet_pton(AF_INET6, peer->hostname, &addr)) {
+ target = GEN_IPADD;
+ addrlen = sizeof(struct in6_addr);
+ }
+ else
#endif
- case CURL_SSL_PEER_DNS:
- target = GEN_DNS;
- break;
- default:
- DEBUGASSERT(0);
- failf(data, "unexpected ssl peer type: %d", peer->type);
- return CURLE_PEER_FAILED_VERIFICATION;
+ if(Curl_inet_pton(AF_INET, peer->hostname, &addr)) {
+ target = GEN_IPADD;
+ addrlen = sizeof(struct in_addr);
+ }
}
/* get a "list" of alternative names */
@@ -2159,7 +2176,7 @@ static CURLcode ossl_verifyhost(struct Curl_easy *data,
bool ipmatched = FALSE;
/* get amount of alternatives, RFC2459 claims there MUST be at least
- one, but we do not depend on it... */
+ one, but we don't depend on it... */
numalts = sk_GENERAL_NAME_num(altnames);
/* loop through all alternatives - until a dnsmatch */
@@ -2180,7 +2197,7 @@ static CURLcode ossl_verifyhost(struct Curl_easy *data,
switch(target) {
case GEN_DNS: /* name/pattern comparison */
- /* The OpenSSL manpage explicitly says: "In general it cannot be
+ /* The OpenSSL man page explicitly says: "In general it cannot be
assumed that the data returned by ASN1_STRING_data() is null
terminated or does not contain embedded nulls." But also that
"The actual format of the data will depend on the actual string
@@ -2190,7 +2207,7 @@ static CURLcode ossl_verifyhost(struct Curl_easy *data,
is always null-terminated.
*/
if((altlen == strlen(altptr)) &&
- /* if this is not true, there was an embedded zero in the name
+ /* if this isn't true, there was an embedded zero in the name
string and we cannot match it. */
subj_alt_hostcheck(data, altptr, altlen,
peer->hostname, hostlen,
@@ -2222,12 +2239,9 @@ static CURLcode ossl_verifyhost(struct Curl_easy *data,
/* an alternative name matched */
;
else if(dNSName || iPAddress) {
- const char *tname = (peer->type == CURL_SSL_PEER_DNS) ? "hostname" :
- (peer->type == CURL_SSL_PEER_IPV4) ?
- "ipv4 address" : "ipv6 address";
- infof(data, " subjectAltName does not match %s %s", tname, peer->dispname);
+ infof(data, " subjectAltName does not match %s", peer->dispname);
failf(data, "SSL: no alternative certificate subject name matches "
- "target %s '%s'", tname, peer->dispname);
+ "target host name '%s'", peer->dispname);
result = CURLE_PEER_FAILED_VERIFICATION;
}
else {
@@ -2293,7 +2307,7 @@ static CURLcode ossl_verifyhost(struct Curl_easy *data,
else if(!Curl_cert_hostcheck((const char *)peer_CN,
peerlen, peer->hostname, hostlen)) {
failf(data, "SSL: certificate subject name '%s' does not match "
- "target hostname '%s'", peer_CN, peer->dispname);
+ "target host name '%s'", peer_CN, peer->dispname);
result = CURLE_PEER_FAILED_VERIFICATION;
}
else {
@@ -2309,9 +2323,9 @@ static CURLcode ossl_verifyhost(struct Curl_easy *data,
#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \
!defined(OPENSSL_NO_OCSP)
static CURLcode verifystatus(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- struct ossl_ctx *octx)
+ struct Curl_easy *data)
{
+ struct ssl_connect_data *connssl = cf->ctx;
int i, ocsp_status;
#if defined(OPENSSL_IS_AWSLC)
const uint8_t *status;
@@ -2324,6 +2338,8 @@ static CURLcode verifystatus(struct Curl_cfilter *cf,
OCSP_BASICRESP *br = NULL;
X509_STORE *st = NULL;
STACK_OF(X509) *ch = NULL;
+ struct ossl_ssl_backend_data *backend =
+ (struct ossl_ssl_backend_data *)connssl->backend;
X509 *cert;
OCSP_CERTID *id = NULL;
int cert_status, crl_reason;
@@ -2331,10 +2347,9 @@ static CURLcode verifystatus(struct Curl_cfilter *cf,
int ret;
long len;
- (void)cf;
- DEBUGASSERT(octx);
+ DEBUGASSERT(backend);
- len = (long)SSL_get_tlsext_status_ocsp_resp(octx->ssl, &status);
+ len = SSL_get_tlsext_status_ocsp_resp(backend->handle, &status);
if(!status) {
failf(data, "No OCSP response received");
@@ -2364,20 +2379,20 @@ static CURLcode verifystatus(struct Curl_cfilter *cf,
goto end;
}
- ch = SSL_get_peer_cert_chain(octx->ssl);
+ ch = SSL_get_peer_cert_chain(backend->handle);
if(!ch) {
failf(data, "Could not get peer certificate chain");
result = CURLE_SSL_INVALIDCERTSTATUS;
goto end;
}
- st = SSL_CTX_get_cert_store(octx->ssl_ctx);
+ st = SSL_CTX_get_cert_store(backend->ctx);
#if ((OPENSSL_VERSION_NUMBER <= 0x1000201fL) /* Fixed after 1.0.2a */ || \
(defined(LIBRESSL_VERSION_NUMBER) && \
LIBRESSL_VERSION_NUMBER <= 0x2040200fL))
/* The authorized responder cert in the OCSP response MUST be signed by the
- peer cert's issuer (see RFC6960 section 4.2.2.2). If that is a root cert,
- no problem, but if it is an intermediate cert OpenSSL has a bug where it
+ peer cert's issuer (see RFC6960 section 4.2.2.2). If that's a root cert,
+ no problem, but if it's an intermediate cert OpenSSL has a bug where it
expects this issuer to be present in the chain embedded in the OCSP
response. So we add it if necessary. */
@@ -2407,7 +2422,7 @@ static CURLcode verifystatus(struct Curl_cfilter *cf,
}
/* Compute the certificate's ID */
- cert = SSL_get1_peer_certificate(octx->ssl);
+ cert = SSL_get1_peer_certificate(backend->handle);
if(!cert) {
failf(data, "Error getting peer certificate");
result = CURLE_SSL_INVALIDCERTSTATUS;
@@ -2415,7 +2430,7 @@ static CURLcode verifystatus(struct Curl_cfilter *cf,
}
for(i = 0; i < (int)sk_X509_num(ch); i++) {
- X509 *issuer = sk_X509_value(ch, (ossl_valsize_t)i);
+ X509 *issuer = sk_X509_value(ch, i);
if(X509_check_issued(issuer, cert) == X509_V_OK) {
id = OCSP_cert_to_id(EVP_sha1(), cert, issuer);
break;
@@ -2476,7 +2491,7 @@ end:
#endif /* USE_OPENSSL */
-/* The SSL_CTRL_SET_MSG_CALLBACK does not exist in ancient OpenSSL versions
+/* The SSL_CTRL_SET_MSG_CALLBACK doesn't exist in ancient OpenSSL versions
and thus this cannot be done there. */
#ifdef SSL_CTRL_SET_MSG_CALLBACK
@@ -2661,7 +2676,7 @@ static void ossl_trace(int direction, int ssl_ver, int content_type,
ssl_ver >>= 8; /* check the upper 8 bits only below */
- /* SSLv2 does not seem to have TLS record-type headers, so OpenSSL
+ /* SSLv2 doesn't seem to have TLS record-type headers, so OpenSSL
* always pass-up content-type as 0. But the interesting message-type
* is at 'buf[0]'.
*/
@@ -2748,7 +2763,7 @@ ossl_set_ssl_version_min_max(struct Curl_cfilter *cf, SSL_CTX *ctx)
}
/* CURL_SSLVERSION_DEFAULT means that no option was selected.
- We do not want to pass 0 to SSL_CTX_set_min_proto_version as
+ We don't want to pass 0 to SSL_CTX_set_min_proto_version as
it would enable all versions down to the lowest supported by
the library.
So we skip this, and stay with the library default
@@ -2760,7 +2775,7 @@ ossl_set_ssl_version_min_max(struct Curl_cfilter *cf, SSL_CTX *ctx)
}
/* ... then, TLS max version */
- curl_ssl_version_max = (long)conn_config->version_max;
+ curl_ssl_version_max = conn_config->version_max;
/* convert curl max SSL version option to OpenSSL constant */
switch(curl_ssl_version_max) {
@@ -2801,9 +2816,6 @@ ossl_set_ssl_version_min_max(struct Curl_cfilter *cf, SSL_CTX *ctx)
typedef uint32_t ctx_option_t;
#elif OPENSSL_VERSION_NUMBER >= 0x30000000L
typedef uint64_t ctx_option_t;
-#elif OPENSSL_VERSION_NUMBER >= 0x10100000L && \
- !defined(LIBRESSL_VERSION_NUMBER)
-typedef unsigned long ctx_option_t;
#else
typedef long ctx_option_t;
#endif
@@ -2811,23 +2823,24 @@ typedef long ctx_option_t;
#if (OPENSSL_VERSION_NUMBER < 0x10100000L) /* 1.1.0 */
static CURLcode
ossl_set_ssl_version_min_max_legacy(ctx_option_t *ctx_options,
- struct Curl_cfilter *cf,
- struct Curl_easy *data)
+ struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
long ssl_version = conn_config->version;
long ssl_version_max = conn_config->version_max;
- (void) data; /* In case it is unused. */
+ (void) data; /* In case it's unused. */
switch(ssl_version) {
case CURL_SSLVERSION_TLSv1_3:
#ifdef TLS1_3_VERSION
{
struct ssl_connect_data *connssl = cf->ctx;
- struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend;
- DEBUGASSERT(octx);
- SSL_CTX_set_max_proto_version(octx->ssl_ctx, TLS1_3_VERSION);
+ struct ossl_ssl_backend_data *backend =
+ (struct ossl_ssl_backend_data *)connssl->backend;
+ DEBUGASSERT(backend);
+ SSL_CTX_set_max_proto_version(backend->ctx, TLS1_3_VERSION);
*ctx_options |= SSL_OP_NO_TLSv1_2;
}
#else
@@ -2835,7 +2848,7 @@ ossl_set_ssl_version_min_max_legacy(ctx_option_t *ctx_options,
failf(data, OSSL_PACKAGE " was built without TLS 1.3 support");
return CURLE_NOT_BUILT_IN;
#endif
- FALLTHROUGH();
+ /* FALLTHROUGH */
case CURL_SSLVERSION_TLSv1_2:
#if OPENSSL_VERSION_NUMBER >= 0x1000100FL
*ctx_options |= SSL_OP_NO_TLSv1_1;
@@ -2843,7 +2856,7 @@ ossl_set_ssl_version_min_max_legacy(ctx_option_t *ctx_options,
failf(data, OSSL_PACKAGE " was built without TLS 1.2 support");
return CURLE_NOT_BUILT_IN;
#endif
- FALLTHROUGH();
+ /* FALLTHROUGH */
case CURL_SSLVERSION_TLSv1_1:
#if OPENSSL_VERSION_NUMBER >= 0x1000100FL
*ctx_options |= SSL_OP_NO_TLSv1;
@@ -2851,7 +2864,7 @@ ossl_set_ssl_version_min_max_legacy(ctx_option_t *ctx_options,
failf(data, OSSL_PACKAGE " was built without TLS 1.1 support");
return CURLE_NOT_BUILT_IN;
#endif
- FALLTHROUGH();
+ /* FALLTHROUGH */
case CURL_SSLVERSION_TLSv1_0:
case CURL_SSLVERSION_TLSv1:
break;
@@ -2862,12 +2875,12 @@ ossl_set_ssl_version_min_max_legacy(ctx_option_t *ctx_options,
#if OPENSSL_VERSION_NUMBER >= 0x1000100FL
*ctx_options |= SSL_OP_NO_TLSv1_1;
#endif
- FALLTHROUGH();
+ /* FALLTHROUGH */
case CURL_SSLVERSION_MAX_TLSv1_1:
#if OPENSSL_VERSION_NUMBER >= 0x1000100FL
*ctx_options |= SSL_OP_NO_TLSv1_2;
#endif
- FALLTHROUGH();
+ /* FALLTHROUGH */
case CURL_SSLVERSION_MAX_TLSv1_2:
#ifdef TLS1_3_VERSION
*ctx_options |= SSL_OP_NO_TLSv1_3;
@@ -2885,66 +2898,61 @@ ossl_set_ssl_version_min_max_legacy(ctx_option_t *ctx_options,
}
#endif
-CURLcode Curl_ossl_add_session(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- const struct ssl_peer *peer,
- SSL_SESSION *session)
+/* The "new session" callback must return zero if the session can be removed
+ * or non-zero if the session has been put into the session cache.
+ */
+static int ossl_new_session_cb(SSL *ssl, SSL_SESSION *ssl_sessionid)
{
+ int res = 0;
+ struct Curl_easy *data;
+ struct Curl_cfilter *cf;
const struct ssl_config_data *config;
- CURLcode result = CURLE_OK;
- size_t der_session_size;
- unsigned char *der_session_buf;
- unsigned char *der_session_ptr;
+ struct ssl_connect_data *connssl;
+ bool isproxy;
+ cf = (struct Curl_cfilter*) SSL_get_app_data(ssl);
+ connssl = cf? cf->ctx : NULL;
+ data = connssl? CF_DATA_CURRENT(cf) : NULL;
+ /* The sockindex has been stored as a pointer to an array element */
if(!cf || !data)
- goto out;
+ return 0;
- config = Curl_ssl_cf_get_config(cf, data);
- if(config->primary.cache_session) {
+ isproxy = Curl_ssl_cf_is_proxy(cf);
- der_session_size = i2d_SSL_SESSION(session, NULL);
- if(der_session_size == 0) {
- result = CURLE_OUT_OF_MEMORY;
- goto out;
- }
+ config = Curl_ssl_cf_get_config(cf, data);
+ if(config->primary.sessionid) {
+ bool incache;
+ bool added = FALSE;
+ void *old_ssl_sessionid = NULL;
- der_session_buf = der_session_ptr = malloc(der_session_size);
- if(!der_session_buf) {
- result = CURLE_OUT_OF_MEMORY;
- goto out;
+ Curl_ssl_sessionid_lock(data);
+ if(isproxy)
+ incache = FALSE;
+ else
+ incache = !(Curl_ssl_getsessionid(cf, data, &old_ssl_sessionid, NULL));
+ if(incache) {
+ if(old_ssl_sessionid != ssl_sessionid) {
+ infof(data, "old SSL session ID is stale, removing");
+ Curl_ssl_delsessionid(data, old_ssl_sessionid);
+ incache = FALSE;
+ }
}
- der_session_size = i2d_SSL_SESSION(session, &der_session_ptr);
- if(der_session_size == 0) {
- result = CURLE_OUT_OF_MEMORY;
- free(der_session_buf);
- goto out;
+ if(!incache) {
+ if(!Curl_ssl_addsessionid(cf, data, ssl_sessionid,
+ 0 /* unknown size */, &added)) {
+ if(added) {
+ /* the session has been put into the session cache */
+ res = 1;
+ }
+ }
+ else
+ failf(data, "failed to store ssl session");
}
-
- Curl_ssl_sessionid_lock(data);
- result = Curl_ssl_set_sessionid(cf, data, peer, der_session_buf,
- der_session_size, ossl_session_free);
Curl_ssl_sessionid_unlock(data);
}
-out:
- return result;
-}
-
-/* The "new session" callback must return zero if the session can be removed
- * or non-zero if the session has been put into the session cache.
- */
-static int ossl_new_session_cb(SSL *ssl, SSL_SESSION *ssl_sessionid)
-{
- struct Curl_cfilter *cf;
- struct Curl_easy *data;
- struct ssl_connect_data *connssl;
-
- cf = (struct Curl_cfilter*) SSL_get_app_data(ssl);
- connssl = cf? cf->ctx : NULL;
- data = connssl? CF_DATA_CURRENT(cf) : NULL;
- Curl_ossl_add_session(cf, data, &connssl->peer, ssl_sessionid);
- return 0;
+ return res;
}
static CURLcode load_cacert_from_memory(X509_STORE *store,
@@ -2973,7 +2981,7 @@ static CURLcode load_cacert_from_memory(X509_STORE *store,
/* add each entry from PEM file to x509_store */
for(i = 0; i < (int)sk_X509_INFO_num(inf); ++i) {
- itmp = sk_X509_INFO_value(inf, (ossl_valsize_t)i);
+ itmp = sk_X509_INFO_value(inf, i);
if(itmp->x509) {
if(X509_STORE_add_cert(store, itmp->x509)) {
++count;
@@ -2999,7 +3007,7 @@ static CURLcode load_cacert_from_memory(X509_STORE *store,
sk_X509_INFO_pop_free(inf, X509_INFO_free);
BIO_free(cbio);
- /* if we did not end up importing anything, treat that as an error */
+ /* if we didn't end up importing anything, treat that as an error */
return (count > 0) ? CURLE_OK : CURLE_SSL_CACERT_BADFILE;
}
@@ -3120,7 +3128,7 @@ static CURLcode import_windows_cert_store(struct Curl_easy *data,
else
continue;
- x509 = d2i_X509(NULL, &encoded_cert, (long)pContext->cbCertEncoded);
+ x509 = d2i_X509(NULL, &encoded_cert, pContext->cbCertEncoded);
if(!x509)
continue;
@@ -3166,8 +3174,6 @@ static CURLcode populate_x509_store(struct Curl_cfilter *cf,
bool imported_native_ca = false;
bool imported_ca_info_blob = false;
- CURL_TRC_CF(data, cf, "populate_x509_store, path=%s, blob=%d",
- ssl_cafile? ssl_cafile : "none", !!ca_info_blob);
if(!store)
return CURLE_OUT_OF_MEMORY;
@@ -3258,8 +3264,8 @@ static CURLcode populate_x509_store(struct Curl_cfilter *cf,
#ifdef CURL_CA_FALLBACK
if(!ssl_cafile && !ssl_capath &&
!imported_native_ca && !imported_ca_info_blob) {
- /* verifying the peer without any CA certificates will not
- work so use OpenSSL's built-in default as fallback */
+ /* verifying the peer without any CA certificates won't
+ work so use openssl's built-in default as fallback */
X509_STORE_set_default_paths(store);
}
#endif
@@ -3284,11 +3290,10 @@ static CURLcode populate_x509_store(struct Curl_cfilter *cf,
if(verifypeer) {
/* Try building a chain using issuers in the trusted store first to avoid
- problems with server-sent legacy intermediates. Newer versions of
+ problems with server-sent legacy intermediates. Newer versions of
OpenSSL do alternate chain checking by default but we do not know how to
determine that in a reliable manner.
- https://web.archive.org/web/20190422050538/
- rt.openssl.org/Ticket/Display.html?id=3621
+ https://rt.openssl.org/Ticket/Display.html?id=3621&user=guest&pass=guest
*/
#if defined(X509_V_FLAG_TRUSTED_FIRST)
X509_STORE_set_flags(store, X509_V_FLAG_TRUSTED_FIRST);
@@ -3312,49 +3317,23 @@ static CURLcode populate_x509_store(struct Curl_cfilter *cf,
}
#if defined(HAVE_SSL_X509_STORE_SHARE)
-
-/* key to use at `multi->proto_hash` */
-#define MPROTO_OSSL_X509_KEY "tls:ossl:x509:share"
-
-struct ossl_x509_share {
- char *CAfile; /* CAfile path used to generate X509 store */
- X509_STORE *store; /* cached X509 store or NULL if none */
- struct curltime time; /* when the cached store was created */
-};
-
-static void oss_x509_share_free(void *key, size_t key_len, void *p)
-{
- struct ossl_x509_share *share = p;
- DEBUGASSERT(key_len == (sizeof(MPROTO_OSSL_X509_KEY)-1));
- DEBUGASSERT(!memcmp(MPROTO_OSSL_X509_KEY, key, key_len));
- (void)key;
- (void)key_len;
- if(share->store) {
- X509_STORE_free(share->store);
- }
- free(share->CAfile);
- free(share);
-}
-
-static bool
-cached_x509_store_expired(const struct Curl_easy *data,
- const struct ossl_x509_share *mb)
+static bool cached_x509_store_expired(const struct Curl_easy *data,
+ const struct multi_ssl_backend_data *mb)
{
const struct ssl_general_config *cfg = &data->set.general_ssl;
- if(cfg->ca_cache_timeout < 0)
- return FALSE;
- else {
- struct curltime now = Curl_now();
- timediff_t elapsed_ms = Curl_timediff(now, mb->time);
- timediff_t timeout_ms = cfg->ca_cache_timeout * (timediff_t)1000;
+ struct curltime now = Curl_now();
+ timediff_t elapsed_ms = Curl_timediff(now, mb->time);
+ timediff_t timeout_ms = cfg->ca_cache_timeout * (timediff_t)1000;
- return elapsed_ms >= timeout_ms;
- }
+ if(timeout_ms < 0)
+ return false;
+
+ return elapsed_ms >= timeout_ms;
}
-static bool
-cached_x509_store_different(struct Curl_cfilter *cf,
- const struct ossl_x509_share *mb)
+static bool cached_x509_store_different(
+ struct Curl_cfilter *cf,
+ const struct multi_ssl_backend_data *mb)
{
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
if(!mb->CAfile || !conn_config->CAfile)
@@ -3366,18 +3345,16 @@ cached_x509_store_different(struct Curl_cfilter *cf,
static X509_STORE *get_cached_x509_store(struct Curl_cfilter *cf,
const struct Curl_easy *data)
{
- struct Curl_multi *multi = data->multi;
- struct ossl_x509_share *share;
+ struct Curl_multi *multi = data->multi_easy ? data->multi_easy : data->multi;
X509_STORE *store = NULL;
DEBUGASSERT(multi);
- share = multi? Curl_hash_pick(&multi->proto_hash,
- (void *)MPROTO_OSSL_X509_KEY,
- sizeof(MPROTO_OSSL_X509_KEY)-1) : NULL;
- if(share && share->store &&
- !cached_x509_store_expired(data, share) &&
- !cached_x509_store_different(cf, share)) {
- store = share->store;
+ if(multi &&
+ multi->ssl_backend_data &&
+ multi->ssl_backend_data->store &&
+ !cached_x509_store_expired(data, multi->ssl_backend_data) &&
+ !cached_x509_store_different(cf, multi->ssl_backend_data)) {
+ store = multi->ssl_backend_data->store;
}
return store;
@@ -3388,29 +3365,21 @@ static void set_cached_x509_store(struct Curl_cfilter *cf,
X509_STORE *store)
{
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
- struct Curl_multi *multi = data->multi;
- struct ossl_x509_share *share;
+ struct Curl_multi *multi = data->multi_easy ? data->multi_easy : data->multi;
+ struct multi_ssl_backend_data *mbackend;
DEBUGASSERT(multi);
if(!multi)
return;
- share = Curl_hash_pick(&multi->proto_hash,
- (void *)MPROTO_OSSL_X509_KEY,
- sizeof(MPROTO_OSSL_X509_KEY)-1);
- if(!share) {
- share = calloc(1, sizeof(*share));
- if(!share)
- return;
- if(!Curl_hash_add2(&multi->proto_hash,
- (void *)MPROTO_OSSL_X509_KEY,
- sizeof(MPROTO_OSSL_X509_KEY)-1,
- share, oss_x509_share_free)) {
- free(share);
+ if(!multi->ssl_backend_data) {
+ multi->ssl_backend_data = calloc(1, sizeof(struct multi_ssl_backend_data));
+ if(!multi->ssl_backend_data)
return;
- }
}
+ mbackend = multi->ssl_backend_data;
+
if(X509_STORE_up_ref(store)) {
char *CAfile = NULL;
@@ -3422,14 +3391,14 @@ static void set_cached_x509_store(struct Curl_cfilter *cf,
}
}
- if(share->store) {
- X509_STORE_free(share->store);
- free(share->CAfile);
+ if(mbackend->store) {
+ X509_STORE_free(mbackend->store);
+ free(mbackend->CAfile);
}
- share->time = Curl_now();
- share->store = store;
- share->CAfile = CAfile;
+ mbackend->time = Curl_now();
+ mbackend->store = store;
+ mbackend->CAfile = CAfile;
}
}
@@ -3444,7 +3413,7 @@ CURLcode Curl_ssl_setup_x509_store(struct Curl_cfilter *cf,
bool cache_criteria_met;
/* Consider the X509 store cacheable if it comes exclusively from a CAfile,
- or no source is provided and we are falling back to OpenSSL's built-in
+ or no source is provided and we are falling back to openssl's built-in
default. */
cache_criteria_met = (data->set.general_ssl.ca_cache_timeout != 0) &&
conn_config->verifypeer &&
@@ -3479,32 +3448,29 @@ CURLcode Curl_ssl_setup_x509_store(struct Curl_cfilter *cf,
}
#endif /* HAVE_SSL_X509_STORE_SHARE */
-CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx,
- struct Curl_cfilter *cf,
- struct Curl_easy *data,
- struct ssl_peer *peer,
- int transport, /* TCP or QUIC */
- const unsigned char *alpn, size_t alpn_len,
- Curl_ossl_ctx_setup_cb *cb_setup,
- void *cb_user_data,
- Curl_ossl_new_session_cb *cb_new_session,
- void *ssl_user_data)
+static CURLcode ossl_connect_step1(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
CURLcode result = CURLE_OK;
- const char *ciphers;
+ char *ciphers;
SSL_METHOD_QUAL SSL_METHOD *req_method = NULL;
+ struct ssl_connect_data *connssl = cf->ctx;
ctx_option_t ctx_options = 0;
- SSL_SESSION *ssl_session = NULL;
- const unsigned char *der_sessionid = NULL;
- size_t der_sessionid_size = 0;
+ void *ssl_sessionid = NULL;
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
- const long int ssl_version_min = conn_config->version;
+ BIO *bio;
+ const long int ssl_version = conn_config->version;
char * const ssl_cert = ssl_config->primary.clientcert;
const struct curl_blob *ssl_cert_blob = ssl_config->primary.cert_blob;
const char * const ssl_cert_type = ssl_config->cert_type;
const bool verifypeer = conn_config->verifypeer;
char error_buffer[256];
+ struct ossl_ssl_backend_data *backend =
+ (struct ossl_ssl_backend_data *)connssl->backend;
+
+ DEBUGASSERT(ssl_connect_1 == connssl->connecting_state);
+ DEBUGASSERT(backend);
/* Make funny stuff to get random input */
result = ossl_seed(data);
@@ -3513,86 +3479,67 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx,
ssl_config->certverifyresult = !X509_V_OK;
- switch(transport) {
- case TRNSPRT_TCP:
- /* check to see if we have been told to use an explicit SSL/TLS version */
- switch(ssl_version_min) {
- case CURL_SSLVERSION_DEFAULT:
- case CURL_SSLVERSION_TLSv1:
- case CURL_SSLVERSION_TLSv1_0:
- case CURL_SSLVERSION_TLSv1_1:
- case CURL_SSLVERSION_TLSv1_2:
- case CURL_SSLVERSION_TLSv1_3:
- /* it will be handled later with the context options */
- #if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
- req_method = TLS_client_method();
- #else
- req_method = SSLv23_client_method();
- #endif
- break;
- case CURL_SSLVERSION_SSLv2:
- failf(data, "No SSLv2 support");
- return CURLE_NOT_BUILT_IN;
- case CURL_SSLVERSION_SSLv3:
- failf(data, "No SSLv3 support");
- return CURLE_NOT_BUILT_IN;
- default:
- failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
- return CURLE_SSL_CONNECT_ERROR;
- }
- break;
- case TRNSPRT_QUIC:
- if(conn_config->version_max &&
- (conn_config->version_max != CURL_SSLVERSION_MAX_TLSv1_3)) {
- failf(data, "QUIC needs at least TLS version 1.3");
- return CURLE_SSL_CONNECT_ERROR;
- }
+ /* check to see if we've been told to use an explicit SSL/TLS version */
-#ifdef USE_OPENSSL_QUIC
- req_method = OSSL_QUIC_client_method();
-#elif (OPENSSL_VERSION_NUMBER >= 0x10100000L)
- req_method = TLS_method();
+ switch(ssl_version) {
+ case CURL_SSLVERSION_DEFAULT:
+ case CURL_SSLVERSION_TLSv1:
+ case CURL_SSLVERSION_TLSv1_0:
+ case CURL_SSLVERSION_TLSv1_1:
+ case CURL_SSLVERSION_TLSv1_2:
+ case CURL_SSLVERSION_TLSv1_3:
+ /* it will be handled later with the context options */
+#if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
+ req_method = TLS_client_method();
#else
req_method = SSLv23_client_method();
#endif
break;
+ case CURL_SSLVERSION_SSLv2:
+ failf(data, "No SSLv2 support");
+ return CURLE_NOT_BUILT_IN;
+ case CURL_SSLVERSION_SSLv3:
+ failf(data, "No SSLv3 support");
+ return CURLE_NOT_BUILT_IN;
default:
- failf(data, "unsupported transport %d in SSL init", transport);
+ failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
return CURLE_SSL_CONNECT_ERROR;
}
+ if(backend->ctx) {
+ /* This happens when an error was encountered before in this
+ * step and we are called to do it again. Get rid of any leftover
+ * from the previous call. */
+ ossl_close(cf, data);
+ }
+ backend->ctx = SSL_CTX_new(req_method);
- DEBUGASSERT(!octx->ssl_ctx);
- octx->ssl_ctx = SSL_CTX_new(req_method);
-
- if(!octx->ssl_ctx) {
- failf(data, "SSL: could not create a context: %s",
+ if(!backend->ctx) {
+ failf(data, "SSL: couldn't create a context: %s",
ossl_strerror(ERR_peek_error(), error_buffer, sizeof(error_buffer)));
return CURLE_OUT_OF_MEMORY;
}
- if(cb_setup) {
- result = cb_setup(cf, data, cb_user_data);
- if(result)
- return result;
- }
+#ifdef SSL_MODE_RELEASE_BUFFERS
+ SSL_CTX_set_mode(backend->ctx, SSL_MODE_RELEASE_BUFFERS);
+#endif
#ifdef SSL_CTRL_SET_MSG_CALLBACK
if(data->set.fdebug && data->set.verbose) {
/* the SSL trace callback is only used for verbose logging */
- SSL_CTX_set_msg_callback(octx->ssl_ctx, ossl_trace);
- SSL_CTX_set_msg_callback_arg(octx->ssl_ctx, cf);
+ SSL_CTX_set_msg_callback(backend->ctx, ossl_trace);
+ SSL_CTX_set_msg_callback_arg(backend->ctx, cf);
}
#endif
/* OpenSSL contains code to work around lots of bugs and flaws in various
SSL-implementations. SSL_CTX_set_options() is used to enabled those
- work-arounds. The manpage for this option states that SSL_OP_ALL enables
+ work-arounds. The man page for this option states that SSL_OP_ALL enables
all the work-arounds and that "It is usually safe to use SSL_OP_ALL to
enable the bug workaround options if compatibility with somewhat broken
implementations is desired."
- The "-no_ticket" option was introduced in OpenSSL 0.9.8j. it is a flag to
+ The "-no_ticket" option was introduced in OpenSSL 0.9.8j. It's a flag to
disable "rfc4507bis session ticket support". rfc4507bis was later turned
into the proper RFC5077: https://datatracker.ietf.org/doc/html/rfc5077
@@ -3613,12 +3560,12 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx,
CVE-2010-4180 when using previous OpenSSL versions we no longer enable
this option regardless of OpenSSL version and SSL_OP_ALL definition.
- OpenSSL added a work-around for a SSL 3.0/TLS 1.0 CBC vulnerability:
- https://web.archive.org/web/20240114184648/openssl.org/~bodo/tls-cbc.txt.
- In 0.9.6e they added a bit to SSL_OP_ALL that _disables_ that work-around
- despite the fact that SSL_OP_ALL is documented to do "rather harmless"
- workarounds. In order to keep the secure work-around, the
- SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS bit must not be set.
+ OpenSSL added a work-around for a SSL 3.0/TLS 1.0 CBC vulnerability
+ (https://www.openssl.org/~bodo/tls-cbc.txt). In 0.9.6e they added a bit to
+ SSL_OP_ALL that _disables_ that work-around despite the fact that
+ SSL_OP_ALL is documented to do "rather harmless" workarounds. In order to
+ keep the secure work-around, the SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS bit
+ must not be set.
*/
ctx_options = SSL_OP_ALL;
@@ -3633,17 +3580,17 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx,
#ifdef SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG
/* mitigate CVE-2010-4180 */
- ctx_options &= ~(ctx_option_t)SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG;
+ ctx_options &= ~SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG;
#endif
#ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS
/* unless the user explicitly asks to allow the protocol vulnerability we
use the work-around */
if(!ssl_config->enable_beast)
- ctx_options &= ~(ctx_option_t)SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS;
+ ctx_options &= ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS;
#endif
- switch(ssl_version_min) {
+ switch(ssl_version) {
case CURL_SSLVERSION_SSLv2:
case CURL_SSLVERSION_SSLv3:
return CURLE_NOT_BUILT_IN;
@@ -3661,7 +3608,7 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx,
ctx_options |= SSL_OP_NO_SSLv3;
#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) /* 1.1.0 */
- result = ossl_set_ssl_version_min_max(cf, octx->ssl_ctx);
+ result = ossl_set_ssl_version_min_max(cf, backend->ctx);
#else
result = ossl_set_ssl_version_min_max_legacy(&ctx_options, cf, data);
#endif
@@ -3674,25 +3621,26 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx,
return CURLE_SSL_CONNECT_ERROR;
}
- SSL_CTX_set_options(octx->ssl_ctx, ctx_options);
-
-#ifdef SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER
- /* We do retry writes sometimes from another buffer address */
- SSL_CTX_set_mode(octx->ssl_ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
-#endif
+ SSL_CTX_set_options(backend->ctx, ctx_options);
#ifdef HAS_ALPN
- if(alpn && alpn_len) {
- if(SSL_CTX_set_alpn_protos(octx->ssl_ctx, alpn, (int)alpn_len)) {
+ if(connssl->alpn) {
+ struct alpn_proto_buf proto;
+
+ result = Curl_alpn_to_proto_buf(&proto, connssl->alpn);
+ if(result ||
+ SSL_CTX_set_alpn_protos(backend->ctx, proto.data, proto.len)) {
failf(data, "Error setting ALPN");
return CURLE_SSL_CONNECT_ERROR;
}
+ Curl_alpn_to_proto_str(&proto, connssl->alpn);
+ infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data);
}
#endif
if(ssl_cert || ssl_cert_blob || ssl_cert_type) {
if(!result &&
- !cert_stuff(data, octx->ssl_ctx,
+ !cert_stuff(data, backend->ctx,
ssl_cert, ssl_cert_blob, ssl_cert_type,
ssl_config->key, ssl_config->key_blob,
ssl_config->key_type, ssl_config->key_passwd))
@@ -3703,10 +3651,10 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx,
}
ciphers = conn_config->cipher_list;
- if(!ciphers && (peer->transport != TRNSPRT_QUIC))
- ciphers = DEFAULT_CIPHER_SELECTION;
+ if(!ciphers)
+ ciphers = (char *)DEFAULT_CIPHER_SELECTION;
if(ciphers) {
- if(!SSL_CTX_set_cipher_list(octx->ssl_ctx, ciphers)) {
+ if(!SSL_CTX_set_cipher_list(backend->ctx, ciphers)) {
failf(data, "failed setting cipher list: %s", ciphers);
return CURLE_SSL_CIPHER;
}
@@ -3715,9 +3663,9 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx,
#ifdef HAVE_SSL_CTX_SET_CIPHERSUITES
{
- const char *ciphers13 = conn_config->cipher_list13;
+ char *ciphers13 = conn_config->cipher_list13;
if(ciphers13) {
- if(!SSL_CTX_set_ciphersuites(octx->ssl_ctx, ciphers13)) {
+ if(!SSL_CTX_set_ciphersuites(backend->ctx, ciphers13)) {
failf(data, "failed setting TLS 1.3 cipher suite: %s", ciphers13);
return CURLE_SSL_CIPHER;
}
@@ -3728,14 +3676,14 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx,
#ifdef HAVE_SSL_CTX_SET_POST_HANDSHAKE_AUTH
/* OpenSSL 1.1.1 requires clients to opt-in for PHA */
- SSL_CTX_set_post_handshake_auth(octx->ssl_ctx, 1);
+ SSL_CTX_set_post_handshake_auth(backend->ctx, 1);
#endif
#ifdef HAVE_SSL_CTX_SET_EC_CURVES
{
- const char *curves = conn_config->curves;
+ char *curves = conn_config->curves;
if(curves) {
- if(!SSL_CTX_set1_curves_list(octx->ssl_ctx, curves)) {
+ if(!SSL_CTX_set1_curves_list(backend->ctx, curves)) {
failf(data, "failed setting curves list: '%s'", curves);
return CURLE_SSL_CIPHER;
}
@@ -3749,18 +3697,18 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx,
char * const ssl_password = ssl_config->primary.password;
infof(data, "Using TLS-SRP username: %s", ssl_username);
- if(!SSL_CTX_set_srp_username(octx->ssl_ctx, ssl_username)) {
- failf(data, "Unable to set SRP username");
+ if(!SSL_CTX_set_srp_username(backend->ctx, ssl_username)) {
+ failf(data, "Unable to set SRP user name");
return CURLE_BAD_FUNCTION_ARGUMENT;
}
- if(!SSL_CTX_set_srp_password(octx->ssl_ctx, ssl_password)) {
+ if(!SSL_CTX_set_srp_password(backend->ctx, ssl_password)) {
failf(data, "failed setting SRP password");
return CURLE_BAD_FUNCTION_ARGUMENT;
}
if(!conn_config->cipher_list) {
infof(data, "Setting cipher list SRP");
- if(!SSL_CTX_set_cipher_list(octx->ssl_ctx, "SRP")) {
+ if(!SSL_CTX_set_cipher_list(backend->ctx, "SRP")) {
failf(data, "failed setting SRP cipher list");
return CURLE_SSL_CIPHER;
}
@@ -3772,40 +3720,38 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx,
* fail to connect if the verification fails, or if it should continue
* anyway. In the latter case the result of the verification is checked with
* SSL_get_verify_result() below. */
- SSL_CTX_set_verify(octx->ssl_ctx,
+ SSL_CTX_set_verify(backend->ctx,
verifypeer ? SSL_VERIFY_PEER : SSL_VERIFY_NONE, NULL);
/* Enable logging of secrets to the file specified in env SSLKEYLOGFILE. */
#ifdef HAVE_KEYLOG_CALLBACK
if(Curl_tls_keylog_enabled()) {
- SSL_CTX_set_keylog_callback(octx->ssl_ctx, ossl_keylog_callback);
+ SSL_CTX_set_keylog_callback(backend->ctx, ossl_keylog_callback);
}
#endif
- if(cb_new_session) {
- /* Enable the session cache because it is a prerequisite for the
- * "new session" callback. Use the "external storage" mode to prevent
- * OpenSSL from creating an internal session cache.
- */
- SSL_CTX_set_session_cache_mode(octx->ssl_ctx,
- SSL_SESS_CACHE_CLIENT |
- SSL_SESS_CACHE_NO_INTERNAL);
- SSL_CTX_sess_set_new_cb(octx->ssl_ctx, cb_new_session);
- }
+ /* Enable the session cache because it's a prerequisite for the "new session"
+ * callback. Use the "external storage" mode to prevent OpenSSL from creating
+ * an internal session cache.
+ */
+ SSL_CTX_set_session_cache_mode(backend->ctx,
+ SSL_SESS_CACHE_CLIENT |
+ SSL_SESS_CACHE_NO_INTERNAL);
+ SSL_CTX_sess_set_new_cb(backend->ctx, ossl_new_session_cb);
/* give application a chance to interfere with SSL set up. */
if(data->set.ssl.fsslctx) {
/* When a user callback is installed to modify the SSL_CTX,
* we need to do the full initialization before calling it.
* See: #11800 */
- if(!octx->x509_store_setup) {
- result = Curl_ssl_setup_x509_store(cf, data, octx->ssl_ctx);
+ if(!backend->x509_store_setup) {
+ result = Curl_ssl_setup_x509_store(cf, data, backend->ctx);
if(result)
return result;
- octx->x509_store_setup = TRUE;
+ backend->x509_store_setup = TRUE;
}
Curl_set_in_callback(data, true);
- result = (*data->set.ssl.fsslctx)(data, octx->ssl_ctx,
+ result = (*data->set.ssl.fsslctx)(data, backend->ctx,
data->set.ssl.fsslctxp);
Curl_set_in_callback(data, false);
if(result) {
@@ -3815,234 +3761,64 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx,
}
/* Let's make an SSL structure */
- if(octx->ssl)
- SSL_free(octx->ssl);
- octx->ssl = SSL_new(octx->ssl_ctx);
- if(!octx->ssl) {
- failf(data, "SSL: could not create a context (handle)");
+ if(backend->handle)
+ SSL_free(backend->handle);
+ backend->handle = SSL_new(backend->ctx);
+ if(!backend->handle) {
+ failf(data, "SSL: couldn't create a context (handle)");
return CURLE_OUT_OF_MEMORY;
}
- SSL_set_app_data(octx->ssl, ssl_user_data);
+ SSL_set_app_data(backend->handle, cf);
#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \
!defined(OPENSSL_NO_OCSP)
if(conn_config->verifystatus)
- SSL_set_tlsext_status_type(octx->ssl, TLSEXT_STATUSTYPE_ocsp);
+ SSL_set_tlsext_status_type(backend->handle, TLSEXT_STATUSTYPE_ocsp);
#endif
#if (defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC)) && \
defined(ALLOW_RENEG)
- SSL_set_renegotiate_mode(octx->ssl, ssl_renegotiate_freely);
+ SSL_set_renegotiate_mode(backend->handle, ssl_renegotiate_freely);
#endif
- SSL_set_connect_state(octx->ssl);
+ SSL_set_connect_state(backend->handle);
- octx->server_cert = 0x0;
+ backend->server_cert = 0x0;
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
- if(peer->sni) {
- if(!SSL_set_tlsext_host_name(octx->ssl, peer->sni)) {
+ if(connssl->peer.sni) {
+ if(!SSL_set_tlsext_host_name(backend->handle, connssl->peer.sni)) {
failf(data, "Failed set SNI");
return CURLE_SSL_CONNECT_ERROR;
}
}
-
-#ifdef USE_ECH
- if(ECH_ENABLED(data)) {
- unsigned char *ech_config = NULL;
- size_t ech_config_len = 0;
- char *outername = data->set.str[STRING_ECH_PUBLIC];
- int trying_ech_now = 0;
-
- if(data->set.tls_ech & CURLECH_GREASE) {
- infof(data, "ECH: will GREASE ClientHello");
-# ifdef OPENSSL_IS_BORINGSSL
- SSL_set_enable_ech_grease(octx->ssl, 1);
-# else
- SSL_set_options(octx->ssl, SSL_OP_ECH_GREASE);
-# endif
- }
- else if(data->set.tls_ech & CURLECH_CLA_CFG) {
-# ifdef OPENSSL_IS_BORINGSSL
- /* have to do base64 decode here for boring */
- const char *b64 = data->set.str[STRING_ECH_CONFIG];
-
- if(!b64) {
- infof(data, "ECH: ECHConfig from command line empty");
- return CURLE_SSL_CONNECT_ERROR;
- }
- ech_config_len = 2 * strlen(b64);
- result = Curl_base64_decode(b64, &ech_config, &ech_config_len);
- if(result || !ech_config) {
- infof(data, "ECH: cannot base64 decode ECHConfig from command line");
- if(data->set.tls_ech & CURLECH_HARD)
- return result;
- }
- if(SSL_set1_ech_config_list(octx->ssl, ech_config,
- ech_config_len) != 1) {
- infof(data, "ECH: SSL_ECH_set1_echconfig failed");
- if(data->set.tls_ech & CURLECH_HARD) {
- free(ech_config);
- return CURLE_SSL_CONNECT_ERROR;
- }
- }
- free(ech_config);
- trying_ech_now = 1;
-# else
- ech_config = (unsigned char *) data->set.str[STRING_ECH_CONFIG];
- if(!ech_config) {
- infof(data, "ECH: ECHConfig from command line empty");
- return CURLE_SSL_CONNECT_ERROR;
- }
- ech_config_len = strlen(data->set.str[STRING_ECH_CONFIG]);
- if(SSL_ech_set1_echconfig(octx->ssl, ech_config, ech_config_len) != 1) {
- infof(data, "ECH: SSL_ECH_set1_echconfig failed");
- if(data->set.tls_ech & CURLECH_HARD)
- return CURLE_SSL_CONNECT_ERROR;
- }
- else
- trying_ech_now = 1;
-# endif
- infof(data, "ECH: ECHConfig from command line");
- }
- else {
- struct Curl_dns_entry *dns = NULL;
-
- if(peer->hostname)
- dns = Curl_fetch_addr(data, peer->hostname, peer->port);
- if(!dns) {
- infof(data, "ECH: requested but no DNS info available");
- if(data->set.tls_ech & CURLECH_HARD)
- return CURLE_SSL_CONNECT_ERROR;
- }
- else {
- struct Curl_https_rrinfo *rinfo = NULL;
-
- rinfo = dns->hinfo;
- if(rinfo && rinfo->echconfiglist) {
- unsigned char *ecl = rinfo->echconfiglist;
- size_t elen = rinfo->echconfiglist_len;
-
- infof(data, "ECH: ECHConfig from DoH HTTPS RR");
-# ifndef OPENSSL_IS_BORINGSSL
- if(SSL_ech_set1_echconfig(octx->ssl, ecl, elen) != 1) {
- infof(data, "ECH: SSL_ECH_set1_echconfig failed");
- if(data->set.tls_ech & CURLECH_HARD)
- return CURLE_SSL_CONNECT_ERROR;
- }
-# else
- if(SSL_set1_ech_config_list(octx->ssl, ecl, elen) != 1) {
- infof(data, "ECH: SSL_set1_ech_config_list failed (boring)");
- if(data->set.tls_ech & CURLECH_HARD)
- return CURLE_SSL_CONNECT_ERROR;
- }
-# endif
- else {
- trying_ech_now = 1;
- infof(data, "ECH: imported ECHConfigList of length %zu", elen);
- }
- }
- else {
- infof(data, "ECH: requested but no ECHConfig available");
- if(data->set.tls_ech & CURLECH_HARD)
- return CURLE_SSL_CONNECT_ERROR;
- }
- Curl_resolv_unlink(data, &dns);
- }
- }
-# ifdef OPENSSL_IS_BORINGSSL
- if(trying_ech_now && outername) {
- infof(data, "ECH: setting public_name not supported with BoringSSL");
- return CURLE_SSL_CONNECT_ERROR;
- }
-# else
- if(trying_ech_now && outername) {
- infof(data, "ECH: inner: '%s', outer: '%s'",
- peer->hostname ? peer->hostname : "NULL", outername);
- result = SSL_ech_set_server_names(octx->ssl,
- peer->hostname, outername,
- 0 /* do send outer */);
- if(result != 1) {
- infof(data, "ECH: rv failed to set server name(s) %d [ERROR]", result);
- return CURLE_SSL_CONNECT_ERROR;
- }
- }
-# endif /* not BORING */
- if(trying_ech_now
- && SSL_set_min_proto_version(octx->ssl, TLS1_3_VERSION) != 1) {
- infof(data, "ECH: cannot force TLSv1.3 [ERROR]");
- return CURLE_SSL_CONNECT_ERROR;
- }
- }
-#endif /* USE_ECH */
-
#endif
- octx->reused_session = FALSE;
- if(ssl_config->primary.cache_session && transport == TRNSPRT_TCP) {
+ SSL_set_app_data(backend->handle, cf);
+
+ connssl->reused_session = FALSE;
+ if(ssl_config->primary.sessionid) {
Curl_ssl_sessionid_lock(data);
- if(!Curl_ssl_getsessionid(cf, data, peer, (void **)&der_sessionid,
- &der_sessionid_size)) {
+ if(!Curl_ssl_getsessionid(cf, data, &ssl_sessionid, NULL)) {
/* we got a session id, use it! */
- ssl_session = d2i_SSL_SESSION(NULL, &der_sessionid,
- (long)der_sessionid_size);
- if(ssl_session) {
- if(!SSL_set_session(octx->ssl, ssl_session)) {
- Curl_ssl_sessionid_unlock(data);
- SSL_SESSION_free(ssl_session);
- failf(data, "SSL: SSL_set_session failed: %s",
- ossl_strerror(ERR_get_error(), error_buffer,
- sizeof(error_buffer)));
- return CURLE_SSL_CONNECT_ERROR;
- }
- SSL_SESSION_free(ssl_session);
- /* Informational message */
- infof(data, "SSL reusing session ID");
- octx->reused_session = TRUE;
- }
- else {
- Curl_ssl_sessionid_unlock(data);
- return CURLE_SSL_CONNECT_ERROR;
+ if(!SSL_set_session(backend->handle, ssl_sessionid)) {
+ Curl_ssl_sessionid_unlock(data);
+ failf(data, "SSL: SSL_set_session failed: %s",
+ ossl_strerror(ERR_get_error(), error_buffer,
+ sizeof(error_buffer)));
+ return CURLE_SSL_CONNECT_ERROR;
}
+ /* Informational message */
+ infof(data, "SSL reusing session ID");
+ connssl->reused_session = TRUE;
}
Curl_ssl_sessionid_unlock(data);
}
- return CURLE_OK;
-}
-
-static CURLcode ossl_connect_step1(struct Curl_cfilter *cf,
- struct Curl_easy *data)
-{
- struct ssl_connect_data *connssl = cf->ctx;
- struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend;
- struct alpn_proto_buf proto;
- BIO *bio;
- CURLcode result;
-
- DEBUGASSERT(ssl_connect_1 == connssl->connecting_state);
- DEBUGASSERT(octx);
- memset(&proto, 0, sizeof(proto));
-#ifdef HAS_ALPN
- if(connssl->alpn) {
- result = Curl_alpn_to_proto_buf(&proto, connssl->alpn);
- if(result) {
- failf(data, "Error determining ALPN");
- return CURLE_SSL_CONNECT_ERROR;
- }
- }
-#endif
-
- result = Curl_ossl_ctx_init(octx, cf, data, &connssl->peer, TRNSPRT_TCP,
- proto.data, proto.len, NULL, NULL,
- ossl_new_session_cb, cf);
- if(result)
- return result;
-
- octx->bio_method = ossl_bio_cf_method_create();
- if(!octx->bio_method)
+ backend->bio_method = ossl_bio_cf_method_create();
+ if(!backend->bio_method)
return CURLE_OUT_OF_MEMORY;
- bio = BIO_new(octx->bio_method);
+ bio = BIO_new(backend->bio_method);
if(!bio)
return CURLE_OUT_OF_MEMORY;
@@ -4051,154 +3827,83 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf,
/* with OpenSSL v1.1.1 we get an alternative to SSL_set_bio() that works
* without backward compat quirks. Every call takes one reference, so we
* up it and pass. SSL* then owns it and will free.
- * We check on the function in configure, since LibreSSL and friends
+ * We check on the function in configure, since libressl and friends
* each have their own versions to add support for this. */
BIO_up_ref(bio);
- SSL_set0_rbio(octx->ssl, bio);
- SSL_set0_wbio(octx->ssl, bio);
+ SSL_set0_rbio(backend->handle, bio);
+ SSL_set0_wbio(backend->handle, bio);
#else
- SSL_set_bio(octx->ssl, bio, bio);
-#endif
-
-#ifdef HAS_ALPN
- if(connssl->alpn) {
- Curl_alpn_to_proto_str(&proto, connssl->alpn);
- infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data);
- }
+ SSL_set_bio(backend->handle, bio, bio);
#endif
connssl->connecting_state = ssl_connect_2;
- return CURLE_OK;
-}
-#ifdef USE_ECH
-/* If we have retry configs, then trace those out */
-static void ossl_trace_ech_retry_configs(struct Curl_easy *data, SSL* ssl,
- int reason)
-{
- CURLcode result = CURLE_OK;
- size_t rcl = 0;
- int rv = 1;
-# ifndef OPENSSL_IS_BORINGSSL
- char *inner = NULL;
- unsigned char *rcs = NULL;
- char *outer = NULL;
-# else
- const char *inner = NULL;
- const uint8_t *rcs = NULL;
- const char *outer = NULL;
- size_t out_name_len = 0;
- int servername_type = 0;
-# endif
-
- /* nothing to trace if not doing ECH */
- if(!ECH_ENABLED(data))
- return;
-# ifndef OPENSSL_IS_BORINGSSL
- rv = SSL_ech_get_retry_config(ssl, &rcs, &rcl);
-# else
- SSL_get0_ech_retry_configs(ssl, &rcs, &rcl);
- rv = (int)rcl;
-# endif
-
- if(rv && rcs) {
-# define HEXSTR_MAX 800
- char *b64str = NULL;
- size_t blen = 0;
-
- result = Curl_base64_encode((const char *)rcs, rcl,
- &b64str, &blen);
- if(!result && b64str)
- infof(data, "ECH: retry_configs %s", b64str);
- free(b64str);
-# ifndef OPENSSL_IS_BORINGSSL
- rv = SSL_ech_get_status(ssl, &inner, &outer);
- infof(data, "ECH: retry_configs for %s from %s, %d %d",
- inner ? inner : "NULL", outer ? outer : "NULL", reason, rv);
-#else
- rv = SSL_ech_accepted(ssl);
- servername_type = SSL_get_servername_type(ssl);
- inner = SSL_get_servername(ssl, servername_type);
- SSL_get0_ech_name_override(ssl, &outer, &out_name_len);
- /* TODO: get the inner from boring */
- infof(data, "ECH: retry_configs for %s from %s, %d %d",
- inner ? inner : "NULL", outer ? outer : "NULL", reason, rv);
-#endif
- }
- else
- infof(data, "ECH: no retry_configs (rv = %d)", rv);
-# ifndef OPENSSL_IS_BORINGSSL
- OPENSSL_free((void *)rcs);
-# endif
- return;
+ return CURLE_OK;
}
-#endif
-
static CURLcode ossl_connect_step2(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
int err;
struct ssl_connect_data *connssl = cf->ctx;
- struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend;
+ struct ossl_ssl_backend_data *backend =
+ (struct ossl_ssl_backend_data *)connssl->backend;
struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
- DEBUGASSERT(ssl_connect_2 == connssl->connecting_state);
- DEBUGASSERT(octx);
+ DEBUGASSERT(ssl_connect_2 == connssl->connecting_state
+ || ssl_connect_2_reading == connssl->connecting_state
+ || ssl_connect_2_writing == connssl->connecting_state);
+ DEBUGASSERT(backend);
- connssl->io_need = CURL_SSL_IO_NEED_NONE;
ERR_clear_error();
- err = SSL_connect(octx->ssl);
+ err = SSL_connect(backend->handle);
- if(!octx->x509_store_setup) {
+ if(!backend->x509_store_setup) {
/* After having send off the ClientHello, we prepare the x509
* store to verify the coming certificate from the server */
- CURLcode result = Curl_ssl_setup_x509_store(cf, data, octx->ssl_ctx);
+ CURLcode result = Curl_ssl_setup_x509_store(cf, data, backend->ctx);
if(result)
return result;
- octx->x509_store_setup = TRUE;
+ backend->x509_store_setup = TRUE;
}
#ifndef HAVE_KEYLOG_CALLBACK
- /* If key logging is enabled, wait for the handshake to complete and then
- * proceed with logging secrets (for TLS 1.2 or older).
- */
- if(Curl_tls_keylog_enabled() && !octx->keylog_done)
- ossl_log_tls12_secret(octx->ssl, &octx->keylog_done);
+ if(Curl_tls_keylog_enabled()) {
+ /* If key logging is enabled, wait for the handshake to complete and then
+ * proceed with logging secrets (for TLS 1.2 or older).
+ */
+ ossl_log_tls12_secret(backend->handle, &backend->keylog_done);
+ }
#endif
/* 1 is fine
0 is "not successful but was shut down controlled"
<0 is "handshake was not successful, because a fatal error occurred" */
if(1 != err) {
- int detail = SSL_get_error(octx->ssl, err);
- CURL_TRC_CF(data, cf, "SSL_connect() -> err=%d, detail=%d", err, detail);
+ int detail = SSL_get_error(backend->handle, err);
if(SSL_ERROR_WANT_READ == detail) {
- CURL_TRC_CF(data, cf, "SSL_connect() -> want recv");
- connssl->io_need = CURL_SSL_IO_NEED_RECV;
+ connssl->connecting_state = ssl_connect_2_reading;
return CURLE_OK;
}
if(SSL_ERROR_WANT_WRITE == detail) {
- CURL_TRC_CF(data, cf, "SSL_connect() -> want send");
- connssl->io_need = CURL_SSL_IO_NEED_SEND;
+ connssl->connecting_state = ssl_connect_2_writing;
return CURLE_OK;
}
#ifdef SSL_ERROR_WANT_ASYNC
if(SSL_ERROR_WANT_ASYNC == detail) {
- CURL_TRC_CF(data, cf, "SSL_connect() -> want async");
- connssl->io_need = CURL_SSL_IO_NEED_RECV;
connssl->connecting_state = ssl_connect_2;
return CURLE_OK;
}
#endif
#ifdef SSL_ERROR_WANT_RETRY_VERIFY
if(SSL_ERROR_WANT_RETRY_VERIFY == detail) {
- CURL_TRC_CF(data, cf, "SSL_connect() -> want retry_verify");
- connssl->io_need = CURL_SSL_IO_NEED_RECV;
connssl->connecting_state = ssl_connect_2;
return CURLE_OK;
}
#endif
+ if(backend->io_result == CURLE_AGAIN) {
+ return CURLE_OK;
+ }
else {
/* untreated error */
sslerr_t errdetail;
@@ -4208,7 +3913,7 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf,
int lib;
int reason;
- /* the connection failed, we are not waiting for anything else. */
+ /* the connection failed, we're not waiting for anything else. */
connssl->connecting_state = ssl_connect_2;
/* Get the earliest error code from the thread's error queue and remove
@@ -4224,7 +3929,7 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf,
(reason == SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED))) {
result = CURLE_PEER_FAILED_VERIFICATION;
- lerr = SSL_get_verify_result(octx->ssl);
+ lerr = SSL_get_verify_result(backend->handle);
if(lerr != X509_V_OK) {
ssl_config->certverifyresult = lerr;
msnprintf(error_buffer, sizeof(error_buffer),
@@ -4247,21 +3952,6 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf,
ossl_strerror(errdetail, error_buffer, sizeof(error_buffer));
}
#endif
-#ifdef USE_ECH
- else if((lib == ERR_LIB_SSL) &&
-# ifndef OPENSSL_IS_BORINGSSL
- (reason == SSL_R_ECH_REQUIRED)) {
-# else
- (reason == SSL_R_ECH_REJECTED)) {
-# endif
-
- /* trace retry_configs if we got some */
- ossl_trace_ech_retry_configs(data, octx->ssl, reason);
-
- result = CURLE_ECH_REQUIRED;
- ossl_strerror(errdetail, error_buffer, sizeof(error_buffer));
- }
-#endif
else {
result = CURLE_SSL_CONNECT_ERROR;
ossl_strerror(errdetail, error_buffer, sizeof(error_buffer));
@@ -4269,7 +3959,7 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf,
/* detail is already set to the SSL error above */
- /* If we e.g. use SSLv2 request-method and the server does not like us
+ /* If we e.g. use SSLv2 request-method and the server doesn't like us
* (RST connection, etc.), OpenSSL gives no explanation whatsoever and
* the SO_ERROR is also lost.
*/
@@ -4281,7 +3971,7 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf,
Curl_strerror(sockerr, extramsg, sizeof(extramsg));
failf(data, OSSL_PACKAGE " SSL_connect: %s in connection to %s:%d ",
extramsg[0] ? extramsg : SSL_ERROR_to_str(detail),
- connssl->peer.hostname, connssl->peer.port);
+ connssl->peer.hostname, connssl->port);
return result;
}
@@ -4295,88 +3985,26 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf,
int psigtype_nid = NID_undef;
const char *negotiated_group_name = NULL;
- /* we connected fine, we are not waiting for anything else. */
+ /* we connected fine, we're not waiting for anything else. */
connssl->connecting_state = ssl_connect_3;
#if (OPENSSL_VERSION_NUMBER >= 0x30000000L)
- SSL_get_peer_signature_type_nid(octx->ssl, &psigtype_nid);
+ SSL_get_peer_signature_type_nid(backend->handle, &psigtype_nid);
#if (OPENSSL_VERSION_NUMBER >= 0x30200000L)
- negotiated_group_name = SSL_get0_group_name(octx->ssl);
+ negotiated_group_name = SSL_get0_group_name(backend->handle);
#else
negotiated_group_name =
- OBJ_nid2sn(SSL_get_negotiated_group(octx->ssl) & 0x0000FFFF);
+ OBJ_nid2sn(SSL_get_negotiated_group(backend->handle) & 0x0000FFFF);
#endif
#endif
/* Informational message */
infof(data, "SSL connection using %s / %s / %s / %s",
- SSL_get_version(octx->ssl),
- SSL_get_cipher(octx->ssl),
+ SSL_get_version(backend->handle),
+ SSL_get_cipher(backend->handle),
negotiated_group_name? negotiated_group_name : "[blank]",
OBJ_nid2sn(psigtype_nid));
-#ifdef USE_ECH
-# ifndef OPENSSL_IS_BORINGSSL
- if(ECH_ENABLED(data)) {
- char *inner = NULL, *outer = NULL;
- const char *status = NULL;
- int rv;
-
- rv = SSL_ech_get_status(octx->ssl, &inner, &outer);
- switch(rv) {
- case SSL_ECH_STATUS_SUCCESS:
- status = "succeeded";
- break;
- case SSL_ECH_STATUS_GREASE_ECH:
- status = "sent GREASE, got retry-configs";
- break;
- case SSL_ECH_STATUS_GREASE:
- status = "sent GREASE";
- break;
- case SSL_ECH_STATUS_NOT_TRIED:
- status = "not attempted";
- break;
- case SSL_ECH_STATUS_NOT_CONFIGURED:
- status = "not configured";
- break;
- case SSL_ECH_STATUS_BACKEND:
- status = "backend (unexpected)";
- break;
- case SSL_ECH_STATUS_FAILED:
- status = "failed";
- break;
- case SSL_ECH_STATUS_BAD_CALL:
- status = "bad call (unexpected)";
- break;
- case SSL_ECH_STATUS_BAD_NAME:
- status = "bad name (unexpected)";
- break;
- default:
- status = "unexpected status";
- infof(data, "ECH: unexpected status %d",rv);
- }
- infof(data, "ECH: result: status is %s, inner is %s, outer is %s",
- (status?status:"NULL"),
- (inner?inner:"NULL"),
- (outer?outer:"NULL"));
- OPENSSL_free(inner);
- OPENSSL_free(outer);
- if(rv == SSL_ECH_STATUS_GREASE_ECH) {
- /* trace retry_configs if we got some */
- ossl_trace_ech_retry_configs(data, octx->ssl, 0);
- }
- if(rv != SSL_ECH_STATUS_SUCCESS
- && data->set.tls_ech & CURLECH_HARD) {
- infof(data, "ECH: ech-hard failed");
- return CURLE_SSL_CONNECT_ERROR;
- }
- }
- else {
- infof(data, "ECH: result: status is not attempted");
- }
-# endif /* BORING */
-#endif /* USE_ECH */
-
#ifdef HAS_ALPN
/* Sets data and len to negotiated protocol, len is 0 if no protocol was
* negotiated
@@ -4384,7 +4012,7 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf,
if(connssl->alpn) {
const unsigned char *neg_protocol;
unsigned int len;
- SSL_get0_alpn_selected(octx->ssl, &neg_protocol, &len);
+ SSL_get0_alpn_selected(backend->handle, &neg_protocol, &len);
return Curl_alpn_set_negotiated(cf, data, neg_protocol, len);
}
@@ -4408,7 +4036,7 @@ static CURLcode ossl_pkp_pin_peer_pubkey(struct Curl_easy *data, X509* cert,
/* Result is returned to caller */
CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
- /* if a path was not specified, do not pin */
+ /* if a path wasn't specified, don't pin */
if(!pinnedpubkey)
return CURLE_OK;
@@ -4429,12 +4057,12 @@ static CURLcode ossl_pkp_pin_peer_pubkey(struct Curl_easy *data, X509* cert,
if(!buff1)
break; /* failed */
- /* https://docs.openssl.org/master/man3/d2i_X509/ */
+ /* https://www.openssl.org/docs/crypto/d2i_X509.html */
len2 = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(cert), &temp);
/*
* These checks are verifying we got back the same values as when we
- * sized the buffer. it is pretty weak since they should always be the
+ * sized the buffer. It's pretty weak since they should always be the
* same. But it gives us something to test.
*/
if((len1 != len2) || !temp || ((temp - buff1) != len1))
@@ -4521,12 +4149,20 @@ static void infof_certstack(struct Curl_easy *data, const SSL *ssl)
#define infof_certstack(data, ssl)
#endif
-CURLcode Curl_oss_check_peer_cert(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- struct ossl_ctx *octx,
- struct ssl_peer *peer)
+/*
+ * Get the server cert, verify it and show it, etc., only call failf() if the
+ * 'strict' argument is TRUE as otherwise all this is for informational
+ * purposes only!
+ *
+ * We check certificates to authenticate the server; otherwise we risk
+ * man-in-the-middle attack.
+ */
+static CURLcode servercert(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ bool strict)
{
struct connectdata *conn = cf->conn;
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
CURLcode result = CURLE_OK;
@@ -4538,9 +4174,10 @@ CURLcode Curl_oss_check_peer_cert(struct Curl_cfilter *cf,
char buffer[2048];
const char *ptr;
BIO *mem = BIO_new(BIO_s_mem());
- bool strict = (conn_config->verifypeer || conn_config->verifyhost);
+ struct ossl_ssl_backend_data *backend =
+ (struct ossl_ssl_backend_data *)connssl->backend;
- DEBUGASSERT(octx);
+ DEBUGASSERT(backend);
if(!mem) {
failf(data,
@@ -4553,34 +4190,34 @@ CURLcode Curl_oss_check_peer_cert(struct Curl_cfilter *cf,
if(data->set.ssl.certinfo)
/* asked to gather certificate info */
- (void)ossl_certchain(data, octx->ssl);
+ (void)Curl_ossl_certchain(data, backend->handle);
- octx->server_cert = SSL_get1_peer_certificate(octx->ssl);
- if(!octx->server_cert) {
+ backend->server_cert = SSL_get1_peer_certificate(backend->handle);
+ if(!backend->server_cert) {
BIO_free(mem);
if(!strict)
return CURLE_OK;
- failf(data, "SSL: could not get peer certificate");
+ failf(data, "SSL: couldn't get peer certificate");
return CURLE_PEER_FAILED_VERIFICATION;
}
infof(data, "%s certificate:",
Curl_ssl_cf_is_proxy(cf)? "Proxy" : "Server");
- rc = x509_name_oneline(X509_get_subject_name(octx->server_cert),
+ rc = x509_name_oneline(X509_get_subject_name(backend->server_cert),
buffer, sizeof(buffer));
infof(data, " subject: %s", rc?"[NONE]":buffer);
#ifndef CURL_DISABLE_VERBOSE_STRINGS
{
long len;
- ASN1_TIME_print(mem, X509_get0_notBefore(octx->server_cert));
+ ASN1_TIME_print(mem, X509_get0_notBefore(backend->server_cert));
len = BIO_get_mem_data(mem, (char **) &ptr);
infof(data, " start date: %.*s", (int)len, ptr);
(void)BIO_reset(mem);
- ASN1_TIME_print(mem, X509_get0_notAfter(octx->server_cert));
+ ASN1_TIME_print(mem, X509_get0_notAfter(backend->server_cert));
len = BIO_get_mem_data(mem, (char **) &ptr);
infof(data, " expire date: %.*s", (int)len, ptr);
(void)BIO_reset(mem);
@@ -4590,19 +4227,20 @@ CURLcode Curl_oss_check_peer_cert(struct Curl_cfilter *cf,
BIO_free(mem);
if(conn_config->verifyhost) {
- result = ossl_verifyhost(data, conn, peer, octx->server_cert);
+ result = Curl_ossl_verifyhost(data, conn, &connssl->peer,
+ backend->server_cert);
if(result) {
- X509_free(octx->server_cert);
- octx->server_cert = NULL;
+ X509_free(backend->server_cert);
+ backend->server_cert = NULL;
return result;
}
}
- rc = x509_name_oneline(X509_get_issuer_name(octx->server_cert),
+ rc = x509_name_oneline(X509_get_issuer_name(backend->server_cert),
buffer, sizeof(buffer));
if(rc) {
if(strict)
- failf(data, "SSL: could not get X509-issuer name");
+ failf(data, "SSL: couldn't get X509-issuer name");
result = CURLE_PEER_FAILED_VERIFICATION;
}
else {
@@ -4622,8 +4260,8 @@ CURLcode Curl_oss_check_peer_cert(struct Curl_cfilter *cf,
" error %s",
ossl_strerror(ERR_get_error(), error_buffer,
sizeof(error_buffer)) );
- X509_free(octx->server_cert);
- octx->server_cert = NULL;
+ X509_free(backend->server_cert);
+ backend->server_cert = NULL;
return CURLE_OUT_OF_MEMORY;
}
}
@@ -4635,8 +4273,8 @@ CURLcode Curl_oss_check_peer_cert(struct Curl_cfilter *cf,
" error %s",
ossl_strerror(ERR_get_error(), error_buffer,
sizeof(error_buffer)) );
- X509_free(octx->server_cert);
- octx->server_cert = NULL;
+ X509_free(backend->server_cert);
+ backend->server_cert = NULL;
return CURLE_OUT_OF_MEMORY;
}
@@ -4645,8 +4283,8 @@ CURLcode Curl_oss_check_peer_cert(struct Curl_cfilter *cf,
failf(data, "SSL: Unable to open issuer cert (%s)",
conn_config->issuercert);
BIO_free(fp);
- X509_free(octx->server_cert);
- octx->server_cert = NULL;
+ X509_free(backend->server_cert);
+ backend->server_cert = NULL;
return CURLE_SSL_ISSUER_ERROR;
}
}
@@ -4658,19 +4296,19 @@ CURLcode Curl_oss_check_peer_cert(struct Curl_cfilter *cf,
conn_config->issuercert);
BIO_free(fp);
X509_free(issuer);
- X509_free(octx->server_cert);
- octx->server_cert = NULL;
+ X509_free(backend->server_cert);
+ backend->server_cert = NULL;
return CURLE_SSL_ISSUER_ERROR;
}
- if(X509_check_issued(issuer, octx->server_cert) != X509_V_OK) {
+ if(X509_check_issued(issuer, backend->server_cert) != X509_V_OK) {
if(strict)
failf(data, "SSL: Certificate issuer check failed (%s)",
conn_config->issuercert);
BIO_free(fp);
X509_free(issuer);
- X509_free(octx->server_cert);
- octx->server_cert = NULL;
+ X509_free(backend->server_cert);
+ backend->server_cert = NULL;
return CURLE_SSL_ISSUER_ERROR;
}
@@ -4680,7 +4318,7 @@ CURLcode Curl_oss_check_peer_cert(struct Curl_cfilter *cf,
X509_free(issuer);
}
- lerr = SSL_get_verify_result(octx->ssl);
+ lerr = SSL_get_verify_result(backend->handle);
ssl_config->certverifyresult = lerr;
if(lerr != X509_V_OK) {
if(conn_config->verifypeer) {
@@ -4700,55 +4338,37 @@ CURLcode Curl_oss_check_peer_cert(struct Curl_cfilter *cf,
infof(data, " SSL certificate verify ok.");
}
- infof_certstack(data, octx->ssl);
+ infof_certstack(data, backend->handle);
#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \
!defined(OPENSSL_NO_OCSP)
- if(conn_config->verifystatus && !octx->reused_session) {
- /* do not do this after Session ID reuse */
- result = verifystatus(cf, data, octx);
+ if(conn_config->verifystatus && !connssl->reused_session) {
+ /* don't do this after Session ID reuse */
+ result = verifystatus(cf, data);
if(result) {
- /* when verifystatus failed, remove the session id from the cache again
- if present */
- if(!Curl_ssl_cf_is_proxy(cf)) {
- void *old_ssl_sessionid = NULL;
- bool incache;
- Curl_ssl_sessionid_lock(data);
- incache = !(Curl_ssl_getsessionid(cf, data, peer,
- &old_ssl_sessionid, NULL));
- if(incache) {
- infof(data, "Remove session ID again from cache");
- Curl_ssl_delsessionid(data, old_ssl_sessionid);
- }
- Curl_ssl_sessionid_unlock(data);
- }
-
- X509_free(octx->server_cert);
- octx->server_cert = NULL;
+ X509_free(backend->server_cert);
+ backend->server_cert = NULL;
return result;
}
}
#endif
if(!strict)
- /* when not strict, we do not bother about the verify cert problems */
+ /* when not strict, we don't bother about the verify cert problems */
result = CURLE_OK;
-#ifndef CURL_DISABLE_PROXY
ptr = Curl_ssl_cf_is_proxy(cf)?
data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]:
data->set.str[STRING_SSL_PINNEDPUBLICKEY];
-#else
- ptr = data->set.str[STRING_SSL_PINNEDPUBLICKEY];
-#endif
if(!result && ptr) {
- result = ossl_pkp_pin_peer_pubkey(data, octx->server_cert, ptr);
+ result = ossl_pkp_pin_peer_pubkey(data, backend->server_cert, ptr);
if(result)
failf(data, "SSL: public key does not match pinned public key");
}
- X509_free(octx->server_cert);
- octx->server_cert = NULL;
+ X509_free(backend->server_cert);
+ backend->server_cert = NULL;
+ connssl->connecting_state = ssl_connect_done;
return result;
}
@@ -4758,18 +4378,20 @@ static CURLcode ossl_connect_step3(struct Curl_cfilter *cf,
{
CURLcode result = CURLE_OK;
struct ssl_connect_data *connssl = cf->ctx;
- struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend;
+ struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
/*
* We check certificates to authenticate the server; otherwise we risk
- * man-in-the-middle attack; NEVERTHELESS, if we are told explicitly not to
+ * man-in-the-middle attack; NEVERTHELESS, if we're told explicitly not to
* verify the peer, ignore faults and failures from the server cert
* operations.
*/
- result = Curl_oss_check_peer_cert(cf, data, octx, &connssl->peer);
+ result = servercert(cf, data, conn_config->verifypeer ||
+ conn_config->verifyhost);
+
if(!result)
connssl->connecting_state = ssl_connect_done;
@@ -4786,7 +4408,6 @@ static CURLcode ossl_connect_common(struct Curl_cfilter *cf,
curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data);
int what;
- connssl->io_need = CURL_SSL_IO_NEED_NONE;
/* check if the connection has already been established */
if(ssl_connection_complete == connssl->state) {
*done = TRUE;
@@ -4794,7 +4415,7 @@ static CURLcode ossl_connect_common(struct Curl_cfilter *cf,
}
if(ssl_connect_1 == connssl->connecting_state) {
- /* Find out how much more time we are allowed */
+ /* Find out how much more time we're allowed */
const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
if(timeout_ms < 0) {
@@ -4808,7 +4429,9 @@ static CURLcode ossl_connect_common(struct Curl_cfilter *cf,
goto out;
}
- while(ssl_connect_2 == connssl->connecting_state) {
+ while(ssl_connect_2 == connssl->connecting_state ||
+ ssl_connect_2_reading == connssl->connecting_state ||
+ ssl_connect_2_writing == connssl->connecting_state) {
/* check allowed time left */
const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
@@ -4820,13 +4443,15 @@ static CURLcode ossl_connect_common(struct Curl_cfilter *cf,
goto out;
}
- /* if ssl is expecting something, check if it is available. */
- if(!nonblocking && connssl->io_need) {
+ /* if ssl is expecting something, check if it's available. */
+ if(!nonblocking &&
+ (connssl->connecting_state == ssl_connect_2_reading ||
+ connssl->connecting_state == ssl_connect_2_writing)) {
- curl_socket_t writefd = (connssl->io_need & CURL_SSL_IO_NEED_SEND)?
- sockfd:CURL_SOCKET_BAD;
- curl_socket_t readfd = (connssl->io_need & CURL_SSL_IO_NEED_RECV)?
- sockfd:CURL_SOCKET_BAD;
+ curl_socket_t writefd = ssl_connect_2_writing ==
+ connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
+ curl_socket_t readfd = ssl_connect_2_reading ==
+ connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
timeout_ms);
@@ -4852,7 +4477,10 @@ static CURLcode ossl_connect_common(struct Curl_cfilter *cf,
* or epoll() will always have a valid fdset to wait on.
*/
result = ossl_connect_step2(cf, data);
- if(result || (nonblocking && (ssl_connect_2 == connssl->connecting_state)))
+ if(result || (nonblocking &&
+ (ssl_connect_2 == connssl->connecting_state ||
+ ssl_connect_2_reading == connssl->connecting_state ||
+ ssl_connect_2_writing == connssl->connecting_state)))
goto out;
} /* repeat step2 until all transactions are done. */
@@ -4903,11 +4531,12 @@ static bool ossl_data_pending(struct Curl_cfilter *cf,
const struct Curl_easy *data)
{
struct ssl_connect_data *connssl = cf->ctx;
- struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend;
+ struct ossl_ssl_backend_data *backend =
+ (struct ossl_ssl_backend_data *)connssl->backend;
(void)data;
- DEBUGASSERT(connssl && octx);
- if(octx->ssl && SSL_pending(octx->ssl))
+ DEBUGASSERT(connssl && backend);
+ if(backend->handle && SSL_pending(backend->handle))
return TRUE;
return FALSE;
}
@@ -4926,27 +4555,26 @@ static ssize_t ossl_send(struct Curl_cfilter *cf,
int memlen;
int rc;
struct ssl_connect_data *connssl = cf->ctx;
- struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend;
+ struct ossl_ssl_backend_data *backend =
+ (struct ossl_ssl_backend_data *)connssl->backend;
(void)data;
- DEBUGASSERT(octx);
+ DEBUGASSERT(backend);
ERR_clear_error();
- connssl->io_need = CURL_SSL_IO_NEED_NONE;
memlen = (len > (size_t)INT_MAX) ? INT_MAX : (int)len;
- rc = SSL_write(octx->ssl, mem, memlen);
+ rc = SSL_write(backend->handle, mem, memlen);
if(rc <= 0) {
- err = SSL_get_error(octx->ssl, rc);
+ err = SSL_get_error(backend->handle, rc);
switch(err) {
case SSL_ERROR_WANT_READ:
- connssl->io_need = CURL_SSL_IO_NEED_RECV;
- *curlcode = CURLE_AGAIN;
- rc = -1;
- goto out;
case SSL_ERROR_WANT_WRITE:
+ /* The operation did not complete; the same TLS/SSL I/O function
+ should be called again later. This is basically an EWOULDBLOCK
+ equivalent. */
*curlcode = CURLE_AGAIN;
rc = -1;
goto out;
@@ -4954,7 +4582,7 @@ static ssize_t ossl_send(struct Curl_cfilter *cf,
{
int sockerr = SOCKERRNO;
- if(octx->io_result == CURLE_AGAIN) {
+ if(backend->io_result == CURLE_AGAIN) {
*curlcode = CURLE_AGAIN;
rc = -1;
goto out;
@@ -4964,10 +4592,10 @@ static ssize_t ossl_send(struct Curl_cfilter *cf,
ossl_strerror(sslerror, error_buffer, sizeof(error_buffer));
else if(sockerr)
Curl_strerror(sockerr, error_buffer, sizeof(error_buffer));
- else
- msnprintf(error_buffer, sizeof(error_buffer), "%s",
- SSL_ERROR_to_str(err));
-
+ else {
+ strncpy(error_buffer, SSL_ERROR_to_str(err), sizeof(error_buffer));
+ error_buffer[sizeof(error_buffer) - 1] = '\0';
+ }
failf(data, OSSL_PACKAGE " SSL_write: %s, errno %d",
error_buffer, sockerr);
*curlcode = CURLE_SEND_ERROR;
@@ -5011,20 +4639,20 @@ static ssize_t ossl_recv(struct Curl_cfilter *cf,
int buffsize;
struct connectdata *conn = cf->conn;
struct ssl_connect_data *connssl = cf->ctx;
- struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend;
+ struct ossl_ssl_backend_data *backend =
+ (struct ossl_ssl_backend_data *)connssl->backend;
(void)data;
- DEBUGASSERT(octx);
+ DEBUGASSERT(backend);
ERR_clear_error();
- connssl->io_need = CURL_SSL_IO_NEED_NONE;
buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize;
- nread = (ssize_t)SSL_read(octx->ssl, buf, buffsize);
+ nread = (ssize_t)SSL_read(backend->handle, buf, buffsize);
if(nread <= 0) {
/* failed SSL_read */
- int err = SSL_get_error(octx->ssl, (int)nread);
+ int err = SSL_get_error(backend->handle, (int)nread);
switch(err) {
case SSL_ERROR_NONE: /* this is not an error */
@@ -5037,19 +4665,16 @@ static ssize_t ossl_recv(struct Curl_cfilter *cf,
connclose(conn, "TLS close_notify");
break;
case SSL_ERROR_WANT_READ:
- *curlcode = CURLE_AGAIN;
- nread = -1;
- goto out;
case SSL_ERROR_WANT_WRITE:
- connssl->io_need = CURL_SSL_IO_NEED_SEND;
+ /* there's data pending, re-invoke SSL_read() */
*curlcode = CURLE_AGAIN;
nread = -1;
goto out;
default:
/* openssl/ssl.h for SSL_ERROR_SYSCALL says "look at error stack/return
value/errno" */
- /* https://docs.openssl.org/master/man3/ERR_get_error/ */
- if(octx->io_result == CURLE_AGAIN) {
+ /* https://www.openssl.org/docs/crypto/ERR_get_error.html */
+ if(backend->io_result == CURLE_AGAIN) {
*curlcode = CURLE_AGAIN;
nread = -1;
goto out;
@@ -5063,9 +4688,10 @@ static ssize_t ossl_recv(struct Curl_cfilter *cf,
ossl_strerror(sslerror, error_buffer, sizeof(error_buffer));
else if(sockerr && err == SSL_ERROR_SYSCALL)
Curl_strerror(sockerr, error_buffer, sizeof(error_buffer));
- else
- msnprintf(error_buffer, sizeof(error_buffer), "%s",
- SSL_ERROR_to_str(err));
+ else {
+ strncpy(error_buffer, SSL_ERROR_to_str(err), sizeof(error_buffer));
+ error_buffer[sizeof(error_buffer) - 1] = '\0';
+ }
failf(data, OSSL_PACKAGE " SSL_read: %s, errno %d",
error_buffer, sockerr);
*curlcode = CURLE_RECV_ERROR;
@@ -5075,7 +4701,7 @@ static ssize_t ossl_recv(struct Curl_cfilter *cf,
/* For debug builds be a little stricter and error on any
SSL_ERROR_SYSCALL. For example a server may have closed the connection
abruptly without a close_notify alert. For compatibility with older
- peers we do not do this by default. #4624
+ peers we don't do this by default. #4624
We can use this to gauge how many users may be affected, and
if it goes ok eventually transition to allow in dev and release with
@@ -5104,97 +4730,12 @@ out:
return nread;
}
-static CURLcode ossl_get_channel_binding(struct Curl_easy *data, int sockindex,
- struct dynbuf *binding)
-{
- /* required for X509_get_signature_nid support */
-#if OPENSSL_VERSION_NUMBER > 0x10100000L
- X509 *cert;
- int algo_nid;
- const EVP_MD *algo_type;
- const char *algo_name;
- unsigned int length;
- unsigned char buf[EVP_MAX_MD_SIZE];
-
- const char prefix[] = "tls-server-end-point:";
- struct connectdata *conn = data->conn;
- struct Curl_cfilter *cf = conn->cfilter[sockindex];
- struct ossl_ctx *octx = NULL;
-
- do {
- const struct Curl_cftype *cft = cf->cft;
- struct ssl_connect_data *connssl = cf->ctx;
-
- if(cft->name && !strcmp(cft->name, "SSL")) {
- octx = (struct ossl_ctx *)connssl->backend;
- break;
- }
-
- if(cf->next)
- cf = cf->next;
-
- } while(cf->next);
-
- if(!octx) {
- failf(data,
- "Failed to find SSL backend for endpoint");
- return CURLE_SSL_ENGINE_INITFAILED;
- }
-
- cert = SSL_get1_peer_certificate(octx->ssl);
- if(!cert) {
- /* No server certificate, don't do channel binding */
- return CURLE_OK;
- }
-
- if(!OBJ_find_sigid_algs(X509_get_signature_nid(cert), &algo_nid, NULL)) {
- failf(data,
- "Unable to find digest NID for certificate signature algorithm");
- return CURLE_SSL_INVALIDCERTSTATUS;
- }
-
- /* https://datatracker.ietf.org/doc/html/rfc5929#section-4.1 */
- if(algo_nid == NID_md5 || algo_nid == NID_sha1) {
- algo_type = EVP_sha256();
- }
- else {
- algo_type = EVP_get_digestbynid(algo_nid);
- if(!algo_type) {
- algo_name = OBJ_nid2sn(algo_nid);
- failf(data, "Could not find digest algorithm %s (NID %d)",
- algo_name ? algo_name : "(null)", algo_nid);
- return CURLE_SSL_INVALIDCERTSTATUS;
- }
- }
-
- if(!X509_digest(cert, algo_type, buf, &length)) {
- failf(data, "X509_digest() failed");
- return CURLE_SSL_INVALIDCERTSTATUS;
- }
-
- /* Append "tls-server-end-point:" */
- if(Curl_dyn_addn(binding, prefix, sizeof(prefix) - 1) != CURLE_OK)
- return CURLE_OUT_OF_MEMORY;
- /* Append digest */
- if(Curl_dyn_addn(binding, buf, length))
- return CURLE_OUT_OF_MEMORY;
-
- return CURLE_OK;
-#else
- /* No X509_get_signature_nid support */
- (void)data; /* unused */
- (void)sockindex; /* unused */
- (void)binding; /* unused */
- return CURLE_OK;
-#endif
-}
-
static size_t ossl_version(char *buffer, size_t size)
{
#ifdef LIBRESSL_VERSION_NUMBER
#ifdef HAVE_OPENSSL_VERSION
char *p;
- size_t count;
+ int count;
const char *ver = OpenSSL_version(OPENSSL_VERSION);
const char expected[] = OSSL_PACKAGE " "; /* ie "LibreSSL " */
if(strncasecompare(ver, expected, sizeof(expected) - 1)) {
@@ -5276,14 +4817,14 @@ static CURLcode ossl_random(struct Curl_easy *data,
int rc;
if(data) {
if(ossl_seed(data)) /* Initiate the seed if not already done */
- return CURLE_FAILED_INIT; /* could not seed for some reason */
+ return CURLE_FAILED_INIT; /* couldn't seed for some reason */
}
else {
if(!rand_enough())
return CURLE_FAILED_INIT;
}
/* RAND_bytes() returns 1 on success, 0 otherwise. */
- rc = RAND_bytes(entropy, (ossl_valsize_t)curlx_uztosi(length));
+ rc = RAND_bytes(entropy, curlx_uztosi(length));
return (rc == 1 ? CURLE_OK : CURLE_FAILED_INIT);
}
@@ -5325,10 +4866,25 @@ static void *ossl_get_internals(struct ssl_connect_data *connssl,
CURLINFO info)
{
/* Legacy: CURLINFO_TLS_SESSION must return an SSL_CTX pointer. */
- struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend;
- DEBUGASSERT(octx);
+ struct ossl_ssl_backend_data *backend =
+ (struct ossl_ssl_backend_data *)connssl->backend;
+ DEBUGASSERT(backend);
return info == CURLINFO_TLS_SESSION ?
- (void *)octx->ssl_ctx : (void *)octx->ssl;
+ (void *)backend->ctx : (void *)backend->handle;
+}
+
+static void ossl_free_multi_ssl_backend_data(
+ struct multi_ssl_backend_data *mbackend)
+{
+#if defined(HAVE_SSL_X509_STORE_SHARE)
+ if(mbackend->store) {
+ X509_STORE_free(mbackend->store);
+ }
+ free(mbackend->CAfile);
+ free(mbackend);
+#else /* HAVE_SSL_X509_STORE_SHARE */
+ (void)mbackend;
+#endif /* HAVE_SSL_X509_STORE_SHARE */
}
const struct Curl_ssl Curl_ssl_openssl = {
@@ -5342,14 +4898,9 @@ const struct Curl_ssl Curl_ssl_openssl = {
#ifdef HAVE_SSL_CTX_SET_CIPHERSUITES
SSLSUPP_TLS13_CIPHERSUITES |
#endif
-#ifdef USE_ECH
- SSLSUPP_ECH |
-#endif
- SSLSUPP_CA_CACHE |
- SSLSUPP_HTTPS_PROXY |
- SSLSUPP_CIPHER_LIST,
+ SSLSUPP_HTTPS_PROXY,
- sizeof(struct ossl_ctx),
+ sizeof(struct ossl_ssl_backend_data),
ossl_init, /* init */
ossl_cleanup, /* cleanup */
@@ -5365,6 +4916,7 @@ const struct Curl_ssl Curl_ssl_openssl = {
ossl_get_internals, /* get_internals */
ossl_close, /* close_one */
ossl_close_all, /* close_all */
+ ossl_session_free, /* session_free */
ossl_set_engine, /* set_engine */
ossl_set_engine_default, /* set_engine_default */
ossl_engines_list, /* engines_list */
@@ -5376,9 +4928,9 @@ const struct Curl_ssl Curl_ssl_openssl = {
#endif
NULL, /* use of data in this connection */
NULL, /* remote of data from this connection */
+ ossl_free_multi_ssl_backend_data, /* free_multi_ssl_backend_data */
ossl_recv, /* recv decrypted data */
ossl_send, /* send data to encrypt */
- ossl_get_channel_binding /* get_channel_binding */
};
#endif /* USE_OPENSSL */
diff --git a/contrib/libs/curl/lib/vtls/openssl.h b/contrib/libs/curl/lib/vtls/openssl.h
index 7aba947d18..e802363a4a 100644
--- a/contrib/libs/curl/lib/vtls/openssl.h
+++ b/contrib/libs/curl/lib/vtls/openssl.h
@@ -36,46 +36,23 @@
#include "urldata.h"
-/* Struct to hold a Curl OpenSSL instance */
-struct ossl_ctx {
- /* these ones requires specific SSL-types */
- SSL_CTX* ssl_ctx;
- SSL* ssl;
- X509* server_cert;
- BIO_METHOD *bio_method;
- CURLcode io_result; /* result of last BIO cfilter operation */
-#ifndef HAVE_KEYLOG_CALLBACK
- /* Set to true once a valid keylog entry has been created to avoid dupes.
- This is a bool and not a bitfield because it is passed by address. */
- bool keylog_done;
-#endif
- BIT(x509_store_setup); /* x509 store has been set up */
- BIT(reused_session); /* session-ID was reused for this */
-};
-
-typedef CURLcode Curl_ossl_ctx_setup_cb(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- void *user_data);
-
-typedef int Curl_ossl_new_session_cb(SSL *ssl, SSL_SESSION *ssl_sessionid);
-
-CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx,
- struct Curl_cfilter *cf,
- struct Curl_easy *data,
- struct ssl_peer *peer,
- int transport, /* TCP or QUIC */
- const unsigned char *alpn, size_t alpn_len,
- Curl_ossl_ctx_setup_cb *cb_setup,
- void *cb_user_data,
- Curl_ossl_new_session_cb *cb_new_session,
- void *ssl_user_data);
-
#if (OPENSSL_VERSION_NUMBER < 0x30000000L)
#define SSL_get1_peer_certificate SSL_get_peer_certificate
#endif
+CURLcode Curl_ossl_verifyhost(struct Curl_easy *data, struct connectdata *conn,
+ struct ssl_peer *peer, X509 *server_cert);
extern const struct Curl_ssl Curl_ssl_openssl;
+CURLcode Curl_ossl_set_client_cert(struct Curl_easy *data,
+ SSL_CTX *ctx, char *cert_file,
+ const struct curl_blob *cert_blob,
+ const char *cert_type, char *key_file,
+ const struct curl_blob *key_blob,
+ const char *key_type, char *key_passwd);
+
+CURLcode Curl_ossl_certchain(struct Curl_easy *data, SSL *ssl);
+
/**
* Setup the OpenSSL X509_STORE in `ssl_ctx` for the cfilter `cf` and
* easy handle `data`. Will allow reuse of a shared cache if suitable
@@ -89,23 +66,5 @@ CURLcode Curl_ossl_ctx_configure(struct Curl_cfilter *cf,
struct Curl_easy *data,
SSL_CTX *ssl_ctx);
-/*
- * Add a new session to the cache. Takes ownership of the session.
- */
-CURLcode Curl_ossl_add_session(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- const struct ssl_peer *peer,
- SSL_SESSION *ssl_sessionid);
-
-/*
- * Get the server cert, verify it and show it, etc., only call failf() if
- * ssl config verifypeer or -host is set. Otherwise all this is for
- * informational purposes only!
- */
-CURLcode Curl_oss_check_peer_cert(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- struct ossl_ctx *octx,
- struct ssl_peer *peer);
-
#endif /* USE_OPENSSL */
#endif /* HEADER_CURL_SSLUSE_H */
diff --git a/contrib/libs/curl/lib/vtls/rustls.c b/contrib/libs/curl/lib/vtls/rustls.c
index 6c05093937..d267e26463 100644
--- a/contrib/libs/curl/lib/vtls/rustls.c
+++ b/contrib/libs/curl/lib/vtls/rustls.c
@@ -7,7 +7,6 @@
*
* Copyright (C) Jacob Hoffman-Andrews,
* <github@hoffman-andrews.com>
- * Copyright (C) kpcyrd, <kpcyrd@archlinux.org>
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -41,16 +40,12 @@
#include "strerror.h"
#include "multiif.h"
#include "connect.h" /* for the connect timeout */
-#error #include "cipher_suite.h"
-#include "rand.h"
struct rustls_ssl_backend_data
{
const struct rustls_client_config *config;
struct rustls_connection *conn;
- size_t plain_out_buffered;
- BIT(data_in_pending);
- BIT(sent_shutdown);
+ bool data_pending;
};
/* For a given rustls_result error code, return the best-matching CURLcode. */
@@ -65,7 +60,7 @@ static CURLcode map_error(rustls_result r)
case RUSTLS_RESULT_NULL_PARAMETER:
return CURLE_BAD_FUNCTION_ARGUMENT;
default:
- return CURLE_RECV_ERROR;
+ return CURLE_READ_ERROR;
}
}
@@ -78,7 +73,7 @@ cr_data_pending(struct Curl_cfilter *cf, const struct Curl_easy *data)
(void)data;
DEBUGASSERT(ctx && ctx->backend);
backend = (struct rustls_ssl_backend_data *)ctx->backend;
- return backend->data_in_pending;
+ return backend->data_pending;
}
struct io_ctx {
@@ -90,7 +85,6 @@ static int
read_cb(void *userdata, uint8_t *buf, uintptr_t len, uintptr_t *out_n)
{
struct io_ctx *io_ctx = userdata;
- struct ssl_connect_data *const connssl = io_ctx->cf->ctx;
CURLcode result;
int ret = 0;
ssize_t nread = Curl_conn_cf_recv(io_ctx->cf->next, io_ctx->data,
@@ -102,11 +96,7 @@ read_cb(void *userdata, uint8_t *buf, uintptr_t len, uintptr_t *out_n)
else
ret = EINVAL;
}
- else if(nread == 0)
- connssl->peer_closed = TRUE;
- *out_n = (uintptr_t)nread;
- CURL_TRC_CF(io_ctx->data, io_ctx->cf, "cf->next recv(len=%zu) -> %zd, %d",
- len, nread, result);
+ *out_n = (int)nread;
return ret;
}
@@ -117,8 +107,7 @@ write_cb(void *userdata, const uint8_t *buf, uintptr_t len, uintptr_t *out_n)
CURLcode result;
int ret = 0;
ssize_t nwritten = Curl_conn_cf_send(io_ctx->cf->next, io_ctx->data,
- (const char *)buf, len, FALSE,
- &result);
+ (const char *)buf, len, &result);
if(nwritten < 0) {
nwritten = 0;
if(CURLE_AGAIN == result)
@@ -126,9 +115,11 @@ write_cb(void *userdata, const uint8_t *buf, uintptr_t len, uintptr_t *out_n)
else
ret = EINVAL;
}
- *out_n = (uintptr_t)nwritten;
- CURL_TRC_CF(io_ctx->data, io_ctx->cf, "cf->next send(len=%zu) -> %zd, %d",
- len, nwritten, result);
+ *out_n = (int)nwritten;
+ /*
+ CURL_TRC_CFX(io_ctx->data, io_ctx->cf, "cf->next send(len=%zu) -> %zd, %d",
+ len, nwritten, result));
+ */
return ret;
}
@@ -155,7 +146,7 @@ static ssize_t tls_recv_more(struct Curl_cfilter *cf,
char buffer[STRERROR_LEN];
failf(data, "reading from socket: %s",
Curl_strerror(io_error, buffer, sizeof(buffer)));
- *err = CURLE_RECV_ERROR;
+ *err = CURLE_READ_ERROR;
return -1;
}
@@ -165,27 +156,27 @@ static ssize_t tls_recv_more(struct Curl_cfilter *cf,
size_t errorlen;
rustls_error(rresult, errorbuf, sizeof(errorbuf), &errorlen);
failf(data, "rustls_connection_process_new_packets: %.*s",
- (int)errorlen, errorbuf);
+ errorlen, errorbuf);
*err = map_error(rresult);
return -1;
}
- backend->data_in_pending = TRUE;
+ backend->data_pending = TRUE;
*err = CURLE_OK;
return (ssize_t)tls_bytes_read;
}
/*
* On each run:
- * - Read a chunk of bytes from the socket into Rustls' TLS input buffer.
- * - Tell Rustls to process any new packets.
- * - Read out as many plaintext bytes from Rustls as possible, until hitting
+ * - Read a chunk of bytes from the socket into rustls' TLS input buffer.
+ * - Tell rustls to process any new packets.
+ * - Read out as many plaintext bytes from rustls as possible, until hitting
* error, EOF, or EAGAIN/EWOULDBLOCK, or plainbuf/plainlen is filled up.
*
- * it is okay to call this function with plainbuf == NULL and plainlen == 0. In
- * that case, it will copy bytes from the socket into Rustls' TLS input
- * buffer, and process packets, but will not consume bytes from Rustls'
- * plaintext output buffer.
+ * It's okay to call this function with plainbuf == NULL and plainlen == 0.
+ * In that case, it will copy bytes from the socket into rustls' TLS input
+ * buffer, and process packets, but won't consume bytes from rustls' plaintext
+ * output buffer.
*/
static ssize_t
cr_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
@@ -205,7 +196,7 @@ cr_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
rconn = backend->conn;
while(plain_bytes_copied < plainlen) {
- if(!backend->data_in_pending) {
+ if(!backend->data_pending) {
if(tls_recv_more(cf, data, err) < 0) {
if(*err != CURLE_AGAIN) {
nread = -1;
@@ -216,26 +207,26 @@ cr_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
}
rresult = rustls_connection_read(rconn,
- (uint8_t *)plainbuf + plain_bytes_copied,
- plainlen - plain_bytes_copied,
- &n);
+ (uint8_t *)plainbuf + plain_bytes_copied,
+ plainlen - plain_bytes_copied,
+ &n);
if(rresult == RUSTLS_RESULT_PLAINTEXT_EMPTY) {
- backend->data_in_pending = FALSE;
+ backend->data_pending = FALSE;
}
else if(rresult == RUSTLS_RESULT_UNEXPECTED_EOF) {
failf(data, "rustls: peer closed TCP connection "
- "without first closing TLS connection");
- *err = CURLE_RECV_ERROR;
+ "without first closing TLS connection");
+ *err = CURLE_READ_ERROR;
nread = -1;
goto out;
}
else if(rresult != RUSTLS_RESULT_OK) {
- /* n always equals 0 in this case, do not need to check it */
+ /* n always equals 0 in this case, don't need to check it */
char errorbuf[255];
size_t errorlen;
rustls_error(rresult, errorbuf, sizeof(errorbuf), &errorlen);
- failf(data, "rustls_connection_read: %.*s", (int)errorlen, errorbuf);
- *err = CURLE_RECV_ERROR;
+ failf(data, "rustls_connection_read: %.*s", errorlen, errorbuf);
+ *err = CURLE_READ_ERROR;
nread = -1;
goto out;
}
@@ -270,51 +261,15 @@ out:
return nread;
}
-static CURLcode cr_flush_out(struct Curl_cfilter *cf, struct Curl_easy *data,
- struct rustls_connection *rconn)
-{
- struct io_ctx io_ctx;
- rustls_io_result io_error;
- size_t tlswritten = 0;
- size_t tlswritten_total = 0;
- CURLcode result = CURLE_OK;
-
- io_ctx.cf = cf;
- io_ctx.data = data;
-
- while(rustls_connection_wants_write(rconn)) {
- io_error = rustls_connection_write_tls(rconn, write_cb, &io_ctx,
- &tlswritten);
- if(io_error == EAGAIN || io_error == EWOULDBLOCK) {
- CURL_TRC_CF(data, cf, "cf_send: EAGAIN after %zu bytes",
- tlswritten_total);
- return CURLE_AGAIN;
- }
- else if(io_error) {
- char buffer[STRERROR_LEN];
- failf(data, "writing to socket: %s",
- Curl_strerror(io_error, buffer, sizeof(buffer)));
- return CURLE_SEND_ERROR;
- }
- if(tlswritten == 0) {
- failf(data, "EOF in swrite");
- return CURLE_SEND_ERROR;
- }
- CURL_TRC_CF(data, cf, "cf_send: wrote %zu TLS bytes", tlswritten);
- tlswritten_total += tlswritten;
- }
- return result;
-}
-
/*
* On each call:
- * - Copy `plainlen` bytes into Rustls' plaintext input buffer (if > 0).
- * - Fully drain Rustls' plaintext output buffer into the socket until
+ * - Copy `plainlen` bytes into rustls' plaintext input buffer (if > 0).
+ * - Fully drain rustls' plaintext output buffer into the socket until
* we get either an error or EAGAIN/EWOULDBLOCK.
*
- * it is okay to call this function with plainbuf == NULL and plainlen == 0.
- * In that case, it will not read anything into Rustls' plaintext input buffer.
- * It will only drain Rustls' plaintext output buffer into the socket.
+ * It's okay to call this function with plainbuf == NULL and plainlen == 0.
+ * In that case, it won't read anything into rustls' plaintext input buffer.
+ * It will only drain rustls' plaintext output buffer into the socket.
*/
static ssize_t
cr_send(struct Curl_cfilter *cf, struct Curl_easy *data,
@@ -324,46 +279,29 @@ cr_send(struct Curl_cfilter *cf, struct Curl_easy *data,
struct rustls_ssl_backend_data *const backend =
(struct rustls_ssl_backend_data *)connssl->backend;
struct rustls_connection *rconn = NULL;
+ struct io_ctx io_ctx;
size_t plainwritten = 0;
+ size_t tlswritten = 0;
+ size_t tlswritten_total = 0;
rustls_result rresult;
+ rustls_io_result io_error;
char errorbuf[256];
size_t errorlen;
- const unsigned char *buf = plainbuf;
- size_t blen = plainlen;
- ssize_t nwritten = 0;
DEBUGASSERT(backend);
rconn = backend->conn;
- DEBUGASSERT(rconn);
-
- CURL_TRC_CF(data, cf, "cf_send(len=%zu)", plainlen);
-
- /* If a previous send blocked, we already added its plain bytes
- * to rustsls and must not do that again. Flush the TLS bytes and,
- * if successful, deduct the previous plain bytes from the current
- * send. */
- if(backend->plain_out_buffered) {
- *err = cr_flush_out(cf, data, rconn);
- CURL_TRC_CF(data, cf, "cf_send: flushing %zu previously added bytes -> %d",
- backend->plain_out_buffered, *err);
- if(*err)
- return -1;
- if(blen > backend->plain_out_buffered) {
- blen -= backend->plain_out_buffered;
- buf += backend->plain_out_buffered;
- }
- else
- blen = 0;
- nwritten += (ssize_t)backend->plain_out_buffered;
- backend->plain_out_buffered = 0;
- }
- if(blen > 0) {
- CURL_TRC_CF(data, cf, "cf_send: adding %zu plain bytes to Rustls", blen);
- rresult = rustls_connection_write(rconn, buf, blen, &plainwritten);
+ CURL_TRC_CF(data, cf, "cf_send: %ld plain bytes", plainlen);
+
+ io_ctx.cf = cf;
+ io_ctx.data = data;
+
+ if(plainlen > 0) {
+ rresult = rustls_connection_write(rconn, plainbuf, plainlen,
+ &plainwritten);
if(rresult != RUSTLS_RESULT_OK) {
rustls_error(rresult, errorbuf, sizeof(errorbuf), &errorlen);
- failf(data, "rustls_connection_write: %.*s", (int)errorlen, errorbuf);
+ failf(data, "rustls_connection_write: %.*s", errorlen, errorbuf);
*err = CURLE_WRITE_ERROR;
return -1;
}
@@ -374,151 +312,57 @@ cr_send(struct Curl_cfilter *cf, struct Curl_easy *data,
}
}
- *err = cr_flush_out(cf, data, rconn);
- if(*err) {
- if(CURLE_AGAIN == *err) {
- /* The TLS bytes may have been partially written, but we fail the
- * complete send() and remember how much we already added to Rustls. */
- CURL_TRC_CF(data, cf, "cf_send: EAGAIN, remember we added %zu plain"
- " bytes already to Rustls", blen);
- backend->plain_out_buffered = plainwritten;
- if(nwritten) {
- *err = CURLE_OK;
- return (ssize_t)nwritten;
- }
+ while(rustls_connection_wants_write(rconn)) {
+ io_error = rustls_connection_write_tls(rconn, write_cb, &io_ctx,
+ &tlswritten);
+ if(io_error == EAGAIN || io_error == EWOULDBLOCK) {
+ CURL_TRC_CF(data, cf, "cf_send: EAGAIN after %zu bytes",
+ tlswritten_total);
+ *err = CURLE_AGAIN;
+ return -1;
}
- return -1;
+ else if(io_error) {
+ char buffer[STRERROR_LEN];
+ failf(data, "writing to socket: %s",
+ Curl_strerror(io_error, buffer, sizeof(buffer)));
+ *err = CURLE_WRITE_ERROR;
+ return -1;
+ }
+ if(tlswritten == 0) {
+ failf(data, "EOF in swrite");
+ *err = CURLE_WRITE_ERROR;
+ return -1;
+ }
+ CURL_TRC_CF(data, cf, "cf_send: wrote %zu TLS bytes", tlswritten);
+ tlswritten_total += tlswritten;
}
- else
- nwritten += (ssize_t)plainwritten;
- CURL_TRC_CF(data, cf, "cf_send(len=%zu) -> %d, %zd",
- plainlen, *err, nwritten);
- return nwritten;
+ return plainwritten;
}
-/* A server certificate verify callback for Rustls that always returns
+/* A server certificate verify callback for rustls that always returns
RUSTLS_RESULT_OK, or in other words disable certificate verification. */
-static uint32_t
+static enum rustls_result
cr_verify_none(void *userdata UNUSED_PARAM,
const rustls_verify_server_cert_params *params UNUSED_PARAM)
{
return RUSTLS_RESULT_OK;
}
-static int
-read_file_into(const char *filename,
- struct dynbuf *out)
-{
- FILE *f = fopen(filename, FOPEN_READTEXT);
- if(!f) {
- return 0;
- }
-
- while(!feof(f)) {
- uint8_t buf[256];
- size_t rr = fread(buf, 1, sizeof(buf), f);
- if(rr == 0 ||
- CURLE_OK != Curl_dyn_addn(out, buf, rr)) {
- fclose(f);
- return 0;
- }
- }
-
- return fclose(f) == 0;
-}
-
-static void
-cr_get_selected_ciphers(struct Curl_easy *data,
- const char *ciphers12,
- const char *ciphers13,
- const struct rustls_supported_ciphersuite **selected,
- size_t *selected_size)
+static bool
+cr_hostname_is_ip(const char *hostname)
{
- size_t supported_len = *selected_size;
- size_t default_len = rustls_default_crypto_provider_ciphersuites_len();
- const struct rustls_supported_ciphersuite *entry;
- const char *ciphers = ciphers12;
- size_t count = 0, default13_count = 0, i, j;
- const char *ptr, *end;
-
- DEBUGASSERT(default_len <= supported_len);
-
- if(!ciphers13) {
- /* Add default TLSv1.3 ciphers to selection */
- for(j = 0; j < default_len; j++) {
- entry = rustls_default_crypto_provider_ciphersuites_get(j);
- if(rustls_supported_ciphersuite_protocol_version(entry) !=
- RUSTLS_TLS_VERSION_TLSV1_3)
- continue;
-
- selected[count++] = entry;
- }
-
- default13_count = count;
-
- if(!ciphers)
- ciphers = "";
+ struct in_addr in;
+#ifdef ENABLE_IPV6
+ struct in6_addr in6;
+ if(Curl_inet_pton(AF_INET6, hostname, &in6) > 0) {
+ return true;
}
- else
- ciphers = ciphers13;
-
-add_ciphers:
- for(ptr = ciphers; ptr[0] != '\0' && count < supported_len; ptr = end) {
- uint16_t id = Curl_cipher_suite_walk_str(&ptr, &end);
-
- /* Check if cipher is supported */
- if(id) {
- for(i = 0; i < supported_len; i++) {
- entry = rustls_default_crypto_provider_ciphersuites_get(i);
- if(rustls_supported_ciphersuite_get_suite(entry) == id)
- break;
- }
- if(i == supported_len)
- id = 0;
- }
- if(!id) {
- if(ptr[0] != '\0')
- infof(data, "rustls: unknown cipher in list: \"%.*s\"",
- (int) (end - ptr), ptr);
- continue;
- }
-
- /* No duplicates allowed (so selected cannot overflow) */
- for(i = 0; i < count && selected[i] != entry; i++);
- if(i < count) {
- if(i >= default13_count)
- infof(data, "rustls: duplicate cipher in list: \"%.*s\"",
- (int) (end - ptr), ptr);
- continue;
- }
-
- selected[count++] = entry;
- }
-
- if(ciphers == ciphers13 && ciphers12) {
- ciphers = ciphers12;
- goto add_ciphers;
+#endif /* ENABLE_IPV6 */
+ if(Curl_inet_pton(AF_INET, hostname, &in) > 0) {
+ return true;
}
-
- if(!ciphers12) {
- /* Add default TLSv1.2 ciphers to selection */
- for(j = 0; j < default_len; j++) {
- entry = rustls_default_crypto_provider_ciphersuites_get(j);
- if(rustls_supported_ciphersuite_protocol_version(entry) ==
- RUSTLS_TLS_VERSION_TLSV1_3)
- continue;
-
- /* No duplicates allowed (so selected cannot overflow) */
- for(i = 0; i < count && selected[i] != entry; i++);
- if(i < count)
- continue;
-
- selected[count++] = entry;
- }
- }
-
- *selected_size = count;
+ return false;
}
static CURLcode
@@ -527,126 +371,23 @@ cr_init_backend(struct Curl_cfilter *cf, struct Curl_easy *data,
{
struct ssl_connect_data *connssl = cf->ctx;
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
- struct rustls_crypto_provider_builder *custom_provider_builder = NULL;
- const struct rustls_crypto_provider *custom_provider = NULL;
struct rustls_connection *rconn = NULL;
struct rustls_client_config_builder *config_builder = NULL;
- const struct rustls_root_cert_store *roots = NULL;
- struct rustls_root_cert_store_builder *roots_builder = NULL;
- struct rustls_web_pki_server_cert_verifier_builder *verifier_builder = NULL;
- struct rustls_server_cert_verifier *server_cert_verifier = NULL;
+ struct rustls_root_cert_store *roots = NULL;
const struct curl_blob *ca_info_blob = conn_config->ca_info_blob;
const char * const ssl_cafile =
/* CURLOPT_CAINFO_BLOB overrides CURLOPT_CAINFO */
(ca_info_blob ? NULL : conn_config->CAfile);
const bool verifypeer = conn_config->verifypeer;
+ const char *hostname = connssl->peer.hostname;
char errorbuf[256];
size_t errorlen;
- rustls_result result;
+ int result;
DEBUGASSERT(backend);
rconn = backend->conn;
- {
- uint16_t tls_versions[2] = {
- RUSTLS_TLS_VERSION_TLSV1_2,
- RUSTLS_TLS_VERSION_TLSV1_3,
- };
- size_t tls_versions_len = 2;
- const struct rustls_supported_ciphersuite **cipher_suites;
- size_t cipher_suites_len =
- rustls_default_crypto_provider_ciphersuites_len();
-
- switch(conn_config->version) {
- case CURL_SSLVERSION_DEFAULT:
- case CURL_SSLVERSION_TLSv1:
- case CURL_SSLVERSION_TLSv1_0:
- case CURL_SSLVERSION_TLSv1_1:
- case CURL_SSLVERSION_TLSv1_2:
- break;
- case CURL_SSLVERSION_TLSv1_3:
- tls_versions[0] = RUSTLS_TLS_VERSION_TLSV1_3;
- tls_versions_len = 1;
- break;
- default:
- failf(data, "rustls: unsupported minimum TLS version value");
- return CURLE_SSL_ENGINE_INITFAILED;
- }
-
- switch(conn_config->version_max) {
- case CURL_SSLVERSION_MAX_DEFAULT:
- case CURL_SSLVERSION_MAX_NONE:
- case CURL_SSLVERSION_MAX_TLSv1_3:
- break;
- case CURL_SSLVERSION_MAX_TLSv1_2:
- if(tls_versions[0] == RUSTLS_TLS_VERSION_TLSV1_2) {
- tls_versions_len = 1;
- break;
- }
- FALLTHROUGH();
- case CURL_SSLVERSION_MAX_TLSv1_1:
- case CURL_SSLVERSION_MAX_TLSv1_0:
- default:
- failf(data, "rustls: unsupported maximum TLS version value");
- return CURLE_SSL_ENGINE_INITFAILED;
- }
-
- cipher_suites = malloc(sizeof(cipher_suites) * (cipher_suites_len));
- if(!cipher_suites)
- return CURLE_OUT_OF_MEMORY;
-
- cr_get_selected_ciphers(data,
- conn_config->cipher_list,
- conn_config->cipher_list13,
- cipher_suites, &cipher_suites_len);
- if(cipher_suites_len == 0) {
- failf(data, "rustls: no supported cipher in list");
- free(cipher_suites);
- return CURLE_SSL_CIPHER;
- }
-
- result = rustls_crypto_provider_builder_new_from_default(
- &custom_provider_builder);
- if(result != RUSTLS_RESULT_OK) {
- failf(data,
- "rustls: failed to create crypto provider builder from default");
- return CURLE_SSL_ENGINE_INITFAILED;
- }
-
- result =
- rustls_crypto_provider_builder_set_cipher_suites(
- custom_provider_builder,
- cipher_suites,
- cipher_suites_len);
- if(result != RUSTLS_RESULT_OK) {
- failf(data,
- "rustls: failed to set ciphersuites for crypto provider builder");
- rustls_crypto_provider_builder_free(custom_provider_builder);
- return CURLE_SSL_ENGINE_INITFAILED;
- }
-
- result = rustls_crypto_provider_builder_build(
- custom_provider_builder, &custom_provider);
- if(result != RUSTLS_RESULT_OK) {
- failf(data, "rustls: failed to build custom crypto provider");
- rustls_crypto_provider_builder_free(custom_provider_builder);
- return CURLE_SSL_ENGINE_INITFAILED;
- }
-
- result = rustls_client_config_builder_new_custom(custom_provider,
- tls_versions,
- tls_versions_len,
- &config_builder);
- free(cipher_suites);
- if(result != RUSTLS_RESULT_OK) {
- failf(data, "rustls: failed to create client config");
- return CURLE_SSL_ENGINE_INITFAILED;
- }
- }
-
- rustls_crypto_provider_builder_free(custom_provider_builder);
- rustls_crypto_provider_free(custom_provider);
-
+ config_builder = rustls_client_config_builder_new();
if(connssl->alpn) {
struct alpn_proto_buf proto;
rustls_slice_bytes alpn[ALPN_ENTRIES_MAX];
@@ -664,101 +405,63 @@ cr_init_backend(struct Curl_cfilter *cf, struct Curl_easy *data,
if(!verifypeer) {
rustls_client_config_builder_dangerous_set_certificate_verifier(
config_builder, cr_verify_none);
- }
- else if(ca_info_blob || ssl_cafile) {
- roots_builder = rustls_root_cert_store_builder_new();
-
- if(ca_info_blob) {
- /* Enable strict parsing only if verification is not disabled. */
- result = rustls_root_cert_store_builder_add_pem(roots_builder,
- ca_info_blob->data,
- ca_info_blob->len,
- verifypeer);
- if(result != RUSTLS_RESULT_OK) {
- failf(data, "rustls: failed to parse trusted certificates from blob");
- rustls_root_cert_store_builder_free(roots_builder);
- rustls_client_config_builder_free(config_builder);
- return CURLE_SSL_CACERT_BADFILE;
- }
- }
- else if(ssl_cafile) {
- /* Enable strict parsing only if verification is not disabled. */
- result = rustls_root_cert_store_builder_load_roots_from_file(
- roots_builder, ssl_cafile, verifypeer);
- if(result != RUSTLS_RESULT_OK) {
- failf(data, "rustls: failed to load trusted certificates");
- rustls_root_cert_store_builder_free(roots_builder);
- rustls_client_config_builder_free(config_builder);
- return CURLE_SSL_CACERT_BADFILE;
- }
+ /* rustls doesn't support IP addresses (as of 0.19.0), and will reject
+ * connections created with an IP address, even when certificate
+ * verification is turned off. Set a placeholder hostname and disable
+ * SNI. */
+ if(cr_hostname_is_ip(hostname)) {
+ rustls_client_config_builder_set_enable_sni(config_builder, false);
+ hostname = "example.invalid";
}
+ }
+ else if(ca_info_blob) {
+ roots = rustls_root_cert_store_new();
- result = rustls_root_cert_store_builder_build(roots_builder, &roots);
- rustls_root_cert_store_builder_free(roots_builder);
+ /* Enable strict parsing only if verification isn't disabled. */
+ result = rustls_root_cert_store_add_pem(roots, ca_info_blob->data,
+ ca_info_blob->len, verifypeer);
if(result != RUSTLS_RESULT_OK) {
- failf(data, "rustls: failed to build trusted root certificate store");
- rustls_client_config_builder_free(config_builder);
+ failf(data, "rustls: failed to parse trusted certificates from blob");
+ rustls_root_cert_store_free(roots);
+ rustls_client_config_free(
+ rustls_client_config_builder_build(config_builder));
return CURLE_SSL_CACERT_BADFILE;
}
- verifier_builder = rustls_web_pki_server_cert_verifier_builder_new(roots);
+ result = rustls_client_config_builder_use_roots(config_builder, roots);
rustls_root_cert_store_free(roots);
-
- if(conn_config->CRLfile) {
- struct dynbuf crl_contents;
- Curl_dyn_init(&crl_contents, SIZE_MAX);
- if(!read_file_into(conn_config->CRLfile, &crl_contents)) {
- failf(data, "rustls: failed to read revocation list file");
- Curl_dyn_free(&crl_contents);
- rustls_web_pki_server_cert_verifier_builder_free(verifier_builder);
- return CURLE_SSL_CRL_BADFILE;
- }
-
- result = rustls_web_pki_server_cert_verifier_builder_add_crl(
- verifier_builder,
- Curl_dyn_uptr(&crl_contents),
- Curl_dyn_len(&crl_contents));
- Curl_dyn_free(&crl_contents);
- if(result != RUSTLS_RESULT_OK) {
- failf(data, "rustls: failed to parse revocation list");
- rustls_web_pki_server_cert_verifier_builder_free(verifier_builder);
- return CURLE_SSL_CRL_BADFILE;
- }
- }
-
- result = rustls_web_pki_server_cert_verifier_builder_build(
- verifier_builder, &server_cert_verifier);
- rustls_web_pki_server_cert_verifier_builder_free(verifier_builder);
if(result != RUSTLS_RESULT_OK) {
- failf(data, "rustls: failed to build certificate verifier");
- rustls_server_cert_verifier_free(server_cert_verifier);
- rustls_client_config_builder_free(config_builder);
+ failf(data, "rustls: failed to load trusted certificates");
+ rustls_client_config_free(
+ rustls_client_config_builder_build(config_builder));
return CURLE_SSL_CACERT_BADFILE;
}
-
- rustls_client_config_builder_set_server_verifier(config_builder,
- server_cert_verifier);
- rustls_server_cert_verifier_free(server_cert_verifier);
}
-
- result = rustls_client_config_builder_build(
- config_builder,
- &backend->config);
- if(result != RUSTLS_RESULT_OK) {
- failf(data, "rustls: failed to build client config");
- rustls_client_config_free(backend->config);
- return CURLE_SSL_ENGINE_INITFAILED;
+ else if(ssl_cafile) {
+ result = rustls_client_config_builder_load_roots_from_file(
+ config_builder, ssl_cafile);
+ if(result != RUSTLS_RESULT_OK) {
+ failf(data, "rustls: failed to load trusted certificates");
+ rustls_client_config_free(
+ rustls_client_config_builder_build(config_builder));
+ return CURLE_SSL_CACERT_BADFILE;
+ }
}
+ backend->config = rustls_client_config_builder_build(config_builder);
DEBUGASSERT(rconn == NULL);
- result = rustls_client_connection_new(backend->config,
- connssl->peer.hostname, &rconn);
+ {
+ /* rustls claims to manage ip address hostnames as well here. So,
+ * if we have an SNI, we use it, otherwise we pass the hostname */
+ char *server = connssl->peer.sni?
+ connssl->peer.sni : connssl->peer.hostname;
+ result = rustls_client_connection_new(backend->config, server, &rconn);
+ }
if(result != RUSTLS_RESULT_OK) {
rustls_error(result, errorbuf, sizeof(errorbuf), &errorlen);
- failf(data, "rustls_client_connection_new: %.*s", (int)errorlen, errorbuf);
+ failf(data, "rustls_client_connection_new: %.*s", errorlen, errorbuf);
return CURLE_COULDNT_CONNECT;
}
- DEBUGASSERT(rconn);
rustls_connection_set_userdata(rconn, backend);
backend->conn = rconn;
return CURLE_OK;
@@ -807,12 +510,9 @@ cr_connect_common(struct Curl_cfilter *cf,
DEBUGASSERT(backend);
- CURL_TRC_CF(data, cf, "cr_connect_common, state=%d", connssl->state);
- *done = FALSE;
- if(!backend->conn) {
+ if(ssl_connection_none == connssl->state) {
result = cr_init_backend(cf, data,
(struct rustls_ssl_backend_data *)connssl->backend);
- CURL_TRC_CF(data, cf, "cr_connect_common, init backend -> %d", result);
if(result != CURLE_OK) {
return result;
}
@@ -824,47 +524,22 @@ cr_connect_common(struct Curl_cfilter *cf,
/* Read/write data until the handshake is done or the socket would block. */
for(;;) {
/*
- * Connection has been established according to Rustls. Set send/recv
+ * Connection has been established according to rustls. Set send/recv
* handlers, and update the state machine.
*/
- connssl->io_need = CURL_SSL_IO_NEED_NONE;
if(!rustls_connection_is_handshaking(rconn)) {
- /* Rustls claims it is no longer handshaking *before* it has
- * send its FINISHED message off. We attempt to let it write
- * one more time. Oh my.
- */
- cr_set_negotiated_alpn(cf, data, rconn);
- cr_send(cf, data, NULL, 0, &tmperr);
- if(tmperr == CURLE_AGAIN) {
- connssl->io_need = CURL_SSL_IO_NEED_SEND;
- return CURLE_OK;
- }
- else if(tmperr != CURLE_OK) {
- return tmperr;
- }
- /* REALLY Done with the handshake. */
- {
- uint16_t proto = rustls_connection_get_protocol_version(rconn);
- uint16_t cipher = rustls_connection_get_negotiated_ciphersuite(rconn);
- char buf[64] = "";
- const char *ver = "TLS version unknown";
- if(proto == RUSTLS_TLS_VERSION_TLSV1_3)
- ver = "TLSv1.3";
- if(proto == RUSTLS_TLS_VERSION_TLSV1_2)
- ver = "TLSv1.2";
- Curl_cipher_suite_get_str(cipher, buf, sizeof(buf), true);
- infof(data, "rustls: handshake complete, %s, cipher: %s",
- ver, buf);
- }
+ infof(data, "Done handshaking");
+ /* Done with the handshake. Set up callbacks to send/receive data. */
connssl->state = ssl_connection_complete;
+
+ cr_set_negotiated_alpn(cf, data, rconn);
+
*done = TRUE;
return CURLE_OK;
}
- connssl->connecting_state = ssl_connect_2;
wants_read = rustls_connection_wants_read(rconn);
- wants_write = rustls_connection_wants_write(rconn) ||
- backend->plain_out_buffered;
+ wants_write = rustls_connection_wants_write(rconn);
DEBUGASSERT(wants_read || wants_write);
writefd = wants_write?sockfd:CURL_SOCKET_BAD;
readfd = wants_read?sockfd:CURL_SOCKET_BAD;
@@ -880,35 +555,32 @@ cr_connect_common(struct Curl_cfilter *cf,
socket_check_timeout = blocking?timeout_ms:0;
- what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
- socket_check_timeout);
+ what = Curl_socket_check(
+ readfd, CURL_SOCKET_BAD, writefd, socket_check_timeout);
if(what < 0) {
/* fatal error */
failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
return CURLE_SSL_CONNECT_ERROR;
}
if(blocking && 0 == what) {
- failf(data, "rustls: connection timeout after %" FMT_TIMEDIFF_T " ms",
- socket_check_timeout);
+ failf(data, "rustls connection timeout after %d ms",
+ socket_check_timeout);
return CURLE_OPERATION_TIMEDOUT;
}
if(0 == what) {
- CURL_TRC_CF(data, cf, "Curl_socket_check: %s would block",
+ infof(data, "Curl_socket_check: %s would block",
wants_read&&wants_write ? "writing and reading" :
wants_write ? "writing" : "reading");
- if(wants_write)
- connssl->io_need |= CURL_SSL_IO_NEED_SEND;
- if(wants_read)
- connssl->io_need |= CURL_SSL_IO_NEED_RECV;
+ *done = FALSE;
return CURLE_OK;
}
/* socket is readable or writable */
if(wants_write) {
- CURL_TRC_CF(data, cf, "rustls_connection wants us to write_tls.");
+ infof(data, "rustls_connection wants us to write_tls.");
cr_send(cf, data, NULL, 0, &tmperr);
if(tmperr == CURLE_AGAIN) {
- CURL_TRC_CF(data, cf, "writing would block");
+ infof(data, "writing would block");
/* fall through */
}
else if(tmperr != CURLE_OK) {
@@ -917,13 +589,14 @@ cr_connect_common(struct Curl_cfilter *cf,
}
if(wants_read) {
- CURL_TRC_CF(data, cf, "rustls_connection wants us to read_tls.");
+ infof(data, "rustls_connection wants us to read_tls.");
+
if(tls_recv_more(cf, data, &tmperr) < 0) {
if(tmperr == CURLE_AGAIN) {
- CURL_TRC_CF(data, cf, "reading would block");
+ infof(data, "reading would block");
/* fall through */
}
- else if(tmperr == CURLE_RECV_ERROR) {
+ else if(tmperr == CURLE_READ_ERROR) {
return CURLE_SSL_CONNECT_ERROR;
}
else {
@@ -934,7 +607,7 @@ cr_connect_common(struct Curl_cfilter *cf,
}
/* We should never fall through the loop. We should return either because
- the handshake is done or because we cannot read/write without blocking. */
+ the handshake is done or because we can't read/write without blocking. */
DEBUGASSERT(false);
}
@@ -946,12 +619,37 @@ cr_connect_nonblocking(struct Curl_cfilter *cf,
}
static CURLcode
-cr_connect_blocking(struct Curl_cfilter *cf, struct Curl_easy *data)
+cr_connect_blocking(struct Curl_cfilter *cf UNUSED_PARAM,
+ struct Curl_easy *data UNUSED_PARAM)
{
bool done; /* unused */
return cr_connect_common(cf, data, true, &done);
}
+static void cr_adjust_pollset(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ struct easy_pollset *ps)
+{
+ if(!cf->connected) {
+ curl_socket_t sock = Curl_conn_cf_get_socket(cf->next, data);
+ struct ssl_connect_data *const connssl = cf->ctx;
+ struct rustls_ssl_backend_data *const backend =
+ (struct rustls_ssl_backend_data *)connssl->backend;
+ struct rustls_connection *rconn = NULL;
+
+ (void)data;
+ DEBUGASSERT(backend);
+ rconn = backend->conn;
+
+ if(rustls_connection_wants_write(rconn)) {
+ Curl_pollset_add_out(data, ps, sock);
+ }
+ if(rustls_connection_wants_read(rconn)) {
+ Curl_pollset_add_in(data, ps, sock);
+ }
+ }
+}
+
static void *
cr_get_internals(struct ssl_connect_data *connssl,
CURLINFO info UNUSED_PARAM)
@@ -962,85 +660,24 @@ cr_get_internals(struct ssl_connect_data *connssl,
return &backend->conn;
}
-static CURLcode
-cr_shutdown(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- bool send_shutdown, bool *done)
-{
- struct ssl_connect_data *connssl = cf->ctx;
- struct rustls_ssl_backend_data *backend =
- (struct rustls_ssl_backend_data *)connssl->backend;
- CURLcode result = CURLE_OK;
- ssize_t nwritten, nread;
- char buf[1024];
- size_t i;
-
- DEBUGASSERT(backend);
- if(!backend->conn || cf->shutdown) {
- *done = TRUE;
- goto out;
- }
-
- connssl->io_need = CURL_SSL_IO_NEED_NONE;
- *done = FALSE;
-
- if(!backend->sent_shutdown) {
- /* do this only once */
- backend->sent_shutdown = TRUE;
- if(send_shutdown) {
- rustls_connection_send_close_notify(backend->conn);
- }
- }
-
- nwritten = cr_send(cf, data, NULL, 0, &result);
- if(nwritten < 0) {
- if(result == CURLE_AGAIN) {
- connssl->io_need = CURL_SSL_IO_NEED_SEND;
- result = CURLE_OK;
- goto out;
- }
- DEBUGASSERT(result);
- CURL_TRC_CF(data, cf, "shutdown send failed: %d", result);
- goto out;
- }
-
- for(i = 0; i < 10; ++i) {
- nread = cr_recv(cf, data, buf, (int)sizeof(buf), &result);
- if(nread <= 0)
- break;
- }
-
- if(nread > 0) {
- /* still data coming in? */
- }
- else if(nread == 0) {
- /* We got the close notify alert and are done. */
- *done = TRUE;
- }
- else if(result == CURLE_AGAIN) {
- connssl->io_need = CURL_SSL_IO_NEED_RECV;
- result = CURLE_OK;
- }
- else {
- DEBUGASSERT(result);
- CURL_TRC_CF(data, cf, "shutdown, error: %d", result);
- }
-
-out:
- cf->shutdown = (result || *done);
- return result;
-}
-
static void
cr_close(struct Curl_cfilter *cf, struct Curl_easy *data)
{
struct ssl_connect_data *connssl = cf->ctx;
struct rustls_ssl_backend_data *backend =
(struct rustls_ssl_backend_data *)connssl->backend;
+ CURLcode tmperr = CURLE_OK;
+ ssize_t n = 0;
- (void)data;
DEBUGASSERT(backend);
+
if(backend->conn) {
+ rustls_connection_send_close_notify(backend->conn);
+ n = cr_send(cf, data, NULL, 0, &tmperr);
+ if(n < 0) {
+ failf(data, "rustls: error sending close_notify: %d", tmperr);
+ }
+
rustls_connection_free(backend->conn);
backend->conn = NULL;
}
@@ -1056,38 +693,28 @@ static size_t cr_version(char *buffer, size_t size)
return msnprintf(buffer, size, "%.*s", (int)ver.len, ver.data);
}
-static CURLcode
-cr_random(struct Curl_easy *data, unsigned char *entropy, size_t length)
-{
- rustls_result rresult = 0;
- (void)data;
- rresult =
- rustls_default_crypto_provider_random(entropy, length);
- return map_error(rresult);
-}
-
const struct Curl_ssl Curl_ssl_rustls = {
{ CURLSSLBACKEND_RUSTLS, "rustls" },
SSLSUPP_CAINFO_BLOB | /* supports */
- SSLSUPP_HTTPS_PROXY |
- SSLSUPP_CIPHER_LIST |
- SSLSUPP_TLS13_CIPHERSUITES,
+ SSLSUPP_TLS13_CIPHERSUITES |
+ SSLSUPP_HTTPS_PROXY,
sizeof(struct rustls_ssl_backend_data),
Curl_none_init, /* init */
Curl_none_cleanup, /* cleanup */
cr_version, /* version */
Curl_none_check_cxn, /* check_cxn */
- cr_shutdown, /* shutdown */
+ Curl_none_shutdown, /* shutdown */
cr_data_pending, /* data_pending */
- cr_random, /* random */
+ Curl_none_random, /* random */
Curl_none_cert_status_request, /* cert_status_request */
cr_connect_blocking, /* connect */
cr_connect_nonblocking, /* connect_nonblocking */
- Curl_ssl_adjust_pollset, /* adjust_pollset */
+ cr_adjust_pollset, /* adjust_pollset */
cr_get_internals, /* get_internals */
cr_close, /* close_one */
Curl_none_close_all, /* close_all */
+ Curl_none_session_free, /* session_free */
Curl_none_set_engine, /* set_engine */
Curl_none_set_engine_default, /* set_engine_default */
Curl_none_engines_list, /* engines_list */
@@ -1095,9 +722,9 @@ const struct Curl_ssl Curl_ssl_rustls = {
NULL, /* sha256sum */
NULL, /* associate_connection */
NULL, /* disassociate_connection */
+ NULL, /* free_multi_ssl_backend_data */
cr_recv, /* recv decrypted data */
cr_send, /* send data to encrypt */
- NULL, /* get_channel_binding */
};
#endif /* USE_RUSTLS */
diff --git a/contrib/libs/curl/lib/vtls/schannel.c b/contrib/libs/curl/lib/vtls/schannel.c
index 9e7ab5a5be..ae7f2956da 100644
--- a/contrib/libs/curl/lib/vtls/schannel.c
+++ b/contrib/libs/curl/lib/vtls/schannel.c
@@ -34,7 +34,7 @@
#ifdef USE_SCHANNEL
#ifndef USE_WINDOWS_SSPI
-# error "cannot compile SCHANNEL support without SSPI."
+# error "Can't compile SCHANNEL support without SSPI."
#endif
#include "schannel.h"
@@ -49,7 +49,7 @@
#include "inet_pton.h" /* for IP addr SNI check */
#include "curl_multibyte.h"
#include "warnless.h"
-#error #include "x509asn1.h"
+#include "x509asn1.h"
#include "curl_printf.h"
#include "multiif.h"
#include "version_win32.h"
@@ -171,7 +171,7 @@ schannel_set_ssl_version_min_max(DWORD *enabled_protocols,
{
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
long ssl_version = conn_config->version;
- long ssl_version_max = (long)conn_config->version_max;
+ long ssl_version_max = conn_config->version_max;
long i = ssl_version;
switch(ssl_version_max) {
@@ -364,7 +364,7 @@ set_ssl_ciphers(SCHANNEL_CRED *schannel_cred, char *ciphers,
if(!alg)
alg = get_alg_id_by_name(startCur);
if(alg)
- algIds[algCount++] = (ALG_ID)alg;
+ algIds[algCount++] = alg;
else if(!strncmp(startCur, "USE_STRONG_CRYPTO",
sizeof("USE_STRONG_CRYPTO") - 1) ||
!strncmp(startCur, "SCH_USE_STRONG_CRYPTO",
@@ -377,7 +377,7 @@ set_ssl_ciphers(SCHANNEL_CRED *schannel_cred, char *ciphers,
startCur++;
}
schannel_cred->palgSupportedAlgs = algIds;
- schannel_cred->cSupportedAlgs = (DWORD)algCount;
+ schannel_cred->cSupportedAlgs = algCount;
return CURLE_OK;
}
@@ -439,12 +439,6 @@ get_cert_location(TCHAR *path, DWORD *store_name, TCHAR **store_path,
return CURLE_OK;
}
#endif
-
-static bool algo(const char *check, char *namep, size_t nlen)
-{
- return (strlen(check) == nlen) && !strncmp(check, namep, nlen);
-}
-
static CURLcode
schannel_acquire_credential_handle(struct Curl_cfilter *cf,
struct Curl_easy *data)
@@ -513,7 +507,7 @@ schannel_acquire_credential_handle(struct Curl_cfilter *cf,
}
if(!ssl_config->auto_client_cert) {
- flags &= ~(DWORD)SCH_CRED_USE_DEFAULT_CREDS;
+ flags &= ~SCH_CRED_USE_DEFAULT_CREDS;
flags |= SCH_CRED_NO_DEFAULT_CREDS;
infof(data, "schannel: disabled automatic use of client certificate");
}
@@ -666,7 +660,7 @@ schannel_acquire_credential_handle(struct Curl_cfilter *cf,
cert_showfilename_error);
else
failf(data, "schannel: Failed to import cert file %s, "
- "last error is 0x%lx",
+ "last error is 0x%x",
cert_showfilename_error, errorcode);
return CURLE_SSL_CERTPROBLEM;
}
@@ -677,7 +671,7 @@ schannel_acquire_credential_handle(struct Curl_cfilter *cf,
if(!client_certs[0]) {
failf(data, "schannel: Failed to get certificate from file %s"
- ", last error is 0x%lx",
+ ", last error is 0x%x",
cert_showfilename_error, GetLastError());
CertCloseStore(cert_store, 0);
return CURLE_SSL_CERTPROBLEM;
@@ -690,15 +684,10 @@ schannel_acquire_credential_handle(struct Curl_cfilter *cf,
CERT_STORE_OPEN_EXISTING_FLAG | cert_store_name,
cert_store_path);
if(!cert_store) {
- char *path_utf8 =
- curlx_convert_tchar_to_UTF8(cert_store_path);
- failf(data, "schannel: Failed to open cert store %lx %s, "
- "last error is 0x%lx",
- cert_store_name,
- (path_utf8 ? path_utf8 : "(unknown)"),
- GetLastError());
+ failf(data, "schannel: Failed to open cert store %x %s, "
+ "last error is 0x%x",
+ cert_store_name, cert_store_path, GetLastError());
free(cert_store_path);
- curlx_unicodefree(path_utf8);
curlx_unicodefree(cert_path);
return CURLE_SSL_CERTPROBLEM;
}
@@ -801,7 +790,9 @@ schannel_acquire_credential_handle(struct Curl_cfilter *cf,
char *startCur = ciphers13;
int algCount = 0;
+ char tmp[LONGEST_ALG_ID] = { 0 };
char *nameEnd;
+ size_t n;
disable_aes_gcm_sha384 = TRUE;
disable_aes_gcm_sha256 = TRUE;
@@ -810,34 +801,40 @@ schannel_acquire_credential_handle(struct Curl_cfilter *cf,
disable_aes_ccm_sha256 = TRUE;
while(startCur && (0 != *startCur) && (algCount < remaining_ciphers)) {
- size_t n;
- char *namep;
nameEnd = strchr(startCur, ':');
n = nameEnd ? (size_t)(nameEnd - startCur) : strlen(startCur);
- namep = startCur;
- if(disable_aes_gcm_sha384 &&
- algo("TLS_AES_256_GCM_SHA384", namep, n)) {
+ /* reject too-long cipher names */
+ if(n > (LONGEST_ALG_ID - 1)) {
+ failf(data, "schannel: Cipher name too long, not checked");
+ return CURLE_SSL_CIPHER;
+ }
+
+ strncpy(tmp, startCur, n);
+ tmp[n] = 0;
+
+ if(disable_aes_gcm_sha384
+ && !strcmp("TLS_AES_256_GCM_SHA384", tmp)) {
disable_aes_gcm_sha384 = FALSE;
}
else if(disable_aes_gcm_sha256
- && algo("TLS_AES_128_GCM_SHA256", namep, n)) {
+ && !strcmp("TLS_AES_128_GCM_SHA256", tmp)) {
disable_aes_gcm_sha256 = FALSE;
}
else if(disable_chacha_poly
- && algo("TLS_CHACHA20_POLY1305_SHA256", namep, n)) {
+ && !strcmp("TLS_CHACHA20_POLY1305_SHA256", tmp)) {
disable_chacha_poly = FALSE;
}
else if(disable_aes_ccm_8_sha256
- && algo("TLS_AES_128_CCM_8_SHA256", namep, n)) {
+ && !strcmp("TLS_AES_128_CCM_8_SHA256", tmp)) {
disable_aes_ccm_8_sha256 = FALSE;
}
else if(disable_aes_ccm_sha256
- && algo("TLS_AES_128_CCM_SHA256", namep, n)) {
+ && !strcmp("TLS_AES_128_CCM_SHA256", tmp)) {
disable_aes_ccm_sha256 = FALSE;
}
else {
- failf(data, "schannel: Unknown TLS 1.3 cipher: %.*s", (int)n, namep);
+ failf(data, "schannel: Unknown TLS 1.3 cipher: %s", tmp);
return CURLE_SSL_CIPHER;
}
@@ -950,7 +947,7 @@ schannel_acquire_credential_handle(struct Curl_cfilter *cf,
tls_parameters.pDisabledCrypto = crypto_settings;
/* The number of blocked suites */
- tls_parameters.cDisabledCrypto = (DWORD)crypto_settings_idx;
+ tls_parameters.cDisabledCrypto = crypto_settings_idx;
credentials.pTlsParameters = &tls_parameters;
credentials.cTlsParameters = 1;
@@ -968,7 +965,7 @@ schannel_acquire_credential_handle(struct Curl_cfilter *cf,
#endif
sspi_status =
- Curl_pSecFn->AcquireCredentialsHandle(NULL, (TCHAR*)UNISP_NAME,
+ s_pSecFn->AcquireCredentialsHandle(NULL, (TCHAR*)UNISP_NAME,
SECPKG_CRED_OUTBOUND, NULL,
&credentials, NULL, NULL,
&backend->cred->cred_handle,
@@ -976,7 +973,7 @@ schannel_acquire_credential_handle(struct Curl_cfilter *cf,
}
else {
/* Pre-Windows 10 1809 or the user set a legacy algorithm list. Although MS
- does not document it, currently Schannel will not negotiate TLS 1.3 when
+ doesn't document it, currently Schannel will not negotiate TLS 1.3 when
SCHANNEL_CRED is used. */
ALG_ID algIds[NUM_CIPHERS];
char *ciphers = conn_config->cipher_list;
@@ -1015,7 +1012,7 @@ schannel_acquire_credential_handle(struct Curl_cfilter *cf,
#endif
sspi_status =
- Curl_pSecFn->AcquireCredentialsHandle(NULL, (TCHAR*)UNISP_NAME,
+ s_pSecFn->AcquireCredentialsHandle(NULL, (TCHAR*)UNISP_NAME,
SECPKG_CRED_OUTBOUND, NULL,
&schannel_cred, NULL, NULL,
&backend->cred->cred_handle,
@@ -1071,7 +1068,7 @@ schannel_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
DEBUGASSERT(backend);
DEBUGF(infof(data,
"schannel: SSL/TLS connection with %s port %d (step 1/3)",
- connssl->peer.hostname, connssl->peer.port));
+ connssl->peer.hostname, connssl->port));
if(curlx_verify_windows_version(5, 1, 0, PLATFORM_WINNT,
VERSION_LESS_THAN_EQUAL)) {
@@ -1083,7 +1080,7 @@ schannel_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
#ifdef HAS_ALPN
/* ALPN is only supported on Windows 8.1 / Server 2012 R2 and above.
- Also it does not seem to be supported for WINE, see curl bug #983. */
+ Also it doesn't seem to be supported for Wine, see curl bug #983. */
backend->use_alpn = connssl->alpn &&
!GetProcAddress(GetModuleHandle(TEXT("ntdll")),
"wine_get_version") &&
@@ -1095,11 +1092,11 @@ schannel_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
#ifdef _WIN32_WCE
#ifdef HAS_MANUAL_VERIFY_API
- /* certificate validation on CE does not seem to work right; we will
+ /* certificate validation on CE doesn't seem to work right; we'll
* do it following a more manual process. */
backend->use_manual_cred_validation = true;
#else
-#error "compiler too old to support Windows CE requisite manual cert verify"
+#error "compiler too old to support requisite manual cert verify for Win CE"
#endif
#else
#ifdef HAS_MANUAL_VERIFY_API
@@ -1127,10 +1124,9 @@ schannel_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
backend->cred = NULL;
/* check for an existing reusable credential handle */
- if(ssl_config->primary.cache_session) {
+ if(ssl_config->primary.sessionid) {
Curl_ssl_sessionid_lock(data);
- if(!Curl_ssl_getsessionid(cf, data, &connssl->peer,
- (void **)&old_cred, NULL)) {
+ if(!Curl_ssl_getsessionid(cf, data, (void **)&old_cred, NULL)) {
backend->cred = old_cred;
DEBUGF(infof(data, "schannel: reusing existing credential handle"));
@@ -1160,7 +1156,7 @@ schannel_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
}
/* Warn if SNI is disabled due to use of an IP address */
- if(connssl->peer.type != CURL_SSL_PEER_DNS) {
+ if(connssl->peer.is_ip_address) {
infof(data, "schannel: using IP address, SNI is not supported by OS.");
}
@@ -1199,8 +1195,9 @@ schannel_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
cur += proto.len;
*list_len = curlx_uitous(cur - list_start_index);
- *extension_len = (unsigned int)(*list_len +
- sizeof(unsigned int) + sizeof(unsigned short));
+ *extension_len = *list_len +
+ (unsigned short)sizeof(unsigned int) +
+ (unsigned short)sizeof(unsigned short);
InitSecBuffer(&inbuf, SECBUFFER_APPLICATION_PROTOCOLS, alpn_buffer, cur);
InitSecBufferDesc(&inbuf_desc, &inbuf, 1);
@@ -1241,11 +1238,11 @@ schannel_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
/* Schannel InitializeSecurityContext:
https://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx
- At the moment we do not pass inbuf unless we are using ALPN since we only
- use it for that, and WINE (for which we currently disable ALPN) is giving
+ At the moment we don't pass inbuf unless we're using ALPN since we only
+ use it for that, and Wine (for which we currently disable ALPN) is giving
us problems with inbuf regardless. https://github.com/curl/curl/issues/983
*/
- sspi_status = Curl_pSecFn->InitializeSecurityContext(
+ sspi_status = s_pSecFn->InitializeSecurityContext(
&backend->cred->cred_handle, NULL, backend->cred->sni_hostname,
backend->req_flags, 0, 0,
(backend->use_alpn ? &inbuf_desc : NULL),
@@ -1287,9 +1284,9 @@ schannel_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
/* send initial handshake data which is now stored in output buffer */
written = Curl_conn_cf_send(cf->next, data,
- outbuf.pvBuffer, outbuf.cbBuffer, FALSE,
+ outbuf.pvBuffer, outbuf.cbBuffer,
&result);
- Curl_pSecFn->FreeContextBuffer(outbuf.pvBuffer);
+ s_pSecFn->FreeContextBuffer(outbuf.pvBuffer);
if((result != CURLE_OK) || (outbuf.cbBuffer != (size_t) written)) {
failf(data, "schannel: failed to send initial handshake data: "
"sent %zd of %lu bytes", written, outbuf.cbBuffer);
@@ -1332,12 +1329,11 @@ schannel_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
DEBUGASSERT(backend);
- doread = (connssl->io_need & CURL_SSL_IO_NEED_SEND)? FALSE : TRUE;
- connssl->io_need = CURL_SSL_IO_NEED_NONE;
+ doread = (connssl->connecting_state != ssl_connect_2_writing) ? TRUE : FALSE;
DEBUGF(infof(data,
"schannel: SSL/TLS connection with %s port %d (step 2/3)",
- connssl->peer.hostname, connssl->peer.port));
+ connssl->peer.hostname, connssl->port));
if(!backend->cred || !backend->ctxt)
return CURLE_SSL_CONNECT_ERROR;
@@ -1394,7 +1390,8 @@ schannel_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
backend->encdata_offset,
&result);
if(result == CURLE_AGAIN) {
- connssl->io_need = CURL_SSL_IO_NEED_RECV;
+ if(connssl->connecting_state != ssl_connect_2_writing)
+ connssl->connecting_state = ssl_connect_2_reading;
DEBUGF(infof(data, "schannel: failed to receive handshake, "
"need more data"));
return CURLE_OK;
@@ -1436,7 +1433,7 @@ schannel_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
memcpy(inbuf[0].pvBuffer, backend->encdata_buffer,
backend->encdata_offset);
- sspi_status = Curl_pSecFn->InitializeSecurityContext(
+ sspi_status = s_pSecFn->InitializeSecurityContext(
&backend->cred->cred_handle, &backend->ctxt->ctxt_handle,
backend->cred->sni_hostname, backend->req_flags,
0, 0, &inbuf_desc, 0, NULL,
@@ -1448,7 +1445,7 @@ schannel_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
/* check if the handshake was incomplete */
if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) {
backend->encdata_is_incomplete = true;
- connssl->io_need = CURL_SSL_IO_NEED_RECV;
+ connssl->connecting_state = ssl_connect_2_reading;
DEBUGF(infof(data,
"schannel: received incomplete message, need more data"));
return CURLE_OK;
@@ -1460,7 +1457,7 @@ schannel_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
if(sspi_status == SEC_I_INCOMPLETE_CREDENTIALS &&
!(backend->req_flags & ISC_REQ_USE_SUPPLIED_CREDS)) {
backend->req_flags |= ISC_REQ_USE_SUPPLIED_CREDS;
- connssl->io_need = CURL_SSL_IO_NEED_SEND;
+ connssl->connecting_state = ssl_connect_2_writing;
DEBUGF(infof(data,
"schannel: a client certificate has been requested"));
return CURLE_OK;
@@ -1477,7 +1474,7 @@ schannel_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
/* send handshake token to server */
written = Curl_conn_cf_send(cf->next, data,
outbuf[i].pvBuffer, outbuf[i].cbBuffer,
- FALSE, &result);
+ &result);
if((result != CURLE_OK) ||
(outbuf[i].cbBuffer != (size_t) written)) {
failf(data, "schannel: failed to send next handshake data: "
@@ -1488,7 +1485,7 @@ schannel_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
/* free obsolete buffer */
if(outbuf[i].pvBuffer) {
- Curl_pSecFn->FreeContextBuffer(outbuf[i].pvBuffer);
+ s_pSecFn->FreeContextBuffer(outbuf[i].pvBuffer);
}
}
}
@@ -1531,7 +1528,7 @@ schannel_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
inbuf[1].cbBuffer));
/*
There are two cases where we could be getting extra data here:
- 1) If we are renegotiating a connection and the handshake is already
+ 1) If we're renegotiating a connection and the handshake is already
complete (from the server perspective), it can encrypted app data
(not handshake data) in an extra buffer at this point.
2) (sspi_status == SEC_I_CONTINUE_NEEDED) We are negotiating a
@@ -1560,7 +1557,7 @@ schannel_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
/* check if the handshake needs to be continued */
if(sspi_status == SEC_I_CONTINUE_NEEDED) {
- connssl->io_need = CURL_SSL_IO_NEED_RECV;
+ connssl->connecting_state = ssl_connect_2_reading;
return CURLE_OK;
}
@@ -1570,13 +1567,9 @@ schannel_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
DEBUGF(infof(data, "schannel: SSL/TLS handshake complete"));
}
-#ifndef CURL_DISABLE_PROXY
pubkey_ptr = Curl_ssl_cf_is_proxy(cf)?
data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]:
data->set.str[STRING_SSL_PINNEDPUBLICKEY];
-#else
- pubkey_ptr = data->set.str[STRING_SSL_PINNEDPUBLICKEY];
-#endif
if(pubkey_ptr) {
result = schannel_pkp_pin_peer_pubkey(cf, data, pubkey_ptr);
if(result) {
@@ -1593,7 +1586,7 @@ schannel_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
#endif
/* Verify the hostname manually when certificate verification is disabled,
- because in that case Schannel will not verify it. */
+ because in that case Schannel won't verify it. */
if(!conn_config->verifypeer && conn_config->verifyhost)
return Curl_verify_host(cf, data);
@@ -1675,28 +1668,6 @@ add_cert_to_certinfo(const CERT_CONTEXT *ccert_context, bool reverse_order,
return args->result == CURLE_OK;
}
-static void schannel_session_free(void *sessionid, size_t idsize)
-{
- /* this is expected to be called under sessionid lock */
- struct Curl_schannel_cred *cred = sessionid;
-
- (void)idsize;
- if(cred) {
- cred->refcount--;
- if(cred->refcount == 0) {
- Curl_pSecFn->FreeCredentialsHandle(&cred->cred_handle);
- curlx_unicodefree(cred->sni_hostname);
-#ifdef HAS_CLIENT_CERT_PATH
- if(cred->client_cert_store) {
- CertCloseStore(cred->client_cert_store, 0);
- cred->client_cert_store = NULL;
- }
-#endif
- Curl_safefree(cred);
- }
- }
-}
-
static CURLcode
schannel_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data)
{
@@ -1716,7 +1687,7 @@ schannel_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data)
DEBUGF(infof(data,
"schannel: SSL/TLS connection with %s port %d (step 3/3)",
- connssl->peer.hostname, connssl->peer.port));
+ connssl->peer.hostname, connssl->port));
if(!backend->cred)
return CURLE_SSL_CONNECT_ERROR;
@@ -1739,7 +1710,7 @@ schannel_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data)
#ifdef HAS_ALPN
if(backend->use_alpn) {
sspi_status =
- Curl_pSecFn->QueryContextAttributes(&backend->ctxt->ctxt_handle,
+ s_pSecFn->QueryContextAttributes(&backend->ctxt->ctxt_handle,
SECPKG_ATTR_APPLICATION_PROTOCOL,
&alpn_result);
@@ -1772,22 +1743,45 @@ schannel_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data)
#endif
/* save the current session data for possible reuse */
- if(ssl_config->primary.cache_session) {
+ if(ssl_config->primary.sessionid) {
+ bool incache;
+ bool added = FALSE;
+ struct Curl_schannel_cred *old_cred = NULL;
+
Curl_ssl_sessionid_lock(data);
- /* Up ref count since call takes ownership */
- backend->cred->refcount++;
- result = Curl_ssl_set_sessionid(cf, data, &connssl->peer, backend->cred,
- sizeof(struct Curl_schannel_cred),
- schannel_session_free);
+ incache = !(Curl_ssl_getsessionid(cf, data, (void **)&old_cred, NULL));
+ if(incache) {
+ if(old_cred != backend->cred) {
+ DEBUGF(infof(data,
+ "schannel: old credential handle is stale, removing"));
+ /* we're not taking old_cred ownership here, no refcount++ is needed */
+ Curl_ssl_delsessionid(data, (void *)old_cred);
+ incache = FALSE;
+ }
+ }
+ if(!incache) {
+ result = Curl_ssl_addsessionid(cf, data, backend->cred,
+ sizeof(struct Curl_schannel_cred),
+ &added);
+ if(result) {
+ Curl_ssl_sessionid_unlock(data);
+ failf(data, "schannel: failed to store credential handle");
+ return result;
+ }
+ else if(added) {
+ /* this cred session is now also referenced by sessionid cache */
+ backend->cred->refcount++;
+ DEBUGF(infof(data,
+ "schannel: stored credential handle in session cache"));
+ }
+ }
Curl_ssl_sessionid_unlock(data);
- if(result)
- return result;
}
if(data->set.ssl.certinfo) {
int certs_count = 0;
sspi_status =
- Curl_pSecFn->QueryContextAttributes(&backend->ctxt->ctxt_handle,
+ s_pSecFn->QueryContextAttributes(&backend->ctxt->ctxt_handle,
SECPKG_ATTR_REMOTE_CERT_CONTEXT,
&ccert_context);
@@ -1835,7 +1829,7 @@ schannel_connect_common(struct Curl_cfilter *cf,
}
if(ssl_connect_1 == connssl->connecting_state) {
- /* check out how much more time we are allowed */
+ /* check out how much more time we're allowed */
timeout_ms = Curl_timeleft(data, NULL, TRUE);
if(timeout_ms < 0) {
@@ -1849,9 +1843,11 @@ schannel_connect_common(struct Curl_cfilter *cf,
return result;
}
- while(ssl_connect_2 == connssl->connecting_state) {
+ while(ssl_connect_2 == connssl->connecting_state ||
+ ssl_connect_2_reading == connssl->connecting_state ||
+ ssl_connect_2_writing == connssl->connecting_state) {
- /* check out how much more time we are allowed */
+ /* check out how much more time we're allowed */
timeout_ms = Curl_timeleft(data, NULL, TRUE);
if(timeout_ms < 0) {
@@ -1860,13 +1856,14 @@ schannel_connect_common(struct Curl_cfilter *cf,
return CURLE_OPERATION_TIMEDOUT;
}
- /* if ssl is expecting something, check if it is available. */
- if(connssl->io_need) {
+ /* if ssl is expecting something, check if it's available. */
+ if(connssl->connecting_state == ssl_connect_2_reading
+ || connssl->connecting_state == ssl_connect_2_writing) {
- curl_socket_t writefd = (connssl->io_need & CURL_SSL_IO_NEED_SEND)?
- sockfd : CURL_SOCKET_BAD;
- curl_socket_t readfd = (connssl->io_need & CURL_SSL_IO_NEED_RECV)?
- sockfd : CURL_SOCKET_BAD;
+ curl_socket_t writefd = ssl_connect_2_writing ==
+ connssl->connecting_state ? sockfd : CURL_SOCKET_BAD;
+ curl_socket_t readfd = ssl_connect_2_reading ==
+ connssl->connecting_state ? sockfd : CURL_SOCKET_BAD;
what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
nonblocking ? 0 : timeout_ms);
@@ -1897,7 +1894,10 @@ schannel_connect_common(struct Curl_cfilter *cf,
* have a valid fdset to wait on.
*/
result = schannel_connect_step2(cf, data);
- if(result || (nonblocking && (ssl_connect_2 == connssl->connecting_state)))
+ if(result || (nonblocking &&
+ (ssl_connect_2 == connssl->connecting_state ||
+ ssl_connect_2_reading == connssl->connecting_state ||
+ ssl_connect_2_writing == connssl->connecting_state)))
return result;
} /* repeat step2 until all transactions are done. */
@@ -1955,7 +1955,7 @@ schannel_send(struct Curl_cfilter *cf, struct Curl_easy *data,
/* check if the maximum stream sizes were queried */
if(backend->stream_sizes.cbMaximumMessage == 0) {
- sspi_status = Curl_pSecFn->QueryContextAttributes(
+ sspi_status = s_pSecFn->QueryContextAttributes(
&backend->ctxt->ctxt_handle,
SECPKG_ATTR_STREAM_SIZES,
&backend->stream_sizes);
@@ -1994,7 +1994,7 @@ schannel_send(struct Curl_cfilter *cf, struct Curl_easy *data,
memcpy(outbuf[1].pvBuffer, buf, len);
/* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375390.aspx */
- sspi_status = Curl_pSecFn->EncryptMessage(&backend->ctxt->ctxt_handle, 0,
+ sspi_status = s_pSecFn->EncryptMessage(&backend->ctxt->ctxt_handle, 0,
&outbuf_desc, 0);
/* check if the message was encrypted */
@@ -2005,10 +2005,10 @@ schannel_send(struct Curl_cfilter *cf, struct Curl_easy *data,
len = outbuf[0].cbBuffer + outbuf[1].cbBuffer + outbuf[2].cbBuffer;
/*
- it is important to send the full message which includes the header,
- encrypted payload, and trailer. Until the client receives all the
+ It's important to send the full message which includes the header,
+ encrypted payload, and trailer. Until the client receives all the
data a coherent message has not been delivered and the client
- cannot read any of it.
+ can't read any of it.
If we wanted to buffer the unwritten encrypted bytes, we would
tell the client that all data it has requested to be sent has been
@@ -2054,7 +2054,7 @@ schannel_send(struct Curl_cfilter *cf, struct Curl_easy *data,
this_write = Curl_conn_cf_send(cf->next, data,
ptr + written, len - written,
- FALSE, &result);
+ &result);
if(result == CURLE_AGAIN)
continue;
else if(result != CURLE_OK) {
@@ -2105,9 +2105,8 @@ schannel_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
DEBUGASSERT(backend);
/****************************************************************************
- * Do not return or set backend->recv_unrecoverable_err unless in the
- * cleanup. The pattern for return error is set *err, optional infof, goto
- * cleanup.
+ * Don't return or set backend->recv_unrecoverable_err unless in the cleanup.
+ * The pattern for return error is set *err, optional infof, goto cleanup.
*
* Our priority is to always return as much decrypted data to the caller as
* possible, even if an error occurs. The state of the decrypted buffer must
@@ -2132,7 +2131,8 @@ schannel_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
infof(data, "schannel: server indicated shutdown in a prior call");
goto cleanup;
}
- /* it is debatable what to return when !len. Regardless we cannot return
+
+ /* It's debatable what to return when !len. Regardless we can't return
immediately because there may be data to decrypt (in the case we want to
decrypt all encrypted cached data) so handle !len later in cleanup.
*/
@@ -2211,7 +2211,7 @@ schannel_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
/* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375348.aspx
*/
- sspi_status = Curl_pSecFn->DecryptMessage(&backend->ctxt->ctxt_handle,
+ sspi_status = s_pSecFn->DecryptMessage(&backend->ctxt->ctxt_handle,
&inbuf_desc, 0, NULL);
/* check if everything went fine (server may want to renegotiate
@@ -2290,15 +2290,14 @@ schannel_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
if(sspi_status == SEC_I_RENEGOTIATE) {
infof(data, "schannel: remote party requests renegotiation");
if(*err && *err != CURLE_AGAIN) {
- infof(data, "schannel: cannot renegotiate, an error is pending");
+ infof(data, "schannel: can't renegotiate, an error is pending");
goto cleanup;
}
/* begin renegotiation */
infof(data, "schannel: renegotiating SSL/TLS connection");
connssl->state = ssl_connection_negotiating;
- connssl->connecting_state = ssl_connect_2;
- connssl->io_need = CURL_SSL_IO_NEED_SEND;
+ connssl->connecting_state = ssl_connect_2_writing;
backend->recv_renegotiating = true;
*err = schannel_connect_common(cf, data, FALSE, &done);
backend->recv_renegotiating = false;
@@ -2316,10 +2315,10 @@ schannel_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
/* In Windows 2000 SEC_I_CONTEXT_EXPIRED (close_notify) is not
returned so we have to work around that in cleanup. */
backend->recv_sspi_close_notify = true;
- if(!backend->recv_connection_closed)
+ if(!backend->recv_connection_closed) {
backend->recv_connection_closed = true;
- infof(data,
- "schannel: server close notification received (close_notify)");
+ infof(data, "schannel: server closed the connection");
+ }
goto cleanup;
}
}
@@ -2333,10 +2332,10 @@ schannel_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
else {
#ifndef CURL_DISABLE_VERBOSE_STRINGS
char buffer[STRERROR_LEN];
- infof(data, "schannel: failed to read data from server: %s",
- Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
#endif
*err = CURLE_RECV_ERROR;
+ infof(data, "schannel: failed to read data from server: %s",
+ Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
goto cleanup;
}
}
@@ -2355,13 +2354,13 @@ cleanup:
/* Error if the connection has closed without a close_notify.
- The behavior here is a matter of debate. We do not want to be vulnerable
- to a truncation attack however there is some browser precedent for
+ The behavior here is a matter of debate. We don't want to be vulnerable
+ to a truncation attack however there's some browser precedent for
ignoring the close_notify for compatibility reasons.
Additionally, Windows 2000 (v5.0) is a special case since it seems it
- does not return close_notify. In that case if the connection was closed we
- assume it was graceful (close_notify) since there does not seem to be a
+ doesn't return close_notify. In that case if the connection was closed we
+ assume it was graceful (close_notify) since there doesn't seem to be a
way to tell.
*/
if(len && !backend->decdata_offset && backend->recv_connection_closed &&
@@ -2398,7 +2397,7 @@ cleanup:
if(!*err && !backend->recv_connection_closed)
*err = CURLE_AGAIN;
- /* it is debatable what to return when !len. We could return whatever error
+ /* It's debatable what to return when !len. We could return whatever error
we got from decryption but instead we override here so the return is
consistent.
*/
@@ -2442,20 +2441,37 @@ static bool schannel_data_pending(struct Curl_cfilter *cf,
if(backend->ctxt) /* SSL/TLS is in use */
return (backend->decdata_offset > 0 ||
- (backend->encdata_offset > 0 && !backend->encdata_is_incomplete) ||
- backend->recv_connection_closed ||
- backend->recv_sspi_close_notify ||
- backend->recv_unrecoverable_err);
+ (backend->encdata_offset > 0 && !backend->encdata_is_incomplete));
else
return FALSE;
}
+static void schannel_session_free(void *ptr)
+{
+ /* this is expected to be called under sessionid lock */
+ struct Curl_schannel_cred *cred = ptr;
+
+ if(cred) {
+ cred->refcount--;
+ if(cred->refcount == 0) {
+ s_pSecFn->FreeCredentialsHandle(&cred->cred_handle);
+ curlx_unicodefree(cred->sni_hostname);
+#ifdef HAS_CLIENT_CERT_PATH
+ if(cred->client_cert_store) {
+ CertCloseStore(cred->client_cert_store, 0);
+ cred->client_cert_store = NULL;
+ }
+#endif
+ Curl_safefree(cred);
+ }
+ }
+}
+
/* shut down the SSL connection and clean up related memory.
this function can be called multiple times on the same connection including
if the SSL connection failed (eg connection made but failed handshake). */
-static CURLcode schannel_shutdown(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- bool send_shutdown, bool *done)
+static int schannel_shutdown(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
{
/* See https://msdn.microsoft.com/en-us/library/windows/desktop/aa380138.aspx
* Shutting Down an Schannel Connection
@@ -2463,57 +2479,41 @@ static CURLcode schannel_shutdown(struct Curl_cfilter *cf,
struct ssl_connect_data *connssl = cf->ctx;
struct schannel_ssl_backend_data *backend =
(struct schannel_ssl_backend_data *)connssl->backend;
- CURLcode result = CURLE_OK;
-
- if(cf->shutdown) {
- *done = TRUE;
- return CURLE_OK;
- }
DEBUGASSERT(data);
DEBUGASSERT(backend);
- /* Not supported in schannel */
- (void)send_shutdown;
-
- *done = FALSE;
if(backend->ctxt) {
infof(data, "schannel: shutting down SSL/TLS connection with %s port %d",
- connssl->peer.hostname, connssl->peer.port);
- }
-
- if(!backend->ctxt || cf->shutdown) {
- *done = TRUE;
- goto out;
+ connssl->peer.hostname, connssl->port);
}
- if(backend->cred && backend->ctxt && !backend->sent_shutdown) {
+ if(backend->cred && backend->ctxt) {
SecBufferDesc BuffDesc;
SecBuffer Buffer;
SECURITY_STATUS sspi_status;
SecBuffer outbuf;
SecBufferDesc outbuf_desc;
+ CURLcode result;
DWORD dwshut = SCHANNEL_SHUTDOWN;
InitSecBuffer(&Buffer, SECBUFFER_TOKEN, &dwshut, sizeof(dwshut));
InitSecBufferDesc(&BuffDesc, &Buffer, 1);
- sspi_status = Curl_pSecFn->ApplyControlToken(&backend->ctxt->ctxt_handle,
+ sspi_status = s_pSecFn->ApplyControlToken(&backend->ctxt->ctxt_handle,
&BuffDesc);
if(sspi_status != SEC_E_OK) {
char buffer[STRERROR_LEN];
failf(data, "schannel: ApplyControlToken failure: %s",
Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
- result = CURLE_SEND_ERROR;
- goto out;
}
/* setup output buffer */
InitSecBuffer(&outbuf, SECBUFFER_EMPTY, NULL, 0);
InitSecBufferDesc(&outbuf_desc, &outbuf, 1);
- sspi_status = Curl_pSecFn->InitializeSecurityContext(
+ sspi_status = s_pSecFn->InitializeSecurityContext(
&backend->cred->cred_handle,
&backend->ctxt->ctxt_handle,
backend->cred->sni_hostname,
@@ -2531,88 +2531,26 @@ static CURLcode schannel_shutdown(struct Curl_cfilter *cf,
/* send close message which is in output buffer */
ssize_t written = Curl_conn_cf_send(cf->next, data,
outbuf.pvBuffer, outbuf.cbBuffer,
- FALSE, &result);
- Curl_pSecFn->FreeContextBuffer(outbuf.pvBuffer);
- if(!result) {
- if(written < (ssize_t)outbuf.cbBuffer) {
- /* TODO: handle partial sends */
- infof(data, "schannel: failed to send close msg: %s"
- " (bytes written: %zd)", curl_easy_strerror(result), written);
- result = CURLE_SEND_ERROR;
- goto out;
- }
- backend->sent_shutdown = TRUE;
- *done = TRUE;
- }
- else if(result == CURLE_AGAIN) {
- connssl->io_need = CURL_SSL_IO_NEED_SEND;
- result = CURLE_OK;
- goto out;
- }
- else {
- if(!backend->recv_connection_closed) {
- infof(data, "schannel: error sending close msg: %d", result);
- result = CURLE_SEND_ERROR;
- goto out;
- }
- /* Looks like server already closed the connection.
- * An error to send our close notify is not a failure. */
- *done = TRUE;
- result = CURLE_OK;
+ &result);
+ s_pSecFn->FreeContextBuffer(outbuf.pvBuffer);
+ if((result != CURLE_OK) || (outbuf.cbBuffer != (size_t) written)) {
+ infof(data, "schannel: failed to send close msg: %s"
+ " (bytes written: %zd)", curl_easy_strerror(result), written);
}
}
}
- /* If the connection seems open and we have not seen the close notify
- * from the server yet, try to receive it. */
- if(backend->cred && backend->ctxt &&
- !backend->recv_sspi_close_notify && !backend->recv_connection_closed) {
- char buffer[1024];
- ssize_t nread;
-
- nread = schannel_recv(cf, data, buffer, sizeof(buffer), &result);
- if(nread > 0) {
- /* still data coming in? */
- }
- else if(nread == 0) {
- /* We got the close notify alert and are done. */
- backend->recv_connection_closed = TRUE;
- *done = TRUE;
- }
- else if(nread < 0 && result == CURLE_AGAIN) {
- connssl->io_need = CURL_SSL_IO_NEED_RECV;
- }
- else {
- CURL_TRC_CF(data, cf, "SSL shutdown, error %d", result);
- result = CURLE_RECV_ERROR;
- }
- }
-
-out:
- cf->shutdown = (result || *done);
- return result;
-}
-
-static void schannel_close(struct Curl_cfilter *cf, struct Curl_easy *data)
-{
- struct ssl_connect_data *connssl = cf->ctx;
- struct schannel_ssl_backend_data *backend =
- (struct schannel_ssl_backend_data *)connssl->backend;
-
- DEBUGASSERT(data);
- DEBUGASSERT(backend);
-
/* free SSPI Schannel API security context handle */
if(backend->ctxt) {
DEBUGF(infof(data, "schannel: clear security context handle"));
- Curl_pSecFn->DeleteSecurityContext(&backend->ctxt->ctxt_handle);
+ s_pSecFn->DeleteSecurityContext(&backend->ctxt->ctxt_handle);
Curl_safefree(backend->ctxt);
}
/* free SSPI Schannel API credential handle */
if(backend->cred) {
Curl_ssl_sessionid_lock(data);
- schannel_session_free(backend->cred, 0);
+ schannel_session_free(backend->cred);
Curl_ssl_sessionid_unlock(data);
backend->cred = NULL;
}
@@ -2631,6 +2569,13 @@ static void schannel_close(struct Curl_cfilter *cf, struct Curl_easy *data)
backend->decdata_length = 0;
backend->decdata_offset = 0;
}
+
+ return CURLE_OK;
+}
+
+static void schannel_close(struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+ schannel_shutdown(cf, data);
}
static int schannel_init(void)
@@ -2645,7 +2590,9 @@ static void schannel_cleanup(void)
static size_t schannel_version(char *buffer, size_t size)
{
- return msnprintf(buffer, size, "Schannel");
+ size = msnprintf(buffer, size, "Schannel");
+
+ return size;
}
static CURLcode schannel_random(struct Curl_easy *data UNUSED_PARAM,
@@ -2670,7 +2617,7 @@ static CURLcode schannel_pkp_pin_peer_pubkey(struct Curl_cfilter *cf,
DEBUGASSERT(backend);
- /* if a path was not specified, do not pin */
+ /* if a path wasn't specified, don't pin */
if(!pinnedpubkey)
return CURLE_OK;
@@ -2682,7 +2629,7 @@ static CURLcode schannel_pkp_pin_peer_pubkey(struct Curl_cfilter *cf,
struct Curl_asn1Element *pubkey;
sspi_status =
- Curl_pSecFn->QueryContextAttributes(&backend->ctxt->ctxt_handle,
+ s_pSecFn->QueryContextAttributes(&backend->ctxt->ctxt_handle,
SECPKG_ATTR_REMOTE_CERT_CONTEXT,
&pCertContextServer);
@@ -2732,13 +2679,6 @@ static void schannel_checksum(const unsigned char *input,
DWORD provType,
const unsigned int algId)
{
-#ifdef CURL_WINDOWS_APP
- (void)input;
- (void)inputlen;
- (void)provType;
- (void)algId;
- memset(checksum, 0, checksumlen);
-#else
HCRYPTPROV hProv = 0;
HCRYPTHASH hHash = 0;
DWORD cbHashSize = 0;
@@ -2779,7 +2719,6 @@ static void schannel_checksum(const unsigned char *input,
if(hProv)
CryptReleaseContext(hProv, 0);
-#endif
}
static CURLcode schannel_sha256sum(const unsigned char *input,
@@ -2806,9 +2745,9 @@ HCERTSTORE Curl_schannel_get_cached_cert_store(struct Curl_cfilter *cf,
const struct Curl_easy *data)
{
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
- struct Curl_multi *multi = data->multi;
+ struct Curl_multi *multi = data->multi_easy ? data->multi_easy : data->multi;
const struct curl_blob *ca_info_blob = conn_config->ca_info_blob;
- struct schannel_cert_share *share;
+ struct schannel_multi_ssl_backend_data *mbackend;
const struct ssl_general_config *cfg = &data->set.general_ssl;
timediff_t timeout_ms;
timediff_t elapsed_ms;
@@ -2817,14 +2756,12 @@ HCERTSTORE Curl_schannel_get_cached_cert_store(struct Curl_cfilter *cf,
DEBUGASSERT(multi);
- if(!multi) {
+ if(!multi || !multi->ssl_backend_data) {
return NULL;
}
- share = Curl_hash_pick(&multi->proto_hash,
- (void *)MPROTO_SCHANNEL_CERT_SHARE_KEY,
- sizeof(MPROTO_SCHANNEL_CERT_SHARE_KEY)-1);
- if(!share || !share->cert_store) {
+ mbackend = (struct schannel_multi_ssl_backend_data *)multi->ssl_backend_data;
+ if(!mbackend->cert_store) {
return NULL;
}
@@ -2839,47 +2776,37 @@ HCERTSTORE Curl_schannel_get_cached_cert_store(struct Curl_cfilter *cf,
timeout_ms = cfg->ca_cache_timeout * (timediff_t)1000;
if(timeout_ms >= 0) {
now = Curl_now();
- elapsed_ms = Curl_timediff(now, share->time);
+ elapsed_ms = Curl_timediff(now, mbackend->time);
if(elapsed_ms >= timeout_ms) {
return NULL;
}
}
if(ca_info_blob) {
- if(share->CAinfo_blob_size != ca_info_blob->len) {
+ if(!mbackend->CAinfo_blob_digest) {
+ return NULL;
+ }
+ if(mbackend->CAinfo_blob_size != ca_info_blob->len) {
return NULL;
}
schannel_sha256sum((const unsigned char *)ca_info_blob->data,
ca_info_blob->len,
info_blob_digest,
CURL_SHA256_DIGEST_LENGTH);
- if(memcmp(share->CAinfo_blob_digest, info_blob_digest,
+ if(memcmp(mbackend->CAinfo_blob_digest,
+ info_blob_digest,
CURL_SHA256_DIGEST_LENGTH)) {
- return NULL;
+ return NULL;
}
}
else {
- if(!conn_config->CAfile || !share->CAfile ||
- strcmp(share->CAfile, conn_config->CAfile)) {
+ if(!conn_config->CAfile || !mbackend->CAfile ||
+ strcmp(mbackend->CAfile, conn_config->CAfile)) {
return NULL;
}
}
- return share->cert_store;
-}
-
-static void schannel_cert_share_free(void *key, size_t key_len, void *p)
-{
- struct schannel_cert_share *share = p;
- DEBUGASSERT(key_len == (sizeof(MPROTO_SCHANNEL_CERT_SHARE_KEY)-1));
- DEBUGASSERT(!memcmp(MPROTO_SCHANNEL_CERT_SHARE_KEY, key, key_len));
- (void)key;
- (void)key_len;
- if(share->cert_store) {
- CertCloseStore(share->cert_store, 0);
- }
- free(share->CAfile);
- free(share);
+ return mbackend->cert_store;
}
bool Curl_schannel_set_cached_cert_store(struct Curl_cfilter *cf,
@@ -2887,9 +2814,10 @@ bool Curl_schannel_set_cached_cert_store(struct Curl_cfilter *cf,
HCERTSTORE cert_store)
{
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
- struct Curl_multi *multi = data->multi;
+ struct Curl_multi *multi = data->multi_easy ? data->multi_easy : data->multi;
const struct curl_blob *ca_info_blob = conn_config->ca_info_blob;
- struct schannel_cert_share *share;
+ struct schannel_multi_ssl_backend_data *mbackend;
+ unsigned char *CAinfo_blob_digest = NULL;
size_t CAinfo_blob_size = 0;
char *CAfile = NULL;
@@ -2899,27 +2827,25 @@ bool Curl_schannel_set_cached_cert_store(struct Curl_cfilter *cf,
return false;
}
- share = Curl_hash_pick(&multi->proto_hash,
- (void *)MPROTO_SCHANNEL_CERT_SHARE_KEY,
- sizeof(MPROTO_SCHANNEL_CERT_SHARE_KEY)-1);
- if(!share) {
- share = calloc(1, sizeof(*share));
- if(!share) {
- return false;
- }
- if(!Curl_hash_add2(&multi->proto_hash,
- (void *)MPROTO_SCHANNEL_CERT_SHARE_KEY,
- sizeof(MPROTO_SCHANNEL_CERT_SHARE_KEY)-1,
- share, schannel_cert_share_free)) {
- free(share);
+ if(!multi->ssl_backend_data) {
+ multi->ssl_backend_data =
+ calloc(1, sizeof(struct schannel_multi_ssl_backend_data));
+ if(!multi->ssl_backend_data) {
return false;
}
}
+ mbackend = (struct schannel_multi_ssl_backend_data *)multi->ssl_backend_data;
+
+
if(ca_info_blob) {
+ CAinfo_blob_digest = malloc(CURL_SHA256_DIGEST_LENGTH);
+ if(!CAinfo_blob_digest) {
+ return false;
+ }
schannel_sha256sum((const unsigned char *)ca_info_blob->data,
ca_info_blob->len,
- share->CAinfo_blob_digest,
+ CAinfo_blob_digest,
CURL_SHA256_DIGEST_LENGTH);
CAinfo_blob_size = ca_info_blob->len;
}
@@ -2933,18 +2859,33 @@ bool Curl_schannel_set_cached_cert_store(struct Curl_cfilter *cf,
}
/* free old cache data */
- if(share->cert_store) {
- CertCloseStore(share->cert_store, 0);
+ if(mbackend->cert_store) {
+ CertCloseStore(mbackend->cert_store, 0);
}
- free(share->CAfile);
+ free(mbackend->CAinfo_blob_digest);
+ free(mbackend->CAfile);
- share->time = Curl_now();
- share->cert_store = cert_store;
- share->CAinfo_blob_size = CAinfo_blob_size;
- share->CAfile = CAfile;
+ mbackend->time = Curl_now();
+ mbackend->cert_store = cert_store;
+ mbackend->CAinfo_blob_digest = CAinfo_blob_digest;
+ mbackend->CAinfo_blob_size = CAinfo_blob_size;
+ mbackend->CAfile = CAfile;
return true;
}
+static void schannel_free_multi_ssl_backend_data(
+ struct multi_ssl_backend_data *msbd)
+{
+ struct schannel_multi_ssl_backend_data *mbackend =
+ (struct schannel_multi_ssl_backend_data*)msbd;
+ if(mbackend->cert_store) {
+ CertCloseStore(mbackend->cert_store, 0);
+ }
+ free(mbackend->CAinfo_blob_digest);
+ free(mbackend->CAfile);
+ free(mbackend);
+}
+
const struct Curl_ssl Curl_ssl_schannel = {
{ CURLSSLBACKEND_SCHANNEL, "schannel" }, /* info */
@@ -2952,13 +2893,9 @@ const struct Curl_ssl Curl_ssl_schannel = {
#ifdef HAS_MANUAL_VERIFY_API
SSLSUPP_CAINFO_BLOB |
#endif
-#ifndef CURL_WINDOWS_APP
SSLSUPP_PINNEDPUBKEY |
-#endif
SSLSUPP_TLS13_CIPHERSUITES |
- SSLSUPP_CA_CACHE |
- SSLSUPP_HTTPS_PROXY |
- SSLSUPP_CIPHER_LIST,
+ SSLSUPP_HTTPS_PROXY,
sizeof(struct schannel_ssl_backend_data),
@@ -2976,6 +2913,7 @@ const struct Curl_ssl Curl_ssl_schannel = {
schannel_get_internals, /* get_internals */
schannel_close, /* close_one */
Curl_none_close_all, /* close_all */
+ schannel_session_free, /* session_free */
Curl_none_set_engine, /* set_engine */
Curl_none_set_engine_default, /* set_engine_default */
Curl_none_engines_list, /* engines_list */
@@ -2983,9 +2921,9 @@ const struct Curl_ssl Curl_ssl_schannel = {
schannel_sha256sum, /* sha256sum */
NULL, /* associate_connection */
NULL, /* disassociate_connection */
+ schannel_free_multi_ssl_backend_data, /* free_multi_ssl_backend_data */
schannel_recv, /* recv decrypted data */
schannel_send, /* send data to encrypt */
- NULL, /* get_channel_binding */
};
#endif /* USE_SCHANNEL */
diff --git a/contrib/libs/curl/lib/vtls/schannel_verify.c b/contrib/libs/curl/lib/vtls/schannel_verify.c
index 11e61b6893..e7c8bc66b9 100644
--- a/contrib/libs/curl/lib/vtls/schannel_verify.c
+++ b/contrib/libs/curl/lib/vtls/schannel_verify.c
@@ -33,7 +33,7 @@
#ifdef USE_SCHANNEL
#ifndef USE_WINDOWS_SSPI
-# error "cannot compile SCHANNEL support without SSPI."
+# error "Can't compile SCHANNEL support without SSPI."
#endif
#include "schannel.h"
@@ -82,8 +82,8 @@ static int is_cr_or_lf(char c)
}
/* Search the substring needle,needlelen into string haystack,haystacklen
- * Strings do not need to be terminated by a '\0'.
- * Similar of macOS/Linux memmem (not available on Visual Studio).
+ * Strings don't need to be terminated by a '\0'.
+ * Similar of OSX/Linux memmem (not available on Visual Studio).
* Return position of beginning of first occurrence or NULL if not found
*/
static const char *c_memmem(const void *haystack, size_t haystacklen,
@@ -172,7 +172,7 @@ static CURLcode add_certs_data_to_store(HCERTSTORE trust_store,
/* Sanity check that the cert_context object is the right type */
if(CERT_QUERY_CONTENT_CERT != actual_content_type) {
failf(data,
- "schannel: unexpected content type '%lu' when extracting "
+ "schannel: unexpected content type '%d' when extracting "
"certificate from CA file '%s'",
actual_content_type, ca_file_text);
result = CURLE_SSL_CACERT_BADFILE;
@@ -335,7 +335,7 @@ cleanup:
/*
* Returns the number of characters necessary to populate all the host_names.
- * If host_names is not NULL, populate it with all the hostnames. Each string
+ * If host_names is not NULL, populate it with all the host names. Each string
* in the host_names is null-terminated and the last string is double
* null-terminated. If no DNS names are found, a single null-terminated empty
* string is returned.
@@ -346,12 +346,6 @@ static DWORD cert_get_name_string(struct Curl_easy *data,
DWORD length)
{
DWORD actual_length = 0;
-#if defined(CURL_WINDOWS_APP)
- (void)data;
- (void)cert_context;
- (void)host_names;
- (void)length;
-#else
BOOL compute_content = FALSE;
CERT_INFO *cert_info = NULL;
CERT_EXTENSION *extension = NULL;
@@ -447,14 +441,14 @@ static DWORD cert_get_name_string(struct Curl_easy *data,
}
/* Sanity check to prevent buffer overrun. */
if((actual_length + current_length) > length) {
- failf(data, "schannel: Not enough memory to list all hostnames.");
+ failf(data, "schannel: Not enough memory to list all host names.");
break;
}
dns_w = entry->pwszDNSName;
- /* pwszDNSName is in ia5 string format and hence does not contain any
- * non-ASCII characters. */
+ /* pwszDNSName is in ia5 string format and hence doesn't contain any
+ * non-ascii characters. */
while(*dns_w != '\0') {
- *current_pos++ = (TCHAR)(*dns_w++);
+ *current_pos++ = (char)(*dns_w++);
}
*current_pos++ = '\0';
actual_length += (DWORD)current_length;
@@ -463,7 +457,6 @@ static DWORD cert_get_name_string(struct Curl_easy *data,
/* Last string has double null-terminator. */
*current_pos = '\0';
}
-#endif
return actual_length;
}
@@ -483,7 +476,7 @@ CURLcode Curl_verify_host(struct Curl_cfilter *cf,
DWORD actual_len = 0;
sspi_status =
- Curl_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle,
+ s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle,
SECPKG_ATTR_REMOTE_CERT_CONTEXT,
&pCertContextServer);
@@ -612,7 +605,7 @@ CURLcode Curl_verify_certificate(struct Curl_cfilter *cf,
DEBUGASSERT(BACKEND);
sspi_status =
- Curl_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle,
+ s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle,
SECPKG_ATTR_REMOTE_CERT_CONTEXT,
&pCertContextServer);
@@ -760,7 +753,7 @@ CURLcode Curl_verify_certificate(struct Curl_cfilter *cf,
failf(data, "schannel: CertGetCertificateChain trust error"
" CERT_TRUST_REVOCATION_STATUS_UNKNOWN");
else
- failf(data, "schannel: CertGetCertificateChain error mask: 0x%08lx",
+ failf(data, "schannel: CertGetCertificateChain error mask: 0x%08x",
dwTrustErrorMask);
result = CURLE_PEER_FAILED_VERIFICATION;
}
diff --git a/contrib/libs/curl/lib/vtls/sectransp.c b/contrib/libs/curl/lib/vtls/sectransp.c
index f841f87917..0a22ff60be 100644
--- a/contrib/libs/curl/lib/vtls/sectransp.c
+++ b/contrib/libs/curl/lib/vtls/sectransp.c
@@ -30,25 +30,26 @@
#include "curl_setup.h"
-#ifdef USE_SECTRANSP
-
#include "urldata.h" /* for the Curl_easy definition */
#include "curl_base64.h"
#include "strtok.h"
#include "multiif.h"
#include "strcase.h"
-#error #include "x509asn1.h"
+#include "x509asn1.h"
#include "strerror.h"
-#error #include "cipher_suite.h"
+
+#ifdef USE_SECTRANSP
#ifdef __clang__
#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wunreachable-code"
+#pragma clang diagnostic ignored "-Wtautological-pointer-compare"
#endif /* __clang__ */
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Waddress"
+#pragma GCC diagnostic ignored "-Wundef"
+#pragma GCC diagnostic ignored "-Wunreachable-code"
#endif
#include <limits.h>
@@ -71,7 +72,7 @@
#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
#if MAC_OS_X_VERSION_MAX_ALLOWED < 1050
-#error "The Secure Transport backend requires Leopard or later."
+#error "The Secure Transport back-end requires Leopard or later."
#endif /* MAC_OS_X_VERSION_MAX_ALLOWED < 1050 */
#define CURL_BUILD_IOS 0
@@ -121,7 +122,7 @@
#define CURL_SUPPORT_MAC_10_9 0
#else
-#error "The Secure Transport backend requires iOS or macOS."
+#error "The Secure Transport back-end requires iOS or macOS."
#endif /* (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) */
#if CURL_BUILD_MAC
@@ -143,8 +144,7 @@
#include "memdebug.h"
-/* From MacTypes.h (which we cannot include because it is not present in
- iOS: */
+/* From MacTypes.h (which we can't include because it isn't present in iOS: */
#define ioErr -36
#define paramErr -50
@@ -152,60 +152,636 @@ struct st_ssl_backend_data {
SSLContextRef ssl_ctx;
bool ssl_direction; /* true if writing, false if reading */
size_t ssl_write_buffered_length;
- BIT(sent_shutdown);
};
-/* Create the list of default ciphers to use by making an intersection of the
- * ciphers supported by Secure Transport and the list below, using the order
- * of the former.
- * This list is based on TLS recommendations by Mozilla, balancing between
- * security and wide compatibility: "Most ciphers that are not clearly broken
- * and dangerous to use are supported"
+struct st_cipher {
+ const char *name; /* Cipher suite IANA name. It starts with "TLS_" prefix */
+ const char *alias_name; /* Alias name is the same as OpenSSL cipher name */
+ SSLCipherSuite num; /* Cipher suite code/number defined in IANA registry */
+ bool weak; /* Flag to mark cipher as weak based on previous implementation
+ of Secure Transport back-end by CURL */
+};
+
+/* Macro to initialize st_cipher data structure: stringify id to name, cipher
+ number/id, 'weak' suite flag
+ */
+#define CIPHER_DEF(num, alias, weak) \
+ { #num, alias, num, weak }
+
+/*
+ Macro to initialize st_cipher data structure with name, code (IANA cipher
+ number/id value), and 'weak' suite flag. The first 28 cipher suite numbers
+ have the same IANA code for both SSL and TLS standards: numbers 0x0000 to
+ 0x001B. They have different names though. The first 4 letters of the cipher
+ suite name are the protocol name: "SSL_" or "TLS_", rest of the IANA name is
+ the same for both SSL and TLS cipher suite name.
+ The second part of the problem is that macOS/iOS SDKs don't define all TLS
+ codes but only 12 of them. The SDK defines all SSL codes though, i.e. SSL_NUM
+ constant is always defined for those 28 ciphers while TLS_NUM is defined only
+ for 12 of the first 28 ciphers. Those 12 TLS cipher codes match to
+ corresponding SSL enum value and represent the same cipher suite. Therefore
+ we'll use the SSL enum value for those cipher suites because it is defined
+ for all 28 of them.
+ We make internal data consistent and based on TLS names, i.e. all st_cipher
+ item names start with the "TLS_" prefix.
+ Summarizing all the above, those 28 first ciphers are presented in our table
+ with both TLS and SSL names. Their cipher numbers are assigned based on the
+ SDK enum value for the SSL cipher, which matches to IANA TLS number.
+ */
+#define CIPHER_DEF_SSLTLS(num_wo_prefix, alias, weak) \
+ { "TLS_" #num_wo_prefix, alias, SSL_##num_wo_prefix, weak }
+
+/*
+ Cipher suites were marked as weak based on the following:
+ RC4 encryption - rfc7465, the document contains a list of deprecated ciphers.
+ Marked in the code below as weak.
+ RC2 encryption - many mentions, was found vulnerable to a relatively easy
+ attack https://link.springer.com/chapter/10.1007%2F3-540-69710-1_14
+ Marked in the code below as weak.
+ DES and IDEA encryption - rfc5469, has a list of deprecated ciphers.
+ Marked in the code below as weak.
+ Anonymous Diffie-Hellman authentication and anonymous elliptic curve
+ Diffie-Hellman - vulnerable to a man-in-the-middle attack. Deprecated by
+ RFC 4346 aka TLS 1.1 (section A.5, page 60)
+ Null bulk encryption suites - not encrypted communication
+ Export ciphers, i.e. ciphers with restrictions to be used outside the US for
+ software exported to some countries, they were excluded from TLS 1.1
+ version. More precisely, they were noted as ciphers which MUST NOT be
+ negotiated in RFC 4346 aka TLS 1.1 (section A.5, pages 60 and 61).
+ All of those filters were considered weak because they contain a weak
+ algorithm like DES, RC2 or RC4, and already considered weak by other
+ criteria.
+ 3DES - NIST deprecated it and is going to retire it by 2023
+ https://csrc.nist.gov/News/2017/Update-to-Current-Use-and-Deprecation-of-TDEA
+ OpenSSL https://www.openssl.org/blog/blog/2016/08/24/sweet32/ also
+ deprecated those ciphers. Some other libraries also consider it
+ vulnerable or at least not strong enough.
+
+ CBC ciphers are vulnerable with SSL3.0 and TLS1.0:
+ https://www.cisco.com/c/en/us/support/docs/security/email-security-appliance
+ /118518-technote-esa-00.html
+ We don't take care of this issue because it is resolved by later TLS
+ versions and for us, it requires more complicated checks, we need to
+ check a protocol version also. Vulnerability doesn't look very critical
+ and we do not filter out those cipher suites.
*/
-static const uint16_t default_ciphers[] = {
- TLS_RSA_WITH_3DES_EDE_CBC_SHA, /* 0x000A */
- TLS_RSA_WITH_AES_128_CBC_SHA, /* 0x002F */
- TLS_RSA_WITH_AES_256_CBC_SHA, /* 0x0035 */
+
+#define CIPHER_WEAK_NOT_ENCRYPTED TRUE
+#define CIPHER_WEAK_RC_ENCRYPTION TRUE
+#define CIPHER_WEAK_DES_ENCRYPTION TRUE
+#define CIPHER_WEAK_IDEA_ENCRYPTION TRUE
+#define CIPHER_WEAK_ANON_AUTH TRUE
+#define CIPHER_WEAK_3DES_ENCRYPTION TRUE
+#define CIPHER_STRONG_ENOUGH FALSE
+
+/* Please do not change the order of the first ciphers available for SSL.
+ Do not insert and do not delete any of them. Code below
+ depends on their order and continuity.
+ If you add a new cipher, please maintain order by number, i.e.
+ insert in between existing items to appropriate place based on
+ cipher suite IANA number
+*/
+static const struct st_cipher ciphertable[] = {
+ /* SSL version 3.0 and initial TLS 1.0 cipher suites.
+ Defined since SDK 10.2.8 */
+ CIPHER_DEF_SSLTLS(NULL_WITH_NULL_NULL, /* 0x0000 */
+ NULL,
+ CIPHER_WEAK_NOT_ENCRYPTED),
+ CIPHER_DEF_SSLTLS(RSA_WITH_NULL_MD5, /* 0x0001 */
+ "NULL-MD5",
+ CIPHER_WEAK_NOT_ENCRYPTED),
+ CIPHER_DEF_SSLTLS(RSA_WITH_NULL_SHA, /* 0x0002 */
+ "NULL-SHA",
+ CIPHER_WEAK_NOT_ENCRYPTED),
+ CIPHER_DEF_SSLTLS(RSA_EXPORT_WITH_RC4_40_MD5, /* 0x0003 */
+ "EXP-RC4-MD5",
+ CIPHER_WEAK_RC_ENCRYPTION),
+ CIPHER_DEF_SSLTLS(RSA_WITH_RC4_128_MD5, /* 0x0004 */
+ "RC4-MD5",
+ CIPHER_WEAK_RC_ENCRYPTION),
+ CIPHER_DEF_SSLTLS(RSA_WITH_RC4_128_SHA, /* 0x0005 */
+ "RC4-SHA",
+ CIPHER_WEAK_RC_ENCRYPTION),
+ CIPHER_DEF_SSLTLS(RSA_EXPORT_WITH_RC2_CBC_40_MD5, /* 0x0006 */
+ "EXP-RC2-CBC-MD5",
+ CIPHER_WEAK_RC_ENCRYPTION),
+ CIPHER_DEF_SSLTLS(RSA_WITH_IDEA_CBC_SHA, /* 0x0007 */
+ "IDEA-CBC-SHA",
+ CIPHER_WEAK_IDEA_ENCRYPTION),
+ CIPHER_DEF_SSLTLS(RSA_EXPORT_WITH_DES40_CBC_SHA, /* 0x0008 */
+ "EXP-DES-CBC-SHA",
+ CIPHER_WEAK_DES_ENCRYPTION),
+ CIPHER_DEF_SSLTLS(RSA_WITH_DES_CBC_SHA, /* 0x0009 */
+ "DES-CBC-SHA",
+ CIPHER_WEAK_DES_ENCRYPTION),
+ CIPHER_DEF_SSLTLS(RSA_WITH_3DES_EDE_CBC_SHA, /* 0x000A */
+ "DES-CBC3-SHA",
+ CIPHER_WEAK_3DES_ENCRYPTION),
+ CIPHER_DEF_SSLTLS(DH_DSS_EXPORT_WITH_DES40_CBC_SHA, /* 0x000B */
+ "EXP-DH-DSS-DES-CBC-SHA",
+ CIPHER_WEAK_DES_ENCRYPTION),
+ CIPHER_DEF_SSLTLS(DH_DSS_WITH_DES_CBC_SHA, /* 0x000C */
+ "DH-DSS-DES-CBC-SHA",
+ CIPHER_WEAK_DES_ENCRYPTION),
+ CIPHER_DEF_SSLTLS(DH_DSS_WITH_3DES_EDE_CBC_SHA, /* 0x000D */
+ "DH-DSS-DES-CBC3-SHA",
+ CIPHER_WEAK_3DES_ENCRYPTION),
+ CIPHER_DEF_SSLTLS(DH_RSA_EXPORT_WITH_DES40_CBC_SHA, /* 0x000E */
+ "EXP-DH-RSA-DES-CBC-SHA",
+ CIPHER_WEAK_DES_ENCRYPTION),
+ CIPHER_DEF_SSLTLS(DH_RSA_WITH_DES_CBC_SHA, /* 0x000F */
+ "DH-RSA-DES-CBC-SHA",
+ CIPHER_WEAK_DES_ENCRYPTION),
+ CIPHER_DEF_SSLTLS(DH_RSA_WITH_3DES_EDE_CBC_SHA, /* 0x0010 */
+ "DH-RSA-DES-CBC3-SHA",
+ CIPHER_WEAK_3DES_ENCRYPTION),
+ CIPHER_DEF_SSLTLS(DHE_DSS_EXPORT_WITH_DES40_CBC_SHA, /* 0x0011 */
+ "EXP-EDH-DSS-DES-CBC-SHA",
+ CIPHER_WEAK_DES_ENCRYPTION),
+ CIPHER_DEF_SSLTLS(DHE_DSS_WITH_DES_CBC_SHA, /* 0x0012 */
+ "EDH-DSS-CBC-SHA",
+ CIPHER_WEAK_DES_ENCRYPTION),
+ CIPHER_DEF_SSLTLS(DHE_DSS_WITH_3DES_EDE_CBC_SHA, /* 0x0013 */
+ "DHE-DSS-DES-CBC3-SHA",
+ CIPHER_WEAK_3DES_ENCRYPTION),
+ CIPHER_DEF_SSLTLS(DHE_RSA_EXPORT_WITH_DES40_CBC_SHA, /* 0x0014 */
+ "EXP-EDH-RSA-DES-CBC-SHA",
+ CIPHER_WEAK_DES_ENCRYPTION),
+ CIPHER_DEF_SSLTLS(DHE_RSA_WITH_DES_CBC_SHA, /* 0x0015 */
+ "EDH-RSA-DES-CBC-SHA",
+ CIPHER_WEAK_DES_ENCRYPTION),
+ CIPHER_DEF_SSLTLS(DHE_RSA_WITH_3DES_EDE_CBC_SHA, /* 0x0016 */
+ "DHE-RSA-DES-CBC3-SHA",
+ CIPHER_WEAK_3DES_ENCRYPTION),
+ CIPHER_DEF_SSLTLS(DH_anon_EXPORT_WITH_RC4_40_MD5, /* 0x0017 */
+ "EXP-ADH-RC4-MD5",
+ CIPHER_WEAK_ANON_AUTH),
+ CIPHER_DEF_SSLTLS(DH_anon_WITH_RC4_128_MD5, /* 0x0018 */
+ "ADH-RC4-MD5",
+ CIPHER_WEAK_ANON_AUTH),
+ CIPHER_DEF_SSLTLS(DH_anon_EXPORT_WITH_DES40_CBC_SHA, /* 0x0019 */
+ "EXP-ADH-DES-CBC-SHA",
+ CIPHER_WEAK_ANON_AUTH),
+ CIPHER_DEF_SSLTLS(DH_anon_WITH_DES_CBC_SHA, /* 0x001A */
+ "ADH-DES-CBC-SHA",
+ CIPHER_WEAK_ANON_AUTH),
+ CIPHER_DEF_SSLTLS(DH_anon_WITH_3DES_EDE_CBC_SHA, /* 0x001B */
+ "ADH-DES-CBC3-SHA",
+ CIPHER_WEAK_3DES_ENCRYPTION),
+ CIPHER_DEF(SSL_FORTEZZA_DMS_WITH_NULL_SHA, /* 0x001C */
+ NULL,
+ CIPHER_WEAK_NOT_ENCRYPTED),
+ CIPHER_DEF(SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA, /* 0x001D */
+ NULL,
+ CIPHER_STRONG_ENOUGH),
+
+#if CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7
+ /* RFC 4785 - Pre-Shared Key (PSK) Ciphersuites with NULL Encryption */
+ CIPHER_DEF(TLS_PSK_WITH_NULL_SHA, /* 0x002C */
+ "PSK-NULL-SHA",
+ CIPHER_WEAK_NOT_ENCRYPTED),
+ CIPHER_DEF(TLS_DHE_PSK_WITH_NULL_SHA, /* 0x002D */
+ "DHE-PSK-NULL-SHA",
+ CIPHER_WEAK_NOT_ENCRYPTED),
+ CIPHER_DEF(TLS_RSA_PSK_WITH_NULL_SHA, /* 0x002E */
+ "RSA-PSK-NULL-SHA",
+ CIPHER_WEAK_NOT_ENCRYPTED),
+#endif /* CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 */
+
+ /* TLS addenda using AES, per RFC 3268. Defined since SDK 10.4u */
+ CIPHER_DEF(TLS_RSA_WITH_AES_128_CBC_SHA, /* 0x002F */
+ "AES128-SHA",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_DH_DSS_WITH_AES_128_CBC_SHA, /* 0x0030 */
+ "DH-DSS-AES128-SHA",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_DH_RSA_WITH_AES_128_CBC_SHA, /* 0x0031 */
+ "DH-RSA-AES128-SHA",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_DHE_DSS_WITH_AES_128_CBC_SHA, /* 0x0032 */
+ "DHE-DSS-AES128-SHA",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_DHE_RSA_WITH_AES_128_CBC_SHA, /* 0x0033 */
+ "DHE-RSA-AES128-SHA",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_DH_anon_WITH_AES_128_CBC_SHA, /* 0x0034 */
+ "ADH-AES128-SHA",
+ CIPHER_WEAK_ANON_AUTH),
+ CIPHER_DEF(TLS_RSA_WITH_AES_256_CBC_SHA, /* 0x0035 */
+ "AES256-SHA",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_DH_DSS_WITH_AES_256_CBC_SHA, /* 0x0036 */
+ "DH-DSS-AES256-SHA",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_DH_RSA_WITH_AES_256_CBC_SHA, /* 0x0037 */
+ "DH-RSA-AES256-SHA",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_DHE_DSS_WITH_AES_256_CBC_SHA, /* 0x0038 */
+ "DHE-DSS-AES256-SHA",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_DHE_RSA_WITH_AES_256_CBC_SHA, /* 0x0039 */
+ "DHE-RSA-AES256-SHA",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_DH_anon_WITH_AES_256_CBC_SHA, /* 0x003A */
+ "ADH-AES256-SHA",
+ CIPHER_WEAK_ANON_AUTH),
+
+#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
+ /* TLS 1.2 addenda, RFC 5246 */
+ /* Server provided RSA certificate for key exchange. */
+ CIPHER_DEF(TLS_RSA_WITH_NULL_SHA256, /* 0x003B */
+ "NULL-SHA256",
+ CIPHER_WEAK_NOT_ENCRYPTED),
+ CIPHER_DEF(TLS_RSA_WITH_AES_128_CBC_SHA256, /* 0x003C */
+ "AES128-SHA256",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_RSA_WITH_AES_256_CBC_SHA256, /* 0x003D */
+ "AES256-SHA256",
+ CIPHER_STRONG_ENOUGH),
+ /* Server-authenticated (and optionally client-authenticated)
+ Diffie-Hellman. */
+ CIPHER_DEF(TLS_DH_DSS_WITH_AES_128_CBC_SHA256, /* 0x003E */
+ "DH-DSS-AES128-SHA256",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_DH_RSA_WITH_AES_128_CBC_SHA256, /* 0x003F */
+ "DH-RSA-AES128-SHA256",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_DHE_DSS_WITH_AES_128_CBC_SHA256, /* 0x0040 */
+ "DHE-DSS-AES128-SHA256",
+ CIPHER_STRONG_ENOUGH),
+
+ /* TLS 1.2 addenda, RFC 5246 */
+ CIPHER_DEF(TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, /* 0x0067 */
+ "DHE-RSA-AES128-SHA256",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_DH_DSS_WITH_AES_256_CBC_SHA256, /* 0x0068 */
+ "DH-DSS-AES256-SHA256",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_DH_RSA_WITH_AES_256_CBC_SHA256, /* 0x0069 */
+ "DH-RSA-AES256-SHA256",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_DHE_DSS_WITH_AES_256_CBC_SHA256, /* 0x006A */
+ "DHE-DSS-AES256-SHA256",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, /* 0x006B */
+ "DHE-RSA-AES256-SHA256",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_DH_anon_WITH_AES_128_CBC_SHA256, /* 0x006C */
+ "ADH-AES128-SHA256",
+ CIPHER_WEAK_ANON_AUTH),
+ CIPHER_DEF(TLS_DH_anon_WITH_AES_256_CBC_SHA256, /* 0x006D */
+ "ADH-AES256-SHA256",
+ CIPHER_WEAK_ANON_AUTH),
+#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */
+
+#if CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7
+ /* Addendum from RFC 4279, TLS PSK */
+ CIPHER_DEF(TLS_PSK_WITH_RC4_128_SHA, /* 0x008A */
+ "PSK-RC4-SHA",
+ CIPHER_WEAK_RC_ENCRYPTION),
+ CIPHER_DEF(TLS_PSK_WITH_3DES_EDE_CBC_SHA, /* 0x008B */
+ "PSK-3DES-EDE-CBC-SHA",
+ CIPHER_WEAK_3DES_ENCRYPTION),
+ CIPHER_DEF(TLS_PSK_WITH_AES_128_CBC_SHA, /* 0x008C */
+ "PSK-AES128-CBC-SHA",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_PSK_WITH_AES_256_CBC_SHA, /* 0x008D */
+ "PSK-AES256-CBC-SHA",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_DHE_PSK_WITH_RC4_128_SHA, /* 0x008E */
+ "DHE-PSK-RC4-SHA",
+ CIPHER_WEAK_RC_ENCRYPTION),
+ CIPHER_DEF(TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA, /* 0x008F */
+ "DHE-PSK-3DES-EDE-CBC-SHA",
+ CIPHER_WEAK_3DES_ENCRYPTION),
+ CIPHER_DEF(TLS_DHE_PSK_WITH_AES_128_CBC_SHA, /* 0x0090 */
+ "DHE-PSK-AES128-CBC-SHA",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_DHE_PSK_WITH_AES_256_CBC_SHA, /* 0x0091 */
+ "DHE-PSK-AES256-CBC-SHA",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_RSA_PSK_WITH_RC4_128_SHA, /* 0x0092 */
+ "RSA-PSK-RC4-SHA",
+ CIPHER_WEAK_RC_ENCRYPTION),
+ CIPHER_DEF(TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA, /* 0x0093 */
+ "RSA-PSK-3DES-EDE-CBC-SHA",
+ CIPHER_WEAK_3DES_ENCRYPTION),
+ CIPHER_DEF(TLS_RSA_PSK_WITH_AES_128_CBC_SHA, /* 0x0094 */
+ "RSA-PSK-AES128-CBC-SHA",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_RSA_PSK_WITH_AES_256_CBC_SHA, /* 0x0095 */
+ "RSA-PSK-AES256-CBC-SHA",
+ CIPHER_STRONG_ENOUGH),
+#endif /* CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 */
+
+#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
+ /* Addenda from rfc 5288 AES Galois Counter Mode (GCM) Cipher Suites
+ for TLS. */
+ CIPHER_DEF(TLS_RSA_WITH_AES_128_GCM_SHA256, /* 0x009C */
+ "AES128-GCM-SHA256",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_RSA_WITH_AES_256_GCM_SHA384, /* 0x009D */
+ "AES256-GCM-SHA384",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, /* 0x009E */
+ "DHE-RSA-AES128-GCM-SHA256",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, /* 0x009F */
+ "DHE-RSA-AES256-GCM-SHA384",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_DH_RSA_WITH_AES_128_GCM_SHA256, /* 0x00A0 */
+ "DH-RSA-AES128-GCM-SHA256",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_DH_RSA_WITH_AES_256_GCM_SHA384, /* 0x00A1 */
+ "DH-RSA-AES256-GCM-SHA384",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_DHE_DSS_WITH_AES_128_GCM_SHA256, /* 0x00A2 */
+ "DHE-DSS-AES128-GCM-SHA256",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_DHE_DSS_WITH_AES_256_GCM_SHA384, /* 0x00A3 */
+ "DHE-DSS-AES256-GCM-SHA384",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_DH_DSS_WITH_AES_128_GCM_SHA256, /* 0x00A4 */
+ "DH-DSS-AES128-GCM-SHA256",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_DH_DSS_WITH_AES_256_GCM_SHA384, /* 0x00A5 */
+ "DH-DSS-AES256-GCM-SHA384",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_DH_anon_WITH_AES_128_GCM_SHA256, /* 0x00A6 */
+ "ADH-AES128-GCM-SHA256",
+ CIPHER_WEAK_ANON_AUTH),
+ CIPHER_DEF(TLS_DH_anon_WITH_AES_256_GCM_SHA384, /* 0x00A7 */
+ "ADH-AES256-GCM-SHA384",
+ CIPHER_WEAK_ANON_AUTH),
+#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */
+
+#if CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7
+ /* RFC 5487 - PSK with SHA-256/384 and AES GCM */
+ CIPHER_DEF(TLS_PSK_WITH_AES_128_GCM_SHA256, /* 0x00A8 */
+ "PSK-AES128-GCM-SHA256",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_PSK_WITH_AES_256_GCM_SHA384, /* 0x00A9 */
+ "PSK-AES256-GCM-SHA384",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_DHE_PSK_WITH_AES_128_GCM_SHA256, /* 0x00AA */
+ "DHE-PSK-AES128-GCM-SHA256",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_DHE_PSK_WITH_AES_256_GCM_SHA384, /* 0x00AB */
+ "DHE-PSK-AES256-GCM-SHA384",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_RSA_PSK_WITH_AES_128_GCM_SHA256, /* 0x00AC */
+ "RSA-PSK-AES128-GCM-SHA256",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_RSA_PSK_WITH_AES_256_GCM_SHA384, /* 0x00AD */
+ "RSA-PSK-AES256-GCM-SHA384",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_PSK_WITH_AES_128_CBC_SHA256, /* 0x00AE */
+ "PSK-AES128-CBC-SHA256",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_PSK_WITH_AES_256_CBC_SHA384, /* 0x00AF */
+ "PSK-AES256-CBC-SHA384",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_PSK_WITH_NULL_SHA256, /* 0x00B0 */
+ "PSK-NULL-SHA256",
+ CIPHER_WEAK_NOT_ENCRYPTED),
+ CIPHER_DEF(TLS_PSK_WITH_NULL_SHA384, /* 0x00B1 */
+ "PSK-NULL-SHA384",
+ CIPHER_WEAK_NOT_ENCRYPTED),
+ CIPHER_DEF(TLS_DHE_PSK_WITH_AES_128_CBC_SHA256, /* 0x00B2 */
+ "DHE-PSK-AES128-CBC-SHA256",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_DHE_PSK_WITH_AES_256_CBC_SHA384, /* 0x00B3 */
+ "DHE-PSK-AES256-CBC-SHA384",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_DHE_PSK_WITH_NULL_SHA256, /* 0x00B4 */
+ "DHE-PSK-NULL-SHA256",
+ CIPHER_WEAK_NOT_ENCRYPTED),
+ CIPHER_DEF(TLS_DHE_PSK_WITH_NULL_SHA384, /* 0x00B5 */
+ "DHE-PSK-NULL-SHA384",
+ CIPHER_WEAK_NOT_ENCRYPTED),
+ CIPHER_DEF(TLS_RSA_PSK_WITH_AES_128_CBC_SHA256, /* 0x00B6 */
+ "RSA-PSK-AES128-CBC-SHA256",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_RSA_PSK_WITH_AES_256_CBC_SHA384, /* 0x00B7 */
+ "RSA-PSK-AES256-CBC-SHA384",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_RSA_PSK_WITH_NULL_SHA256, /* 0x00B8 */
+ "RSA-PSK-NULL-SHA256",
+ CIPHER_WEAK_NOT_ENCRYPTED),
+ CIPHER_DEF(TLS_RSA_PSK_WITH_NULL_SHA384, /* 0x00B9 */
+ "RSA-PSK-NULL-SHA384",
+ CIPHER_WEAK_NOT_ENCRYPTED),
+#endif /* CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 */
+
+ /* RFC 5746 - Secure Renegotiation. This is not a real suite,
+ it is a response to initiate negotiation again */
+ CIPHER_DEF(TLS_EMPTY_RENEGOTIATION_INFO_SCSV, /* 0x00FF */
+ NULL,
+ CIPHER_STRONG_ENOUGH),
+
+#if CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11
+ /* TLS 1.3 standard cipher suites for ChaCha20+Poly1305.
+ Note: TLS 1.3 ciphersuites do not specify the key exchange
+ algorithm -- they only specify the symmetric ciphers.
+ Cipher alias name matches to OpenSSL cipher name, and for
+ TLS 1.3 ciphers */
+ CIPHER_DEF(TLS_AES_128_GCM_SHA256, /* 0x1301 */
+ NULL, /* The OpenSSL cipher name matches to the IANA name */
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_AES_256_GCM_SHA384, /* 0x1302 */
+ NULL, /* The OpenSSL cipher name matches to the IANA name */
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_CHACHA20_POLY1305_SHA256, /* 0x1303 */
+ NULL, /* The OpenSSL cipher name matches to the IANA name */
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_AES_128_CCM_SHA256, /* 0x1304 */
+ NULL, /* The OpenSSL cipher name matches to the IANA name */
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_AES_128_CCM_8_SHA256, /* 0x1305 */
+ NULL, /* The OpenSSL cipher name matches to the IANA name */
+ CIPHER_STRONG_ENOUGH),
+#endif /* CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11 */
#if CURL_BUILD_MAC_10_6 || CURL_BUILD_IOS
- TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, /* 0xC009 */
- TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, /* 0xC00A */
- TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, /* 0xC013 */
- TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, /* 0xC014 */
+ /* ECDSA addenda, RFC 4492 */
+ CIPHER_DEF(TLS_ECDH_ECDSA_WITH_NULL_SHA, /* 0xC001 */
+ "ECDH-ECDSA-NULL-SHA",
+ CIPHER_WEAK_NOT_ENCRYPTED),
+ CIPHER_DEF(TLS_ECDH_ECDSA_WITH_RC4_128_SHA, /* 0xC002 */
+ "ECDH-ECDSA-RC4-SHA",
+ CIPHER_WEAK_RC_ENCRYPTION),
+ CIPHER_DEF(TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, /* 0xC003 */
+ "ECDH-ECDSA-DES-CBC3-SHA",
+ CIPHER_WEAK_3DES_ENCRYPTION),
+ CIPHER_DEF(TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, /* 0xC004 */
+ "ECDH-ECDSA-AES128-SHA",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, /* 0xC005 */
+ "ECDH-ECDSA-AES256-SHA",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_NULL_SHA, /* 0xC006 */
+ "ECDHE-ECDSA-NULL-SHA",
+ CIPHER_WEAK_NOT_ENCRYPTED),
+ CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, /* 0xC007 */
+ "ECDHE-ECDSA-RC4-SHA",
+ CIPHER_WEAK_RC_ENCRYPTION),
+ CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, /* 0xC008 */
+ "ECDHE-ECDSA-DES-CBC3-SHA",
+ CIPHER_WEAK_3DES_ENCRYPTION),
+ CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, /* 0xC009 */
+ "ECDHE-ECDSA-AES128-SHA",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, /* 0xC00A */
+ "ECDHE-ECDSA-AES256-SHA",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_ECDH_RSA_WITH_NULL_SHA, /* 0xC00B */
+ "ECDH-RSA-NULL-SHA",
+ CIPHER_WEAK_NOT_ENCRYPTED),
+ CIPHER_DEF(TLS_ECDH_RSA_WITH_RC4_128_SHA, /* 0xC00C */
+ "ECDH-RSA-RC4-SHA",
+ CIPHER_WEAK_RC_ENCRYPTION),
+ CIPHER_DEF(TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, /* 0xC00D */
+ "ECDH-RSA-DES-CBC3-SHA",
+ CIPHER_WEAK_3DES_ENCRYPTION),
+ CIPHER_DEF(TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, /* 0xC00E */
+ "ECDH-RSA-AES128-SHA",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, /* 0xC00F */
+ "ECDH-RSA-AES256-SHA",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_ECDHE_RSA_WITH_NULL_SHA, /* 0xC010 */
+ "ECDHE-RSA-NULL-SHA",
+ CIPHER_WEAK_NOT_ENCRYPTED),
+ CIPHER_DEF(TLS_ECDHE_RSA_WITH_RC4_128_SHA, /* 0xC011 */
+ "ECDHE-RSA-RC4-SHA",
+ CIPHER_WEAK_RC_ENCRYPTION),
+ CIPHER_DEF(TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, /* 0xC012 */
+ "ECDHE-RSA-DES-CBC3-SHA",
+ CIPHER_WEAK_3DES_ENCRYPTION),
+ CIPHER_DEF(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, /* 0xC013 */
+ "ECDHE-RSA-AES128-SHA",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, /* 0xC014 */
+ "ECDHE-RSA-AES256-SHA",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_ECDH_anon_WITH_NULL_SHA, /* 0xC015 */
+ "AECDH-NULL-SHA",
+ CIPHER_WEAK_ANON_AUTH),
+ CIPHER_DEF(TLS_ECDH_anon_WITH_RC4_128_SHA, /* 0xC016 */
+ "AECDH-RC4-SHA",
+ CIPHER_WEAK_ANON_AUTH),
+ CIPHER_DEF(TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA, /* 0xC017 */
+ "AECDH-DES-CBC3-SHA",
+ CIPHER_WEAK_3DES_ENCRYPTION),
+ CIPHER_DEF(TLS_ECDH_anon_WITH_AES_128_CBC_SHA, /* 0xC018 */
+ "AECDH-AES128-SHA",
+ CIPHER_WEAK_ANON_AUTH),
+ CIPHER_DEF(TLS_ECDH_anon_WITH_AES_256_CBC_SHA, /* 0xC019 */
+ "AECDH-AES256-SHA",
+ CIPHER_WEAK_ANON_AUTH),
#endif /* CURL_BUILD_MAC_10_6 || CURL_BUILD_IOS */
#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
- TLS_RSA_WITH_AES_128_CBC_SHA256, /* 0x003C */
- TLS_RSA_WITH_AES_256_CBC_SHA256, /* 0x003D */
- TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, /* 0x0067 */
- TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, /* 0x006B */
- TLS_RSA_WITH_AES_128_GCM_SHA256, /* 0x009C */
- TLS_RSA_WITH_AES_256_GCM_SHA384, /* 0x009D */
- TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, /* 0x009E */
- TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, /* 0x009F */
- TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, /* 0xC023 */
- TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, /* 0xC024 */
- TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, /* 0xC027 */
- TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, /* 0xC028 */
- TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, /* 0xC02B */
- TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, /* 0xC02C */
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, /* 0xC02F */
- TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, /* 0xC030 */
+ /* Addenda from rfc 5289 Elliptic Curve Cipher Suites with
+ HMAC SHA-256/384. */
+ CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, /* 0xC023 */
+ "ECDHE-ECDSA-AES128-SHA256",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, /* 0xC024 */
+ "ECDHE-ECDSA-AES256-SHA384",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256, /* 0xC025 */
+ "ECDH-ECDSA-AES128-SHA256",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384, /* 0xC026 */
+ "ECDH-ECDSA-AES256-SHA384",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, /* 0xC027 */
+ "ECDHE-RSA-AES128-SHA256",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, /* 0xC028 */
+ "ECDHE-RSA-AES256-SHA384",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256, /* 0xC029 */
+ "ECDH-RSA-AES128-SHA256",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384, /* 0xC02A */
+ "ECDH-RSA-AES256-SHA384",
+ CIPHER_STRONG_ENOUGH),
+ /* Addenda from rfc 5289 Elliptic Curve Cipher Suites with
+ SHA-256/384 and AES Galois Counter Mode (GCM) */
+ CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, /* 0xC02B */
+ "ECDHE-ECDSA-AES128-GCM-SHA256",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, /* 0xC02C */
+ "ECDHE-ECDSA-AES256-GCM-SHA384",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256, /* 0xC02D */
+ "ECDH-ECDSA-AES128-GCM-SHA256",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384, /* 0xC02E */
+ "ECDH-ECDSA-AES256-GCM-SHA384",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, /* 0xC02F */
+ "ECDHE-RSA-AES128-GCM-SHA256",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, /* 0xC030 */
+ "ECDHE-RSA-AES256-GCM-SHA384",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256, /* 0xC031 */
+ "ECDH-RSA-AES128-GCM-SHA256",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384, /* 0xC032 */
+ "ECDH-RSA-AES256-GCM-SHA384",
+ CIPHER_STRONG_ENOUGH),
#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */
+#if CURL_BUILD_MAC_10_15 || CURL_BUILD_IOS_13
+ /* ECDHE_PSK Cipher Suites for Transport Layer Security (TLS), RFC 5489 */
+ CIPHER_DEF(TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA, /* 0xC035 */
+ "ECDHE-PSK-AES128-CBC-SHA",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA, /* 0xC036 */
+ "ECDHE-PSK-AES256-CBC-SHA",
+ CIPHER_STRONG_ENOUGH),
+#endif /* CURL_BUILD_MAC_10_15 || CURL_BUILD_IOS_13 */
+
#if CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11
- TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, /* 0xCCA8 */
- TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, /* 0xCCA9 */
-
- /* TLSv1.3 is not supported by sectransp, but there is also other
- * code referencing TLSv1.3, like: kTLSProtocol13 ? */
- TLS_AES_128_GCM_SHA256, /* 0x1301 */
- TLS_AES_256_GCM_SHA384, /* 0x1302 */
- TLS_CHACHA20_POLY1305_SHA256, /* 0x1303 */
+ /* Addenda from rfc 7905 ChaCha20-Poly1305 Cipher Suites for
+ Transport Layer Security (TLS). */
+ CIPHER_DEF(TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, /* 0xCCA8 */
+ "ECDHE-RSA-CHACHA20-POLY1305",
+ CIPHER_STRONG_ENOUGH),
+ CIPHER_DEF(TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, /* 0xCCA9 */
+ "ECDHE-ECDSA-CHACHA20-POLY1305",
+ CIPHER_STRONG_ENOUGH),
#endif /* CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11 */
+
+#if CURL_BUILD_MAC_10_15 || CURL_BUILD_IOS_13
+ /* ChaCha20-Poly1305 Cipher Suites for Transport Layer Security (TLS),
+ RFC 7905 */
+ CIPHER_DEF(TLS_PSK_WITH_CHACHA20_POLY1305_SHA256, /* 0xCCAB */
+ "PSK-CHACHA20-POLY1305",
+ CIPHER_STRONG_ENOUGH),
+#endif /* CURL_BUILD_MAC_10_15 || CURL_BUILD_IOS_13 */
+
+ /* Tags for SSL 2 cipher kinds which are not specified for SSL 3.
+ Defined since SDK 10.2.8 */
+ CIPHER_DEF(SSL_RSA_WITH_RC2_CBC_MD5, /* 0xFF80 */
+ NULL,
+ CIPHER_WEAK_RC_ENCRYPTION),
+ CIPHER_DEF(SSL_RSA_WITH_IDEA_CBC_MD5, /* 0xFF81 */
+ NULL,
+ CIPHER_WEAK_IDEA_ENCRYPTION),
+ CIPHER_DEF(SSL_RSA_WITH_DES_CBC_MD5, /* 0xFF82 */
+ NULL,
+ CIPHER_WEAK_DES_ENCRYPTION),
+ CIPHER_DEF(SSL_RSA_WITH_3DES_EDE_CBC_MD5, /* 0xFF83 */
+ NULL,
+ CIPHER_WEAK_3DES_ENCRYPTION),
};
-#define DEFAULT_CIPHERS_LEN sizeof(default_ciphers)/sizeof(default_ciphers[0])
+#define NUM_OF_CIPHERS sizeof(ciphertable)/sizeof(ciphertable[0])
/* pinned public key support tests */
@@ -216,7 +792,7 @@ static const uint16_t default_ciphers[] = {
#define SECTRANSP_PINNEDPUBKEY_V1 1
#endif
-/* version 2 supports macOS 10.7+ */
+/* version 2 supports MacOSX 10.7+ */
#if (!TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070)
#define SECTRANSP_PINNEDPUBKEY_V2 1
#endif
@@ -240,7 +816,7 @@ static const unsigned char rsa2048SpkiHeader[] = {
0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05,
0x00, 0x03, 0x82, 0x01, 0x0f, 0x00};
#ifdef SECTRANSP_PINNEDPUBKEY_V1
-/* the *new* version does not return DER encoded ecdsa certs like the old... */
+/* the *new* version doesn't return DER encoded ecdsa certs like the old... */
static const unsigned char ecDsaSecp256r1SpkiHeader[] = {
0x30, 0x59, 0x30, 0x13, 0x06, 0x07,
0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02,
@@ -310,8 +886,7 @@ static OSStatus sectransp_bio_cf_out_write(SSLConnectionRef connection,
OSStatus rtn = noErr;
DEBUGASSERT(data);
- nwritten = Curl_conn_cf_send(cf->next, data, buf, *dataLength, FALSE,
- &result);
+ nwritten = Curl_conn_cf_send(cf->next, data, buf, *dataLength, &result);
CURL_TRC_CF(data, cf, "bio_send(len=%zu) -> %zd, result=%d",
*dataLength, nwritten, result);
if(nwritten <= 0) {
@@ -331,6 +906,27 @@ static OSStatus sectransp_bio_cf_out_write(SSLConnectionRef connection,
return rtn;
}
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+CF_INLINE const char *TLSCipherNameForNumber(SSLCipherSuite cipher)
+{
+ /* The first ciphers in the ciphertable are continuous. Here we do small
+ optimization and instead of loop directly get SSL name by cipher number.
+ */
+ size_t i;
+ if(cipher <= SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA) {
+ return ciphertable[cipher].name;
+ }
+ /* Iterate through the rest of the ciphers */
+ for(i = SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA + 1; i < NUM_OF_CIPHERS;
+ ++i) {
+ if(ciphertable[i].num == cipher) {
+ return ciphertable[i].name;
+ }
+ }
+ return ciphertable[SSL_NULL_WITH_NULL_NULL].name;
+}
+#endif /* !CURL_DISABLE_VERBOSE_STRINGS */
+
#if CURL_BUILD_MAC
CF_INLINE void GetDarwinVersionNumber(int *major, int *minor)
{
@@ -363,27 +959,27 @@ CF_INLINE void GetDarwinVersionNumber(int *major, int *minor)
#endif /* CURL_BUILD_MAC */
/* Apple provides a myriad of ways of getting information about a certificate
- into a string. Some are not available under iOS or newer cats. Here's a
- unified function for getting a string describing the certificate that ought
- to work in all cats starting with Leopard. */
+ into a string. Some aren't available under iOS or newer cats. So here's
+ a unified function for getting a string describing the certificate that
+ ought to work in all cats starting with Leopard. */
CF_INLINE CFStringRef getsubject(SecCertificateRef cert)
{
CFStringRef server_cert_summary = CFSTR("(null)");
#if CURL_BUILD_IOS
- /* iOS: There is only one way to do this. */
+ /* iOS: There's only one way to do this. */
server_cert_summary = SecCertificateCopySubjectSummary(cert);
#else
#if CURL_BUILD_MAC_10_7
/* Lion & later: Get the long description if we can. */
- if(&SecCertificateCopyLongDescription)
+ if(SecCertificateCopyLongDescription)
server_cert_summary =
SecCertificateCopyLongDescription(NULL, cert, NULL);
else
#endif /* CURL_BUILD_MAC_10_7 */
#if CURL_BUILD_MAC_10_6
/* Snow Leopard: Get the certificate summary. */
- if(&SecCertificateCopySubjectSummary)
+ if(SecCertificateCopySubjectSummary)
server_cert_summary = SecCertificateCopySubjectSummary(cert);
else
#endif /* CURL_BUILD_MAC_10_6 */
@@ -421,7 +1017,7 @@ static CURLcode CopyCertSubject(struct Curl_easy *data,
size_t cbuf_size = ((size_t)CFStringGetLength(c) * 4) + 1;
cbuf = calloc(1, cbuf_size);
if(cbuf) {
- if(!CFStringGetCString(c, cbuf, (CFIndex)cbuf_size,
+ if(!CFStringGetCString(c, cbuf, cbuf_size,
kCFStringEncodingUTF8)) {
failf(data, "SSL: invalid CA certificate subject");
result = CURLE_PEER_FAILED_VERIFICATION;
@@ -431,7 +1027,7 @@ static CURLcode CopyCertSubject(struct Curl_easy *data,
*certp = cbuf;
}
else {
- failf(data, "SSL: could not allocate %zu bytes of memory", cbuf_size);
+ failf(data, "SSL: couldn't allocate %zu bytes of memory", cbuf_size);
result = CURLE_OUT_OF_MEMORY;
}
}
@@ -443,7 +1039,7 @@ static CURLcode CopyCertSubject(struct Curl_easy *data,
#if CURL_SUPPORT_MAC_10_6
/* The SecKeychainSearch API was deprecated in Lion, and using it will raise
- deprecation warnings, so let's not compile this unless it is necessary: */
+ deprecation warnings, so let's not compile this unless it's necessary: */
static OSStatus CopyIdentityWithLabelOldSchool(char *label,
SecIdentityRef *out_c_a_k)
{
@@ -496,7 +1092,7 @@ static OSStatus CopyIdentityWithLabel(char *label,
/* SecItemCopyMatching() was introduced in iOS and Snow Leopard.
kSecClassIdentity was introduced in Lion. If both exist, let's use them
to find the certificate. */
- if(&SecItemCopyMatching && kSecClassIdentity) {
+ if(SecItemCopyMatching && kSecClassIdentity) {
CFTypeRef keys[5];
CFTypeRef values[5];
CFDictionaryRef query_dict;
@@ -514,7 +1110,7 @@ static OSStatus CopyIdentityWithLabel(char *label,
/* identity searches need a SecPolicyRef in order to work */
values[3] = SecPolicyCreateSSL(false, NULL);
keys[3] = kSecMatchPolicy;
- /* match the name of the certificate (does not work in macOS 10.12.1) */
+ /* match the name of the certificate (doesn't work in macOS 10.12.1) */
values[4] = label_cf;
keys[4] = kSecAttrLabel;
query_dict = CFDictionaryCreate(NULL, (const void **)keys,
@@ -526,7 +1122,7 @@ static OSStatus CopyIdentityWithLabel(char *label,
/* Do we have a match? */
status = SecItemCopyMatching(query_dict, (CFTypeRef *) &keys_list);
- /* Because kSecAttrLabel matching does not work with kSecClassIdentity,
+ /* Because kSecAttrLabel matching doesn't work with kSecClassIdentity,
* we need to find the correct identity ourselves */
if(status == noErr) {
keys_list_count = CFArrayGetCount(keys_list);
@@ -592,7 +1188,7 @@ static OSStatus CopyIdentityFromPKCS12File(const char *cPath,
cPassword, kCFStringEncodingUTF8) : NULL;
CFDataRef pkcs_data = NULL;
- /* We can import P12 files on iOS or macOS 10.7 or later: */
+ /* We can import P12 files on iOS or OS X 10.7 or later: */
/* These constants are documented as having first appeared in 10.6 but they
raise linker errors when used on that cat for some reason. */
#if CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS
@@ -600,8 +1196,7 @@ static OSStatus CopyIdentityFromPKCS12File(const char *cPath,
if(blob) {
pkcs_data = CFDataCreate(kCFAllocatorDefault,
- (const unsigned char *)blob->data,
- (CFIndex)blob->len);
+ (const unsigned char *)blob->data, blob->len);
status = (pkcs_data != NULL) ? errSecSuccess : errSecAllocate;
resource_imported = (pkcs_data != NULL);
}
@@ -609,7 +1204,7 @@ static OSStatus CopyIdentityFromPKCS12File(const char *cPath,
pkcs_url =
CFURLCreateFromFileSystemRepresentation(NULL,
(const UInt8 *)cPath,
- (CFIndex)strlen(cPath), false);
+ strlen(cPath), false);
resource_imported =
CFURLCreateDataAndPropertiesFromResource(NULL,
pkcs_url, &pkcs_data,
@@ -638,7 +1233,7 @@ static OSStatus CopyIdentityFromPKCS12File(const char *cPath,
/* On macOS SecPKCS12Import will always add the client certificate to
* the Keychain.
*
- * As this does not match iOS, and apps may not want to see their client
+ * As this doesn't match iOS, and apps may not want to see their client
* certificate saved in the user's keychain, we use SecItemImport
* with a NULL keychain to avoid importing it.
*
@@ -718,313 +1313,329 @@ CF_INLINE bool is_file(const char *filename)
return false;
}
-static CURLcode
-sectransp_set_ssl_version_min_max(struct Curl_easy *data,
- struct st_ssl_backend_data *backend,
- struct ssl_primary_config *conn_config)
-{
#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
- OSStatus err;
- SSLProtocol ver_min;
- SSLProtocol ver_max;
-
-#if CURL_SUPPORT_MAC_10_7
- if(!&SSLSetProtocolVersionMax)
- goto legacy;
-#endif
-
- switch(conn_config->version) {
- case CURL_SSLVERSION_DEFAULT:
- case CURL_SSLVERSION_TLSv1:
+static CURLcode sectransp_version_from_curl(SSLProtocol *darwinver,
+ long ssl_version)
+{
+ switch(ssl_version) {
case CURL_SSLVERSION_TLSv1_0:
- ver_min = kTLSProtocol1;
- break;
+ *darwinver = kTLSProtocol1;
+ return CURLE_OK;
case CURL_SSLVERSION_TLSv1_1:
- ver_min = kTLSProtocol11;
- break;
+ *darwinver = kTLSProtocol11;
+ return CURLE_OK;
case CURL_SSLVERSION_TLSv1_2:
- ver_min = kTLSProtocol12;
- break;
+ *darwinver = kTLSProtocol12;
+ return CURLE_OK;
case CURL_SSLVERSION_TLSv1_3:
- default:
- failf(data, "SSL: unsupported minimum TLS version value");
- return CURLE_SSL_CONNECT_ERROR;
- }
-
- switch(conn_config->version_max) {
- case CURL_SSLVERSION_MAX_DEFAULT:
- case CURL_SSLVERSION_MAX_NONE:
- case CURL_SSLVERSION_MAX_TLSv1_3:
- case CURL_SSLVERSION_MAX_TLSv1_2:
- ver_max = kTLSProtocol12;
- break;
- case CURL_SSLVERSION_MAX_TLSv1_1:
- ver_max = kTLSProtocol11;
- break;
- case CURL_SSLVERSION_MAX_TLSv1_0:
- ver_max = kTLSProtocol1;
+ /* TLS 1.3 support first appeared in iOS 11 and macOS 10.13 */
+#if (CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) && HAVE_BUILTIN_AVAILABLE == 1
+ if(__builtin_available(macOS 10.13, iOS 11.0, *)) {
+ *darwinver = kTLSProtocol13;
+ return CURLE_OK;
+ }
+#endif /* (CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) &&
+ HAVE_BUILTIN_AVAILABLE == 1 */
break;
- default:
- failf(data, "SSL: unsupported maximum TLS version value");
- return CURLE_SSL_CONNECT_ERROR;
}
+ return CURLE_SSL_CONNECT_ERROR;
+}
+#endif
- err = SSLSetProtocolVersionMin(backend->ssl_ctx, ver_min);
- if(err != noErr) {
- failf(data, "SSL: failed to set minimum TLS version");
- return CURLE_SSL_CONNECT_ERROR;
+static CURLcode set_ssl_version_min_max(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
+{
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct st_ssl_backend_data *backend =
+ (struct st_ssl_backend_data *)connssl->backend;
+ struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+ long ssl_version = conn_config->version;
+ long ssl_version_max = conn_config->version_max;
+ long max_supported_version_by_os;
+
+ DEBUGASSERT(backend);
+
+ /* macOS 10.5-10.7 supported TLS 1.0 only.
+ macOS 10.8 and later, and iOS 5 and later, added TLS 1.1 and 1.2.
+ macOS 10.13 and later, and iOS 11 and later, added TLS 1.3. */
+#if (CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) && HAVE_BUILTIN_AVAILABLE == 1
+ if(__builtin_available(macOS 10.13, iOS 11.0, *)) {
+ max_supported_version_by_os = CURL_SSLVERSION_MAX_TLSv1_3;
}
- err = SSLSetProtocolVersionMax(backend->ssl_ctx, ver_max);
- if(err != noErr) {
- failf(data, "SSL: failed to set maximum TLS version");
- return CURLE_SSL_CONNECT_ERROR;
+ else {
+ max_supported_version_by_os = CURL_SSLVERSION_MAX_TLSv1_2;
}
+#else
+ max_supported_version_by_os = CURL_SSLVERSION_MAX_TLSv1_2;
+#endif /* (CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) &&
+ HAVE_BUILTIN_AVAILABLE == 1 */
- return CURLE_OK;
-#endif
-#if CURL_SUPPORT_MAC_10_7
- goto legacy;
-legacy:
- switch(conn_config->version) {
+ switch(ssl_version) {
case CURL_SSLVERSION_DEFAULT:
case CURL_SSLVERSION_TLSv1:
- case CURL_SSLVERSION_TLSv1_0:
+ ssl_version = CURL_SSLVERSION_TLSv1_0;
break;
- default:
- failf(data, "SSL: unsupported minimum TLS version value");
- return CURLE_SSL_CONNECT_ERROR;
}
- /* only TLS 1.0 is supported, disable SSL 3.0 and SSL 2.0 */
- SSLSetProtocolVersionEnabled(backend->ssl_ctx, kSSLProtocolAll, false);
- SSLSetProtocolVersionEnabled(backend->ssl_ctx, kTLSProtocol1, true);
+ switch(ssl_version_max) {
+ case CURL_SSLVERSION_MAX_NONE:
+ case CURL_SSLVERSION_MAX_DEFAULT:
+ ssl_version_max = max_supported_version_by_os;
+ break;
+ }
- return CURLE_OK;
-#endif
-}
+#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
+ if(SSLSetProtocolVersionMax) {
+ SSLProtocol darwin_ver_min = kTLSProtocol1;
+ SSLProtocol darwin_ver_max = kTLSProtocol1;
+ CURLcode result = sectransp_version_from_curl(&darwin_ver_min,
+ ssl_version);
+ if(result) {
+ failf(data, "unsupported min version passed via CURLOPT_SSLVERSION");
+ return result;
+ }
+ result = sectransp_version_from_curl(&darwin_ver_max,
+ ssl_version_max >> 16);
+ if(result) {
+ failf(data, "unsupported max version passed via CURLOPT_SSLVERSION");
+ return result;
+ }
-static int sectransp_cipher_suite_get_str(uint16_t id, char *buf,
- size_t buf_size, bool prefer_rfc)
-{
- /* are these fortezza suites even supported ? */
- if(id == SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA)
- msnprintf(buf, buf_size, "%s", "SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA");
- else if(id == SSL_FORTEZZA_DMS_WITH_NULL_SHA)
- msnprintf(buf, buf_size, "%s", "SSL_FORTEZZA_DMS_WITH_NULL_SHA");
- /* can TLS_EMPTY_RENEGOTIATION_INFO_SCSV even be set ? */
- else if(id == TLS_EMPTY_RENEGOTIATION_INFO_SCSV)
- msnprintf(buf, buf_size, "%s", "TLS_EMPTY_RENEGOTIATION_INFO_SCSV");
- /* do we still need to support these SSL2-only ciphers ? */
- else if(id == SSL_RSA_WITH_RC2_CBC_MD5)
- msnprintf(buf, buf_size, "%s", "SSL_RSA_WITH_RC2_CBC_MD5");
- else if(id == SSL_RSA_WITH_IDEA_CBC_MD5)
- msnprintf(buf, buf_size, "%s", "SSL_RSA_WITH_IDEA_CBC_MD5");
- else if(id == SSL_RSA_WITH_DES_CBC_MD5)
- msnprintf(buf, buf_size, "%s", "SSL_RSA_WITH_DES_CBC_MD5");
- else if(id == SSL_RSA_WITH_3DES_EDE_CBC_MD5)
- msnprintf(buf, buf_size, "%s", "SSL_RSA_WITH_3DES_EDE_CBC_MD5");
- else
- return Curl_cipher_suite_get_str(id, buf, buf_size, prefer_rfc);
- return 0;
+ (void)SSLSetProtocolVersionMin(backend->ssl_ctx, darwin_ver_min);
+ (void)SSLSetProtocolVersionMax(backend->ssl_ctx, darwin_ver_max);
+ return result;
+ }
+ else {
+#if CURL_SUPPORT_MAC_10_8
+ long i = ssl_version;
+ (void)SSLSetProtocolVersionEnabled(backend->ssl_ctx,
+ kSSLProtocolAll,
+ false);
+ for(; i <= (ssl_version_max >> 16); i++) {
+ switch(i) {
+ case CURL_SSLVERSION_TLSv1_0:
+ (void)SSLSetProtocolVersionEnabled(backend->ssl_ctx,
+ kTLSProtocol1,
+ true);
+ break;
+ case CURL_SSLVERSION_TLSv1_1:
+ (void)SSLSetProtocolVersionEnabled(backend->ssl_ctx,
+ kTLSProtocol11,
+ true);
+ break;
+ case CURL_SSLVERSION_TLSv1_2:
+ (void)SSLSetProtocolVersionEnabled(backend->ssl_ctx,
+ kTLSProtocol12,
+ true);
+ break;
+ case CURL_SSLVERSION_TLSv1_3:
+ failf(data, "Your version of the OS does not support TLSv1.3");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ }
+ return CURLE_OK;
+#endif /* CURL_SUPPORT_MAC_10_8 */
+ }
+#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */
+ failf(data, "Secure Transport: cannot set SSL protocol");
+ return CURLE_SSL_CONNECT_ERROR;
}
-static uint16_t sectransp_cipher_suite_walk_str(const char **str,
- const char **end)
+static bool is_cipher_suite_strong(SSLCipherSuite suite_num)
{
- uint16_t id = Curl_cipher_suite_walk_str(str, end);
- size_t len = *end - *str;
-
- if(!id) {
- /* are these fortezza suites even supported ? */
- if(strncasecompare("SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA", *str, len))
- id = SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA;
- else if(strncasecompare("SSL_FORTEZZA_DMS_WITH_NULL_SHA", *str, len))
- id = SSL_FORTEZZA_DMS_WITH_NULL_SHA;
- /* can TLS_EMPTY_RENEGOTIATION_INFO_SCSV even be set ? */
- else if(strncasecompare("TLS_EMPTY_RENEGOTIATION_INFO_SCSV", *str, len))
- id = TLS_EMPTY_RENEGOTIATION_INFO_SCSV;
- /* do we still need to support these SSL2-only ciphers ? */
- else if(strncasecompare("SSL_RSA_WITH_RC2_CBC_MD5", *str, len))
- id = SSL_RSA_WITH_RC2_CBC_MD5;
- else if(strncasecompare("SSL_RSA_WITH_IDEA_CBC_MD5", *str, len))
- id = SSL_RSA_WITH_IDEA_CBC_MD5;
- else if(strncasecompare("SSL_RSA_WITH_DES_CBC_MD5", *str, len))
- id = SSL_RSA_WITH_DES_CBC_MD5;
- else if(strncasecompare("SSL_RSA_WITH_3DES_EDE_CBC_MD5", *str, len))
- id = SSL_RSA_WITH_3DES_EDE_CBC_MD5;
- }
- return id;
+ size_t i;
+ for(i = 0; i < NUM_OF_CIPHERS; ++i) {
+ if(ciphertable[i].num == suite_num) {
+ return !ciphertable[i].weak;
+ }
+ }
+ /* If the cipher is not in our list, assume it is a new one
+ and therefore strong. Previous implementation was the same,
+ if cipher suite is not in the list, it was considered strong enough */
+ return true;
}
-/* allocated memory must be freed */
-static SSLCipherSuite * sectransp_get_supported_ciphers(SSLContextRef ssl_ctx,
- size_t *len)
+static bool is_separator(char c)
{
- SSLCipherSuite *ciphers = NULL;
- OSStatus err = noErr;
- *len = 0;
-
- err = SSLGetNumberSupportedCiphers(ssl_ctx, len);
- if(err != noErr)
- goto failed;
-
- ciphers = malloc(*len * sizeof(SSLCipherSuite));
- if(!ciphers)
- goto failed;
-
- err = SSLGetSupportedCiphers(ssl_ctx, ciphers, len);
- if(err != noErr)
- goto failed;
-
-#if CURL_BUILD_MAC
- {
- int maj = 0, min = 0;
- GetDarwinVersionNumber(&maj, &min);
- /* There is a known bug in early versions of Mountain Lion where ST's ECC
- ciphers (cipher suite 0xC001 through 0xC032) simply do not work.
- Work around the problem here by disabling those ciphers if we are
- running in an affected version of macOS. */
- if(maj == 12 && min <= 3) {
- size_t i = 0, j = 0;
- for(; i < *len; i++) {
- if(ciphers[i] >= 0xC001 && ciphers[i] <= 0xC032)
- continue;
- ciphers[j++] = ciphers[i];
- }
- *len = j;
- }
+ /* Return whether character is a cipher list separator. */
+ switch(c) {
+ case ' ':
+ case '\t':
+ case ':':
+ case ',':
+ case ';':
+ return true;
}
-#endif
-
- return ciphers;
-failed:
- *len = 0;
- Curl_safefree(ciphers);
- return NULL;
+ return false;
}
static CURLcode sectransp_set_default_ciphers(struct Curl_easy *data,
SSLContextRef ssl_ctx)
{
- CURLcode ret = CURLE_SSL_CIPHER;
- size_t count = 0, i, j;
- OSStatus err;
- size_t supported_len;
- SSLCipherSuite *ciphers = NULL;
+ size_t all_ciphers_count = 0UL, allowed_ciphers_count = 0UL, i;
+ SSLCipherSuite *all_ciphers = NULL, *allowed_ciphers = NULL;
+ OSStatus err = noErr;
- ciphers = sectransp_get_supported_ciphers(ssl_ctx, &supported_len);
- if(!ciphers) {
- failf(data, "SSL: Failed to get supported ciphers");
- goto failed;
- }
+#if CURL_BUILD_MAC
+ int darwinver_maj = 0, darwinver_min = 0;
- /* Intersect the ciphers supported by Secure Transport with the default
- * ciphers, using the order of the former. */
- for(i = 0; i < supported_len; i++) {
- for(j = 0; j < DEFAULT_CIPHERS_LEN; j++) {
- if(default_ciphers[j] == ciphers[i]) {
- ciphers[count++] = ciphers[i];
- break;
- }
- }
- }
+ GetDarwinVersionNumber(&darwinver_maj, &darwinver_min);
+#endif /* CURL_BUILD_MAC */
- if(count == 0) {
- failf(data, "SSL: no supported default ciphers");
- goto failed;
+ /* Disable cipher suites that ST supports but are not safe. These ciphers
+ are unlikely to be used in any case since ST gives other ciphers a much
+ higher priority, but it's probably better that we not connect at all than
+ to give the user a false sense of security if the server only supports
+ insecure ciphers. (Note: We don't care about SSLv2-only ciphers.) */
+ err = SSLGetNumberSupportedCiphers(ssl_ctx, &all_ciphers_count);
+ if(err != noErr) {
+ failf(data, "SSL: SSLGetNumberSupportedCiphers() failed: OSStatus %d",
+ err);
+ return CURLE_SSL_CIPHER;
}
-
- err = SSLSetEnabledCiphers(ssl_ctx, ciphers, count);
+ all_ciphers = malloc(all_ciphers_count*sizeof(SSLCipherSuite));
+ if(!all_ciphers) {
+ failf(data, "SSL: Failed to allocate memory for all ciphers");
+ return CURLE_OUT_OF_MEMORY;
+ }
+ allowed_ciphers = malloc(all_ciphers_count*sizeof(SSLCipherSuite));
+ if(!allowed_ciphers) {
+ Curl_safefree(all_ciphers);
+ failf(data, "SSL: Failed to allocate memory for allowed ciphers");
+ return CURLE_OUT_OF_MEMORY;
+ }
+ err = SSLGetSupportedCiphers(ssl_ctx, all_ciphers,
+ &all_ciphers_count);
+ if(err != noErr) {
+ Curl_safefree(all_ciphers);
+ Curl_safefree(allowed_ciphers);
+ return CURLE_SSL_CIPHER;
+ }
+ for(i = 0UL ; i < all_ciphers_count ; i++) {
+#if CURL_BUILD_MAC
+ /* There's a known bug in early versions of Mountain Lion where ST's ECC
+ ciphers (cipher suite 0xC001 through 0xC032) simply do not work.
+ Work around the problem here by disabling those ciphers if we are
+ running in an affected version of OS X. */
+ if(darwinver_maj == 12 && darwinver_min <= 3 &&
+ all_ciphers[i] >= 0xC001 && all_ciphers[i] <= 0xC032) {
+ continue;
+ }
+#endif /* CURL_BUILD_MAC */
+ if(is_cipher_suite_strong(all_ciphers[i])) {
+ allowed_ciphers[allowed_ciphers_count++] = all_ciphers[i];
+ }
+ }
+ err = SSLSetEnabledCiphers(ssl_ctx, allowed_ciphers,
+ allowed_ciphers_count);
+ Curl_safefree(all_ciphers);
+ Curl_safefree(allowed_ciphers);
if(err != noErr) {
failf(data, "SSL: SSLSetEnabledCiphers() failed: OSStatus %d", err);
- goto failed;
+ return CURLE_SSL_CIPHER;
}
-
- ret = CURLE_OK;
-failed:
- Curl_safefree(ciphers);
- return ret;
+ return CURLE_OK;
}
static CURLcode sectransp_set_selected_ciphers(struct Curl_easy *data,
SSLContextRef ssl_ctx,
const char *ciphers)
{
- CURLcode ret = CURLE_SSL_CIPHER;
- size_t count = 0, i;
- const char *ptr, *end;
- OSStatus err;
- size_t supported_len;
- SSLCipherSuite *supported = NULL;
- SSLCipherSuite *selected = NULL;
-
- supported = sectransp_get_supported_ciphers(ssl_ctx, &supported_len);
- if(!supported) {
- failf(data, "SSL: Failed to get supported ciphers");
- goto failed;
- }
+ size_t ciphers_count = 0;
+ const char *cipher_start = ciphers;
+ OSStatus err = noErr;
+ SSLCipherSuite selected_ciphers[NUM_OF_CIPHERS];
- selected = malloc(supported_len * sizeof(SSLCipherSuite));
- if(!selected) {
- failf(data, "SSL: Failed to allocate memory");
- goto failed;
- }
+ if(!ciphers)
+ return CURLE_OK;
- for(ptr = ciphers; ptr[0] != '\0' && count < supported_len; ptr = end) {
- uint16_t id = sectransp_cipher_suite_walk_str(&ptr, &end);
+ while(is_separator(*ciphers)) /* Skip initial separators. */
+ ciphers++;
+ if(!*ciphers)
+ return CURLE_OK;
- /* Check if cipher is supported */
- if(id) {
- for(i = 0; i < supported_len && supported[i] != id; i++);
- if(i == supported_len)
- id = 0;
+ cipher_start = ciphers;
+ while(*cipher_start && ciphers_count < NUM_OF_CIPHERS) {
+ bool cipher_found = FALSE;
+ size_t cipher_len = 0;
+ const char *cipher_end = NULL;
+ bool tls_name = FALSE;
+ size_t i;
+
+ /* Skip separators */
+ while(is_separator(*cipher_start))
+ cipher_start++;
+ if(*cipher_start == '\0') {
+ break;
}
- if(!id) {
- if(ptr[0] != '\0')
- infof(data, "SSL: unknown cipher in list: \"%.*s\"", (int) (end - ptr),
- ptr);
- continue;
+ /* Find last position of a cipher in the ciphers string */
+ cipher_end = cipher_start;
+ while(*cipher_end != '\0' && !is_separator(*cipher_end)) {
+ ++cipher_end;
}
- /* No duplicates allowed (so selected cannot overflow) */
- for(i = 0; i < count && selected[i] != id; i++);
- if(i < count) {
- infof(data, "SSL: duplicate cipher in list: \"%.*s\"", (int) (end - ptr),
- ptr);
- continue;
+ /* IANA cipher names start with the TLS_ or SSL_ prefix.
+ If the 4th symbol of the cipher is '_' we look for a cipher in the
+ table by its (TLS) name.
+ Otherwise, we try to match cipher by an alias. */
+ if(cipher_start[3] == '_') {
+ tls_name = TRUE;
+ }
+ /* Iterate through the cipher table and look for the cipher, starting
+ the cipher number 0x01 because the 0x00 is not the real cipher */
+ cipher_len = cipher_end - cipher_start;
+ for(i = 1; i < NUM_OF_CIPHERS; ++i) {
+ const char *table_cipher_name = NULL;
+ if(tls_name) {
+ table_cipher_name = ciphertable[i].name;
+ }
+ else if(ciphertable[i].alias_name) {
+ table_cipher_name = ciphertable[i].alias_name;
+ }
+ else {
+ continue;
+ }
+ /* Compare a part of the string between separators with a cipher name
+ in the table and make sure we matched the whole cipher name */
+ if(strncmp(cipher_start, table_cipher_name, cipher_len) == 0
+ && table_cipher_name[cipher_len] == '\0') {
+ selected_ciphers[ciphers_count] = ciphertable[i].num;
+ ++ciphers_count;
+ cipher_found = TRUE;
+ break;
+ }
+ }
+ if(!cipher_found) {
+ /* It would be more human-readable if we print the wrong cipher name
+ but we don't want to allocate any additional memory and copy the name
+ into it, then add it into logs.
+ Also, we do not modify an original cipher list string. We just point
+ to positions where cipher starts and ends in the cipher list string.
+ The message is a bit cryptic and longer than necessary but can be
+ understood by humans. */
+ failf(data, "SSL: cipher string \"%s\" contains unsupported cipher name"
+ " starting position %zd and ending position %zd",
+ ciphers,
+ cipher_start - ciphers,
+ cipher_end - ciphers);
+ return CURLE_SSL_CIPHER;
+ }
+ if(*cipher_end) {
+ cipher_start = cipher_end + 1;
+ }
+ else {
+ break;
}
-
- selected[count++] = id;
- }
-
- if(count == 0) {
- failf(data, "SSL: no supported cipher in list");
- goto failed;
}
+ /* All cipher suites in the list are found. Report to logs as-is */
+ infof(data, "SSL: Setting cipher suites list \"%s\"", ciphers);
- err = SSLSetEnabledCiphers(ssl_ctx, selected, count);
+ err = SSLSetEnabledCiphers(ssl_ctx, selected_ciphers, ciphers_count);
if(err != noErr) {
failf(data, "SSL: SSLSetEnabledCiphers() failed: OSStatus %d", err);
- goto failed;
+ return CURLE_SSL_CIPHER;
}
-
- ret = CURLE_OK;
-failed:
- Curl_safefree(supported);
- Curl_safefree(selected);
- return ret;
-}
-
-static void sectransp_session_free(void *sessionid, size_t idsize)
-{
- /* ST, as of iOS 5 and Mountain Lion, has no public method of deleting a
- cached session ID inside the Security framework. There is a private
- function that does this, but I do not want to have to explain to you why I
- got your application rejected from the App Store due to the use of a
- private API, so the best we can do is free up our own char array that we
- created way back in sectransp_connect_step1... */
- (void)idsize;
- Curl_safefree(sessionid);
+ return CURLE_OK;
}
static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf,
@@ -1044,7 +1655,6 @@ static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf,
const struct curl_blob *ssl_cert_blob = ssl_config->primary.cert_blob;
char *ciphers;
OSStatus err = noErr;
- CURLcode result;
#if CURL_BUILD_MAC
int darwinver_maj = 0, darwinver_min = 0;
@@ -1055,23 +1665,23 @@ static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf,
#endif /* CURL_BUILD_MAC */
#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
- if(&SSLCreateContext) { /* use the newer API if available */
+ if(SSLCreateContext) { /* use the newer API if available */
if(backend->ssl_ctx)
CFRelease(backend->ssl_ctx);
backend->ssl_ctx = SSLCreateContext(NULL, kSSLClientSide, kSSLStreamType);
if(!backend->ssl_ctx) {
- failf(data, "SSL: could not create a context");
+ failf(data, "SSL: couldn't create a context");
return CURLE_OUT_OF_MEMORY;
}
}
else {
- /* The old ST API does not exist under iOS, so do not compile it: */
+ /* The old ST API does not exist under iOS, so don't compile it: */
#if CURL_SUPPORT_MAC_10_8
if(backend->ssl_ctx)
(void)SSLDisposeContext(backend->ssl_ctx);
err = SSLNewContext(false, &(backend->ssl_ctx));
if(err != noErr) {
- failf(data, "SSL: could not create a context: OSStatus %d", err);
+ failf(data, "SSL: couldn't create a context: OSStatus %d", err);
return CURLE_OUT_OF_MEMORY;
}
#endif /* CURL_SUPPORT_MAC_10_8 */
@@ -1081,18 +1691,123 @@ static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf,
(void)SSLDisposeContext(backend->ssl_ctx);
err = SSLNewContext(false, &(backend->ssl_ctx));
if(err != noErr) {
- failf(data, "SSL: could not create a context: OSStatus %d", err);
+ failf(data, "SSL: couldn't create a context: OSStatus %d", err);
return CURLE_OUT_OF_MEMORY;
}
#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */
backend->ssl_write_buffered_length = 0UL; /* reset buffered write length */
- result = sectransp_set_ssl_version_min_max(data, backend, conn_config);
- if(result != CURLE_OK)
- return result;
+ /* check to see if we've been told to use an explicit SSL/TLS version */
+#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
+ if(SSLSetProtocolVersionMax) {
+ switch(conn_config->version) {
+ case CURL_SSLVERSION_TLSv1:
+ (void)SSLSetProtocolVersionMin(backend->ssl_ctx, kTLSProtocol1);
+#if (CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) && HAVE_BUILTIN_AVAILABLE == 1
+ if(__builtin_available(macOS 10.13, iOS 11.0, *)) {
+ (void)SSLSetProtocolVersionMax(backend->ssl_ctx, kTLSProtocol13);
+ }
+ else {
+ (void)SSLSetProtocolVersionMax(backend->ssl_ctx, kTLSProtocol12);
+ }
+#else
+ (void)SSLSetProtocolVersionMax(backend->ssl_ctx, kTLSProtocol12);
+#endif /* (CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) &&
+ HAVE_BUILTIN_AVAILABLE == 1 */
+ break;
+ case CURL_SSLVERSION_DEFAULT:
+ case CURL_SSLVERSION_TLSv1_0:
+ case CURL_SSLVERSION_TLSv1_1:
+ case CURL_SSLVERSION_TLSv1_2:
+ case CURL_SSLVERSION_TLSv1_3:
+ {
+ CURLcode result = set_ssl_version_min_max(cf, data);
+ if(result != CURLE_OK)
+ return result;
+ break;
+ }
+ case CURL_SSLVERSION_SSLv3:
+ case CURL_SSLVERSION_SSLv2:
+ failf(data, "SSL versions not supported");
+ return CURLE_NOT_BUILT_IN;
+ default:
+ failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ }
+ else {
+#if CURL_SUPPORT_MAC_10_8
+ (void)SSLSetProtocolVersionEnabled(backend->ssl_ctx,
+ kSSLProtocolAll,
+ false);
+ switch(conn_config->version) {
+ case CURL_SSLVERSION_DEFAULT:
+ case CURL_SSLVERSION_TLSv1:
+ (void)SSLSetProtocolVersionEnabled(backend->ssl_ctx,
+ kTLSProtocol1,
+ true);
+ (void)SSLSetProtocolVersionEnabled(backend->ssl_ctx,
+ kTLSProtocol11,
+ true);
+ (void)SSLSetProtocolVersionEnabled(backend->ssl_ctx,
+ kTLSProtocol12,
+ true);
+ break;
+ case CURL_SSLVERSION_TLSv1_0:
+ case CURL_SSLVERSION_TLSv1_1:
+ case CURL_SSLVERSION_TLSv1_2:
+ case CURL_SSLVERSION_TLSv1_3:
+ {
+ CURLcode result = set_ssl_version_min_max(cf, data);
+ if(result != CURLE_OK)
+ return result;
+ break;
+ }
+ case CURL_SSLVERSION_SSLv3:
+ case CURL_SSLVERSION_SSLv2:
+ failf(data, "SSL versions not supported");
+ return CURLE_NOT_BUILT_IN;
+ default:
+ failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+#endif /* CURL_SUPPORT_MAC_10_8 */
+ }
+#else
+ if(conn_config->version_max != CURL_SSLVERSION_MAX_NONE) {
+ failf(data, "Your version of the OS does not support to set maximum"
+ " SSL/TLS version");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ (void)SSLSetProtocolVersionEnabled(backend->ssl_ctx, kSSLProtocolAll, false);
+ switch(conn_config->version) {
+ case CURL_SSLVERSION_DEFAULT:
+ case CURL_SSLVERSION_TLSv1:
+ case CURL_SSLVERSION_TLSv1_0:
+ (void)SSLSetProtocolVersionEnabled(backend->ssl_ctx,
+ kTLSProtocol1,
+ true);
+ break;
+ case CURL_SSLVERSION_TLSv1_1:
+ failf(data, "Your version of the OS does not support TLSv1.1");
+ return CURLE_SSL_CONNECT_ERROR;
+ case CURL_SSLVERSION_TLSv1_2:
+ failf(data, "Your version of the OS does not support TLSv1.2");
+ return CURLE_SSL_CONNECT_ERROR;
+ case CURL_SSLVERSION_TLSv1_3:
+ failf(data, "Your version of the OS does not support TLSv1.3");
+ return CURLE_SSL_CONNECT_ERROR;
+ case CURL_SSLVERSION_SSLv2:
+ case CURL_SSLVERSION_SSLv3:
+ failf(data, "SSL versions not supported");
+ return CURLE_NOT_BUILT_IN;
+ default:
+ failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */
-#if (CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) && \
- defined(HAVE_BUILTIN_AVAILABLE)
+#if (CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) && HAVE_BUILTIN_AVAILABLE == 1
if(connssl->alpn) {
if(__builtin_available(macOS 10.13.4, iOS 11, tvOS 11, *)) {
struct alpn_proto_buf proto;
@@ -1161,7 +1876,7 @@ static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf,
err = SecIdentityCopyCertificate(cert_and_key, &cert);
if(err == noErr) {
char *certp;
- result = CopyCertSubject(data, cert, &certp);
+ CURLcode result = CopyCertSubject(data, cert, &certp);
if(!result) {
infof(data, "Client certificate: %s", certp);
free(certp);
@@ -1204,11 +1919,11 @@ static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf,
cert_showfilename_error);
break;
case errSecItemNotFound:
- failf(data, "SSL: cannot find the certificate \"%s\" and its private "
+ failf(data, "SSL: Can't find the certificate \"%s\" and its private "
"key in the Keychain.", cert_showfilename_error);
break;
default:
- failf(data, "SSL: cannot load the certificate \"%s\" and its private "
+ failf(data, "SSL: Can't load the certificate \"%s\" and its private "
"key: OSStatus %d", cert_showfilename_error, err);
break;
}
@@ -1223,7 +1938,7 @@ static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf,
#if CURL_BUILD_MAC_10_6 || CURL_BUILD_IOS
/* Snow Leopard introduced the SSLSetSessionOption() function, but due to
a library bug with the way the kSSLSessionOptionBreakOnServerAuth flag
- works, it does not work as expected under Snow Leopard, Lion or
+ works, it doesn't work as expected under Snow Leopard, Lion or
Mountain Lion.
So we need to call SSLSetEnableCertVerify() on those older cats in order
to disable certificate validation if the user turned that off.
@@ -1237,9 +1952,9 @@ static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf,
Darwin 15.x.x is El Capitan (10.11)
*/
#if CURL_BUILD_MAC
- if(&SSLSetSessionOption && darwinver_maj >= 13) {
+ if(SSLSetSessionOption && darwinver_maj >= 13) {
#else
- if(&SSLSetSessionOption) {
+ if(SSLSetSessionOption) {
#endif /* CURL_BUILD_MAC */
bool break_on_auth = !conn_config->verifypeer ||
ssl_cafile || ssl_cablob;
@@ -1275,7 +1990,7 @@ static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf,
bool is_cert_file = (!is_cert_data) && is_file(ssl_cafile);
if(!(is_cert_file || is_cert_data)) {
- failf(data, "SSL: cannot load CA certificate file %s",
+ failf(data, "SSL: can't load CA certificate file %s",
ssl_cafile ? ssl_cafile : "(blob memory)");
return CURLE_SSL_CACERT_BADFILE;
}
@@ -1295,7 +2010,7 @@ static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf,
return CURLE_SSL_CONNECT_ERROR;
}
- if(connssl->peer.type != CURL_SSL_PEER_DNS) {
+ if(connssl->peer.is_ip_address) {
infof(data, "WARNING: using IP address, SNI is being disabled by "
"the OS.");
}
@@ -1306,21 +2021,21 @@ static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf,
ciphers = conn_config->cipher_list;
if(ciphers) {
- result = sectransp_set_selected_ciphers(data, backend->ssl_ctx, ciphers);
+ err = sectransp_set_selected_ciphers(data, backend->ssl_ctx, ciphers);
}
else {
- result = sectransp_set_default_ciphers(data, backend->ssl_ctx);
+ err = sectransp_set_default_ciphers(data, backend->ssl_ctx);
}
- if(result != CURLE_OK) {
+ if(err != noErr) {
failf(data, "SSL: Unable to set ciphers for SSL/TLS handshake. "
- "Error code: %d", (int)result);
+ "Error code: %d", err);
return CURLE_SSL_CIPHER;
}
#if CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7
/* We want to enable 1/n-1 when using a CBC cipher unless the user
- specifically does not want us doing that: */
- if(&SSLSetSessionOption) {
+ specifically doesn't want us doing that: */
+ if(SSLSetSessionOption) {
SSLSetSessionOption(backend->ssl_ctx, kSSLSessionOptionSendOneByteRecord,
!ssl_config->enable_beast);
SSLSetSessionOption(backend->ssl_ctx, kSSLSessionOptionFalseStart,
@@ -1328,14 +2043,14 @@ static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf,
}
#endif /* CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 */
- /* Check if there is a cached ID we can/should use here! */
- if(ssl_config->primary.cache_session) {
+ /* Check if there's a cached ID we can/should use here! */
+ if(ssl_config->primary.sessionid) {
char *ssl_sessionid;
size_t ssl_sessionid_len;
Curl_ssl_sessionid_lock(data);
- if(!Curl_ssl_getsessionid(cf, data, &connssl->peer,
- (void **)&ssl_sessionid, &ssl_sessionid_len)) {
+ if(!Curl_ssl_getsessionid(cf, data, (void **)&ssl_sessionid,
+ &ssl_sessionid_len)) {
/* we got a session id, use it! */
err = SSLSetPeerID(backend->ssl_ctx, ssl_sessionid, ssl_sessionid_len);
Curl_ssl_sessionid_unlock(data);
@@ -1346,14 +2061,15 @@ static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf,
/* Informational message */
infof(data, "SSL reusing session ID");
}
- /* If there is not one, then let's make one up! This has to be done prior
+ /* If there isn't one, then let's make one up! This has to be done prior
to starting the handshake. */
else {
+ CURLcode result;
ssl_sessionid =
aprintf("%s:%d:%d:%s:%d",
ssl_cafile ? ssl_cafile : "(blob memory)",
verifypeer, conn_config->verifyhost, connssl->peer.hostname,
- connssl->peer.port);
+ connssl->port);
ssl_sessionid_len = strlen(ssl_sessionid);
err = SSLSetPeerID(backend->ssl_ctx, ssl_sessionid, ssl_sessionid_len);
@@ -1363,12 +2079,13 @@ static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf,
return CURLE_SSL_CONNECT_ERROR;
}
- result = Curl_ssl_set_sessionid(cf, data, &connssl->peer, ssl_sessionid,
- ssl_sessionid_len,
- sectransp_session_free);
+ result = Curl_ssl_addsessionid(cf, data, ssl_sessionid,
+ ssl_sessionid_len, NULL);
Curl_ssl_sessionid_unlock(data);
- if(result)
+ if(result) {
+ failf(data, "failed to store ssl session");
return result;
+ }
}
}
@@ -1395,7 +2112,7 @@ static long pem_to_der(const char *in, unsigned char **out, size_t *outlen)
char *sep_start, *sep_end, *cert_start, *cert_end;
size_t i, j, err;
size_t len;
- char *b64;
+ unsigned char *b64;
/* Jump through the separators at the beginning of the certificate. */
sep_start = strstr(in, "-----");
@@ -1476,16 +2193,16 @@ static int read_cert(const char *file, unsigned char **out, size_t *outlen)
return 0;
}
-static CURLcode append_cert_to_array(struct Curl_easy *data,
- const unsigned char *buf, size_t buflen,
- CFMutableArrayRef array)
+static int append_cert_to_array(struct Curl_easy *data,
+ const unsigned char *buf, size_t buflen,
+ CFMutableArrayRef array)
{
char *certp;
CURLcode result;
SecCertificateRef cacert;
CFDataRef certdata;
- certdata = CFDataCreate(kCFAllocatorDefault, buf, (CFIndex)buflen);
+ certdata = CFDataCreate(kCFAllocatorDefault, buf, buflen);
if(!certdata) {
failf(data, "SSL: failed to allocate array for CA certificate");
return CURLE_OUT_OF_MEMORY;
@@ -1522,8 +2239,7 @@ static CURLcode verify_cert_buf(struct Curl_cfilter *cf,
const unsigned char *certbuf, size_t buflen,
SSLContextRef ctx)
{
- int n = 0;
- CURLcode rc;
+ int n = 0, rc;
long res;
unsigned char *der;
size_t derlen, offset = 0;
@@ -1653,15 +2369,19 @@ static CURLcode verify_cert(struct Curl_cfilter *cf,
const struct curl_blob *ca_info_blob,
SSLContextRef ctx)
{
- CURLcode result;
+ int result;
unsigned char *certbuf;
size_t buflen;
- bool free_certbuf = FALSE;
if(ca_info_blob) {
CURL_TRC_CF(data, cf, "verify_peer, CA from config blob");
- certbuf = ca_info_blob->data;
+ certbuf = (unsigned char *)malloc(ca_info_blob->len + 1);
+ if(!certbuf) {
+ return CURLE_OUT_OF_MEMORY;
+ }
buflen = ca_info_blob->len;
+ memcpy(certbuf, ca_info_blob->data, ca_info_blob->len);
+ certbuf[ca_info_blob->len]='\0';
}
else if(cafile) {
CURL_TRC_CF(data, cf, "verify_peer, CA from file '%s'", cafile);
@@ -1669,14 +2389,12 @@ static CURLcode verify_cert(struct Curl_cfilter *cf,
failf(data, "SSL: failed to read or invalid CA certificate");
return CURLE_SSL_CACERT_BADFILE;
}
- free_certbuf = TRUE;
}
else
return CURLE_SSL_CACERT_BADFILE;
result = verify_cert_buf(cf, data, certbuf, buflen, ctx);
- if(free_certbuf)
- free(certbuf);
+ free(certbuf);
return result;
}
@@ -1694,7 +2412,7 @@ static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data,
/* Result is returned to caller */
CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
- /* if a path was not specified, do not pin */
+ /* if a path wasn't specified, don't pin */
if(!pinnedpubkey)
return CURLE_OK;
@@ -1726,17 +2444,17 @@ static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data,
#elif SECTRANSP_PINNEDPUBKEY_V2
{
- OSStatus success;
- success = SecItemExport(keyRef, kSecFormatOpenSSL, 0, NULL,
- &publicKeyBits);
- CFRelease(keyRef);
- if(success != errSecSuccess || !publicKeyBits)
- break;
+ OSStatus success;
+ success = SecItemExport(keyRef, kSecFormatOpenSSL, 0, NULL,
+ &publicKeyBits);
+ CFRelease(keyRef);
+ if(success != errSecSuccess || !publicKeyBits)
+ break;
}
#endif /* SECTRANSP_PINNEDPUBKEY_V2 */
- pubkeylen = (size_t)CFDataGetLength(publicKeyBits);
+ pubkeylen = CFDataGetLength(publicKeyBits);
pubkey = (unsigned char *)CFDataGetBytePtr(publicKeyBits);
switch(pubkeylen) {
@@ -1805,23 +2523,24 @@ static CURLcode sectransp_connect_step2(struct Curl_cfilter *cf,
SSLCipherSuite cipher;
SSLProtocol protocol = 0;
- DEBUGASSERT(ssl_connect_2 == connssl->connecting_state);
+ DEBUGASSERT(ssl_connect_2 == connssl->connecting_state
+ || ssl_connect_2_reading == connssl->connecting_state
+ || ssl_connect_2_writing == connssl->connecting_state);
DEBUGASSERT(backend);
CURL_TRC_CF(data, cf, "connect_step2");
/* Here goes nothing: */
check_handshake:
- connssl->io_need = CURL_SSL_IO_NEED_NONE;
err = SSLHandshake(backend->ssl_ctx);
if(err != noErr) {
switch(err) {
- case errSSLWouldBlock: /* they are not done with us yet */
- connssl->io_need = backend->ssl_direction ?
- CURL_SSL_IO_NEED_SEND : CURL_SSL_IO_NEED_RECV;
+ case errSSLWouldBlock: /* they're not done with us yet */
+ connssl->connecting_state = backend->ssl_direction ?
+ ssl_connect_2_writing : ssl_connect_2_reading;
return CURLE_OK;
- /* The below is errSSLServerAuthCompleted; it is not defined in
+ /* The below is errSSLServerAuthCompleted; it's not defined in
Leopard's headers */
case -9841:
if((conn_config->CAfile || conn_config->ca_info_blob) &&
@@ -1931,8 +2650,8 @@ check_handshake:
"authority");
break;
- /* This error is raised if the server's cert did not match the server's
- hostname: */
+ /* This error is raised if the server's cert didn't match the server's
+ host name: */
case errSSLHostNameMismatch:
failf(data, "SSL certificate peer verification failed, the "
"certificate did not match \"%s\"\n", connssl->peer.dispname);
@@ -2033,8 +2752,7 @@ check_handshake:
return CURLE_SSL_CONNECT_ERROR;
}
else {
- char cipher_str[64];
- /* we have been connected fine, we are not waiting for anything else. */
+ /* we have been connected fine, we're not waiting for anything else. */
connssl->connecting_state = ssl_connect_3;
#ifdef SECTRANSP_PINNEDPUBKEY
@@ -2052,30 +2770,33 @@ check_handshake:
/* Informational message */
(void)SSLGetNegotiatedCipher(backend->ssl_ctx, &cipher);
(void)SSLGetNegotiatedProtocolVersion(backend->ssl_ctx, &protocol);
-
- sectransp_cipher_suite_get_str((uint16_t) cipher, cipher_str,
- sizeof(cipher_str), true);
switch(protocol) {
case kSSLProtocol2:
- infof(data, "SSL 2.0 connection using %s", cipher_str);
+ infof(data, "SSL 2.0 connection using %s",
+ TLSCipherNameForNumber(cipher));
break;
case kSSLProtocol3:
- infof(data, "SSL 3.0 connection using %s", cipher_str);
+ infof(data, "SSL 3.0 connection using %s",
+ TLSCipherNameForNumber(cipher));
break;
case kTLSProtocol1:
- infof(data, "TLS 1.0 connection using %s", cipher_str);
+ infof(data, "TLS 1.0 connection using %s",
+ TLSCipherNameForNumber(cipher));
break;
#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
case kTLSProtocol11:
- infof(data, "TLS 1.1 connection using %s", cipher_str);
+ infof(data, "TLS 1.1 connection using %s",
+ TLSCipherNameForNumber(cipher));
break;
case kTLSProtocol12:
- infof(data, "TLS 1.2 connection using %s", cipher_str);
+ infof(data, "TLS 1.2 connection using %s",
+ TLSCipherNameForNumber(cipher));
break;
#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */
#if CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11
case kTLSProtocol13:
- infof(data, "TLS 1.3 connection using %s", cipher_str);
+ infof(data, "TLS 1.3 connection using %s",
+ TLSCipherNameForNumber(cipher));
break;
#endif /* CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11 */
default:
@@ -2083,8 +2804,7 @@ check_handshake:
break;
}
-#if (CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) && \
- defined(HAVE_BUILTIN_AVAILABLE)
+#if(CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) && HAVE_BUILTIN_AVAILABLE == 1
if(connssl->alpn) {
if(__builtin_available(macOS 10.13.4, iOS 11, tvOS 11, *)) {
CFArrayRef alpnArr = NULL;
@@ -2108,8 +2828,11 @@ check_handshake:
else
infof(data, VTLS_INFOF_NO_ALPN);
+ Curl_multiuse_state(data, cf->conn->alpn == CURL_HTTP_VERSION_2 ?
+ BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);
+
/* chosenProtocol is a reference to the string within alpnArr
- and does not need to be freed separately */
+ and doesn't need to be freed separately */
if(alpnArr)
CFRelease(alpnArr);
}
@@ -2211,10 +2934,10 @@ static CURLcode collect_server_cert(struct Curl_cfilter *cf,
/* SSLCopyPeerCertificates() is deprecated as of Mountain Lion.
The function SecTrustGetCertificateAtIndex() is officially present
in Lion, but it is unfortunately also present in Snow Leopard as
- private API and does not work as expected. So we have to look for
+ private API and doesn't work as expected. So we have to look for
a different symbol to make sure this code is only executed under
Lion or later. */
- if(&SecTrustCopyPublicKey) {
+ if(SecTrustCopyPublicKey) {
#pragma unused(server_certs)
err = SSLCopyPeerTrust(backend->ssl_ctx, &trust);
/* For some reason, SSLCopyPeerTrust() can return noErr and yet return
@@ -2300,7 +3023,7 @@ sectransp_connect_common(struct Curl_cfilter *cf, struct Curl_easy *data,
}
if(ssl_connect_1 == connssl->connecting_state) {
- /* Find out how much more time we are allowed */
+ /* Find out how much more time we're allowed */
const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
if(timeout_ms < 0) {
@@ -2314,7 +3037,9 @@ sectransp_connect_common(struct Curl_cfilter *cf, struct Curl_easy *data,
return result;
}
- while(ssl_connect_2 == connssl->connecting_state) {
+ while(ssl_connect_2 == connssl->connecting_state ||
+ ssl_connect_2_reading == connssl->connecting_state ||
+ ssl_connect_2_writing == connssl->connecting_state) {
/* check allowed time left */
const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
@@ -2325,13 +3050,14 @@ sectransp_connect_common(struct Curl_cfilter *cf, struct Curl_easy *data,
return CURLE_OPERATION_TIMEDOUT;
}
- /* if ssl is expecting something, check if it is available. */
- if(connssl->io_need) {
+ /* if ssl is expecting something, check if it's available. */
+ if(connssl->connecting_state == ssl_connect_2_reading ||
+ connssl->connecting_state == ssl_connect_2_writing) {
- curl_socket_t writefd = (connssl->io_need & CURL_SSL_IO_NEED_SEND)?
- sockfd:CURL_SOCKET_BAD;
- curl_socket_t readfd = (connssl->io_need & CURL_SSL_IO_NEED_RECV)?
- sockfd:CURL_SOCKET_BAD;
+ curl_socket_t writefd = ssl_connect_2_writing ==
+ connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
+ curl_socket_t readfd = ssl_connect_2_reading ==
+ connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
nonblocking ? 0 : timeout_ms);
@@ -2361,7 +3087,10 @@ sectransp_connect_common(struct Curl_cfilter *cf, struct Curl_easy *data,
* or epoll() will always have a valid fdset to wait on.
*/
result = sectransp_connect_step2(cf, data);
- if(result || (nonblocking && (ssl_connect_2 == connssl->connecting_state)))
+ if(result || (nonblocking &&
+ (ssl_connect_2 == connssl->connecting_state ||
+ ssl_connect_2_reading == connssl->connecting_state ||
+ ssl_connect_2_writing == connssl->connecting_state)))
return result;
} /* repeat step2 until all transactions are done. */
@@ -2410,92 +3139,6 @@ static CURLcode sectransp_connect(struct Curl_cfilter *cf,
return CURLE_OK;
}
-static ssize_t sectransp_recv(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- char *buf,
- size_t buffersize,
- CURLcode *curlcode);
-
-static CURLcode sectransp_shutdown(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- bool send_shutdown, bool *done)
-{
- struct ssl_connect_data *connssl = cf->ctx;
- struct st_ssl_backend_data *backend =
- (struct st_ssl_backend_data *)connssl->backend;
- CURLcode result = CURLE_OK;
- ssize_t nread;
- char buf[1024];
- size_t i;
-
- DEBUGASSERT(backend);
- if(!backend->ssl_ctx || cf->shutdown) {
- *done = TRUE;
- goto out;
- }
-
- connssl->io_need = CURL_SSL_IO_NEED_NONE;
- *done = FALSE;
-
- if(send_shutdown && !backend->sent_shutdown) {
- OSStatus err;
-
- CURL_TRC_CF(data, cf, "shutdown, send close notify");
- err = SSLClose(backend->ssl_ctx);
- switch(err) {
- case noErr:
- backend->sent_shutdown = TRUE;
- break;
- case errSSLWouldBlock:
- connssl->io_need = CURL_SSL_IO_NEED_SEND;
- result = CURLE_OK;
- goto out;
- default:
- CURL_TRC_CF(data, cf, "shutdown, error: %d", (int)err);
- result = CURLE_SEND_ERROR;
- goto out;
- }
- }
-
- for(i = 0; i < 10; ++i) {
- if(!backend->sent_shutdown) {
- nread = sectransp_recv(cf, data, buf, (int)sizeof(buf), &result);
- }
- else {
- /* We would like to read the close notify from the server using
- * secure transport, however SSLRead() no longer works after we
- * sent the notify from our side. So, we just read from the
- * underlying filter and hope it will end. */
- nread = Curl_conn_cf_recv(cf->next, data, buf, sizeof(buf), &result);
- }
- CURL_TRC_CF(data, cf, "shutdown read -> %zd, %d", nread, result);
- if(nread <= 0)
- break;
- }
-
- if(nread > 0) {
- /* still data coming in? */
- connssl->io_need = CURL_SSL_IO_NEED_RECV;
- }
- else if(nread == 0) {
- /* We got the close notify alert and are done. */
- CURL_TRC_CF(data, cf, "shutdown done");
- *done = TRUE;
- }
- else if(result == CURLE_AGAIN) {
- connssl->io_need = CURL_SSL_IO_NEED_RECV;
- result = CURLE_OK;
- }
- else {
- DEBUGASSERT(result);
- CURL_TRC_CF(data, cf, "shutdown, error: %d", result);
- }
-
-out:
- cf->shutdown = (result || *done);
- return result;
-}
-
static void sectransp_close(struct Curl_cfilter *cf, struct Curl_easy *data)
{
struct ssl_connect_data *connssl = cf->ctx;
@@ -2508,8 +3151,9 @@ static void sectransp_close(struct Curl_cfilter *cf, struct Curl_easy *data)
if(backend->ssl_ctx) {
CURL_TRC_CF(data, cf, "close");
+ (void)SSLClose(backend->ssl_ctx);
#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
- if(&SSLCreateContext)
+ if(SSLCreateContext)
CFRelease(backend->ssl_ctx);
#if CURL_SUPPORT_MAC_10_8
else
@@ -2522,6 +3166,80 @@ static void sectransp_close(struct Curl_cfilter *cf, struct Curl_easy *data)
}
}
+static int sectransp_shutdown(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
+{
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct st_ssl_backend_data *backend =
+ (struct st_ssl_backend_data *)connssl->backend;
+ ssize_t nread;
+ int what;
+ int rc;
+ char buf[120];
+ int loop = 10; /* avoid getting stuck */
+ CURLcode result;
+
+ DEBUGASSERT(backend);
+
+ if(!backend->ssl_ctx)
+ return 0;
+
+#ifndef CURL_DISABLE_FTP
+ if(data->set.ftp_ccc != CURLFTPSSL_CCC_ACTIVE)
+ return 0;
+#endif
+
+ sectransp_close(cf, data);
+
+ rc = 0;
+
+ what = SOCKET_READABLE(Curl_conn_cf_get_socket(cf, data),
+ SSL_SHUTDOWN_TIMEOUT);
+
+ CURL_TRC_CF(data, cf, "shutdown");
+ while(loop--) {
+ if(what < 0) {
+ /* anything that gets here is fatally bad */
+ failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
+ rc = -1;
+ break;
+ }
+
+ if(!what) { /* timeout */
+ failf(data, "SSL shutdown timeout");
+ break;
+ }
+
+ /* Something to read, let's do it and hope that it is the close
+ notify alert from the server. No way to SSL_Read now, so use read(). */
+
+ nread = Curl_conn_cf_recv(cf->next, data, buf, sizeof(buf), &result);
+
+ if(nread < 0) {
+ failf(data, "read: %s", curl_easy_strerror(result));
+ rc = -1;
+ }
+
+ if(nread <= 0)
+ break;
+
+ what = SOCKET_READABLE(Curl_conn_cf_get_socket(cf, data), 0);
+ }
+
+ return rc;
+}
+
+static void sectransp_session_free(void *ptr)
+{
+ /* ST, as of iOS 5 and Mountain Lion, has no public method of deleting a
+ cached session ID inside the Security framework. There is a private
+ function that does this, but I don't want to have to explain to you why I
+ got your application rejected from the App Store due to the use of a
+ private API, so the best we can do is free up our own char array that we
+ created way back in sectransp_connect_step1... */
+ Curl_safefree(ptr);
+}
+
static size_t sectransp_version(char *buffer, size_t size)
{
return msnprintf(buffer, size, "SecureTransport");
@@ -2553,7 +3271,7 @@ static bool sectransp_data_pending(struct Curl_cfilter *cf,
static CURLcode sectransp_random(struct Curl_easy *data UNUSED_PARAM,
unsigned char *entropy, size_t length)
{
- /* arc4random_buf() is not available on cats older than Lion, so let's
+ /* arc4random_buf() isn't available on cats older than Lion, so let's
do this manually for the benefit of the older cats. */
size_t i;
u_int32_t random_number = 0;
@@ -2584,7 +3302,7 @@ static CURLcode sectransp_sha256sum(const unsigned char *tmp, /* input */
static bool sectransp_false_start(void)
{
#if CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7
- if(&SSLSetSessionOption)
+ if(SSLSetSessionOption)
return TRUE;
#endif
return FALSE;
@@ -2611,7 +3329,7 @@ static ssize_t sectransp_send(struct Curl_cfilter *cf,
Now, one could interpret that as "written to the socket," but actually,
it returns the amount of data that was written to a buffer internal to
- the SSLContextRef instead. So it is possible for SSLWrite() to return
+ the SSLContextRef instead. So it's possible for SSLWrite() to return
errSSLWouldBlock and a number of bytes "written" because those bytes were
encrypted and written to a buffer, not to the socket.
@@ -2624,7 +3342,7 @@ static ssize_t sectransp_send(struct Curl_cfilter *cf,
err = SSLWrite(backend->ssl_ctx, NULL, 0UL, &processed);
switch(err) {
case noErr:
- /* processed is always going to be 0 because we did not write to
+ /* processed is always going to be 0 because we didn't write to
the buffer, so return how much was written to the socket */
processed = backend->ssl_write_buffered_length;
backend->ssl_write_buffered_length = 0UL;
@@ -2639,7 +3357,7 @@ static ssize_t sectransp_send(struct Curl_cfilter *cf,
}
}
else {
- /* We have got new data to write: */
+ /* We've got new data to write: */
err = SSLWrite(backend->ssl_ctx, mem, len, &processed);
if(err != noErr) {
switch(err) {
@@ -2696,7 +3414,7 @@ again:
*curlcode = CURLE_OK;
return 0;
- /* The below is errSSLPeerAuthCompleted; it is not defined in
+ /* The below is errSSLPeerAuthCompleted; it's not defined in
Leopard's headers */
case -9841:
if((conn_config->CAfile || conn_config->ca_info_blob) &&
@@ -2737,8 +3455,7 @@ const struct Curl_ssl Curl_ssl_sectransp = {
#ifdef SECTRANSP_PINNEDPUBKEY
SSLSUPP_PINNEDPUBKEY |
#endif /* SECTRANSP_PINNEDPUBKEY */
- SSLSUPP_HTTPS_PROXY |
- SSLSUPP_CIPHER_LIST,
+ SSLSUPP_HTTPS_PROXY,
sizeof(struct st_ssl_backend_data),
@@ -2756,6 +3473,7 @@ const struct Curl_ssl Curl_ssl_sectransp = {
sectransp_get_internals, /* get_internals */
sectransp_close, /* close_one */
Curl_none_close_all, /* close_all */
+ sectransp_session_free, /* session_free */
Curl_none_set_engine, /* set_engine */
Curl_none_set_engine_default, /* set_engine_default */
Curl_none_engines_list, /* engines_list */
@@ -2763,9 +3481,9 @@ const struct Curl_ssl Curl_ssl_sectransp = {
sectransp_sha256sum, /* sha256sum */
NULL, /* associate_connection */
NULL, /* disassociate_connection */
+ NULL, /* free_multi_ssl_backend_data */
sectransp_recv, /* recv decrypted data */
sectransp_send, /* send data to encrypt */
- NULL, /* get_channel_binding */
};
#ifdef __GNUC__
diff --git a/contrib/libs/curl/lib/vtls/vtls.c b/contrib/libs/curl/lib/vtls/vtls.c
index 36a422678e..34eda3e5a0 100644
--- a/contrib/libs/curl/lib/vtls/vtls.c
+++ b/contrib/libs/curl/lib/vtls/vtls.c
@@ -68,10 +68,7 @@
#include "curl_base64.h"
#include "curl_printf.h"
#include "inet_pton.h"
-#include "connect.h"
-#include "select.h"
#include "strdup.h"
-#include "rand.h"
/* The last #include files should be: */
#include "curl_memory.h"
@@ -106,7 +103,7 @@ static CURLcode blobdup(struct curl_blob **dest,
DEBUGASSERT(dest);
DEBUGASSERT(!*dest);
if(src) {
- /* only if there is data to dupe! */
+ /* only if there's data to dupe! */
struct curl_blob *d;
d = malloc(sizeof(struct curl_blob) + src->len);
if(!d)
@@ -139,9 +136,6 @@ static const struct alpn_spec ALPN_SPEC_H11 = {
{ ALPN_HTTP_1_1 }, 1
};
#ifdef USE_HTTP2
-static const struct alpn_spec ALPN_SPEC_H2 = {
- { ALPN_H2 }, 1
-};
static const struct alpn_spec ALPN_SPEC_H2_H11 = {
{ ALPN_H2, ALPN_HTTP_1_1 }, 2
};
@@ -152,15 +146,13 @@ static const struct alpn_spec *alpn_get_spec(int httpwant, bool use_alpn)
if(!use_alpn)
return NULL;
#ifdef USE_HTTP2
- if(httpwant == CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE)
- return &ALPN_SPEC_H2;
if(httpwant >= CURL_HTTP_VERSION_2)
return &ALPN_SPEC_H2_H11;
#else
(void)httpwant;
#endif
/* Use the ALPN protocol "http/1.1" for HTTP/1.x.
- Avoid "http/1.0" because some servers do not support it. */
+ Avoid "http/1.0" because some servers don't support it. */
return &ALPN_SPEC_H11;
}
#endif /* USE_SSL */
@@ -174,7 +166,7 @@ void Curl_ssl_easy_config_init(struct Curl_easy *data)
*/
data->set.ssl.primary.verifypeer = TRUE;
data->set.ssl.primary.verifyhost = TRUE;
- data->set.ssl.primary.cache_session = TRUE; /* caching by default */
+ data->set.ssl.primary.sessionid = TRUE; /* session ID caching by default */
#ifndef CURL_DISABLE_PROXY
data->set.proxy_ssl = data->set.ssl;
#endif
@@ -236,7 +228,7 @@ static bool clone_ssl_primary_config(struct ssl_primary_config *source,
dest->verifypeer = source->verifypeer;
dest->verifyhost = source->verifyhost;
dest->verifystatus = source->verifystatus;
- dest->cache_session = source->cache_session;
+ dest->sessionid = source->sessionid;
dest->ssl_options = source->ssl_options;
CLONE_BLOB(cert_blob);
@@ -419,6 +411,23 @@ int Curl_ssl_init(void)
return Curl_ssl->init();
}
+#if defined(CURL_WITH_MULTI_SSL)
+static const struct Curl_ssl Curl_ssl_multi;
+#endif
+
+/* Global cleanup */
+void Curl_ssl_cleanup(void)
+{
+ if(init_ssl) {
+ /* only cleanup if we did a previous init */
+ Curl_ssl->cleanup();
+#if defined(CURL_WITH_MULTI_SSL)
+ Curl_ssl = &Curl_ssl_multi;
+#endif
+ init_ssl = FALSE;
+ }
+}
+
static bool ssl_prefs_check(struct Curl_easy *data)
{
/* check for CURLOPT_SSLVERSION invalid parameter value */
@@ -444,7 +453,7 @@ static bool ssl_prefs_check(struct Curl_easy *data)
}
static struct ssl_connect_data *cf_ctx_new(struct Curl_easy *data,
- const struct alpn_spec *alpn)
+ const struct alpn_spec *alpn)
{
struct ssl_connect_data *ctx;
@@ -520,15 +529,15 @@ void Curl_ssl_sessionid_unlock(struct Curl_easy *data)
}
/*
- * Check if there is a session ID for the given connection in the cache, and if
- * there is one suitable, it is provided. Returns TRUE when no entry matched.
+ * Check if there's a session ID for the given connection in the cache, and if
+ * there's one suitable, it is provided. Returns TRUE when no entry matched.
*/
bool Curl_ssl_getsessionid(struct Curl_cfilter *cf,
struct Curl_easy *data,
- const struct ssl_peer *peer,
void **ssl_sessionid,
size_t *idsize) /* set 0 if unknown */
{
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
struct Curl_ssl_session *check;
@@ -540,9 +549,9 @@ bool Curl_ssl_getsessionid(struct Curl_cfilter *cf,
if(!ssl_config)
return TRUE;
- DEBUGASSERT(ssl_config->primary.cache_session);
+ DEBUGASSERT(ssl_config->primary.sessionid);
- if(!ssl_config->primary.cache_session || !data->state.session)
+ if(!ssl_config->primary.sessionid || !data->state.session)
/* session ID reuse is disabled or the session cache has not been
setup */
return TRUE;
@@ -558,15 +567,14 @@ bool Curl_ssl_getsessionid(struct Curl_cfilter *cf,
if(!check->sessionid)
/* not session ID means blank entry */
continue;
- if(strcasecompare(peer->hostname, check->name) &&
+ if(strcasecompare(connssl->peer.hostname, check->name) &&
((!cf->conn->bits.conn_to_host && !check->conn_to_host) ||
(cf->conn->bits.conn_to_host && check->conn_to_host &&
strcasecompare(cf->conn->conn_to_host.name, check->conn_to_host))) &&
((!cf->conn->bits.conn_to_port && check->conn_to_port == -1) ||
(cf->conn->bits.conn_to_port && check->conn_to_port != -1 &&
cf->conn->conn_to_port == check->conn_to_port)) &&
- (peer->port == check->remote_port) &&
- (peer->transport == check->transport) &&
+ (connssl->port == check->remote_port) &&
strcasecompare(cf->conn->handler->scheme, check->scheme) &&
match_ssl_primary_config(data, conn_config, &check->ssl_config)) {
/* yes, we have a session ID! */
@@ -580,9 +588,11 @@ bool Curl_ssl_getsessionid(struct Curl_cfilter *cf,
}
}
- CURL_TRC_CF(data, cf, "%s cached session ID for %s://%s:%d",
- no_match? "No": "Found",
- cf->conn->handler->scheme, peer->hostname, peer->port);
+ DEBUGF(infof(data, "%s Session ID in cache for %s %s://%s:%d",
+ no_match? "Didn't find": "Found",
+ Curl_ssl_cf_is_proxy(cf) ? "proxy" : "host",
+ cf->conn->handler->scheme, connssl->peer.hostname,
+ connssl->port));
return no_match;
}
@@ -595,10 +605,9 @@ void Curl_ssl_kill_session(struct Curl_ssl_session *session)
/* defensive check */
/* free the ID the SSL-layer specific way */
- session->sessionid_free(session->sessionid, session->idsize);
+ Curl_ssl->session_free(session->sessionid);
session->sessionid = NULL;
- session->sessionid_free = NULL;
session->age = 0; /* fresh */
Curl_free_primary_ssl_config(&session->ssl_config);
@@ -625,66 +634,60 @@ void Curl_ssl_delsessionid(struct Curl_easy *data, void *ssl_sessionid)
}
}
-CURLcode Curl_ssl_set_sessionid(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- const struct ssl_peer *peer,
- void *ssl_sessionid,
- size_t idsize,
- Curl_ssl_sessionid_dtor *sessionid_free_cb)
+/*
+ * Store session id in the session cache. The ID passed on to this function
+ * must already have been extracted and allocated the proper way for the SSL
+ * layer. Curl_XXXX_session_free() will be called to free/kill the session ID
+ * later on.
+ */
+CURLcode Curl_ssl_addsessionid(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ void *ssl_sessionid,
+ size_t idsize,
+ bool *added)
{
+ struct ssl_connect_data *connssl = cf->ctx;
struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
size_t i;
struct Curl_ssl_session *store;
long oldest_age;
- char *clone_host = NULL;
- char *clone_conn_to_host = NULL;
+ char *clone_host;
+ char *clone_conn_to_host;
int conn_to_port;
long *general_age;
- void *old_sessionid;
- size_t old_size;
- CURLcode result = CURLE_OUT_OF_MEMORY;
- DEBUGASSERT(ssl_sessionid);
- DEBUGASSERT(sessionid_free_cb);
+ if(added)
+ *added = FALSE;
- if(!data->state.session) {
- sessionid_free_cb(ssl_sessionid, idsize);
+ if(!data->state.session)
return CURLE_OK;
- }
-
- if(!Curl_ssl_getsessionid(cf, data, peer, &old_sessionid, &old_size)) {
- if((old_size == idsize) &&
- ((old_sessionid == ssl_sessionid) ||
- (idsize && !memcmp(old_sessionid, ssl_sessionid, idsize)))) {
- /* the very same */
- sessionid_free_cb(ssl_sessionid, idsize);
- return CURLE_OK;
- }
- Curl_ssl_delsessionid(data, old_sessionid);
- }
store = &data->state.session[0];
oldest_age = data->state.session[0].age; /* zero if unused */
- DEBUGASSERT(ssl_config->primary.cache_session);
(void)ssl_config;
+ DEBUGASSERT(ssl_config->primary.sessionid);
- clone_host = strdup(peer->hostname);
+ clone_host = strdup(connssl->peer.hostname);
if(!clone_host)
- goto out;
+ return CURLE_OUT_OF_MEMORY; /* bail out */
if(cf->conn->bits.conn_to_host) {
clone_conn_to_host = strdup(cf->conn->conn_to_host.name);
- if(!clone_conn_to_host)
- goto out;
+ if(!clone_conn_to_host) {
+ free(clone_host);
+ return CURLE_OUT_OF_MEMORY; /* bail out */
+ }
}
+ else
+ clone_conn_to_host = NULL;
if(cf->conn->bits.conn_to_port)
conn_to_port = cf->conn->conn_to_port;
else
conn_to_port = -1;
- /* Now we should add the session ID and the hostname to the cache, (remove
+ /* Now we should add the session ID and the host name to the cache, (remove
the oldest if necessary) */
/* If using shared SSL session, lock! */
@@ -710,52 +713,40 @@ CURLcode Curl_ssl_set_sessionid(struct Curl_cfilter *cf,
store = &data->state.session[i]; /* use this slot */
/* now init the session struct wisely */
- if(!clone_ssl_primary_config(conn_config, &store->ssl_config)) {
- Curl_free_primary_ssl_config(&store->ssl_config);
- store->sessionid = NULL; /* let caller free sessionid */
- goto out;
- }
store->sessionid = ssl_sessionid;
store->idsize = idsize;
- store->sessionid_free = sessionid_free_cb;
store->age = *general_age; /* set current age */
- /* free it if there is one already present */
+ /* free it if there's one already present */
free(store->name);
free(store->conn_to_host);
- store->name = clone_host; /* clone hostname */
- clone_host = NULL;
- store->conn_to_host = clone_conn_to_host; /* clone connect to hostname */
- clone_conn_to_host = NULL;
+ store->name = clone_host; /* clone host name */
+ store->conn_to_host = clone_conn_to_host; /* clone connect to host name */
store->conn_to_port = conn_to_port; /* connect to port number */
/* port number */
- store->remote_port = peer->port;
+ store->remote_port = connssl->port;
store->scheme = cf->conn->handler->scheme;
- store->transport = peer->transport;
-
- result = CURLE_OK;
-out:
- free(clone_host);
- free(clone_conn_to_host);
- if(result) {
- failf(data, "Failed to add Session ID to cache for %s://%s:%d [%s]",
- store->scheme, store->name, store->remote_port,
- Curl_ssl_cf_is_proxy(cf) ? "PROXY" : "server");
- sessionid_free_cb(ssl_sessionid, idsize);
- return result;
+ if(!clone_ssl_primary_config(conn_config, &store->ssl_config)) {
+ Curl_free_primary_ssl_config(&store->ssl_config);
+ store->sessionid = NULL; /* let caller free sessionid */
+ free(clone_host);
+ free(clone_conn_to_host);
+ return CURLE_OUT_OF_MEMORY;
}
- CURL_TRC_CF(data, cf, "Added Session ID to cache for %s://%s:%d [%s]",
- store->scheme, store->name, store->remote_port,
- Curl_ssl_cf_is_proxy(cf) ? "PROXY" : "server");
+
+ if(added)
+ *added = TRUE;
+
+ DEBUGF(infof(data, "Added Session ID to cache for %s://%s:%d [%s]",
+ store->scheme, store->name, store->remote_port,
+ Curl_ssl_cf_is_proxy(cf) ? "PROXY" : "server"));
return CURLE_OK;
}
-CURLcode Curl_ssl_get_channel_binding(struct Curl_easy *data, int sockindex,
- struct dynbuf *binding)
+void Curl_free_multi_ssl_backend_data(struct multi_ssl_backend_data *mbackend)
{
- if(Curl_ssl->get_channel_binding)
- return Curl_ssl->get_channel_binding(data, sockindex, binding);
- return CURLE_OK;
+ if(Curl_ssl->free_multi_ssl_backend_data && mbackend)
+ Curl_ssl->free_multi_ssl_backend_data(mbackend);
}
void Curl_ssl_close_all(struct Curl_easy *data)
@@ -777,20 +768,15 @@ void Curl_ssl_close_all(struct Curl_easy *data)
void Curl_ssl_adjust_pollset(struct Curl_cfilter *cf, struct Curl_easy *data,
struct easy_pollset *ps)
{
- struct ssl_connect_data *connssl = cf->ctx;
-
- if(connssl->io_need) {
+ if(!cf->connected) {
+ struct ssl_connect_data *connssl = cf->ctx;
curl_socket_t sock = Curl_conn_cf_get_socket(cf->next, data);
if(sock != CURL_SOCKET_BAD) {
- if(connssl->io_need & CURL_SSL_IO_NEED_SEND) {
+ if(connssl->connecting_state == ssl_connect_2_writing) {
Curl_pollset_set_out_only(data, ps, sock);
- CURL_TRC_CF(data, cf, "adjust_pollset, POLLOUT fd=%" FMT_SOCKET_T,
- sock);
}
else {
Curl_pollset_set_in_only(data, ps, sock);
- CURL_TRC_CF(data, cf, "adjust_pollset, POLLIN fd=%" FMT_SOCKET_T,
- sock);
}
}
}
@@ -897,23 +883,28 @@ CURLcode Curl_ssl_push_certinfo_len(struct Curl_easy *data,
size_t valuelen)
{
struct curl_certinfo *ci = &data->info.certs;
+ char *output;
struct curl_slist *nl;
CURLcode result = CURLE_OK;
- struct dynbuf build;
+ size_t labellen = strlen(label);
+ size_t outlen = labellen + 1 + valuelen + 1; /* label:value\0 */
- DEBUGASSERT(certnum < ci->num_of_certs);
+ output = malloc(outlen);
+ if(!output)
+ return CURLE_OUT_OF_MEMORY;
- Curl_dyn_init(&build, CURL_X509_STR_MAX);
+ /* sprintf the label and colon */
+ msnprintf(output, outlen, "%s:", label);
- if(Curl_dyn_add(&build, label) ||
- Curl_dyn_addn(&build, ":", 1) ||
- Curl_dyn_addn(&build, value, valuelen))
- return CURLE_OUT_OF_MEMORY;
+ /* memcpy the value (it might not be null-terminated) */
+ memcpy(&output[labellen + 1], value, valuelen);
- nl = Curl_slist_append_nodup(ci->certinfo[certnum],
- Curl_dyn_ptr(&build));
+ /* null-terminate the output */
+ output[labellen + 1 + valuelen] = 0;
+
+ nl = Curl_slist_append_nodup(ci->certinfo[certnum], output);
if(!nl) {
- Curl_dyn_free(&build);
+ free(output);
curl_slist_free_all(ci->certinfo[certnum]);
result = CURLE_OUT_OF_MEMORY;
}
@@ -922,16 +913,11 @@ CURLcode Curl_ssl_push_certinfo_len(struct Curl_easy *data,
return result;
}
-/* get 32 bits of random */
CURLcode Curl_ssl_random(struct Curl_easy *data,
unsigned char *entropy,
size_t length)
{
- DEBUGASSERT(length == sizeof(int));
- if(Curl_ssl->random)
- return Curl_ssl->random(data, entropy, length);
- else
- return CURLE_NOT_BUILT_IN;
+ return Curl_ssl->random(data, entropy, length);
}
/*
@@ -1007,7 +993,7 @@ CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data,
(void)data;
#endif
- /* if a path was not specified, do not pin */
+ /* if a path wasn't specified, don't pin */
if(!pinnedpubkey)
return CURLE_OK;
if(!pubkey || !pubkeylen)
@@ -1016,7 +1002,7 @@ CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data,
/* only do this if pinnedpubkey starts with "sha256//", length 8 */
if(strncmp(pinnedpubkey, "sha256//", 8) == 0) {
CURLcode encode;
- size_t encodedlen = 0;
+ size_t encodedlen = 0, pinkeylen;
char *encoded = NULL, *pinkeycopy, *begin_pos, *end_pos;
unsigned char *sha256sumdigest;
@@ -1044,18 +1030,20 @@ CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data,
infof(data, " public key hash: sha256//%s", encoded);
/* it starts with sha256//, copy so we can modify it */
- pinkeycopy = strdup(pinnedpubkey);
+ pinkeylen = strlen(pinnedpubkey) + 1;
+ pinkeycopy = malloc(pinkeylen);
if(!pinkeycopy) {
Curl_safefree(encoded);
return CURLE_OUT_OF_MEMORY;
}
+ memcpy(pinkeycopy, pinnedpubkey, pinkeylen);
/* point begin_pos to the copy, and start extracting keys */
begin_pos = pinkeycopy;
do {
end_pos = strstr(begin_pos, ";sha256//");
/*
* if there is an end_pos, null terminate,
- * otherwise it will go to the end of the original string
+ * otherwise it'll go to the end of the original string
*/
if(end_pos)
end_pos[0] = '\0';
@@ -1101,7 +1089,7 @@ CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data,
/*
* if the size of our certificate is bigger than the file
- * size then it cannot match
+ * size then it can't match
*/
size = curlx_sotouz((curl_off_t) filesize);
if(pubkeylen > size)
@@ -1119,7 +1107,7 @@ CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data,
if((int) fread(buf, size, 1, fp) != 1)
break;
- /* If the sizes are the same, it cannot be base64 encoded, must be der */
+ /* If the sizes are the same, it can't be base64 encoded, must be der */
if(pubkeylen == size) {
if(!memcmp(pubkey, buf, pubkeylen))
result = CURLE_OK;
@@ -1127,18 +1115,18 @@ CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data,
}
/*
- * Otherwise we will assume it is PEM and try to decode it
+ * Otherwise we will assume it's PEM and try to decode it
* after placing null terminator
*/
buf[size] = '\0';
pem_read = pubkey_pem_to_der((const char *)buf, &pem_ptr, &pem_len);
- /* if it was not read successfully, exit */
+ /* if it wasn't read successfully, exit */
if(pem_read)
break;
/*
- * if the size of our certificate does not match the size of
- * the decoded file, they cannot be the same, otherwise compare
+ * if the size of our certificate doesn't match the size of
+ * the decoded file, they can't be the same, otherwise compare
*/
if(pubkeylen == pem_len && !memcmp(pubkey, pem_ptr, pubkeylen))
result = CURLE_OK;
@@ -1180,18 +1168,12 @@ int Curl_none_init(void)
void Curl_none_cleanup(void)
{ }
-CURLcode Curl_none_shutdown(struct Curl_cfilter *cf UNUSED_PARAM,
- struct Curl_easy *data UNUSED_PARAM,
- bool send_shutdown UNUSED_PARAM,
- bool *done)
+int Curl_none_shutdown(struct Curl_cfilter *cf UNUSED_PARAM,
+ struct Curl_easy *data UNUSED_PARAM)
{
(void)data;
(void)cf;
- (void)send_shutdown;
- /* Every SSL backend should have a shutdown implementation. Until we
- * have implemented that, we put this fake in place. */
- *done = TRUE;
- return CURLE_OK;
+ return 0;
}
int Curl_none_check_cxn(struct Curl_cfilter *cf, struct Curl_easy *data)
@@ -1201,6 +1183,16 @@ int Curl_none_check_cxn(struct Curl_cfilter *cf, struct Curl_easy *data)
return -1;
}
+CURLcode Curl_none_random(struct Curl_easy *data UNUSED_PARAM,
+ unsigned char *entropy UNUSED_PARAM,
+ size_t length UNUSED_PARAM)
+{
+ (void)data;
+ (void)entropy;
+ (void)length;
+ return CURLE_NOT_BUILT_IN;
+}
+
void Curl_none_close_all(struct Curl_easy *data UNUSED_PARAM)
{
(void)data;
@@ -1327,7 +1319,7 @@ static const struct Curl_ssl Curl_ssl_multi = {
Curl_none_check_cxn, /* check_cxn */
Curl_none_shutdown, /* shutdown */
Curl_none_data_pending, /* data_pending */
- NULL, /* random */
+ Curl_none_random, /* random */
Curl_none_cert_status_request, /* cert_status_request */
multissl_connect, /* connect */
multissl_connect_nonblocking, /* connect_nonblocking */
@@ -1335,6 +1327,7 @@ static const struct Curl_ssl Curl_ssl_multi = {
multissl_get_internals, /* get_internals */
multissl_close, /* close_one */
Curl_none_close_all, /* close_all */
+ Curl_none_session_free, /* session_free */
Curl_none_set_engine, /* set_engine */
Curl_none_set_engine_default, /* set_engine_default */
Curl_none_engines_list, /* engines_list */
@@ -1342,9 +1335,9 @@ static const struct Curl_ssl Curl_ssl_multi = {
NULL, /* sha256sum */
NULL, /* associate_connection */
NULL, /* disassociate_connection */
+ NULL, /* free_multi_ssl_backend_data */
multissl_recv_plain, /* recv decrypted data */
multissl_send_plain, /* send data to encrypt */
- NULL, /* get_channel_binding */
};
const struct Curl_ssl *Curl_ssl =
@@ -1352,6 +1345,8 @@ const struct Curl_ssl *Curl_ssl =
&Curl_ssl_multi;
#elif defined(USE_WOLFSSL)
&Curl_ssl_wolfssl;
+#elif defined(USE_SECTRANSP)
+ &Curl_ssl_sectransp;
#elif defined(USE_GNUTLS)
&Curl_ssl_gnutls;
#elif defined(USE_MBEDTLS)
@@ -1360,8 +1355,6 @@ const struct Curl_ssl *Curl_ssl =
&Curl_ssl_rustls;
#elif defined(USE_OPENSSL)
&Curl_ssl_openssl;
-#elif defined(USE_SECTRANSP)
- &Curl_ssl_sectransp;
#elif defined(USE_SCHANNEL)
&Curl_ssl_schannel;
#elif defined(USE_BEARSSL)
@@ -1374,6 +1367,9 @@ static const struct Curl_ssl *available_backends[] = {
#if defined(USE_WOLFSSL)
&Curl_ssl_wolfssl,
#endif
+#if defined(USE_SECTRANSP)
+ &Curl_ssl_sectransp,
+#endif
#if defined(USE_GNUTLS)
&Curl_ssl_gnutls,
#endif
@@ -1383,9 +1379,6 @@ static const struct Curl_ssl *available_backends[] = {
#if defined(USE_OPENSSL)
&Curl_ssl_openssl,
#endif
-#if defined(USE_SECTRANSP)
- &Curl_ssl_sectransp,
-#endif
#if defined(USE_SCHANNEL)
&Curl_ssl_schannel,
#endif
@@ -1398,19 +1391,6 @@ static const struct Curl_ssl *available_backends[] = {
NULL
};
-/* Global cleanup */
-void Curl_ssl_cleanup(void)
-{
- if(init_ssl) {
- /* only cleanup if we did a previous init */
- Curl_ssl->cleanup();
-#if defined(CURL_WITH_MULTI_SSL)
- Curl_ssl = &Curl_ssl_multi;
-#endif
- init_ssl = FALSE;
- }
-}
-
static size_t multissl_version(char *buffer, size_t size)
{
static const struct Curl_ssl *selected;
@@ -1442,13 +1422,17 @@ static size_t multissl_version(char *buffer, size_t size)
backends_len = p - backends;
}
- if(size) {
- if(backends_len < size)
- strcpy(buffer, backends);
- else
- *buffer = 0; /* did not fit */
+ if(!size)
+ return 0;
+
+ if(size <= backends_len) {
+ strncpy(buffer, backends, size - 1);
+ buffer[size - 1] = '\0';
+ return size - 1;
}
- return 0;
+
+ strcpy(buffer, backends);
+ return backends_len;
}
static int multissl_setup(const struct Curl_ssl *backend)
@@ -1541,7 +1525,7 @@ void Curl_ssl_peer_cleanup(struct ssl_peer *peer)
free(peer->sni);
free(peer->hostname);
peer->hostname = peer->sni = peer->dispname = NULL;
- peer->type = CURL_SSL_PEER_DNS;
+ peer->is_ip_address = FALSE;
}
static void cf_close(struct Curl_cfilter *cf, struct Curl_easy *data)
@@ -1555,93 +1539,86 @@ static void cf_close(struct Curl_cfilter *cf, struct Curl_easy *data)
cf->connected = FALSE;
}
-static ssl_peer_type get_peer_type(const char *hostname)
+static int is_ip_address(const char *hostname)
{
- if(hostname && hostname[0]) {
-#ifdef USE_IPV6
- struct in6_addr addr;
+#ifdef ENABLE_IPV6
+ struct in6_addr addr;
#else
- struct in_addr addr;
+ struct in_addr addr;
#endif
- if(Curl_inet_pton(AF_INET, hostname, &addr))
- return CURL_SSL_PEER_IPV4;
-#ifdef USE_IPV6
- else if(Curl_inet_pton(AF_INET6, hostname, &addr)) {
- return CURL_SSL_PEER_IPV6;
- }
+ return (hostname && hostname[0] && (Curl_inet_pton(AF_INET, hostname, &addr)
+#ifdef ENABLE_IPV6
+ || Curl_inet_pton(AF_INET6, hostname, &addr)
#endif
- }
- return CURL_SSL_PEER_DNS;
+ ));
}
-CURLcode Curl_ssl_peer_init(struct ssl_peer *peer, struct Curl_cfilter *cf,
- int transport)
+CURLcode Curl_ssl_peer_init(struct ssl_peer *peer, struct Curl_cfilter *cf)
{
+ struct ssl_connect_data *connssl = cf->ctx;
const char *ehostname, *edispname;
- CURLcode result = CURLE_OUT_OF_MEMORY;
-
- /* We expect a clean struct, e.g. called only ONCE */
- DEBUGASSERT(peer);
- DEBUGASSERT(!peer->hostname);
- DEBUGASSERT(!peer->dispname);
- DEBUGASSERT(!peer->sni);
- /* We need the hostname for SNI negotiation. Once handshaked, this remains
- * the SNI hostname for the TLS connection. When the connection is reused,
- * the settings in cf->conn might change. We keep a copy of the hostname we
- * use for SNI.
+ int eport;
+
+ /* We need the hostname for SNI negotiation. Once handshaked, this
+ * remains the SNI hostname for the TLS connection. But when the
+ * connection is reused, the settings in cf->conn might change.
+ * So we keep a copy of the hostname we use for SNI.
*/
- peer->transport = transport;
#ifndef CURL_DISABLE_PROXY
if(Curl_ssl_cf_is_proxy(cf)) {
ehostname = cf->conn->http_proxy.host.name;
edispname = cf->conn->http_proxy.host.dispname;
- peer->port = cf->conn->http_proxy.port;
+ eport = cf->conn->http_proxy.port;
}
else
#endif
{
ehostname = cf->conn->host.name;
edispname = cf->conn->host.dispname;
- peer->port = cf->conn->remote_port;
+ eport = cf->conn->remote_port;
}
- /* hostname MUST exist and not be empty */
- if(!ehostname || !ehostname[0]) {
- result = CURLE_FAILED_INIT;
- goto out;
- }
+ /* change if ehostname changed */
+ if(ehostname && (!peer->hostname
+ || strcmp(ehostname, peer->hostname))) {
+ Curl_ssl_peer_cleanup(peer);
+ peer->hostname = strdup(ehostname);
+ if(!peer->hostname) {
+ Curl_ssl_peer_cleanup(peer);
+ return CURLE_OUT_OF_MEMORY;
+ }
+ if(!edispname || !strcmp(ehostname, edispname))
+ peer->dispname = peer->hostname;
+ else {
+ peer->dispname = strdup(edispname);
+ if(!peer->dispname) {
+ Curl_ssl_peer_cleanup(peer);
+ return CURLE_OUT_OF_MEMORY;
+ }
+ }
- peer->hostname = strdup(ehostname);
- if(!peer->hostname)
- goto out;
- if(!edispname || !strcmp(ehostname, edispname))
- peer->dispname = peer->hostname;
- else {
- peer->dispname = strdup(edispname);
- if(!peer->dispname)
- goto out;
- }
- peer->type = get_peer_type(peer->hostname);
- if(peer->type == CURL_SSL_PEER_DNS) {
- /* not an IP address, normalize according to RCC 6066 ch. 3,
- * max len of SNI is 2^16-1, no trailing dot */
- size_t len = strlen(peer->hostname);
- if(len && (peer->hostname[len-1] == '.'))
- len--;
- if(len < USHRT_MAX) {
- peer->sni = calloc(1, len + 1);
- if(!peer->sni)
- goto out;
- Curl_strntolower(peer->sni, peer->hostname, len);
- peer->sni[len] = 0;
+ peer->sni = NULL;
+ peer->is_ip_address = is_ip_address(peer->hostname)? TRUE : FALSE;
+ if(peer->hostname[0] && !peer->is_ip_address) {
+ /* not an IP address, normalize according to RCC 6066 ch. 3,
+ * max len of SNI is 2^16-1, no trailing dot */
+ size_t len = strlen(peer->hostname);
+ if(len && (peer->hostname[len-1] == '.'))
+ len--;
+ if(len < USHRT_MAX) {
+ peer->sni = calloc(1, len + 1);
+ if(!peer->sni) {
+ Curl_ssl_peer_cleanup(peer);
+ return CURLE_OUT_OF_MEMORY;
+ }
+ Curl_strntolower(peer->sni, peer->hostname, len);
+ peer->sni[len] = 0;
+ }
}
- }
- result = CURLE_OK;
-out:
- if(result)
- Curl_ssl_peer_cleanup(peer);
- return result;
+ }
+ connssl->port = eport;
+ return CURLE_OK;
}
static void ssl_cf_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
@@ -1680,29 +1657,22 @@ static CURLcode ssl_cf_connect(struct Curl_cfilter *cf,
return CURLE_OK;
}
- if(!cf->next) {
- *done = FALSE;
- return CURLE_FAILED_INIT;
- }
-
- if(!cf->next->connected) {
- result = cf->next->cft->do_connect(cf->next, data, blocking, done);
- if(result || !*done)
- return result;
- }
-
CF_DATA_SAVE(save, cf, data);
CURL_TRC_CF(data, cf, "cf_connect()");
+ (void)connssl;
DEBUGASSERT(data->conn);
DEBUGASSERT(data->conn == cf->conn);
DEBUGASSERT(connssl);
+ DEBUGASSERT(cf->conn->host.name);
+
+ result = cf->next->cft->do_connect(cf->next, data, blocking, done);
+ if(result || !*done)
+ goto out;
*done = FALSE;
- if(!connssl->peer.hostname) {
- result = Curl_ssl_peer_init(&connssl->peer, cf, TRNSPRT_TCP);
- if(result)
- goto out;
- }
+ result = Curl_ssl_peer_init(&connssl->peer, cf);
+ if(result)
+ goto out;
if(blocking) {
result = ssl_connect(cf, data);
@@ -1740,12 +1710,11 @@ static bool ssl_cf_data_pending(struct Curl_cfilter *cf,
static ssize_t ssl_cf_send(struct Curl_cfilter *cf,
struct Curl_easy *data, const void *buf, size_t len,
- bool eos, CURLcode *err)
+ CURLcode *err)
{
struct cf_call_data save;
ssize_t nwritten;
- (void)eos; /* unused */
CF_DATA_SAVE(save, cf, data);
*err = CURLE_OK;
nwritten = Curl_ssl->send_plain(cf, data, buf, len, err);
@@ -1770,40 +1739,22 @@ static ssize_t ssl_cf_recv(struct Curl_cfilter *cf,
/* eof */
*err = CURLE_OK;
}
- CURL_TRC_CF(data, cf, "cf_recv(len=%zu) -> %zd, %d", len,
- nread, *err);
+ CURL_TRC_CF(data, cf, "cf_recv(len=%zu) -> %zd, %d", len, nread, *err);
CF_DATA_RESTORE(cf, save);
return nread;
}
-static CURLcode ssl_cf_shutdown(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- bool *done)
+static void ssl_cf_adjust_pollset(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ struct easy_pollset *ps)
{
- CURLcode result = CURLE_OK;
-
- *done = TRUE;
- if(!cf->shutdown) {
- struct cf_call_data save;
+ struct cf_call_data save;
+ if(!cf->connected) {
CF_DATA_SAVE(save, cf, data);
- result = Curl_ssl->shut_down(cf, data, TRUE, done);
- CURL_TRC_CF(data, cf, "cf_shutdown -> %d, done=%d", result, *done);
+ Curl_ssl->adjust_pollset(cf, data, ps);
CF_DATA_RESTORE(cf, save);
- cf->shutdown = (result || *done);
}
- return result;
-}
-
-static void ssl_cf_adjust_pollset(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- struct easy_pollset *ps)
-{
- struct cf_call_data save;
-
- CF_DATA_SAVE(save, cf, data);
- Curl_ssl->adjust_pollset(cf, data, ps);
- CF_DATA_RESTORE(cf, save);
}
static CURLcode ssl_cf_cntrl(struct Curl_cfilter *cf,
@@ -1893,7 +1844,6 @@ struct Curl_cftype Curl_cft_ssl = {
ssl_cf_destroy,
ssl_cf_connect,
ssl_cf_close,
- ssl_cf_shutdown,
Curl_cf_def_get_host,
ssl_cf_adjust_pollset,
ssl_cf_data_pending,
@@ -1905,16 +1855,13 @@ struct Curl_cftype Curl_cft_ssl = {
ssl_cf_query,
};
-#ifndef CURL_DISABLE_PROXY
-
struct Curl_cftype Curl_cft_ssl_proxy = {
"SSL-PROXY",
- CF_TYPE_SSL|CF_TYPE_PROXY,
+ CF_TYPE_SSL,
CURL_LOG_LVL_NONE,
ssl_cf_destroy,
ssl_cf_connect,
ssl_cf_close,
- ssl_cf_shutdown,
Curl_cf_def_get_host,
ssl_cf_adjust_pollset,
ssl_cf_data_pending,
@@ -1926,8 +1873,6 @@ struct Curl_cftype Curl_cft_ssl_proxy = {
Curl_cf_def_query,
};
-#endif /* !CURL_DISABLE_PROXY */
-
static CURLcode cf_ssl_create(struct Curl_cfilter **pcf,
struct Curl_easy *data,
struct connectdata *conn)
@@ -2026,21 +1971,17 @@ CURLcode Curl_cf_ssl_proxy_insert_after(struct Curl_cfilter *cf_at,
#endif /* !CURL_DISABLE_PROXY */
-bool Curl_ssl_supports(struct Curl_easy *data, unsigned int ssl_option)
+bool Curl_ssl_supports(struct Curl_easy *data, int option)
{
(void)data;
- return (Curl_ssl->supports & ssl_option)? TRUE : FALSE;
+ return (Curl_ssl->supports & option)? TRUE : FALSE;
}
static struct Curl_cfilter *get_ssl_filter(struct Curl_cfilter *cf)
{
for(; cf; cf = cf->next) {
- if(cf->cft == &Curl_cft_ssl)
+ if(cf->cft == &Curl_cft_ssl || cf->cft == &Curl_cft_ssl_proxy)
return cf;
-#ifndef CURL_DISABLE_PROXY
- if(cf->cft == &Curl_cft_ssl_proxy)
- return cf;
-#endif
}
return NULL;
}
@@ -2065,77 +2006,19 @@ void *Curl_ssl_get_internals(struct Curl_easy *data, int sockindex,
return result;
}
-static CURLcode vtls_shutdown_blocking(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- bool send_shutdown, bool *done)
-{
- struct ssl_connect_data *connssl = cf->ctx;
- struct cf_call_data save;
- CURLcode result = CURLE_OK;
- timediff_t timeout_ms;
- int what, loop = 10;
-
- if(cf->shutdown) {
- *done = TRUE;
- return CURLE_OK;
- }
- CF_DATA_SAVE(save, cf, data);
-
- *done = FALSE;
- while(!result && !*done && loop--) {
- timeout_ms = Curl_shutdown_timeleft(cf->conn, cf->sockindex, NULL);
-
- if(timeout_ms < 0) {
- /* no need to continue if time is already up */
- failf(data, "SSL shutdown timeout");
- return CURLE_OPERATION_TIMEDOUT;
- }
-
- result = Curl_ssl->shut_down(cf, data, send_shutdown, done);
- if(result ||*done)
- goto out;
-
- if(connssl->io_need) {
- what = Curl_conn_cf_poll(cf, data, timeout_ms);
- if(what < 0) {
- /* fatal error */
- failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
- result = CURLE_RECV_ERROR;
- goto out;
- }
- else if(0 == what) {
- /* timeout */
- failf(data, "SSL shutdown timeout");
- result = CURLE_OPERATION_TIMEDOUT;
- goto out;
- }
- /* socket is readable or writable */
- }
- }
-out:
- CF_DATA_RESTORE(cf, save);
- cf->shutdown = (result || *done);
- return result;
-}
-
CURLcode Curl_ssl_cfilter_remove(struct Curl_easy *data,
- int sockindex, bool send_shutdown)
+ int sockindex)
{
struct Curl_cfilter *cf, *head;
CURLcode result = CURLE_OK;
+ (void)data;
head = data->conn? data->conn->cfilter[sockindex] : NULL;
for(cf = head; cf; cf = cf->next) {
if(cf->cft == &Curl_cft_ssl) {
- bool done;
- CURL_TRC_CF(data, cf, "shutdown and remove SSL, start");
- Curl_shutdown_start(data, sockindex, NULL);
- result = vtls_shutdown_blocking(cf, data, send_shutdown, &done);
- Curl_shutdown_clear(data, sockindex);
- if(!result && !done) /* blocking failed? */
+ if(Curl_ssl->shut_down(cf, data))
result = CURLE_SSL_SHUTDOWN_FAILED;
Curl_conn_cf_discard_sub(head, cf, data, FALSE);
- CURL_TRC_CF(data, cf, "shutdown and remove SSL, done -> %d", result);
break;
}
}
@@ -2144,7 +2027,7 @@ CURLcode Curl_ssl_cfilter_remove(struct Curl_easy *data,
bool Curl_ssl_cf_is_proxy(struct Curl_cfilter *cf)
{
- return (cf->cft->flags & CF_TYPE_SSL) && (cf->cft->flags & CF_TYPE_PROXY);
+ return (cf->cft == &Curl_cft_ssl_proxy);
}
struct ssl_config_data *
@@ -2220,6 +2103,7 @@ CURLcode Curl_alpn_set_negotiated(struct Curl_cfilter *cf,
const unsigned char *proto,
size_t proto_len)
{
+ int can_multi = 0;
unsigned char *palpn =
#ifndef CURL_DISABLE_PROXY
(cf->conn->bits.tunnel_proxy && Curl_ssl_cf_is_proxy(cf))?
@@ -2238,12 +2122,14 @@ CURLcode Curl_alpn_set_negotiated(struct Curl_cfilter *cf,
else if(proto_len == ALPN_H2_LENGTH &&
!memcmp(ALPN_H2, proto, ALPN_H2_LENGTH)) {
*palpn = CURL_HTTP_VERSION_2;
+ can_multi = 1;
}
#endif
#ifdef USE_HTTP3
else if(proto_len == ALPN_H3_LENGTH &&
!memcmp(ALPN_H3, proto, ALPN_H3_LENGTH)) {
*palpn = CURL_HTTP_VERSION_3;
+ can_multi = 1;
}
#endif
else {
@@ -2262,6 +2148,9 @@ CURLcode Curl_alpn_set_negotiated(struct Curl_cfilter *cf,
}
out:
+ if(!Curl_ssl_cf_is_proxy(cf))
+ Curl_multiuse_state(data, can_multi?
+ BUNDLE_MULTIPLEX : BUNDLE_NO_MULTIUSE);
return CURLE_OK;
}
diff --git a/contrib/libs/curl/lib/vtls/vtls.h b/contrib/libs/curl/lib/vtls/vtls.h
index fce1e00183..f1856bd333 100644
--- a/contrib/libs/curl/lib/vtls/vtls.h
+++ b/contrib/libs/curl/lib/vtls/vtls.h
@@ -37,9 +37,6 @@ struct Curl_ssl_session;
#define SSLSUPP_HTTPS_PROXY (1<<4) /* supports access via HTTPS proxies */
#define SSLSUPP_TLS13_CIPHERSUITES (1<<5) /* supports TLS 1.3 ciphersuites */
#define SSLSUPP_CAINFO_BLOB (1<<6)
-#define SSLSUPP_ECH (1<<7)
-#define SSLSUPP_CA_CACHE (1<<8)
-#define SSLSUPP_CIPHER_LIST (1<<9) /* supports TLS 1.0-1.2 ciphersuites */
#define ALPN_ACCEPTED "ALPN: server accepted "
@@ -54,6 +51,7 @@ struct Curl_ssl_session;
/* Curl_multi SSL backend-specific data; declared differently by each SSL
backend */
+struct multi_ssl_backend_data;
struct Curl_cfilter;
CURLsslset Curl_init_sslset_nolock(curl_sslbackend id, const char *name,
@@ -93,7 +91,7 @@ CURLcode Curl_ssl_conn_config_init(struct Curl_easy *data,
void Curl_ssl_conn_config_cleanup(struct connectdata *conn);
/**
- * Return TRUE iff SSL configuration from `data` is functionally the
+ * Return TRUE iff SSL configuration from `conn` is functionally the
* same as the one on `candidate`.
* @param proxy match the proxy SSL config or the main one
*/
@@ -109,8 +107,7 @@ void Curl_ssl_conn_config_update(struct Curl_easy *data, bool for_proxy);
/**
* Init SSL peer information for filter. Can be called repeatedly.
*/
-CURLcode Curl_ssl_peer_init(struct ssl_peer *peer,
- struct Curl_cfilter *cf, int transport);
+CURLcode Curl_ssl_peer_init(struct ssl_peer *peer, struct Curl_cfilter *cf);
/**
* Free all allocated data and reset peer information.
*/
@@ -132,7 +129,6 @@ CURLcode Curl_ssl_initsessions(struct Curl_easy *, size_t);
void Curl_ssl_version(char *buffer, size_t size);
/* Certificate information list handling. */
-#define CURL_X509_STR_MAX 100000
void Curl_ssl_free_certinfo(struct Curl_easy *data);
CURLcode Curl_ssl_init_certinfo(struct Curl_easy *data, int num);
@@ -183,24 +179,7 @@ bool Curl_ssl_cert_status_request(void);
bool Curl_ssl_false_start(struct Curl_easy *data);
-/* The maximum size of the SSL channel binding is 85 bytes, as defined in
- * RFC 5929, Section 4.1. The 'tls-server-end-point:' prefix is 21 bytes long,
- * and SHA-512 is the longest supported hash algorithm, with a digest length of
- * 64 bytes.
- * The maximum size of the channel binding is therefore 21 + 64 = 85 bytes.
- */
-#define SSL_CB_MAX_SIZE 85
-
-/* Return the tls-server-end-point channel binding, including the
- * 'tls-server-end-point:' prefix.
- * If successful, the data is written to the dynbuf, and CURLE_OK is returned.
- * The dynbuf MUST HAVE a minimum toobig size of SSL_CB_MAX_SIZE.
- * If the dynbuf is too small, CURLE_OUT_OF_MEMORY is returned.
- * If channel binding is not supported, binding stays empty and CURLE_OK is
- * returned.
- */
-CURLcode Curl_ssl_get_channel_binding(struct Curl_easy *data, int sockindex,
- struct dynbuf *binding);
+void Curl_free_multi_ssl_backend_data(struct multi_ssl_backend_data *mbackend);
#define SSL_SHUTDOWN_TIMEOUT 10000 /* ms */
@@ -212,7 +191,7 @@ CURLcode Curl_cf_ssl_insert_after(struct Curl_cfilter *cf_at,
struct Curl_easy *data);
CURLcode Curl_ssl_cfilter_remove(struct Curl_easy *data,
- int sockindex, bool send_shutdown);
+ int sockindex);
#ifndef CURL_DISABLE_PROXY
CURLcode Curl_cf_ssl_proxy_insert_after(struct Curl_cfilter *cf_at,
@@ -224,7 +203,7 @@ CURLcode Curl_cf_ssl_proxy_insert_after(struct Curl_cfilter *cf_at,
* Option is one of the defined SSLSUPP_* values.
* `data` maybe NULL for the features of the default implementation.
*/
-bool Curl_ssl_supports(struct Curl_easy *data, unsigned int ssl_option);
+bool Curl_ssl_supports(struct Curl_easy *data, int ssl_option);
/**
* Get the internal ssl instance (like OpenSSL's SSL*) from the filter
@@ -249,9 +228,7 @@ struct ssl_primary_config *
Curl_ssl_cf_get_primary_config(struct Curl_cfilter *cf);
extern struct Curl_cftype Curl_cft_ssl;
-#ifndef CURL_DISABLE_PROXY
extern struct Curl_cftype Curl_cft_ssl_proxy;
-#endif
#else /* if not USE_SSL */
@@ -271,7 +248,7 @@ extern struct Curl_cftype Curl_cft_ssl_proxy;
#define Curl_ssl_get_internals(a,b,c,d) NULL
#define Curl_ssl_supports(a,b) FALSE
#define Curl_ssl_cfilter_add(a,b,c) CURLE_NOT_BUILT_IN
-#define Curl_ssl_cfilter_remove(a,b,c) CURLE_OK
+#define Curl_ssl_cfilter_remove(a,b) CURLE_OK
#define Curl_ssl_cf_get_config(a,b) NULL
#define Curl_ssl_cf_get_primary_config(a) NULL
#endif
diff --git a/contrib/libs/curl/lib/vtls/vtls_int.h b/contrib/libs/curl/lib/vtls/vtls_int.h
index 836bfad708..af7ae552ed 100644
--- a/contrib/libs/curl/lib/vtls/vtls_int.h
+++ b/contrib/libs/curl/lib/vtls/vtls_int.h
@@ -64,36 +64,18 @@ CURLcode Curl_alpn_set_negotiated(struct Curl_cfilter *cf,
const unsigned char *proto,
size_t proto_len);
-/* enum for the nonblocking SSL connection state machine */
-typedef enum {
- ssl_connect_1,
- ssl_connect_2,
- ssl_connect_3,
- ssl_connect_done
-} ssl_connect_state;
-
-typedef enum {
- ssl_connection_none,
- ssl_connection_negotiating,
- ssl_connection_complete
-} ssl_connection_state;
-
-#define CURL_SSL_IO_NEED_NONE (0)
-#define CURL_SSL_IO_NEED_RECV (1<<0)
-#define CURL_SSL_IO_NEED_SEND (1<<1)
-
/* Information in each SSL cfilter context: cf->ctx */
struct ssl_connect_data {
+ ssl_connection_state state;
+ ssl_connect_state connecting_state;
struct ssl_peer peer;
const struct alpn_spec *alpn; /* ALPN to use or NULL for none */
void *backend; /* vtls backend specific props */
struct cf_call_data call_data; /* data handle used in current call */
struct curltime handshake_done; /* time when handshake finished */
- ssl_connection_state state;
- ssl_connect_state connecting_state;
- int io_need; /* TLS signals special SEND/RECV needs */
+ int port; /* remote port at origin */
BIT(use_alpn); /* if ALPN shall be used in handshake */
- BIT(peer_closed); /* peer has closed connection */
+ BIT(reused_session); /* session-ID was reused for this */
};
@@ -118,8 +100,8 @@ struct Curl_ssl {
size_t (*version)(char *buffer, size_t size);
int (*check_cxn)(struct Curl_cfilter *cf, struct Curl_easy *data);
- CURLcode (*shut_down)(struct Curl_cfilter *cf, struct Curl_easy *data,
- bool send_shutdown, bool *done);
+ int (*shut_down)(struct Curl_cfilter *cf,
+ struct Curl_easy *data);
bool (*data_pending)(struct Curl_cfilter *cf,
const struct Curl_easy *data);
@@ -134,13 +116,15 @@ struct Curl_ssl {
struct Curl_easy *data,
bool *done);
- /* During handshake/shutdown, adjust the pollset to include the socket
- * for POLLOUT or POLLIN as needed. Mandatory. */
+ /* During handshake, adjust the pollset to include the socket
+ * for POLLOUT or POLLIN as needed.
+ * Mandatory. */
void (*adjust_pollset)(struct Curl_cfilter *cf, struct Curl_easy *data,
struct easy_pollset *ps);
void *(*get_internals)(struct ssl_connect_data *connssl, CURLINFO info);
void (*close)(struct Curl_cfilter *cf, struct Curl_easy *data);
void (*close_all)(struct Curl_easy *data);
+ void (*session_free)(void *ptr);
CURLcode (*set_engine)(struct Curl_easy *data, const char *engine);
CURLcode (*set_engine_default)(struct Curl_easy *data);
@@ -153,14 +137,13 @@ struct Curl_ssl {
bool (*attach_data)(struct Curl_cfilter *cf, struct Curl_easy *data);
void (*detach_data)(struct Curl_cfilter *cf, struct Curl_easy *data);
+ void (*free_multi_ssl_backend_data)(struct multi_ssl_backend_data *mbackend);
+
ssize_t (*recv_plain)(struct Curl_cfilter *cf, struct Curl_easy *data,
char *buf, size_t len, CURLcode *code);
ssize_t (*send_plain)(struct Curl_cfilter *cf, struct Curl_easy *data,
const void *mem, size_t len, CURLcode *code);
- CURLcode (*get_channel_binding)(struct Curl_easy *data, int sockindex,
- struct dynbuf *binding);
-
};
extern const struct Curl_ssl *Curl_ssl;
@@ -168,9 +151,10 @@ extern const struct Curl_ssl *Curl_ssl;
int Curl_none_init(void);
void Curl_none_cleanup(void);
-CURLcode Curl_none_shutdown(struct Curl_cfilter *cf, struct Curl_easy *data,
- bool send_shutdown, bool *done);
+int Curl_none_shutdown(struct Curl_cfilter *cf, struct Curl_easy *data);
int Curl_none_check_cxn(struct Curl_cfilter *cf, struct Curl_easy *data);
+CURLcode Curl_none_random(struct Curl_easy *data, unsigned char *entropy,
+ size_t length);
void Curl_none_close_all(struct Curl_easy *data);
void Curl_none_session_free(void *ptr);
bool Curl_none_data_pending(struct Curl_cfilter *cf,
@@ -196,25 +180,18 @@ bool Curl_ssl_cf_is_proxy(struct Curl_cfilter *cf);
*/
bool Curl_ssl_getsessionid(struct Curl_cfilter *cf,
struct Curl_easy *data,
- const struct ssl_peer *peer,
void **ssl_sessionid,
size_t *idsize); /* set 0 if unknown */
-
-/* Set a TLS session ID for `peer`. Replaces an existing session ID if
- * not already the very same.
+/* add a new session ID
* Sessionid mutex must be locked (see Curl_ssl_sessionid_lock).
- * Call takes ownership of `ssl_sessionid`, using `sessionid_free_cb`
- * to deallocate it. Is called in all outcomes, either right away or
- * later when the session cache is cleaned up.
* Caller must ensure that it has properly shared ownership of this sessionid
* object with cache (e.g. incrementing refcount on success)
*/
-CURLcode Curl_ssl_set_sessionid(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- const struct ssl_peer *peer,
- void *sessionid,
- size_t sessionid_size,
- Curl_ssl_sessionid_dtor *sessionid_free_cb);
+CURLcode Curl_ssl_addsessionid(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ void *ssl_sessionid,
+ size_t idsize,
+ bool *added);
#include "openssl.h" /* OpenSSL versions */
#include "gtls.h" /* GnuTLS versions */
@@ -223,7 +200,7 @@ CURLcode Curl_ssl_set_sessionid(struct Curl_cfilter *cf,
#include "sectransp.h" /* SecureTransport (Darwin) version */
#include "mbedtls.h" /* mbedTLS versions */
#include "bearssl.h" /* BearSSL versions */
-#include "rustls.h" /* Rustls versions */
+#include "rustls.h" /* rustls versions */
#endif /* USE_SSL */
diff --git a/contrib/libs/curl/lib/vtls/wolfssl.c b/contrib/libs/curl/lib/vtls/wolfssl.c
index d2a25455b8..fa5f51eb26 100644
--- a/contrib/libs/curl/lib/vtls/wolfssl.c
+++ b/contrib/libs/curl/lib/vtls/wolfssl.c
@@ -36,10 +36,6 @@
#error #include <wolfssl/version.h>
#error #include <wolfssl/options.h>
-#if LIBWOLFSSL_VERSION_HEX < 0x03004006 /* wolfSSL 3.4.6 (2015) */
-#error "wolfSSL version should be at least 3.4.6"
-#endif
-
/* To determine what functions are available we rely on one or both of:
- the user's options.h generated by wolfSSL
- the symbols detected by curl's configure
@@ -65,7 +61,7 @@
#include "connect.h" /* for the connect timeout */
#include "select.h"
#include "strcase.h"
-#error #include "x509asn1.h"
+#include "x509asn1.h"
#include "curl_printf.h"
#include "multiif.h"
@@ -78,14 +74,6 @@
#include "curl_memory.h"
#include "memdebug.h"
-#ifdef USE_ECH
-# include "curl_base64.h"
-# define ECH_ENABLED(__data__) \
- (__data__->set.tls_ech && \
- !(__data__->set.tls_ech & CURLECH_DISABLE)\
- )
-#endif /* USE_ECH */
-
/* KEEP_PEER_CERT is a product of the presence of build time symbol
OPENSSL_EXTRA without NO_CERTS, depending on the version. KEEP_PEER_CERT is
in wolfSSL's settings.h, and the latter two are build time symbols in
@@ -103,11 +91,17 @@
#undef USE_BIO_CHAIN
#endif
+struct wolfssl_ssl_backend_data {
+ WOLFSSL_CTX *ctx;
+ WOLFSSL *handle;
+ CURLcode io_result; /* result of last BIO cfilter operation */
+};
+
#ifdef OPENSSL_EXTRA
/*
* Availability note:
* The TLS 1.3 secret callback (wolfSSL_set_tls13_secret_cb) was added in
- * wolfSSL 4.4.0, but requires the -DHAVE_SECRET_CALLBACK build option. If that
+ * WolfSSL 4.4.0, but requires the -DHAVE_SECRET_CALLBACK build option. If that
* option is not set, then TLS 1.3 will not be logged.
* For TLS 1.2 and before, we use wolfSSL_get_keys().
* SSL_get_client_random and wolfSSL_get_keys require OPENSSL_EXTRA
@@ -205,7 +199,7 @@ wolfssl_log_tls12_secret(SSL *ssl)
}
#endif /* OPENSSL_EXTRA */
-static int wolfssl_do_file_type(const char *type)
+static int do_file_type(const char *type)
{
if(!type || !type[0])
return SSL_FILETYPE_PEM;
@@ -216,7 +210,7 @@ static int wolfssl_do_file_type(const char *type)
return -1;
}
-#ifdef WOLFSSL_HAVE_KYBER
+#ifdef HAVE_LIBOQS
struct group_name_map {
const word16 group;
const char *name;
@@ -238,6 +232,7 @@ static const struct group_name_map gnm[] = {
static int wolfssl_bio_cf_create(WOLFSSL_BIO *bio)
{
wolfSSL_BIO_set_shutdown(bio, 1);
+ wolfSSL_BIO_set_init(bio, 1);
wolfSSL_BIO_set_data(bio, NULL);
return 1;
}
@@ -288,35 +283,20 @@ static int wolfssl_bio_cf_out_write(WOLFSSL_BIO *bio,
{
struct Curl_cfilter *cf = wolfSSL_BIO_get_data(bio);
struct ssl_connect_data *connssl = cf->ctx;
- struct wolfssl_ctx *backend =
- (struct wolfssl_ctx *)connssl->backend;
+ struct wolfssl_ssl_backend_data *backend =
+ (struct wolfssl_ssl_backend_data *)connssl->backend;
struct Curl_easy *data = CF_DATA_CURRENT(cf);
- ssize_t nwritten, skiplen = 0;
+ ssize_t nwritten;
CURLcode result = CURLE_OK;
DEBUGASSERT(data);
- if(backend->shutting_down && backend->io_send_blocked_len &&
- (backend->io_send_blocked_len < blen)) {
- /* bug in wolfSSL: <https://github.com/wolfSSL/wolfssl/issues/7784>
- * It adds the close notify message again every time we retry
- * sending during shutdown. */
- CURL_TRC_CF(data, cf, "bio_write, shutdown restrict send of %d"
- " to %d bytes", blen, backend->io_send_blocked_len);
- skiplen = (ssize_t)(blen - backend->io_send_blocked_len);
- blen = backend->io_send_blocked_len;
- }
- nwritten = Curl_conn_cf_send(cf->next, data, buf, blen, FALSE, &result);
+ nwritten = Curl_conn_cf_send(cf->next, data, buf, blen, &result);
backend->io_result = result;
CURL_TRC_CF(data, cf, "bio_write(len=%d) -> %zd, %d",
blen, nwritten, result);
wolfSSL_BIO_clear_retry_flags(bio);
- if(nwritten < 0 && CURLE_AGAIN == result) {
+ if(nwritten < 0 && CURLE_AGAIN == result)
BIO_set_retry_write(bio);
- if(backend->shutting_down && !backend->io_send_blocked_len)
- backend->io_send_blocked_len = blen;
- }
- else if(!result && skiplen)
- nwritten += skiplen;
return (int)nwritten;
}
@@ -324,8 +304,8 @@ static int wolfssl_bio_cf_in_read(WOLFSSL_BIO *bio, char *buf, int blen)
{
struct Curl_cfilter *cf = wolfSSL_BIO_get_data(bio);
struct ssl_connect_data *connssl = cf->ctx;
- struct wolfssl_ctx *backend =
- (struct wolfssl_ctx *)connssl->backend;
+ struct wolfssl_ssl_backend_data *backend =
+ (struct wolfssl_ssl_backend_data *)connssl->backend;
struct Curl_easy *data = CF_DATA_CURRENT(cf);
ssize_t nread;
CURLcode result = CURLE_OK;
@@ -341,8 +321,6 @@ static int wolfssl_bio_cf_in_read(WOLFSSL_BIO *bio, char *buf, int blen)
wolfSSL_BIO_clear_retry_flags(bio);
if(nread < 0 && CURLE_AGAIN == result)
BIO_set_retry_read(bio);
- else if(nread == 0)
- connssl->peer_closed = TRUE;
return (int)nread;
}
@@ -370,335 +348,6 @@ static void wolfssl_bio_cf_free_methods(void)
#endif /* !USE_BIO_CHAIN */
-static CURLcode populate_x509_store(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- X509_STORE *store,
- struct wolfssl_ctx *wssl)
-{
- struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
- const struct curl_blob *ca_info_blob = conn_config->ca_info_blob;
- const char * const ssl_cafile =
- /* CURLOPT_CAINFO_BLOB overrides CURLOPT_CAINFO */
- (ca_info_blob ? NULL : conn_config->CAfile);
- const char * const ssl_capath = conn_config->CApath;
- struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
- bool imported_native_ca = false;
-
-#if !defined(NO_FILESYSTEM) && defined(WOLFSSL_SYS_CA_CERTS)
- /* load native CA certificates */
- if(ssl_config->native_ca_store) {
- if(wolfSSL_CTX_load_system_CA_certs(wssl->ctx) != WOLFSSL_SUCCESS) {
- infof(data, "error importing native CA store, continuing anyway");
- }
- else {
- imported_native_ca = true;
- infof(data, "successfully imported native CA store");
- wssl->x509_store_setup = TRUE;
- }
- }
-#endif /* !NO_FILESYSTEM */
-
- /* load certificate blob */
- if(ca_info_blob) {
- if(wolfSSL_CTX_load_verify_buffer(wssl->ctx, ca_info_blob->data,
- (long)ca_info_blob->len,
- SSL_FILETYPE_PEM) != SSL_SUCCESS) {
- if(imported_native_ca) {
- infof(data, "error importing CA certificate blob, continuing anyway");
- }
- else {
- failf(data, "error importing CA certificate blob");
- return CURLE_SSL_CACERT_BADFILE;
- }
- }
- else {
- infof(data, "successfully imported CA certificate blob");
- wssl->x509_store_setup = TRUE;
- }
- }
-
-#ifndef NO_FILESYSTEM
- /* load trusted cacert from file if not blob */
-
- CURL_TRC_CF(data, cf, "populate_x509_store, path=%s, blob=%d",
- ssl_cafile? ssl_cafile : "none", !!ca_info_blob);
- if(!store)
- return CURLE_OUT_OF_MEMORY;
-
- if((ssl_cafile || ssl_capath) && (!wssl->x509_store_setup)) {
- int rc =
- wolfSSL_CTX_load_verify_locations_ex(wssl->ctx,
- ssl_cafile,
- ssl_capath,
- WOLFSSL_LOAD_FLAG_IGNORE_ERR);
- if(SSL_SUCCESS != rc) {
- if(conn_config->verifypeer) {
- /* Fail if we insist on successfully verifying the server. */
- failf(data, "error setting certificate verify locations:"
- " CAfile: %s CApath: %s",
- ssl_cafile ? ssl_cafile : "none",
- ssl_capath ? ssl_capath : "none");
- return CURLE_SSL_CACERT_BADFILE;
- }
- else {
- /* Just continue with a warning if no strict certificate
- verification is required. */
- infof(data, "error setting certificate verify locations,"
- " continuing anyway:");
- }
- }
- else {
- /* Everything is fine. */
- infof(data, "successfully set certificate verify locations:");
- }
- infof(data, " CAfile: %s", ssl_cafile ? ssl_cafile : "none");
- infof(data, " CApath: %s", ssl_capath ? ssl_capath : "none");
- }
-#endif
- (void)store;
- wssl->x509_store_setup = TRUE;
- return CURLE_OK;
-}
-
-/* key to use at `multi->proto_hash` */
-#define MPROTO_WSSL_X509_KEY "tls:wssl:x509:share"
-
-struct wssl_x509_share {
- char *CAfile; /* CAfile path used to generate X509 store */
- WOLFSSL_X509_STORE *store; /* cached X509 store or NULL if none */
- struct curltime time; /* when the cached store was created */
-};
-
-static void wssl_x509_share_free(void *key, size_t key_len, void *p)
-{
- struct wssl_x509_share *share = p;
- DEBUGASSERT(key_len == (sizeof(MPROTO_WSSL_X509_KEY)-1));
- DEBUGASSERT(!memcmp(MPROTO_WSSL_X509_KEY, key, key_len));
- (void)key;
- (void)key_len;
- if(share->store) {
- wolfSSL_X509_STORE_free(share->store);
- }
- free(share->CAfile);
- free(share);
-}
-
-static bool
-cached_x509_store_expired(const struct Curl_easy *data,
- const struct wssl_x509_share *mb)
-{
- const struct ssl_general_config *cfg = &data->set.general_ssl;
- struct curltime now = Curl_now();
- timediff_t elapsed_ms = Curl_timediff(now, mb->time);
- timediff_t timeout_ms = cfg->ca_cache_timeout * (timediff_t)1000;
-
- if(timeout_ms < 0)
- return false;
-
- return elapsed_ms >= timeout_ms;
-}
-
-static bool
-cached_x509_store_different(struct Curl_cfilter *cf,
- const struct wssl_x509_share *mb)
-{
- struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
- if(!mb->CAfile || !conn_config->CAfile)
- return mb->CAfile != conn_config->CAfile;
-
- return strcmp(mb->CAfile, conn_config->CAfile);
-}
-
-static X509_STORE *get_cached_x509_store(struct Curl_cfilter *cf,
- const struct Curl_easy *data)
-{
- struct Curl_multi *multi = data->multi;
- struct wssl_x509_share *share;
- WOLFSSL_X509_STORE *store = NULL;
-
- DEBUGASSERT(multi);
- share = multi? Curl_hash_pick(&multi->proto_hash,
- (void *)MPROTO_WSSL_X509_KEY,
- sizeof(MPROTO_WSSL_X509_KEY)-1) : NULL;
- if(share && share->store &&
- !cached_x509_store_expired(data, share) &&
- !cached_x509_store_different(cf, share)) {
- store = share->store;
- }
-
- return store;
-}
-
-static void set_cached_x509_store(struct Curl_cfilter *cf,
- const struct Curl_easy *data,
- X509_STORE *store)
-{
- struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
- struct Curl_multi *multi = data->multi;
- struct wssl_x509_share *share;
-
- DEBUGASSERT(multi);
- if(!multi)
- return;
- share = Curl_hash_pick(&multi->proto_hash,
- (void *)MPROTO_WSSL_X509_KEY,
- sizeof(MPROTO_WSSL_X509_KEY)-1);
-
- if(!share) {
- share = calloc(1, sizeof(*share));
- if(!share)
- return;
- if(!Curl_hash_add2(&multi->proto_hash,
- (void *)MPROTO_WSSL_X509_KEY,
- sizeof(MPROTO_WSSL_X509_KEY)-1,
- share, wssl_x509_share_free)) {
- free(share);
- return;
- }
- }
-
- if(wolfSSL_X509_STORE_up_ref(store)) {
- char *CAfile = NULL;
-
- if(conn_config->CAfile) {
- CAfile = strdup(conn_config->CAfile);
- if(!CAfile) {
- X509_STORE_free(store);
- return;
- }
- }
-
- if(share->store) {
- X509_STORE_free(share->store);
- free(share->CAfile);
- }
-
- share->time = Curl_now();
- share->store = store;
- share->CAfile = CAfile;
- }
-}
-
-CURLcode Curl_wssl_setup_x509_store(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- struct wolfssl_ctx *wssl)
-{
- struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
- struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
- CURLcode result = CURLE_OK;
- WOLFSSL_X509_STORE *cached_store;
- bool cache_criteria_met;
-
- /* Consider the X509 store cacheable if it comes exclusively from a CAfile,
- or no source is provided and we are falling back to wolfSSL's built-in
- default. */
- cache_criteria_met = (data->set.general_ssl.ca_cache_timeout != 0) &&
- conn_config->verifypeer &&
- !conn_config->CApath &&
- !conn_config->ca_info_blob &&
- !ssl_config->primary.CRLfile &&
- !ssl_config->native_ca_store;
-
- cached_store = cache_criteria_met ? get_cached_x509_store(cf, data) : NULL;
- if(cached_store && wolfSSL_CTX_get_cert_store(wssl->ctx) == cached_store) {
- /* The cached store is already in use, do nothing. */
- }
- else if(cached_store && wolfSSL_X509_STORE_up_ref(cached_store)) {
- wolfSSL_CTX_set_cert_store(wssl->ctx, cached_store);
- }
- else if(cache_criteria_met) {
- /* wolfSSL's initial store in CTX is not shareable by default.
- * Make a new one, suitable for adding to the cache. See #14278 */
- X509_STORE *store = wolfSSL_X509_STORE_new();
- if(!store) {
- failf(data, "SSL: could not create a X509 store");
- return CURLE_OUT_OF_MEMORY;
- }
- wolfSSL_CTX_set_cert_store(wssl->ctx, store);
-
- result = populate_x509_store(cf, data, store, wssl);
- if(!result) {
- set_cached_x509_store(cf, data, store);
- }
- }
- else {
- /* We never share the CTX's store, use it. */
- X509_STORE *store = wolfSSL_CTX_get_cert_store(wssl->ctx);
- result = populate_x509_store(cf, data, store, wssl);
- }
-
- return result;
-}
-
-#ifdef WOLFSSL_TLS13
-static size_t
-wssl_get_default_ciphers(bool tls13, char *buf, size_t size)
-{
- size_t len = 0;
- char *term = buf;
- int i;
- char *str;
- size_t n;
-
- for(i = 0; (str = wolfSSL_get_cipher_list(i)); i++) {
- if((strncmp(str, "TLS13", 5) == 0) != tls13)
- continue;
-
- n = strlen(str);
- if(buf && len + n + 1 <= size) {
- memcpy(buf + len, str, n);
- term = buf + len + n;
- *term = ':';
- }
- len += n + 1;
- }
-
- if(buf)
- *term = '\0';
-
- return len > 0 ? len - 1 : 0;
-}
-#endif
-
-#if LIBWOLFSSL_VERSION_HEX < 0x04002000 /* 4.2.0 (2019) */
-static int
-wssl_legacy_CTX_set_min_proto_version(WOLFSSL_CTX* ctx, int version)
-{
- int res;
- switch(version) {
- default:
- case TLS1_VERSION:
- res = wolfSSL_CTX_SetMinVersion(ctx, WOLFSSL_TLSV1);
- if(res == WOLFSSL_SUCCESS)
- return res;
- FALLTHROUGH();
- case TLS1_1_VERSION:
- res = wolfSSL_CTX_SetMinVersion(ctx, WOLFSSL_TLSV1_1);
- if(res == WOLFSSL_SUCCESS)
- return res;
- FALLTHROUGH();
- case TLS1_2_VERSION:
- res = wolfSSL_CTX_SetMinVersion(ctx, WOLFSSL_TLSV1_2);
-#ifdef WOLFSSL_TLS13
- if(res == WOLFSSL_SUCCESS)
- return res;
- FALLTHROUGH();
- case TLS1_3_VERSION:
- res = wolfSSL_CTX_SetMinVersion(ctx, WOLFSSL_TLSV1_3);
-#endif
- }
- return res;
-}
-static int
-wssl_legacy_CTX_set_max_proto_version(WOLFSSL_CTX* ctx, int version)
-{
- (void) ctx, (void) version;
- return WOLFSSL_NOT_IMPLEMENTED;
-}
-#define wolfSSL_CTX_set_min_proto_version wssl_legacy_CTX_set_min_proto_version
-#define wolfSSL_CTX_set_max_proto_version wssl_legacy_CTX_set_max_proto_version
-#endif
-
/*
* This function loads all the client/CA certificates and CRLs. Setup the TLS
* layer and do all necessary magic.
@@ -706,98 +355,135 @@ wssl_legacy_CTX_set_max_proto_version(WOLFSSL_CTX* ctx, int version)
static CURLcode
wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
{
- int res;
char *ciphers, *curves;
struct ssl_connect_data *connssl = cf->ctx;
- struct wolfssl_ctx *backend =
- (struct wolfssl_ctx *)connssl->backend;
+ struct wolfssl_ssl_backend_data *backend =
+ (struct wolfssl_ssl_backend_data *)connssl->backend;
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+ const struct curl_blob *ca_info_blob = conn_config->ca_info_blob;
const struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
+ const char * const ssl_cafile =
+ /* CURLOPT_CAINFO_BLOB overrides CURLOPT_CAINFO */
+ (ca_info_blob ? NULL : conn_config->CAfile);
+ const char * const ssl_capath = conn_config->CApath;
WOLFSSL_METHOD* req_method = NULL;
-#ifdef WOLFSSL_HAVE_KYBER
- word16 pqkem = 0;
+#ifdef HAVE_LIBOQS
+ word16 oqsAlg = 0;
size_t idx = 0;
#endif
+#ifdef HAVE_SNI
+ bool sni = FALSE;
+#define use_sni(x) sni = (x)
+#else
+#define use_sni(x) Curl_nop_stmt
+#endif
+ bool imported_native_ca = false;
+ bool imported_ca_info_blob = false;
DEBUGASSERT(backend);
if(connssl->state == ssl_connection_complete)
return CURLE_OK;
-#if LIBWOLFSSL_VERSION_HEX < 0x04002000 /* 4.2.0 (2019) */
- req_method = wolfSSLv23_client_method();
-#else
- req_method = wolfTLS_client_method();
-#endif
- if(!req_method) {
- failf(data, "wolfSSL: could not create a client method");
- return CURLE_OUT_OF_MEMORY;
- }
-
- if(backend->ctx)
- wolfSSL_CTX_free(backend->ctx);
-
- backend->ctx = wolfSSL_CTX_new(req_method);
- if(!backend->ctx) {
- failf(data, "wolfSSL: could not create a context");
- return CURLE_OUT_OF_MEMORY;
+ if(conn_config->version_max != CURL_SSLVERSION_MAX_NONE) {
+ failf(data, "wolfSSL does not support to set maximum SSL/TLS version");
+ return CURLE_SSL_CONNECT_ERROR;
}
+ /* check to see if we've been told to use an explicit SSL/TLS version */
switch(conn_config->version) {
case CURL_SSLVERSION_DEFAULT:
case CURL_SSLVERSION_TLSv1:
+#if LIBWOLFSSL_VERSION_HEX >= 0x03003000 /* >= 3.3.0 */
+ /* minimum protocol version is set later after the CTX object is created */
+ req_method = SSLv23_client_method();
+#else
+ infof(data, "wolfSSL <3.3.0 cannot be configured to use TLS 1.0-1.2, "
+ "TLS 1.0 is used exclusively");
+ req_method = TLSv1_client_method();
+#endif
+ use_sni(TRUE);
+ break;
case CURL_SSLVERSION_TLSv1_0:
- res = wolfSSL_CTX_set_min_proto_version(backend->ctx, TLS1_VERSION);
+#if defined(WOLFSSL_ALLOW_TLSV10) && !defined(NO_OLD_TLS)
+ req_method = TLSv1_client_method();
+ use_sni(TRUE);
+#else
+ failf(data, "wolfSSL does not support TLS 1.0");
+ return CURLE_NOT_BUILT_IN;
+#endif
break;
case CURL_SSLVERSION_TLSv1_1:
- res = wolfSSL_CTX_set_min_proto_version(backend->ctx, TLS1_1_VERSION);
+#ifndef NO_OLD_TLS
+ req_method = TLSv1_1_client_method();
+ use_sni(TRUE);
+#else
+ failf(data, "wolfSSL does not support TLS 1.1");
+ return CURLE_NOT_BUILT_IN;
+#endif
break;
case CURL_SSLVERSION_TLSv1_2:
- res = wolfSSL_CTX_set_min_proto_version(backend->ctx, TLS1_2_VERSION);
+#ifndef WOLFSSL_NO_TLS12
+ req_method = TLSv1_2_client_method();
+ use_sni(TRUE);
+#else
+ failf(data, "wolfSSL does not support TLS 1.2");
+ return CURLE_NOT_BUILT_IN;
+#endif
break;
-#ifdef WOLFSSL_TLS13
case CURL_SSLVERSION_TLSv1_3:
- res = wolfSSL_CTX_set_min_proto_version(backend->ctx, TLS1_3_VERSION);
+#ifdef WOLFSSL_TLS13
+ req_method = wolfTLSv1_3_client_method();
+ use_sni(TRUE);
break;
+#else
+ failf(data, "wolfSSL: TLS 1.3 is not yet supported");
+ return CURLE_SSL_CONNECT_ERROR;
#endif
default:
- failf(data, "wolfSSL: unsupported minimum TLS version value");
+ failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
return CURLE_SSL_CONNECT_ERROR;
}
- if(res != WOLFSSL_SUCCESS) {
- failf(data, "wolfSSL: failed set the minimum TLS version");
- return CURLE_SSL_CONNECT_ERROR;
+
+ if(!req_method) {
+ failf(data, "SSL: couldn't create a method");
+ return CURLE_OUT_OF_MEMORY;
}
- switch(conn_config->version_max) {
+ if(backend->ctx)
+ wolfSSL_CTX_free(backend->ctx);
+ backend->ctx = wolfSSL_CTX_new(req_method);
+
+ if(!backend->ctx) {
+ failf(data, "SSL: couldn't create a context");
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ switch(conn_config->version) {
+ case CURL_SSLVERSION_DEFAULT:
+ case CURL_SSLVERSION_TLSv1:
+#if LIBWOLFSSL_VERSION_HEX > 0x03004006 /* > 3.4.6 */
+ /* Versions 3.3.0 to 3.4.6 we know the minimum protocol version is
+ * whatever minimum version of TLS was built in and at least TLS 1.0. For
+ * later library versions that could change (eg TLS 1.0 built in but
+ * defaults to TLS 1.1) so we have this short circuit evaluation to find
+ * the minimum supported TLS version.
+ */
+ if((wolfSSL_CTX_SetMinVersion(backend->ctx, WOLFSSL_TLSV1) != 1) &&
+ (wolfSSL_CTX_SetMinVersion(backend->ctx, WOLFSSL_TLSV1_1) != 1) &&
+ (wolfSSL_CTX_SetMinVersion(backend->ctx, WOLFSSL_TLSV1_2) != 1)
#ifdef WOLFSSL_TLS13
- case CURL_SSLVERSION_MAX_TLSv1_3:
- res = wolfSSL_CTX_set_max_proto_version(backend->ctx, TLS1_3_VERSION);
- break;
+ && (wolfSSL_CTX_SetMinVersion(backend->ctx, WOLFSSL_TLSV1_3) != 1)
+#endif
+ ) {
+ failf(data, "SSL: couldn't set the minimum protocol version");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
#endif
- case CURL_SSLVERSION_MAX_TLSv1_2:
- res = wolfSSL_CTX_set_max_proto_version(backend->ctx, TLS1_2_VERSION);
- break;
- case CURL_SSLVERSION_MAX_TLSv1_1:
- res = wolfSSL_CTX_set_max_proto_version(backend->ctx, TLS1_1_VERSION);
- break;
- case CURL_SSLVERSION_MAX_TLSv1_0:
- res = wolfSSL_CTX_set_max_proto_version(backend->ctx, TLS1_VERSION);
- break;
- case CURL_SSLVERSION_MAX_DEFAULT:
- case CURL_SSLVERSION_MAX_NONE:
- res = WOLFSSL_SUCCESS;
- break;
default:
- failf(data, "wolfSSL: unsupported maximum TLS version value");
- return CURLE_SSL_CONNECT_ERROR;
- }
- if(res != WOLFSSL_SUCCESS) {
- failf(data, "wolfSSL: failed set the maximum TLS version");
- return CURLE_SSL_CONNECT_ERROR;
+ break;
}
-#ifndef WOLFSSL_TLS13
ciphers = conn_config->cipher_list;
if(ciphers) {
if(!SSL_CTX_set_cipher_list(backend->ctx, ciphers)) {
@@ -806,57 +492,19 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
}
infof(data, "Cipher selection: %s", ciphers);
}
-#else
- if(conn_config->cipher_list || conn_config->cipher_list13) {
- const char *ciphers12 = conn_config->cipher_list;
- const char *ciphers13 = conn_config->cipher_list13;
-
- /* Set ciphers to a combination of ciphers_list and ciphers_list13.
- * If cipher_list is not set use the default TLSv1.2 (1.1, 1.0) ciphers.
- * If cipher_list13 is not set use the default TLSv1.3 ciphers. */
- size_t len13 = ciphers13 ? strlen(ciphers13)
- : wssl_get_default_ciphers(true, NULL, 0);
- size_t len12 = ciphers12 ? strlen(ciphers12)
- : wssl_get_default_ciphers(false, NULL, 0);
-
- ciphers = malloc(len13 + 1 + len12 + 1);
- if(!ciphers)
- return CURLE_OUT_OF_MEMORY;
-
- if(ciphers13)
- memcpy(ciphers, ciphers13, len13);
- else
- wssl_get_default_ciphers(true, ciphers, len13 + 1);
- ciphers[len13] = ':';
-
- if(ciphers12)
- memcpy(ciphers + len13 + 1, ciphers12, len12);
- else
- wssl_get_default_ciphers(false, ciphers + len13 + 1, len12 + 1);
- ciphers[len13 + 1 + len12] = '\0';
-
- if(!SSL_CTX_set_cipher_list(backend->ctx, ciphers)) {
- failf(data, "failed setting cipher list: %s", ciphers);
- free(ciphers);
- return CURLE_SSL_CIPHER;
- }
- infof(data, "Cipher selection: %s", ciphers);
- free(ciphers);
- }
-#endif
curves = conn_config->curves;
if(curves) {
-#ifdef WOLFSSL_HAVE_KYBER
+#ifdef HAVE_LIBOQS
for(idx = 0; gnm[idx].name != NULL; idx++) {
if(strncmp(curves, gnm[idx].name, strlen(gnm[idx].name)) == 0) {
- pqkem = gnm[idx].group;
+ oqsAlg = gnm[idx].group;
break;
}
}
- if(pqkem == 0)
+ if(oqsAlg == 0)
#endif
{
if(!SSL_CTX_set1_curves_list(backend->ctx, curves)) {
@@ -866,89 +514,86 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
}
}
- /* Load the client certificate, and private key */
-#ifndef NO_FILESYSTEM
- if(ssl_config->primary.cert_blob || ssl_config->primary.clientcert) {
- const char *cert_file = ssl_config->primary.clientcert;
- const char *key_file = ssl_config->key;
- const struct curl_blob *cert_blob = ssl_config->primary.cert_blob;
- const struct curl_blob *key_blob = ssl_config->key_blob;
- int file_type = wolfssl_do_file_type(ssl_config->cert_type);
- int rc;
-
- switch(file_type) {
- case WOLFSSL_FILETYPE_PEM:
- rc = cert_blob ?
- wolfSSL_CTX_use_certificate_chain_buffer(backend->ctx,
- cert_blob->data,
- (long)cert_blob->len) :
- wolfSSL_CTX_use_certificate_chain_file(backend->ctx, cert_file);
- break;
- case WOLFSSL_FILETYPE_ASN1:
- rc = cert_blob ?
- wolfSSL_CTX_use_certificate_buffer(backend->ctx, cert_blob->data,
- (long)cert_blob->len, file_type) :
- wolfSSL_CTX_use_certificate_file(backend->ctx, cert_file, file_type);
- break;
- default:
- failf(data, "unknown cert type");
- return CURLE_BAD_FUNCTION_ARGUMENT;
+#if !defined(NO_FILESYSTEM) && defined(WOLFSSL_SYS_CA_CERTS)
+ /* load native CA certificates */
+ if(ssl_config->native_ca_store) {
+ if(wolfSSL_CTX_load_system_CA_certs(backend->ctx) != WOLFSSL_SUCCESS) {
+ infof(data, "error importing native CA store, continuing anyway");
}
- if(rc != 1) {
- failf(data, "unable to use client certificate");
- return CURLE_SSL_CONNECT_ERROR;
+ else {
+ imported_native_ca = true;
+ infof(data, "successfully imported native CA store");
}
+ }
+#endif /* !NO_FILESYSTEM */
- if(!key_blob && !key_file) {
- key_blob = cert_blob;
- key_file = cert_file;
+ /* load certificate blob */
+ if(ca_info_blob) {
+ if(wolfSSL_CTX_load_verify_buffer(backend->ctx, ca_info_blob->data,
+ ca_info_blob->len,
+ SSL_FILETYPE_PEM) != SSL_SUCCESS) {
+ if(imported_native_ca) {
+ infof(data, "error importing CA certificate blob, continuing anyway");
+ }
+ else {
+ failf(data, "error importing CA certificate blob");
+ return CURLE_SSL_CACERT_BADFILE;
+ }
}
- else
- file_type = wolfssl_do_file_type(ssl_config->key_type);
-
- rc = key_blob ?
- wolfSSL_CTX_use_PrivateKey_buffer(backend->ctx, key_blob->data,
- (long)key_blob->len, file_type) :
- wolfSSL_CTX_use_PrivateKey_file(backend->ctx, key_file, file_type);
- if(rc != 1) {
- failf(data, "unable to set private key");
- return CURLE_SSL_CONNECT_ERROR;
+ else {
+ imported_ca_info_blob = true;
+ infof(data, "successfully imported CA certificate blob");
}
}
-#else /* NO_FILESYSTEM */
- if(ssl_config->primary.cert_blob) {
- const struct curl_blob *cert_blob = ssl_config->primary.cert_blob;
- const struct curl_blob *key_blob = ssl_config->key_blob;
- int file_type = wolfssl_do_file_type(ssl_config->cert_type);
- int rc;
- switch(file_type) {
- case WOLFSSL_FILETYPE_PEM:
- rc = wolfSSL_CTX_use_certificate_chain_buffer(backend->ctx,
- cert_blob->data,
- (long)cert_blob->len);
- break;
- case WOLFSSL_FILETYPE_ASN1:
- rc = wolfSSL_CTX_use_certificate_buffer(backend->ctx, cert_blob->data,
- (long)cert_blob->len, file_type);
- break;
- default:
- failf(data, "unknown cert type");
- return CURLE_BAD_FUNCTION_ARGUMENT;
+#ifndef NO_FILESYSTEM
+ /* load trusted cacert from file if not blob */
+ if(ssl_cafile || ssl_capath) {
+ int rc =
+ wolfSSL_CTX_load_verify_locations_ex(backend->ctx,
+ ssl_cafile,
+ ssl_capath,
+ WOLFSSL_LOAD_FLAG_IGNORE_ERR);
+ if(SSL_SUCCESS != rc) {
+ if(conn_config->verifypeer && !imported_ca_info_blob &&
+ !imported_native_ca) {
+ /* Fail if we insist on successfully verifying the server. */
+ failf(data, "error setting certificate verify locations:"
+ " CAfile: %s CApath: %s",
+ ssl_cafile ? ssl_cafile : "none",
+ ssl_capath ? ssl_capath : "none");
+ return CURLE_SSL_CACERT_BADFILE;
+ }
+ else {
+ /* Just continue with a warning if no strict certificate
+ verification is required. */
+ infof(data, "error setting certificate verify locations,"
+ " continuing anyway:");
+ }
}
- if(rc != 1) {
- failf(data, "unable to use client certificate");
- return CURLE_SSL_CONNECT_ERROR;
+ else {
+ /* Everything is fine. */
+ infof(data, "successfully set certificate verify locations:");
}
+ infof(data, " CAfile: %s", ssl_cafile ? ssl_cafile : "none");
+ infof(data, " CApath: %s", ssl_capath ? ssl_capath : "none");
+ }
- if(!key_blob)
- key_blob = cert_blob;
- else
- file_type = wolfssl_do_file_type(ssl_config->key_type);
+ /* Load the client certificate, and private key */
+ if(ssl_config->primary.clientcert && ssl_config->key) {
+ int file_type = do_file_type(ssl_config->cert_type);
+
+ if(wolfSSL_CTX_use_certificate_file(backend->ctx,
+ ssl_config->primary.clientcert,
+ file_type) != 1) {
+ failf(data, "unable to use client certificate (no key or wrong pass"
+ " phrase?)");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
- if(wolfSSL_CTX_use_PrivateKey_buffer(backend->ctx, key_blob->data,
- (long)key_blob->len,
- file_type) != 1) {
+ file_type = do_file_type(ssl_config->key_type);
+ if(wolfSSL_CTX_use_PrivateKey_file(backend->ctx, ssl_config->key,
+ file_type) != 1) {
failf(data, "unable to set private key");
return CURLE_SSL_CONNECT_ERROR;
}
@@ -964,7 +609,7 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
SSL_VERIFY_NONE, NULL);
#ifdef HAVE_SNI
- if(connssl->peer.sni) {
+ if(sni && connssl->peer.sni) {
size_t sni_len = strlen(connssl->peer.sni);
if((sni_len < USHRT_MAX)) {
if(wolfSSL_CTX_UseSNI(backend->ctx, WOLFSSL_SNI_HOST_NAME,
@@ -979,14 +624,8 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
/* give application a chance to interfere with SSL set up. */
if(data->set.ssl.fsslctx) {
- CURLcode result;
- if(!backend->x509_store_setup) {
- result = Curl_wssl_setup_x509_store(cf, data, backend);
- if(result)
- return result;
- }
- result = (*data->set.ssl.fsslctx)(data, backend->ctx,
- data->set.ssl.fsslctxp);
+ CURLcode result = (*data->set.ssl.fsslctx)(data, backend->ctx,
+ data->set.ssl.fsslctxp);
if(result) {
failf(data, "error signaled by ssl ctx callback");
return result;
@@ -994,7 +633,7 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
}
#ifdef NO_FILESYSTEM
else if(conn_config->verifypeer) {
- failf(data, "SSL: Certificates cannot be loaded because wolfSSL was built"
+ failf(data, "SSL: Certificates can't be loaded because wolfSSL was built"
" with \"no filesystem\". Either disable peer verification"
" (insecure) or if you are building an application with libcurl you"
" can load certificates via CURLOPT_SSL_CTX_FUNCTION.");
@@ -1007,14 +646,14 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
wolfSSL_free(backend->handle);
backend->handle = wolfSSL_new(backend->ctx);
if(!backend->handle) {
- failf(data, "SSL: could not create a handle");
+ failf(data, "SSL: couldn't create a handle");
return CURLE_OUT_OF_MEMORY;
}
-#ifdef WOLFSSL_HAVE_KYBER
- if(pqkem) {
- if(wolfSSL_UseKeyShare(backend->handle, pqkem) != WOLFSSL_SUCCESS) {
- failf(data, "unable to use PQ KEM");
+#ifdef HAVE_LIBOQS
+ if(oqsAlg) {
+ if(wolfSSL_UseKeyShare(backend->handle, oqsAlg) != WOLFSSL_SUCCESS) {
+ failf(data, "unable to use oqs KEM");
}
}
#endif
@@ -1026,8 +665,7 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
result = Curl_alpn_to_proto_str(&proto, connssl->alpn);
if(result ||
- wolfSSL_UseALPN(backend->handle,
- (char *)proto.data, (unsigned int)proto.len,
+ wolfSSL_UseALPN(backend->handle, (char *)proto.data, proto.len,
WOLFSSL_ALPN_CONTINUE_ON_MISMATCH) != SSL_SUCCESS) {
failf(data, "SSL: failed setting ALPN protocols");
return CURLE_SSL_CONNECT_ERROR;
@@ -1054,17 +692,16 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
}
#endif /* HAVE_SECURE_RENEGOTIATION */
- /* Check if there is a cached ID we can/should use here! */
- if(ssl_config->primary.cache_session) {
+ /* Check if there's a cached ID we can/should use here! */
+ if(ssl_config->primary.sessionid) {
void *ssl_sessionid = NULL;
Curl_ssl_sessionid_lock(data);
- if(!Curl_ssl_getsessionid(cf, data, &connssl->peer,
- &ssl_sessionid, NULL)) {
+ if(!Curl_ssl_getsessionid(cf, data, &ssl_sessionid, NULL)) {
/* we got a session id, use it! */
if(!SSL_set_session(backend->handle, ssl_sessionid)) {
Curl_ssl_delsessionid(data, ssl_sessionid);
- infof(data, "cannot use session ID, going on without");
+ infof(data, "Can't use session ID, going on without");
}
else
infof(data, "SSL reusing session ID");
@@ -1072,82 +709,6 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
Curl_ssl_sessionid_unlock(data);
}
-#ifdef USE_ECH
- if(ECH_ENABLED(data)) {
- int trying_ech_now = 0;
-
- if(data->set.str[STRING_ECH_PUBLIC]) {
- infof(data, "ECH: outername not (yet) supported with wolfSSL");
- return CURLE_SSL_CONNECT_ERROR;
- }
- if(data->set.tls_ech == CURLECH_GREASE) {
- infof(data, "ECH: GREASE'd ECH not yet supported for wolfSSL");
- return CURLE_SSL_CONNECT_ERROR;
- }
- if(data->set.tls_ech & CURLECH_CLA_CFG
- && data->set.str[STRING_ECH_CONFIG]) {
- char *b64val = data->set.str[STRING_ECH_CONFIG];
- word32 b64len = 0;
-
- b64len = (word32) strlen(b64val);
- if(b64len
- && wolfSSL_SetEchConfigsBase64(backend->handle, b64val, b64len)
- != WOLFSSL_SUCCESS) {
- if(data->set.tls_ech & CURLECH_HARD)
- return CURLE_SSL_CONNECT_ERROR;
- }
- else {
- trying_ech_now = 1;
- infof(data, "ECH: ECHConfig from command line");
- }
- }
- else {
- struct Curl_dns_entry *dns = NULL;
-
- dns = Curl_fetch_addr(data, connssl->peer.hostname, connssl->peer.port);
- if(!dns) {
- infof(data, "ECH: requested but no DNS info available");
- if(data->set.tls_ech & CURLECH_HARD)
- return CURLE_SSL_CONNECT_ERROR;
- }
- else {
- struct Curl_https_rrinfo *rinfo = NULL;
-
- rinfo = dns->hinfo;
- if(rinfo && rinfo->echconfiglist) {
- unsigned char *ecl = rinfo->echconfiglist;
- size_t elen = rinfo->echconfiglist_len;
-
- infof(data, "ECH: ECHConfig from DoH HTTPS RR");
- if(wolfSSL_SetEchConfigs(backend->handle, ecl, (word32) elen) !=
- WOLFSSL_SUCCESS) {
- infof(data, "ECH: wolfSSL_SetEchConfigs failed");
- if(data->set.tls_ech & CURLECH_HARD)
- return CURLE_SSL_CONNECT_ERROR;
- }
- else {
- trying_ech_now = 1;
- infof(data, "ECH: imported ECHConfigList of length %ld", elen);
- }
- }
- else {
- infof(data, "ECH: requested but no ECHConfig available");
- if(data->set.tls_ech & CURLECH_HARD)
- return CURLE_SSL_CONNECT_ERROR;
- }
- Curl_resolv_unlink(data, &dns);
- }
- }
-
- if(trying_ech_now
- && SSL_set_min_proto_version(backend->handle, TLS1_3_VERSION) != 1) {
- infof(data, "ECH: cannot force TLSv1.3 [ERROR]");
- return CURLE_SSL_CONNECT_ERROR;
- }
-
- }
-#endif /* USE_ECH */
-
#ifdef USE_BIO_CHAIN
{
WOLFSSL_BIO *bio;
@@ -1173,39 +734,17 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
}
-static char *wolfssl_strerror(unsigned long error, char *buf,
- unsigned long size)
-{
- DEBUGASSERT(size > 40);
- *buf = '\0';
-
- wolfSSL_ERR_error_string_n(error, buf, size);
-
- if(!*buf) {
- const char *msg = error ? "Unknown error" : "No error";
- /* the string fits because the assert above assures this */
- strcpy(buf, msg);
- }
-
- return buf;
-}
-
-
static CURLcode
wolfssl_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
{
int ret = -1;
struct ssl_connect_data *connssl = cf->ctx;
- struct wolfssl_ctx *backend =
- (struct wolfssl_ctx *)connssl->backend;
+ struct wolfssl_ssl_backend_data *backend =
+ (struct wolfssl_ssl_backend_data *)connssl->backend;
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
-#ifndef CURL_DISABLE_PROXY
const char * const pinnedpubkey = Curl_ssl_cf_is_proxy(cf)?
data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY]:
data->set.str[STRING_SSL_PINNEDPUBLICKEY];
-#else
- const char * const pinnedpubkey = data->set.str[STRING_SSL_PINNEDPUBLICKEY];
-#endif
DEBUGASSERT(backend);
@@ -1219,16 +758,6 @@ wolfssl_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
return CURLE_SSL_CONNECT_ERROR;
}
- if(!backend->x509_store_setup) {
- /* After having send off the ClientHello, we prepare the x509
- * store to verify the coming certificate from the server */
- CURLcode result;
- result = Curl_wssl_setup_x509_store(cf, data, backend);
- if(result)
- return result;
- }
-
- connssl->io_need = CURL_SSL_IO_NEED_NONE;
ret = wolfSSL_connect(backend->handle);
#ifdef OPENSSL_EXTRA
@@ -1256,14 +785,15 @@ wolfssl_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
#endif /* OPENSSL_EXTRA */
if(ret != 1) {
- int detail = wolfSSL_get_error(backend->handle, ret);
+ char error_buffer[WOLFSSL_MAX_ERROR_SZ];
+ int detail = wolfSSL_get_error(backend->handle, ret);
if(SSL_ERROR_WANT_READ == detail) {
- connssl->io_need = CURL_SSL_IO_NEED_RECV;
+ connssl->connecting_state = ssl_connect_2_reading;
return CURLE_OK;
}
else if(SSL_ERROR_WANT_WRITE == detail) {
- connssl->io_need = CURL_SSL_IO_NEED_SEND;
+ connssl->connecting_state = ssl_connect_2_writing;
return CURLE_OK;
}
/* There is no easy way to override only the CN matching.
@@ -1295,6 +825,7 @@ wolfssl_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
}
#endif
}
+#if LIBWOLFSSL_VERSION_HEX >= 0x02007000 /* 2.7.0 */
else if(ASN_NO_SIGNER_E == detail) {
if(conn_config->verifypeer) {
failf(data, " CA signer not available for verification");
@@ -1307,47 +838,13 @@ wolfssl_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
"continuing anyway");
}
}
- else if(ASN_AFTER_DATE_E == detail) {
- failf(data, "server verification failed: certificate has expired.");
- return CURLE_PEER_FAILED_VERIFICATION;
- }
- else if(ASN_BEFORE_DATE_E == detail) {
- failf(data, "server verification failed: certificate not valid yet.");
- return CURLE_PEER_FAILED_VERIFICATION;
- }
-#ifdef USE_ECH
- else if(-1 == detail) {
- /* try access a retry_config ECHConfigList for tracing */
- byte echConfigs[1000];
- word32 echConfigsLen = 1000;
- int rv = 0;
-
- /* this currently does not produce the retry_configs */
- rv = wolfSSL_GetEchConfigs(backend->handle, echConfigs,
- &echConfigsLen);
- if(rv != WOLFSSL_SUCCESS) {
- infof(data, "Failed to get ECHConfigs");
- }
- else {
- char *b64str = NULL;
- size_t blen = 0;
-
- rv = Curl_base64_encode((const char *)echConfigs, echConfigsLen,
- &b64str, &blen);
- if(!rv && b64str)
- infof(data, "ECH: (not yet) retry_configs %s", b64str);
- free(b64str);
- }
- }
#endif
else if(backend->io_result == CURLE_AGAIN) {
return CURLE_OK;
}
else {
- char error_buffer[256];
failf(data, "SSL_connect failed with error %d: %s", detail,
- wolfssl_strerror((unsigned long)detail, error_buffer,
- sizeof(error_buffer)));
+ wolfSSL_ERR_error_string(detail, error_buffer));
return CURLE_SSL_CONNECT_ERROR;
}
}
@@ -1387,7 +884,6 @@ wolfssl_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
pinnedpubkey,
(const unsigned char *)pubkey->header,
(size_t)(pubkey->end - pubkey->header));
- wolfSSL_FreeX509(x509);
if(result) {
failf(data, "SSL: public key does not match pinned public key");
return result;
@@ -1432,39 +928,53 @@ wolfssl_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
}
-static void wolfssl_session_free(void *sessionid, size_t idsize)
-{
- (void)idsize;
- wolfSSL_SESSION_free(sessionid);
-}
-
-
static CURLcode
wolfssl_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data)
{
CURLcode result = CURLE_OK;
struct ssl_connect_data *connssl = cf->ctx;
- struct wolfssl_ctx *backend =
- (struct wolfssl_ctx *)connssl->backend;
+ struct wolfssl_ssl_backend_data *backend =
+ (struct wolfssl_ssl_backend_data *)connssl->backend;
const struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
DEBUGASSERT(backend);
- if(ssl_config->primary.cache_session) {
+ if(ssl_config->primary.sessionid) {
+ bool incache;
+ bool added = FALSE;
+ void *old_ssl_sessionid = NULL;
/* wolfSSL_get1_session allocates memory that has to be freed. */
WOLFSSL_SESSION *our_ssl_sessionid = wolfSSL_get1_session(backend->handle);
if(our_ssl_sessionid) {
Curl_ssl_sessionid_lock(data);
- /* call takes ownership of `our_ssl_sessionid` */
- result = Curl_ssl_set_sessionid(cf, data, &connssl->peer,
- our_ssl_sessionid, 0,
- wolfssl_session_free);
+ incache = !(Curl_ssl_getsessionid(cf, data, &old_ssl_sessionid, NULL));
+ if(incache) {
+ if(old_ssl_sessionid != our_ssl_sessionid) {
+ infof(data, "old SSL session ID is stale, removing");
+ Curl_ssl_delsessionid(data, old_ssl_sessionid);
+ incache = FALSE;
+ }
+ }
+
+ if(!incache) {
+ result = Curl_ssl_addsessionid(cf, data, our_ssl_sessionid, 0, NULL);
+ if(result) {
+ Curl_ssl_sessionid_unlock(data);
+ wolfSSL_SESSION_free(our_ssl_sessionid);
+ failf(data, "failed to store ssl session");
+ return result;
+ }
+ else {
+ added = TRUE;
+ }
+ }
Curl_ssl_sessionid_unlock(data);
- if(result) {
- failf(data, "failed to store ssl session");
- return result;
+
+ if(!added) {
+ /* If the session info wasn't added to the cache, free our copy. */
+ wolfSSL_SESSION_free(our_ssl_sessionid);
}
}
}
@@ -1482,8 +992,9 @@ static ssize_t wolfssl_send(struct Curl_cfilter *cf,
CURLcode *curlcode)
{
struct ssl_connect_data *connssl = cf->ctx;
- struct wolfssl_ctx *backend =
- (struct wolfssl_ctx *)connssl->backend;
+ struct wolfssl_ssl_backend_data *backend =
+ (struct wolfssl_ssl_backend_data *)connssl->backend;
+ char error_buffer[WOLFSSL_MAX_ERROR_SZ];
int memlen = (len > (size_t)INT_MAX) ? INT_MAX : (int)len;
int rc;
@@ -1498,7 +1009,7 @@ static ssize_t wolfssl_send(struct Curl_cfilter *cf,
switch(err) {
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_WRITE:
- /* there is data pending, re-invoke SSL_write() */
+ /* there's data pending, re-invoke SSL_write() */
CURL_TRC_CF(data, cf, "wolfssl_send(len=%zu) -> AGAIN", len);
*curlcode = CURLE_AGAIN;
return -1;
@@ -1509,13 +1020,9 @@ static ssize_t wolfssl_send(struct Curl_cfilter *cf,
return -1;
}
CURL_TRC_CF(data, cf, "wolfssl_send(len=%zu) -> %d, %d", len, rc, err);
- {
- char error_buffer[256];
- failf(data, "SSL write: %s, errno %d",
- wolfssl_strerror((unsigned long)err, error_buffer,
- sizeof(error_buffer)),
- SOCKERRNO);
- }
+ failf(data, "SSL write: %s, errno %d",
+ wolfSSL_ERR_error_string(err, error_buffer),
+ SOCKERRNO);
*curlcode = CURLE_SEND_ERROR;
return -1;
}
@@ -1524,122 +1031,22 @@ static ssize_t wolfssl_send(struct Curl_cfilter *cf,
return rc;
}
-static CURLcode wolfssl_shutdown(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- bool send_shutdown, bool *done)
-{
- struct ssl_connect_data *connssl = cf->ctx;
- struct wolfssl_ctx *wctx = (struct wolfssl_ctx *)connssl->backend;
- CURLcode result = CURLE_OK;
- char buf[1024];
- char error_buffer[256];
- int nread = -1, err;
- size_t i;
- int detail;
-
- DEBUGASSERT(wctx);
- if(!wctx->handle || cf->shutdown) {
- *done = TRUE;
- goto out;
- }
-
- wctx->shutting_down = TRUE;
- connssl->io_need = CURL_SSL_IO_NEED_NONE;
- *done = FALSE;
- if(!(wolfSSL_get_shutdown(wctx->handle) & SSL_SENT_SHUTDOWN)) {
- /* We have not started the shutdown from our side yet. Check
- * if the server already sent us one. */
- ERR_clear_error();
- nread = wolfSSL_read(wctx->handle, buf, (int)sizeof(buf));
- err = wolfSSL_get_error(wctx->handle, nread);
- CURL_TRC_CF(data, cf, "wolfSSL_read, nread=%d, err=%d", nread, err);
- if(!nread && err == SSL_ERROR_ZERO_RETURN) {
- bool input_pending;
- /* Yes, it did. */
- if(!send_shutdown) {
- CURL_TRC_CF(data, cf, "SSL shutdown received, not sending");
- *done = TRUE;
- goto out;
- }
- else if(!cf->next->cft->is_alive(cf->next, data, &input_pending)) {
- /* Server closed the connection after its closy notify. It
- * seems not interested to see our close notify, so do not
- * send it. We are done. */
- CURL_TRC_CF(data, cf, "peer closed connection");
- connssl->peer_closed = TRUE;
- *done = TRUE;
- goto out;
- }
- }
- }
-
- /* SSL should now have started the shutdown from our side. Since it
- * was not complete, we are lacking the close notify from the server. */
- if(send_shutdown) {
- ERR_clear_error();
- if(wolfSSL_shutdown(wctx->handle) == 1) {
- CURL_TRC_CF(data, cf, "SSL shutdown finished");
- *done = TRUE;
- goto out;
- }
- if(SSL_ERROR_WANT_WRITE == wolfSSL_get_error(wctx->handle, nread)) {
- CURL_TRC_CF(data, cf, "SSL shutdown still wants to send");
- connssl->io_need = CURL_SSL_IO_NEED_SEND;
- goto out;
- }
- /* Having sent the close notify, we use wolfSSL_read() to get the
- * missing close notify from the server. */
- }
-
- for(i = 0; i < 10; ++i) {
- ERR_clear_error();
- nread = wolfSSL_read(wctx->handle, buf, (int)sizeof(buf));
- if(nread <= 0)
- break;
- }
- err = wolfSSL_get_error(wctx->handle, nread);
- switch(err) {
- case SSL_ERROR_ZERO_RETURN: /* no more data */
- CURL_TRC_CF(data, cf, "SSL shutdown received");
- *done = TRUE;
- break;
- case SSL_ERROR_NONE: /* just did not get anything */
- case SSL_ERROR_WANT_READ:
- /* SSL has send its notify and now wants to read the reply
- * from the server. We are not really interested in that. */
- CURL_TRC_CF(data, cf, "SSL shutdown sent, want receive");
- connssl->io_need = CURL_SSL_IO_NEED_RECV;
- break;
- case SSL_ERROR_WANT_WRITE:
- CURL_TRC_CF(data, cf, "SSL shutdown send blocked");
- connssl->io_need = CURL_SSL_IO_NEED_SEND;
- break;
- default:
- detail = wolfSSL_get_error(wctx->handle, err);
- CURL_TRC_CF(data, cf, "SSL shutdown, error: '%s'(%d)",
- wolfssl_strerror((unsigned long)err, error_buffer,
- sizeof(error_buffer)),
- detail);
- result = CURLE_RECV_ERROR;
- break;
- }
-
-out:
- cf->shutdown = (result || *done);
- return result;
-}
-
static void wolfssl_close(struct Curl_cfilter *cf, struct Curl_easy *data)
{
struct ssl_connect_data *connssl = cf->ctx;
- struct wolfssl_ctx *backend =
- (struct wolfssl_ctx *)connssl->backend;
+ struct wolfssl_ssl_backend_data *backend =
+ (struct wolfssl_ssl_backend_data *)connssl->backend;
(void) data;
DEBUGASSERT(backend);
if(backend->handle) {
+ char buf[32];
+ /* Maybe the server has already sent a close notify alert.
+ Read it to avoid an RST on the TCP connection. */
+ (void)wolfSSL_read(backend->handle, buf, (int)sizeof(buf));
+ (void)wolfSSL_shutdown(backend->handle);
wolfSSL_free(backend->handle);
backend->handle = NULL;
}
@@ -1655,8 +1062,9 @@ static ssize_t wolfssl_recv(struct Curl_cfilter *cf,
CURLcode *curlcode)
{
struct ssl_connect_data *connssl = cf->ctx;
- struct wolfssl_ctx *backend =
- (struct wolfssl_ctx *)connssl->backend;
+ struct wolfssl_ssl_backend_data *backend =
+ (struct wolfssl_ssl_backend_data *)connssl->backend;
+ char error_buffer[WOLFSSL_MAX_ERROR_SZ];
int buffsize = (blen > (size_t)INT_MAX) ? INT_MAX : (int)blen;
int nread;
@@ -1676,9 +1084,11 @@ static ssize_t wolfssl_recv(struct Curl_cfilter *cf,
*curlcode = CURLE_OK;
return 0;
case SSL_ERROR_NONE:
+ /* FALLTHROUGH */
case SSL_ERROR_WANT_READ:
+ /* FALLTHROUGH */
case SSL_ERROR_WANT_WRITE:
- /* there is data pending, re-invoke wolfSSL_read() */
+ /* there's data pending, re-invoke wolfSSL_read() */
CURL_TRC_CF(data, cf, "wolfssl_recv(len=%zu) -> AGAIN", blen);
*curlcode = CURLE_AGAIN;
return -1;
@@ -1688,13 +1098,8 @@ static ssize_t wolfssl_recv(struct Curl_cfilter *cf,
*curlcode = CURLE_AGAIN;
return -1;
}
- {
- char error_buffer[256];
- failf(data, "SSL read: %s, errno %d",
- wolfssl_strerror((unsigned long)err, error_buffer,
- sizeof(error_buffer)),
- SOCKERRNO);
- }
+ failf(data, "SSL read: %s, errno %d",
+ wolfSSL_ERR_error_string(err, error_buffer), SOCKERRNO);
*curlcode = CURLE_RECV_ERROR;
return -1;
}
@@ -1704,6 +1109,12 @@ static ssize_t wolfssl_recv(struct Curl_cfilter *cf,
}
+static void wolfssl_session_free(void *ptr)
+{
+ wolfSSL_SESSION_free(ptr);
+}
+
+
static size_t wolfssl_version(char *buffer, size_t size)
{
#if LIBWOLFSSL_VERSION_HEX >= 0x03006000
@@ -1741,18 +1152,43 @@ static bool wolfssl_data_pending(struct Curl_cfilter *cf,
const struct Curl_easy *data)
{
struct ssl_connect_data *ctx = cf->ctx;
- struct wolfssl_ctx *backend;
+ struct wolfssl_ssl_backend_data *backend;
(void)data;
DEBUGASSERT(ctx && ctx->backend);
- backend = (struct wolfssl_ctx *)ctx->backend;
+ backend = (struct wolfssl_ssl_backend_data *)ctx->backend;
if(backend->handle) /* SSL is in use */
return (0 != wolfSSL_pending(backend->handle)) ? TRUE : FALSE;
else
return FALSE;
}
+
+/*
+ * This function is called to shut down the SSL layer but keep the
+ * socket open (CCC - Clear Command Channel)
+ */
+static int wolfssl_shutdown(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
+{
+ struct ssl_connect_data *ctx = cf->ctx;
+ struct wolfssl_ssl_backend_data *backend;
+ int retval = 0;
+
+ (void)data;
+ DEBUGASSERT(ctx && ctx->backend);
+
+ backend = (struct wolfssl_ssl_backend_data *)ctx->backend;
+ if(backend->handle) {
+ wolfSSL_ERR_clear_error();
+ wolfSSL_free(backend->handle);
+ backend->handle = NULL;
+ }
+ return retval;
+}
+
+
static CURLcode
wolfssl_connect_common(struct Curl_cfilter *cf,
struct Curl_easy *data,
@@ -1771,7 +1207,7 @@ wolfssl_connect_common(struct Curl_cfilter *cf,
}
if(ssl_connect_1 == connssl->connecting_state) {
- /* Find out how much more time we are allowed */
+ /* Find out how much more time we're allowed */
const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
if(timeout_ms < 0) {
@@ -1785,7 +1221,9 @@ wolfssl_connect_common(struct Curl_cfilter *cf,
return result;
}
- while(ssl_connect_2 == connssl->connecting_state) {
+ while(ssl_connect_2 == connssl->connecting_state ||
+ ssl_connect_2_reading == connssl->connecting_state ||
+ ssl_connect_2_writing == connssl->connecting_state) {
/* check allowed time left */
const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
@@ -1796,13 +1234,14 @@ wolfssl_connect_common(struct Curl_cfilter *cf,
return CURLE_OPERATION_TIMEDOUT;
}
- /* if ssl is expecting something, check if it is available. */
- if(connssl->io_need) {
+ /* if ssl is expecting something, check if it's available. */
+ if(connssl->connecting_state == ssl_connect_2_reading
+ || connssl->connecting_state == ssl_connect_2_writing) {
- curl_socket_t writefd = (connssl->io_need & CURL_SSL_IO_NEED_SEND)?
- sockfd:CURL_SOCKET_BAD;
- curl_socket_t readfd = (connssl->io_need & CURL_SSL_IO_NEED_RECV)?
- sockfd:CURL_SOCKET_BAD;
+ curl_socket_t writefd = ssl_connect_2_writing ==
+ connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
+ curl_socket_t readfd = ssl_connect_2_reading ==
+ connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
nonblocking?0:timeout_ms);
@@ -1833,7 +1272,10 @@ wolfssl_connect_common(struct Curl_cfilter *cf,
* have a valid fdset to wait on.
*/
result = wolfssl_connect_step2(cf, data);
- if(result || (nonblocking && (ssl_connect_2 == connssl->connecting_state)))
+ if(result || (nonblocking &&
+ (ssl_connect_2 == connssl->connecting_state ||
+ ssl_connect_2_reading == connssl->connecting_state ||
+ ssl_connect_2_writing == connssl->connecting_state)))
return result;
} /* repeat step2 until all transactions are done. */
@@ -1913,15 +1355,15 @@ static CURLcode wolfssl_sha256sum(const unsigned char *tmp, /* input */
static void *wolfssl_get_internals(struct ssl_connect_data *connssl,
CURLINFO info UNUSED_PARAM)
{
- struct wolfssl_ctx *backend =
- (struct wolfssl_ctx *)connssl->backend;
+ struct wolfssl_ssl_backend_data *backend =
+ (struct wolfssl_ssl_backend_data *)connssl->backend;
(void)info;
DEBUGASSERT(backend);
return backend->handle;
}
const struct Curl_ssl Curl_ssl_wolfssl = {
- { CURLSSLBACKEND_WOLFSSL, "wolfssl" }, /* info */
+ { CURLSSLBACKEND_WOLFSSL, "WolfSSL" }, /* info */
#ifdef KEEP_PEER_CERT
SSLSUPP_PINNEDPUBKEY |
@@ -1931,17 +1373,9 @@ const struct Curl_ssl Curl_ssl_wolfssl = {
#endif
SSLSUPP_CA_PATH |
SSLSUPP_CAINFO_BLOB |
-#ifdef USE_ECH
- SSLSUPP_ECH |
-#endif
- SSLSUPP_SSL_CTX |
-#ifdef WOLFSSL_TLS13
- SSLSUPP_TLS13_CIPHERSUITES |
-#endif
- SSLSUPP_CA_CACHE |
- SSLSUPP_CIPHER_LIST,
+ SSLSUPP_SSL_CTX,
- sizeof(struct wolfssl_ctx),
+ sizeof(struct wolfssl_ssl_backend_data),
wolfssl_init, /* init */
wolfssl_cleanup, /* cleanup */
@@ -1957,6 +1391,7 @@ const struct Curl_ssl Curl_ssl_wolfssl = {
wolfssl_get_internals, /* get_internals */
wolfssl_close, /* close_one */
Curl_none_close_all, /* close_all */
+ wolfssl_session_free, /* session_free */
Curl_none_set_engine, /* set_engine */
Curl_none_set_engine_default, /* set_engine_default */
Curl_none_engines_list, /* engines_list */
@@ -1964,9 +1399,9 @@ const struct Curl_ssl Curl_ssl_wolfssl = {
wolfssl_sha256sum, /* sha256sum */
NULL, /* associate_connection */
NULL, /* disassociate_connection */
+ NULL, /* free_multi_ssl_backend_data */
wolfssl_recv, /* recv decrypted data */
wolfssl_send, /* send data to encrypt */
- NULL, /* get_channel_binding */
};
#endif
diff --git a/contrib/libs/curl/lib/vtls/wolfssl.h b/contrib/libs/curl/lib/vtls/wolfssl.h
index 941c1ce52c..a5ed848099 100644
--- a/contrib/libs/curl/lib/vtls/wolfssl.h
+++ b/contrib/libs/curl/lib/vtls/wolfssl.h
@@ -26,27 +26,8 @@
#include "curl_setup.h"
#ifdef USE_WOLFSSL
-#error #include <wolfssl/version.h>
-#error #include <wolfssl/options.h>
-#error #include <wolfssl/ssl.h>
-#error #include <wolfssl/error-ssl.h>
-
-#include "urldata.h"
extern const struct Curl_ssl Curl_ssl_wolfssl;
-struct wolfssl_ctx {
- WOLFSSL_CTX *ctx;
- WOLFSSL *handle;
- CURLcode io_result; /* result of last BIO cfilter operation */
- int io_send_blocked_len; /* length of last BIO write that EAGAINed */
- BIT(x509_store_setup); /* x509 store has been set up */
- BIT(shutting_down); /* TLS is being shut down */
-};
-
-CURLcode Curl_wssl_setup_x509_store(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- struct wolfssl_ctx *wssl);
-
#endif /* USE_WOLFSSL */
#endif /* HEADER_CURL_WOLFSSL_H */
diff --git a/contrib/libs/curl/lib/vtls/x509asn1.c b/contrib/libs/curl/lib/vtls/x509asn1.c
index 7fceb64f56..8b1eed63f3 100644
--- a/contrib/libs/curl/lib/vtls/x509asn1.c
+++ b/contrib/libs/curl/lib/vtls/x509asn1.c
@@ -25,15 +25,13 @@
#include "curl_setup.h"
#if defined(USE_GNUTLS) || defined(USE_WOLFSSL) || \
- defined(USE_SCHANNEL) || defined(USE_SECTRANSP) || \
- defined(USE_MBEDTLS)
+ defined(USE_SCHANNEL) || defined(USE_SECTRANSP)
#if defined(USE_WOLFSSL) || defined(USE_SCHANNEL)
#define WANT_PARSEX509 /* uses Curl_parseX509() */
#endif
-#if defined(USE_GNUTLS) || defined(USE_SCHANNEL) || defined(USE_SECTRANSP) || \
- defined(USE_MBEDTLS)
+#if defined(USE_GNUTLS) || defined(USE_SCHANNEL) || defined(USE_SECTRANSP)
#define WANT_EXTRACT_CERTINFO /* uses Curl_extract_certinfo() */
#define WANT_PARSEX509 /* ... uses Curl_parseX509() */
#endif
@@ -48,7 +46,7 @@
#include "sendf.h"
#include "inet_pton.h"
#include "curl_base64.h"
-#error #include "x509asn1.h"
+#include "x509asn1.h"
#include "dynbuf.h"
/* The last 3 #include files should be in this order */
@@ -99,7 +97,6 @@
#define CURL_ASN1_CHARACTER_STRING 29
#define CURL_ASN1_BMP_STRING 30
-
#ifdef WANT_EXTRACT_CERTINFO
/* ASN.1 OID table entry. */
struct Curl_OID {
@@ -108,16 +105,15 @@ struct Curl_OID {
};
/* ASN.1 OIDs. */
+static const char cnOID[] = "2.5.4.3"; /* Common name. */
+static const char sanOID[] = "2.5.29.17"; /* Subject alternative name. */
+
static const struct Curl_OID OIDtable[] = {
{ "1.2.840.10040.4.1", "dsa" },
{ "1.2.840.10040.4.3", "dsa-with-sha1" },
{ "1.2.840.10045.2.1", "ecPublicKey" },
{ "1.2.840.10045.3.0.1", "c2pnb163v1" },
{ "1.2.840.10045.4.1", "ecdsa-with-SHA1" },
- { "1.2.840.10045.4.3.1", "ecdsa-with-SHA224" },
- { "1.2.840.10045.4.3.2", "ecdsa-with-SHA256" },
- { "1.2.840.10045.4.3.3", "ecdsa-with-SHA384" },
- { "1.2.840.10045.4.3.4", "ecdsa-with-SHA512" },
{ "1.2.840.10046.2.1", "dhpublicnumber" },
{ "1.2.840.113549.1.1.1", "rsaEncryption" },
{ "1.2.840.113549.1.1.2", "md2WithRSAEncryption" },
@@ -131,7 +127,7 @@ static const struct Curl_OID OIDtable[] = {
{ "1.2.840.113549.2.2", "md2" },
{ "1.2.840.113549.2.5", "md5" },
{ "1.3.14.3.2.26", "sha1" },
- { "2.5.4.3", "CN" },
+ { cnOID, "CN" },
{ "2.5.4.4", "SN" },
{ "2.5.4.5", "serialNumber" },
{ "2.5.4.6", "C" },
@@ -152,14 +148,13 @@ static const struct Curl_OID OIDtable[] = {
{ "2.5.4.65", "pseudonym" },
{ "1.2.840.113549.1.9.1", "emailAddress" },
{ "2.5.4.72", "role" },
- { "2.5.29.17", "subjectAltName" },
+ { sanOID, "subjectAltName" },
{ "2.5.29.18", "issuerAltName" },
{ "2.5.29.19", "basicConstraints" },
{ "2.16.840.1.101.3.4.2.4", "sha224" },
{ "2.16.840.1.101.3.4.2.1", "sha256" },
{ "2.16.840.1.101.3.4.2.2", "sha384" },
{ "2.16.840.1.101.3.4.2.3", "sha512" },
- { "1.2.840.113549.1.9.2", "unstructuredName" },
{ (const char *) NULL, (const char *) NULL }
};
@@ -260,61 +255,61 @@ static const struct Curl_OID *searchOID(const char *oid)
}
/*
- * Convert an ASN.1 Boolean value into its string representation.
- *
- * Return error code.
+ * Convert an ASN.1 Boolean value into its string representation. Return the
+ * dynamically allocated string, or NULL if source is not an ASN.1 Boolean
+ * value.
*/
-static CURLcode bool2str(struct dynbuf *store,
- const char *beg, const char *end)
+static const char *bool2str(const char *beg, const char *end)
{
if(end - beg != 1)
- return CURLE_BAD_FUNCTION_ARGUMENT;
- return Curl_dyn_add(store, *beg? "TRUE": "FALSE");
+ return NULL;
+ return strdup(*beg? "TRUE": "FALSE");
}
/*
* Convert an ASN.1 octet string to a printable string.
- *
- * Return error code.
+ * Return the dynamically allocated string, or NULL if an error occurs.
*/
-static CURLcode octet2str(struct dynbuf *store,
- const char *beg, const char *end)
+static const char *octet2str(const char *beg, const char *end)
{
- CURLcode result = CURLE_OK;
+ struct dynbuf buf;
+ CURLcode result;
+
+ Curl_dyn_init(&buf, 3 * CURL_ASN1_MAX + 1);
+ result = Curl_dyn_addn(&buf, "", 0);
while(!result && beg < end)
- result = Curl_dyn_addf(store, "%02x:", (unsigned char) *beg++);
+ result = Curl_dyn_addf(&buf, "%02x:", (unsigned char) *beg++);
- return result;
+ return Curl_dyn_ptr(&buf);
}
-static CURLcode bit2str(struct dynbuf *store,
- const char *beg, const char *end)
+static const char *bit2str(const char *beg, const char *end)
{
- /* Convert an ASN.1 bit string to a printable string. */
+ /* Convert an ASN.1 bit string to a printable string.
+ Return the dynamically allocated string, or NULL if an error occurs. */
if(++beg > end)
- return CURLE_BAD_FUNCTION_ARGUMENT;
- return octet2str(store, beg, end);
+ return NULL;
+ return octet2str(beg, end);
}
/*
* Convert an ASN.1 integer value into its string representation.
- *
- * Returns error.
+ * Return the dynamically allocated string, or NULL if source is not an
+ * ASN.1 integer value.
*/
-static CURLcode int2str(struct dynbuf *store,
- const char *beg, const char *end)
+static const char *int2str(const char *beg, const char *end)
{
unsigned int val = 0;
size_t n = end - beg;
if(!n)
- return CURLE_BAD_FUNCTION_ARGUMENT;
+ return NULL;
if(n > 4)
- return octet2str(store, beg, end);
+ return octet2str(beg, end);
/* Represent integers <= 32-bit as a single value. */
if(*beg & 0x80)
@@ -323,24 +318,25 @@ static CURLcode int2str(struct dynbuf *store,
do
val = (val << 8) | *(const unsigned char *) beg++;
while(beg < end);
- return Curl_dyn_addf(store, "%s%x", val >= 10? "0x": "", val);
+ return curl_maprintf("%s%x", val >= 10? "0x": "", val);
}
/*
- * Convert from an ASN.1 typed string to UTF8.
- *
- * The result is stored in a dynbuf that is inited by the user of this
- * function.
- *
- * Returns error.
+ * Perform a lazy conversion from an ASN.1 typed string to UTF8. Allocate the
+ * destination buffer dynamically. The allocation size will normally be too
+ * large: this is to avoid buffer overflows.
+ * Terminate the string with a nul byte and return the converted
+ * string length.
*/
-static CURLcode
-utf8asn1str(struct dynbuf *to, int type, const char *from, const char *end)
+static ssize_t
+utf8asn1str(char **to, int type, const char *from, const char *end)
{
size_t inlength = end - from;
int size = 1;
- CURLcode result = CURLE_OK;
+ size_t outlength;
+ char *buf;
+ *to = NULL;
switch(type) {
case CURL_ASN1_BMP_STRING:
size = 2;
@@ -356,84 +352,133 @@ utf8asn1str(struct dynbuf *to, int type, const char *from, const char *end)
case CURL_ASN1_UTF8_STRING:
break;
default:
- return CURLE_BAD_FUNCTION_ARGUMENT; /* Conversion not supported. */
+ return -1; /* Conversion not supported. */
}
if(inlength % size)
- /* Length inconsistent with character size. */
- return CURLE_BAD_FUNCTION_ARGUMENT;
+ return -1; /* Length inconsistent with character size. */
+ if(inlength / size > (SIZE_T_MAX - 1) / 4)
+ return -1; /* Too big. */
+ buf = malloc(4 * (inlength / size) + 1);
+ if(!buf)
+ return -1; /* Not enough memory. */
if(type == CURL_ASN1_UTF8_STRING) {
/* Just copy. */
- if(inlength)
- result = Curl_dyn_addn(to, from, inlength);
+ outlength = inlength;
+ if(outlength)
+ memcpy(buf, from, outlength);
}
else {
- while(!result && (from < end)) {
- char buf[4]; /* decode buffer */
- size_t charsize = 1;
- unsigned int wc = 0;
+ for(outlength = 0; from < end;) {
+ int charsize;
+ unsigned int wc;
+ wc = 0;
switch(size) {
case 4:
wc = (wc << 8) | *(const unsigned char *) from++;
wc = (wc << 8) | *(const unsigned char *) from++;
- FALLTHROUGH();
+ /* FALLTHROUGH */
case 2:
wc = (wc << 8) | *(const unsigned char *) from++;
- FALLTHROUGH();
+ /* FALLTHROUGH */
default: /* case 1: */
wc = (wc << 8) | *(const unsigned char *) from++;
}
+ charsize = 1;
if(wc >= 0x00000080) {
if(wc >= 0x00000800) {
if(wc >= 0x00010000) {
if(wc >= 0x00200000) {
- /* Invalid char. size for target encoding. */
- return CURLE_WEIRD_SERVER_REPLY;
+ free(buf);
+ return -1; /* Invalid char. size for target encoding. */
}
- buf[3] = (char) (0x80 | (wc & 0x3F));
+ buf[outlength + 3] = (char) (0x80 | (wc & 0x3F));
wc = (wc >> 6) | 0x00010000;
charsize++;
}
- buf[2] = (char) (0x80 | (wc & 0x3F));
+ buf[outlength + 2] = (char) (0x80 | (wc & 0x3F));
wc = (wc >> 6) | 0x00000800;
charsize++;
}
- buf[1] = (char) (0x80 | (wc & 0x3F));
+ buf[outlength + 1] = (char) (0x80 | (wc & 0x3F));
wc = (wc >> 6) | 0x000000C0;
charsize++;
}
- buf[0] = (char) wc;
- result = Curl_dyn_addn(to, buf, charsize);
+ buf[outlength] = (char) wc;
+ outlength += charsize;
}
}
- return result;
+ buf[outlength] = '\0';
+ *to = buf;
+ return outlength;
+}
+
+/*
+ * Convert an ASN.1 String into its UTF-8 string representation.
+ * Return the dynamically allocated string, or NULL if an error occurs.
+ */
+static const char *string2str(int type, const char *beg, const char *end)
+{
+ char *buf;
+ if(utf8asn1str(&buf, type, beg, end) < 0)
+ return NULL;
+ return buf;
+}
+
+/*
+ * Decimal ASCII encode unsigned integer `x' into the buflen sized buffer at
+ * buf. Return the total number of encoded digits, even if larger than
+ * `buflen'.
+ */
+static size_t encodeUint(char *buf, size_t buflen, unsigned int x)
+{
+ size_t i = 0;
+ unsigned int y = x / 10;
+
+ if(y) {
+ i = encodeUint(buf, buflen, y);
+ x -= y * 10;
+ }
+ if(i < buflen)
+ buf[i] = (char) ('0' + x);
+ i++;
+ if(i < buflen)
+ buf[i] = '\0'; /* Store a terminator if possible. */
+ return i;
}
/*
* Convert an ASN.1 OID into its dotted string representation.
- *
- * Return error code.
+ * Store the result in th `n'-byte buffer at `buf'.
+ * Return the converted string length, or 0 on errors.
*/
-static CURLcode encodeOID(struct dynbuf *store,
- const char *beg, const char *end)
+static size_t encodeOID(char *buf, size_t buflen,
+ const char *beg, const char *end)
{
+ size_t i;
unsigned int x;
unsigned int y;
- CURLcode result = CURLE_OK;
/* Process the first two numbers. */
y = *(const unsigned char *) beg++;
x = y / 40;
y -= x * 40;
-
- result = Curl_dyn_addf(store, "%u.%u", x, y);
- if(result)
- return result;
+ i = encodeUint(buf, buflen, x);
+ if(i < buflen)
+ buf[i] = '.';
+ i++;
+ if(i >= buflen)
+ i += encodeUint(NULL, 0, y);
+ else
+ i += encodeUint(buf + i, buflen - i, y);
/* Process the trailing numbers. */
while(beg < end) {
+ if(i < buflen)
+ buf[i] = '.';
+ i++;
x = 0;
do {
if(x & 0xFF000000)
@@ -441,44 +486,46 @@ static CURLcode encodeOID(struct dynbuf *store,
y = *(const unsigned char *) beg++;
x = (x << 7) | (y & 0x7F);
} while(y & 0x80);
- result = Curl_dyn_addf(store, ".%u", x);
+ if(i >= buflen)
+ i += encodeUint(NULL, 0, x);
+ else
+ i += encodeUint(buf + i, buflen - i, x);
}
- return result;
+ if(i < buflen)
+ buf[i] = '\0';
+ return i;
}
/*
* Convert an ASN.1 OID into its dotted or symbolic string representation.
- *
- * Return error code.
+ * Return the dynamically allocated string, or NULL if an error occurs.
*/
-static CURLcode OID2str(struct dynbuf *store,
- const char *beg, const char *end, bool symbolic)
+static const char *OID2str(const char *beg, const char *end, bool symbolic)
{
- CURLcode result = CURLE_OK;
+ char *buf = NULL;
if(beg < end) {
- if(symbolic) {
- struct dynbuf buf;
- Curl_dyn_init(&buf, CURL_X509_STR_MAX);
- result = encodeOID(&buf, beg, end);
-
- if(!result) {
- const struct Curl_OID *op = searchOID(Curl_dyn_ptr(&buf));
- if(op)
- result = Curl_dyn_add(store, op->textoid);
- else
- result = Curl_dyn_add(store, Curl_dyn_ptr(&buf));
- Curl_dyn_free(&buf);
+ size_t buflen = encodeOID(NULL, 0, beg, end);
+ if(buflen) {
+ buf = malloc(buflen + 1); /* one extra for the zero byte */
+ if(buf) {
+ encodeOID(buf, buflen, beg, end);
+ buf[buflen] = '\0';
+
+ if(symbolic) {
+ const struct Curl_OID *op = searchOID(buf);
+ if(op) {
+ free(buf);
+ buf = strdup(op->textoid);
+ }
+ }
}
}
- else
- result = encodeOID(store, beg, end);
}
- return result;
+ return buf;
}
-static CURLcode GTime2str(struct dynbuf *store,
- const char *beg, const char *end)
+static const char *GTime2str(const char *beg, const char *end)
{
const char *tzp;
const char *fracp;
@@ -490,7 +537,7 @@ static CURLcode GTime2str(struct dynbuf *store,
/* Convert an ASN.1 Generalized time to a printable string.
Return the dynamically allocated string, or NULL if an error occurs. */
- for(fracp = beg; fracp < end && ISDIGIT(*fracp); fracp++)
+ for(fracp = beg; fracp < end && *fracp >= '0' && *fracp <= '9'; fracp++)
;
/* Get seconds digits. */
@@ -501,76 +548,52 @@ static CURLcode GTime2str(struct dynbuf *store,
break;
case 2:
sec1 = fracp[-2];
- FALLTHROUGH();
+ /* FALLTHROUGH */
case 1:
sec2 = fracp[-1];
break;
default:
- return CURLE_BAD_FUNCTION_ARGUMENT;
+ return NULL;
}
- /* timezone follows optional fractional seconds. */
+ /* Scan for timezone, measure fractional seconds. */
tzp = fracp;
- fracl = 0; /* no fractional seconds detected so far */
+ fracl = 0;
if(fracp < end && (*fracp == '.' || *fracp == ',')) {
- /* Have fractional seconds, e.g. "[.,]\d+". How many? */
- fracp++; /* should be a digit char or BAD ARGUMENT */
- tzp = fracp;
- while(tzp < end && ISDIGIT(*tzp))
+ fracp++;
+ do
tzp++;
- if(tzp == fracp) /* never looped, no digit after [.,] */
- return CURLE_BAD_FUNCTION_ARGUMENT;
- fracl = tzp - fracp; /* number of fractional sec digits */
- DEBUGASSERT(fracl > 0);
- /* Strip trailing zeroes in fractional seconds.
- * May reduce fracl to 0 if only '0's are present. */
- while(fracl && fracp[fracl - 1] == '0')
- fracl--;
+ while(tzp < end && *tzp >= '0' && *tzp <= '9');
+ /* Strip leading zeroes in fractional seconds. */
+ for(fracl = tzp - fracp - 1; fracl && fracp[fracl - 1] == '0'; fracl--)
+ ;
}
/* Process timezone. */
- if(tzp >= end) {
- tzp = "";
- tzl = 0;
- }
+ if(tzp >= end)
+ ; /* Nothing to do. */
else if(*tzp == 'Z') {
- sep = " ";
- tzp = "GMT";
- tzl = 3;
- }
- else if((*tzp == '+') || (*tzp == '-')) {
- sep = " UTC";
- tzl = end - tzp;
+ tzp = " GMT";
+ end = tzp + 4;
}
else {
sep = " ";
- tzl = end - tzp;
+ tzp++;
}
- return Curl_dyn_addf(store,
- "%.4s-%.2s-%.2s %.2s:%.2s:%c%c%s%.*s%s%.*s",
+ tzl = end - tzp;
+ return curl_maprintf("%.4s-%.2s-%.2s %.2s:%.2s:%c%c%s%.*s%s%.*s",
beg, beg + 4, beg + 6,
beg + 8, beg + 10, sec1, sec2,
fracl? ".": "", (int)fracl, fracp,
sep, (int)tzl, tzp);
}
-#ifdef UNITTESTS
-/* used by unit1656.c */
-CURLcode Curl_x509_GTime2str(struct dynbuf *store,
- const char *beg, const char *end)
-{
- return GTime2str(store, beg, end);
-}
-#endif
-
/*
- * Convert an ASN.1 UTC time to a printable string.
- *
- * Return error code.
+ * Convert an ASN.1 UTC time to a printable string.
+ * Return the dynamically allocated string, or NULL if an error occurs.
*/
-static CURLcode UTime2str(struct dynbuf *store,
- const char *beg, const char *end)
+static const char *UTime2str(const char *beg, const char *end)
{
const char *tzp;
size_t tzl;
@@ -583,16 +606,15 @@ static CURLcode UTime2str(struct dynbuf *store,
switch(tzp - sec) {
case 0:
sec = "00";
- FALLTHROUGH();
case 2:
break;
default:
- return CURLE_BAD_FUNCTION_ARGUMENT;
+ return NULL;
}
/* Process timezone. */
if(tzp >= end)
- return CURLE_BAD_FUNCTION_ARGUMENT;
+ return NULL;
if(*tzp == 'Z') {
tzp = "GMT";
end = tzp + 3;
@@ -601,7 +623,7 @@ static CURLcode UTime2str(struct dynbuf *store,
tzp++;
tzl = end - tzp;
- return Curl_dyn_addf(store, "%u%.2s-%.2s-%.2s %.2s:%.2s:%.2s %.*s",
+ return curl_maprintf("%u%.2s-%.2s-%.2s %.2s:%.2s:%.2s %.*s",
20 - (*beg >= '5'), beg, beg + 2, beg + 4,
beg + 6, beg + 8, sec,
(int)tzl, tzp);
@@ -609,45 +631,34 @@ static CURLcode UTime2str(struct dynbuf *store,
/*
* Convert an ASN.1 element to a printable string.
- *
- * Return error
+ * Return the dynamically allocated string, or NULL if an error occurs.
*/
-static CURLcode ASN1tostr(struct dynbuf *store,
- struct Curl_asn1Element *elem, int type)
+static const char *ASN1tostr(struct Curl_asn1Element *elem, int type)
{
- CURLcode result = CURLE_BAD_FUNCTION_ARGUMENT;
if(elem->constructed)
- return result; /* No conversion of structured elements. */
+ return NULL; /* No conversion of structured elements. */
if(!type)
type = elem->tag; /* Type not forced: use element tag as type. */
switch(type) {
case CURL_ASN1_BOOLEAN:
- result = bool2str(store, elem->beg, elem->end);
- break;
+ return bool2str(elem->beg, elem->end);
case CURL_ASN1_INTEGER:
case CURL_ASN1_ENUMERATED:
- result = int2str(store, elem->beg, elem->end);
- break;
+ return int2str(elem->beg, elem->end);
case CURL_ASN1_BIT_STRING:
- result = bit2str(store, elem->beg, elem->end);
- break;
+ return bit2str(elem->beg, elem->end);
case CURL_ASN1_OCTET_STRING:
- result = octet2str(store, elem->beg, elem->end);
- break;
+ return octet2str(elem->beg, elem->end);
case CURL_ASN1_NULL:
- result = Curl_dyn_addn(store, "", 1);
- break;
+ return strdup("");
case CURL_ASN1_OBJECT_IDENTIFIER:
- result = OID2str(store, elem->beg, elem->end, TRUE);
- break;
+ return OID2str(elem->beg, elem->end, TRUE);
case CURL_ASN1_UTC_TIME:
- result = UTime2str(store, elem->beg, elem->end);
- break;
+ return UTime2str(elem->beg, elem->end);
case CURL_ASN1_GENERALIZED_TIME:
- result = GTime2str(store, elem->beg, elem->end);
- break;
+ return GTime2str(elem->beg, elem->end);
case CURL_ASN1_UTF8_STRING:
case CURL_ASN1_NUMERIC_STRING:
case CURL_ASN1_PRINTABLE_STRING:
@@ -656,101 +667,87 @@ static CURLcode ASN1tostr(struct dynbuf *store,
case CURL_ASN1_VISIBLE_STRING:
case CURL_ASN1_UNIVERSAL_STRING:
case CURL_ASN1_BMP_STRING:
- result = utf8asn1str(store, type, elem->beg, elem->end);
- break;
+ return string2str(type, elem->beg, elem->end);
}
- return result;
+ return NULL; /* Unsupported. */
}
/*
- * ASCII encode distinguished name at `dn' into the store dynbuf.
+ * ASCII encode distinguished name at `dn' into the `buflen'-sized buffer at
+ * `buf'.
*
- * Returns error.
+ * Returns the total string length, even if larger than `buflen' or -1 on
+ * error.
*/
-static CURLcode encodeDN(struct dynbuf *store, struct Curl_asn1Element *dn)
+static ssize_t encodeDN(char *buf, size_t buflen, struct Curl_asn1Element *dn)
{
struct Curl_asn1Element rdn;
struct Curl_asn1Element atv;
struct Curl_asn1Element oid;
struct Curl_asn1Element value;
+ size_t l = 0;
const char *p1;
const char *p2;
const char *p3;
const char *str;
- CURLcode result = CURLE_OK;
- bool added = FALSE;
- struct dynbuf temp;
- Curl_dyn_init(&temp, CURL_X509_STR_MAX);
for(p1 = dn->beg; p1 < dn->end;) {
p1 = getASN1Element(&rdn, p1, dn->end);
- if(!p1) {
- result = CURLE_BAD_FUNCTION_ARGUMENT;
- goto error;
- }
+ if(!p1)
+ return -1;
for(p2 = rdn.beg; p2 < rdn.end;) {
p2 = getASN1Element(&atv, p2, rdn.end);
- if(!p2) {
- result = CURLE_BAD_FUNCTION_ARGUMENT;
- goto error;
- }
+ if(!p2)
+ return -1;
p3 = getASN1Element(&oid, atv.beg, atv.end);
- if(!p3) {
- result = CURLE_BAD_FUNCTION_ARGUMENT;
- goto error;
- }
- if(!getASN1Element(&value, p3, atv.end)) {
- result = CURLE_BAD_FUNCTION_ARGUMENT;
- goto error;
- }
- Curl_dyn_reset(&temp);
- result = ASN1tostr(&temp, &oid, 0);
- if(result)
- goto error;
-
- str = Curl_dyn_ptr(&temp);
-
- if(!str) {
- result = CURLE_BAD_FUNCTION_ARGUMENT;
- goto error;
- }
+ if(!p3)
+ return -1;
+ if(!getASN1Element(&value, p3, atv.end))
+ return -1;
+ str = ASN1tostr(&oid, 0);
+ if(!str)
+ return -1;
/* Encode delimiter.
If attribute has a short uppercase name, delimiter is ", ". */
- for(p3 = str; ISUPPER(*p3); p3++)
- ;
- if(added) {
- if(p3 - str > 2)
- result = Curl_dyn_addn(store, "/", 1);
- else
- result = Curl_dyn_addn(store, ", ", 2);
- if(result)
- goto error;
+ if(l) {
+ for(p3 = str; ISUPPER(*p3); p3++)
+ ;
+ for(p3 = (*p3 || p3 - str > 2)? "/": ", "; *p3; p3++) {
+ if(l < buflen)
+ buf[l] = *p3;
+ l++;
+ }
}
/* Encode attribute name. */
- result = Curl_dyn_add(store, str);
- if(result)
- goto error;
+ for(p3 = str; *p3; p3++) {
+ if(l < buflen)
+ buf[l] = *p3;
+ l++;
+ }
+ free((char *) str);
/* Generate equal sign. */
- result = Curl_dyn_addn(store, "=", 1);
- if(result)
- goto error;
+ if(l < buflen)
+ buf[l] = '=';
+ l++;
/* Generate value. */
- result = ASN1tostr(store, &value, 0);
- if(result)
- goto error;
- Curl_dyn_reset(&temp);
- added = TRUE; /* use separator for next */
+ str = ASN1tostr(&value, 0);
+ if(!str)
+ return -1;
+ for(p3 = str; *p3; p3++) {
+ if(l < buflen)
+ buf[l] = *p3;
+ l++;
+ }
+ free((char *) str);
}
}
-error:
- Curl_dyn_free(&temp);
- return result;
+ return l;
}
#endif /* WANT_EXTRACT_CERTINFO */
@@ -879,9 +876,25 @@ int Curl_parseX509(struct Curl_X509certificate *cert,
#ifdef WANT_EXTRACT_CERTINFO
-static CURLcode dumpAlgo(struct dynbuf *store,
- struct Curl_asn1Element *param,
- const char *beg, const char *end)
+/*
+ * Copy at most 64-characters, terminate with a newline and returns the
+ * effective number of stored characters.
+ */
+static size_t copySubstring(char *to, const char *from)
+{
+ size_t i;
+ for(i = 0; i < 64; i++) {
+ to[i] = *from;
+ if(!*from++)
+ break;
+ }
+
+ to[i++] = '\n';
+ return i;
+}
+
+static const char *dumpAlgo(struct Curl_asn1Element *param,
+ const char *beg, const char *end)
{
struct Curl_asn1Element oid;
@@ -889,16 +902,14 @@ static CURLcode dumpAlgo(struct dynbuf *store,
beg = getASN1Element(&oid, beg, end);
if(!beg)
- return CURLE_BAD_FUNCTION_ARGUMENT;
+ return NULL;
param->header = NULL;
param->tag = 0;
param->beg = param->end = end;
- if(beg < end) {
- const char *p = getASN1Element(param, beg, end);
- if(!p)
- return CURLE_BAD_FUNCTION_ARGUMENT;
- }
- return OID2str(store, oid.beg, oid.end, TRUE);
+ if(beg < end)
+ if(!getASN1Element(param, beg, end))
+ return NULL;
+ return OID2str(oid.beg, oid.end, TRUE);
}
/*
@@ -915,47 +926,24 @@ static CURLcode ssl_push_certinfo(struct Curl_easy *data,
return Curl_ssl_push_certinfo_len(data, certnum, label, value, valuelen);
}
-/*
- * This is a convenience function for push_certinfo_len that takes a
- * dynbuf value.
- *
- * It also does the verbose output if !certnum.
- */
-static CURLcode ssl_push_certinfo_dyn(struct Curl_easy *data,
- int certnum,
- const char *label,
- struct dynbuf *ptr)
-{
- size_t valuelen = Curl_dyn_len(ptr);
- char *value = Curl_dyn_ptr(ptr);
-
- CURLcode result = Curl_ssl_push_certinfo_len(data, certnum, label,
- value, valuelen);
-
- if(!certnum && !result)
- infof(data, " %s: %s", label, value);
-
- return result;
-}
-
-static CURLcode do_pubkey_field(struct Curl_easy *data, int certnum,
- const char *label,
- struct Curl_asn1Element *elem)
+/* return 0 on success, 1 on error */
+static int do_pubkey_field(struct Curl_easy *data, int certnum,
+ const char *label, struct Curl_asn1Element *elem)
{
- CURLcode result;
- struct dynbuf out;
-
- Curl_dyn_init(&out, CURL_X509_STR_MAX);
+ const char *output;
+ CURLcode result = CURLE_OK;
/* Generate a certificate information record for the public key. */
- result = ASN1tostr(&out, elem, 0);
- if(!result) {
+ output = ASN1tostr(elem, 0);
+ if(output) {
if(data->set.ssl.certinfo)
- result = ssl_push_certinfo_dyn(data, certnum, label, &out);
- Curl_dyn_free(&out);
+ result = ssl_push_certinfo(data, certnum, label, output);
+ if(!certnum && !result)
+ infof(data, " %s: %s", label, output);
+ free((char *) output);
}
- return result;
+ return result ? 1 : 0;
}
/* return 0 on success, 1 on error */
@@ -976,15 +964,14 @@ static int do_pubkey(struct Curl_easy *data, int certnum,
*/
const size_t len = ((pubkey->end - pubkey->beg - 2) * 4);
if(!certnum)
- infof(data, " ECC Public Key (%zu bits)", len);
+ infof(data, " ECC Public Key (%lu bits)", len);
if(data->set.ssl.certinfo) {
char q[sizeof(len) * 8 / 3 + 1];
(void)msnprintf(q, sizeof(q), "%zu", len);
if(ssl_push_certinfo(data, certnum, "ECC Public Key", q))
return 1;
}
- return do_pubkey_field(data, certnum, "ecPublicKey", pubkey) == CURLE_OK
- ? 0 : 1;
+ return do_pubkey_field(data, certnum, "ecPublicKey", pubkey);
}
/* Get the public key (single element). */
@@ -1011,7 +998,7 @@ static int do_pubkey(struct Curl_easy *data, int certnum,
if(len > 32)
elem.beg = q; /* Strip leading zero bytes. */
if(!certnum)
- infof(data, " RSA Public Key (%zu bits)", len);
+ infof(data, " RSA Public Key (%lu bits)", len);
if(data->set.ssl.certinfo) {
char r[sizeof(len) * 8 / 3 + 1];
msnprintf(r, sizeof(r), "%zu", len);
@@ -1062,12 +1049,24 @@ static int do_pubkey(struct Curl_easy *data, int certnum,
/*
* Convert an ASN.1 distinguished name into a printable string.
- * Return error.
+ * Return the dynamically allocated string, or NULL if an error occurs.
*/
-static CURLcode DNtostr(struct dynbuf *store,
- struct Curl_asn1Element *dn)
+static const char *DNtostr(struct Curl_asn1Element *dn)
{
- return encodeDN(store, dn);
+ char *buf = NULL;
+ ssize_t buflen = encodeDN(NULL, 0, dn);
+
+ if(buflen >= 0) {
+ buf = malloc(buflen + 1);
+ if(buf) {
+ if(encodeDN(buf, buflen + 1, dn) == -1) {
+ free(buf);
+ return NULL;
+ }
+ buf[buflen] = '\0';
+ }
+ }
+ return buf;
}
CURLcode Curl_extract_certinfo(struct Curl_easy *data,
@@ -1077,19 +1076,19 @@ CURLcode Curl_extract_certinfo(struct Curl_easy *data,
{
struct Curl_X509certificate cert;
struct Curl_asn1Element param;
- char *certptr;
- size_t clen;
- struct dynbuf out;
+ const char *ccp;
+ char *cp1;
+ size_t cl1;
+ char *cp2;
CURLcode result = CURLE_OK;
unsigned int version;
- const char *ptr;
- int rc;
+ size_t i;
+ size_t j;
if(!data->set.ssl.certinfo)
if(certnum)
return CURLE_OK;
- Curl_dyn_init(&out, CURL_X509_STR_MAX);
/* Prepare the certificate information for curl_easy_getinfo(). */
/* Extract the certificate ASN.1 elements. */
@@ -1097,126 +1096,135 @@ CURLcode Curl_extract_certinfo(struct Curl_easy *data,
return CURLE_PEER_FAILED_VERIFICATION;
/* Subject. */
- result = DNtostr(&out, &cert.subject);
- if(result)
- goto done;
+ ccp = DNtostr(&cert.subject);
+ if(!ccp)
+ return CURLE_OUT_OF_MEMORY;
if(data->set.ssl.certinfo) {
- result = ssl_push_certinfo_dyn(data, certnum, "Subject", &out);
+ result = ssl_push_certinfo(data, certnum, "Subject", ccp);
if(result)
- goto done;
+ return result;
}
- Curl_dyn_reset(&out);
+ if(!certnum)
+ infof(data, "%2d Subject: %s", certnum, ccp);
+ free((char *) ccp);
/* Issuer. */
- result = DNtostr(&out, &cert.issuer);
- if(result)
- goto done;
+ ccp = DNtostr(&cert.issuer);
+ if(!ccp)
+ return CURLE_OUT_OF_MEMORY;
if(data->set.ssl.certinfo) {
- result = ssl_push_certinfo_dyn(data, certnum, "Issuer", &out);
- if(result)
- goto done;
+ result = ssl_push_certinfo(data, certnum, "Issuer", ccp);
}
- Curl_dyn_reset(&out);
+ if(!certnum)
+ infof(data, " Issuer: %s", ccp);
+ free((char *) ccp);
+ if(result)
+ return result;
/* Version (always fits in less than 32 bits). */
version = 0;
- for(ptr = cert.version.beg; ptr < cert.version.end; ptr++)
- version = (version << 8) | *(const unsigned char *) ptr;
+ for(ccp = cert.version.beg; ccp < cert.version.end; ccp++)
+ version = (version << 8) | *(const unsigned char *) ccp;
if(data->set.ssl.certinfo) {
- result = Curl_dyn_addf(&out, "%x", version);
+ ccp = curl_maprintf("%x", version);
+ if(!ccp)
+ return CURLE_OUT_OF_MEMORY;
+ result = ssl_push_certinfo(data, certnum, "Version", ccp);
+ free((char *) ccp);
if(result)
- goto done;
- result = ssl_push_certinfo_dyn(data, certnum, "Version", &out);
- if(result)
- goto done;
- Curl_dyn_reset(&out);
+ return result;
}
+ if(!certnum)
+ infof(data, " Version: %u (0x%x)", version + 1, version);
/* Serial number. */
- result = ASN1tostr(&out, &cert.serialNumber, 0);
+ ccp = ASN1tostr(&cert.serialNumber, 0);
+ if(!ccp)
+ return CURLE_OUT_OF_MEMORY;
+ if(data->set.ssl.certinfo)
+ result = ssl_push_certinfo(data, certnum, "Serial Number", ccp);
+ if(!certnum)
+ infof(data, " Serial Number: %s", ccp);
+ free((char *) ccp);
if(result)
- goto done;
- if(data->set.ssl.certinfo) {
- result = ssl_push_certinfo_dyn(data, certnum, "Serial Number", &out);
- if(result)
- goto done;
- }
- Curl_dyn_reset(&out);
+ return result;
/* Signature algorithm .*/
- result = dumpAlgo(&out, &param, cert.signatureAlgorithm.beg,
- cert.signatureAlgorithm.end);
+ ccp = dumpAlgo(&param, cert.signatureAlgorithm.beg,
+ cert.signatureAlgorithm.end);
+ if(!ccp)
+ return CURLE_OUT_OF_MEMORY;
+ if(data->set.ssl.certinfo)
+ result = ssl_push_certinfo(data, certnum, "Signature Algorithm", ccp);
+ if(!certnum)
+ infof(data, " Signature Algorithm: %s", ccp);
+ free((char *) ccp);
if(result)
- goto done;
- if(data->set.ssl.certinfo) {
- result = ssl_push_certinfo_dyn(data, certnum, "Signature Algorithm",
- &out);
- if(result)
- goto done;
- }
- Curl_dyn_reset(&out);
+ return result;
/* Start Date. */
- result = ASN1tostr(&out, &cert.notBefore, 0);
+ ccp = ASN1tostr(&cert.notBefore, 0);
+ if(!ccp)
+ return CURLE_OUT_OF_MEMORY;
+ if(data->set.ssl.certinfo)
+ result = ssl_push_certinfo(data, certnum, "Start Date", ccp);
+ if(!certnum)
+ infof(data, " Start Date: %s", ccp);
+ free((char *) ccp);
if(result)
- goto done;
- if(data->set.ssl.certinfo) {
- result = ssl_push_certinfo_dyn(data, certnum, "Start Date", &out);
- if(result)
- goto done;
- }
- Curl_dyn_reset(&out);
+ return result;
/* Expire Date. */
- result = ASN1tostr(&out, &cert.notAfter, 0);
+ ccp = ASN1tostr(&cert.notAfter, 0);
+ if(!ccp)
+ return CURLE_OUT_OF_MEMORY;
+ if(data->set.ssl.certinfo)
+ result = ssl_push_certinfo(data, certnum, "Expire Date", ccp);
+ if(!certnum)
+ infof(data, " Expire Date: %s", ccp);
+ free((char *) ccp);
if(result)
- goto done;
- if(data->set.ssl.certinfo) {
- result = ssl_push_certinfo_dyn(data, certnum, "Expire Date", &out);
- if(result)
- goto done;
- }
- Curl_dyn_reset(&out);
+ return result;
/* Public Key Algorithm. */
- result = dumpAlgo(&out, &param, cert.subjectPublicKeyAlgorithm.beg,
- cert.subjectPublicKeyAlgorithm.end);
- if(result)
- goto done;
- if(data->set.ssl.certinfo) {
- result = ssl_push_certinfo_dyn(data, certnum, "Public Key Algorithm",
- &out);
- if(result)
- goto done;
- }
-
- rc = do_pubkey(data, certnum, Curl_dyn_ptr(&out),
- &param, &cert.subjectPublicKey);
- if(rc) {
- result = CURLE_OUT_OF_MEMORY; /* the most likely error */
- goto done;
+ ccp = dumpAlgo(&param, cert.subjectPublicKeyAlgorithm.beg,
+ cert.subjectPublicKeyAlgorithm.end);
+ if(!ccp)
+ return CURLE_OUT_OF_MEMORY;
+ if(data->set.ssl.certinfo)
+ result = ssl_push_certinfo(data, certnum, "Public Key Algorithm",
+ ccp);
+ if(!result) {
+ int ret;
+ if(!certnum)
+ infof(data, " Public Key Algorithm: %s", ccp);
+ ret = do_pubkey(data, certnum, ccp, &param, &cert.subjectPublicKey);
+ if(ret)
+ result = CURLE_OUT_OF_MEMORY; /* the most likely error */
}
- Curl_dyn_reset(&out);
+ free((char *) ccp);
+ if(result)
+ return result;
/* Signature. */
- result = ASN1tostr(&out, &cert.signature, 0);
+ ccp = ASN1tostr(&cert.signature, 0);
+ if(!ccp)
+ return CURLE_OUT_OF_MEMORY;
+ if(data->set.ssl.certinfo)
+ result = ssl_push_certinfo(data, certnum, "Signature", ccp);
+ if(!certnum)
+ infof(data, " Signature: %s", ccp);
+ free((char *) ccp);
if(result)
- goto done;
- if(data->set.ssl.certinfo) {
- result = ssl_push_certinfo_dyn(data, certnum, "Signature", &out);
- if(result)
- goto done;
- }
- Curl_dyn_reset(&out);
+ return result;
/* Generate PEM certificate. */
result = Curl_base64_encode(cert.certificate.beg,
cert.certificate.end - cert.certificate.beg,
- &certptr, &clen);
+ &cp1, &cl1);
if(result)
- goto done;
-
- /* Generate the final output certificate string. Format is:
+ return result;
+ /* Compute the number of characters in final certificate string. Format is:
-----BEGIN CERTIFICATE-----\n
<max 64 base64 characters>\n
.
@@ -1224,36 +1232,207 @@ CURLcode Curl_extract_certinfo(struct Curl_easy *data,
.
-----END CERTIFICATE-----\n
*/
-
- Curl_dyn_reset(&out);
-
- /* Build the certificate string. */
- result = Curl_dyn_add(&out, "-----BEGIN CERTIFICATE-----\n");
- if(!result) {
- size_t j = 0;
-
- while(!result && (j < clen)) {
- size_t chunksize = (clen - j) > 64 ? 64 : (clen - j);
- result = Curl_dyn_addn(&out, &certptr[j], chunksize);
- if(!result)
- result = Curl_dyn_addn(&out, "\n", 1);
- j += chunksize;
- }
- if(!result)
- result = Curl_dyn_add(&out, "-----END CERTIFICATE-----\n");
+ i = 28 + cl1 + (cl1 + 64 - 1) / 64 + 26;
+ cp2 = malloc(i + 1);
+ if(!cp2) {
+ free(cp1);
+ return CURLE_OUT_OF_MEMORY;
}
- free(certptr);
- if(!result)
- if(data->set.ssl.certinfo)
- result = ssl_push_certinfo_dyn(data, certnum, "Cert", &out);
-
-done:
- if(result)
- failf(data, "Failed extracting certificate chain");
- Curl_dyn_free(&out);
+ /* Build the certificate string. */
+ i = copySubstring(cp2, "-----BEGIN CERTIFICATE-----");
+ for(j = 0; j < cl1; j += 64)
+ i += copySubstring(cp2 + i, cp1 + j);
+ i += copySubstring(cp2 + i, "-----END CERTIFICATE-----");
+ cp2[i] = '\0';
+ free(cp1);
+ if(data->set.ssl.certinfo)
+ result = ssl_push_certinfo(data, certnum, "Cert", cp2);
+ if(!certnum)
+ infof(data, "%s", cp2);
+ free(cp2);
return result;
}
#endif /* WANT_EXTRACT_CERTINFO */
#endif /* USE_GNUTLS or USE_WOLFSSL or USE_SCHANNEL or USE_SECTRANSP */
+
+#ifdef WANT_VERIFYHOST
+
+static const char *checkOID(const char *beg, const char *end,
+ const char *oid)
+{
+ struct Curl_asn1Element e;
+ const char *ccp;
+ const char *p;
+ bool matched;
+
+ /* Check if first ASN.1 element at `beg' is the given OID.
+ Return a pointer in the source after the OID if found, else NULL. */
+
+ ccp = getASN1Element(&e, beg, end);
+ if(!ccp || e.tag != CURL_ASN1_OBJECT_IDENTIFIER)
+ return NULL;
+
+ p = OID2str(e.beg, e.end, FALSE);
+ if(!p)
+ return NULL;
+
+ matched = !strcmp(p, oid);
+ free((char *) p);
+ return matched? ccp: NULL;
+}
+
+CURLcode Curl_verifyhost(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ const char *beg, const char *end)
+{
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+ struct Curl_X509certificate cert;
+ struct Curl_asn1Element dn;
+ struct Curl_asn1Element elem;
+ struct Curl_asn1Element ext;
+ struct Curl_asn1Element name;
+ const char *p;
+ const char *q;
+ char *dnsname;
+ int matched = -1;
+ size_t addrlen = (size_t) -1;
+ ssize_t len;
+ size_t hostlen;
+
+#ifdef ENABLE_IPV6
+ struct in6_addr addr;
+#else
+ struct in_addr addr;
+#endif
+
+ /* Verify that connection server matches info in X509 certificate at
+ `beg'..`end'. */
+
+ if(!conn_config->verifyhost)
+ return CURLE_OK;
+
+ if(Curl_parseX509(&cert, beg, end))
+ return CURLE_PEER_FAILED_VERIFICATION;
+
+ hostlen = strlen(connssl->peer.hostname);
+
+ /* Get the server IP address. */
+#ifdef ENABLE_IPV6
+ if(cf->conn->bits.ipv6_ip &&
+ Curl_inet_pton(AF_INET6, connssl->peer.hostname, &addr))
+ addrlen = sizeof(struct in6_addr);
+ else
+#endif
+ if(Curl_inet_pton(AF_INET, connssl->peer.hostname, &addr))
+ addrlen = sizeof(struct in_addr);
+
+ /* Process extensions. */
+ for(p = cert.extensions.beg; p < cert.extensions.end && matched != 1;) {
+ p = getASN1Element(&ext, p, cert.extensions.end);
+ if(!p)
+ return CURLE_PEER_FAILED_VERIFICATION;
+
+ /* Check if extension is a subjectAlternativeName. */
+ ext.beg = checkOID(ext.beg, ext.end, sanOID);
+ if(ext.beg) {
+ ext.beg = getASN1Element(&elem, ext.beg, ext.end);
+ if(!ext.beg)
+ return CURLE_PEER_FAILED_VERIFICATION;
+ /* Skip critical if present. */
+ if(elem.tag == CURL_ASN1_BOOLEAN) {
+ ext.beg = getASN1Element(&elem, ext.beg, ext.end);
+ if(!ext.beg)
+ return CURLE_PEER_FAILED_VERIFICATION;
+ }
+ /* Parse the octet string contents: is a single sequence. */
+ if(!getASN1Element(&elem, elem.beg, elem.end))
+ return CURLE_PEER_FAILED_VERIFICATION;
+ /* Check all GeneralNames. */
+ for(q = elem.beg; matched != 1 && q < elem.end;) {
+ q = getASN1Element(&name, q, elem.end);
+ if(!q)
+ break;
+ switch(name.tag) {
+ case 2: /* DNS name. */
+ len = utf8asn1str(&dnsname, CURL_ASN1_IA5_STRING,
+ name.beg, name.end);
+ if(len > 0 && (size_t)len == strlen(dnsname))
+ matched = Curl_cert_hostcheck(dnsname, (size_t)len,
+ connssl->peer.hostname, hostlen);
+ else
+ matched = 0;
+ free(dnsname);
+ break;
+
+ case 7: /* IP address. */
+ matched = (size_t)(name.end - name.beg) == addrlen &&
+ !memcmp(&addr, name.beg, addrlen);
+ break;
+ }
+ }
+ }
+ }
+
+ switch(matched) {
+ case 1:
+ /* an alternative name matched the server hostname */
+ infof(data, " subjectAltName: %s matched", connssl->dispname);
+ return CURLE_OK;
+ case 0:
+ /* an alternative name field existed, but didn't match and then
+ we MUST fail */
+ infof(data, " subjectAltName does not match %s", connssl->dispname);
+ return CURLE_PEER_FAILED_VERIFICATION;
+ }
+
+ /* Process subject. */
+ name.header = NULL;
+ name.beg = name.end = "";
+ q = cert.subject.beg;
+ /* we have to look to the last occurrence of a commonName in the
+ distinguished one to get the most significant one. */
+ while(q < cert.subject.end) {
+ q = getASN1Element(&dn, q, cert.subject.end);
+ if(!q)
+ break;
+ for(p = dn.beg; p < dn.end;) {
+ p = getASN1Element(&elem, p, dn.end);
+ if(!p)
+ return CURLE_PEER_FAILED_VERIFICATION;
+ /* We have a DN's AttributeTypeAndValue: check it in case it's a CN. */
+ elem.beg = checkOID(elem.beg, elem.end, cnOID);
+ if(elem.beg)
+ name = elem; /* Latch CN. */
+ }
+ }
+
+ /* Check the CN if found. */
+ if(!getASN1Element(&elem, name.beg, name.end))
+ failf(data, "SSL: unable to obtain common name from peer certificate");
+ else {
+ len = utf8asn1str(&dnsname, elem.tag, elem.beg, elem.end);
+ if(len < 0) {
+ free(dnsname);
+ return CURLE_OUT_OF_MEMORY;
+ }
+ if(strlen(dnsname) != (size_t) len) /* Nul byte in string ? */
+ failf(data, "SSL: illegal cert name field");
+ else if(Curl_cert_hostcheck((const char *) dnsname,
+ len, connssl->peer.hostname, hostlen)) {
+ infof(data, " common name: %s (matched)", dnsname);
+ free(dnsname);
+ return CURLE_OK;
+ }
+ else
+ failf(data, "SSL: certificate subject name '%s' does not match "
+ "target host name '%s'", dnsname, connssl->dispname);
+ free(dnsname);
+ }
+
+ return CURLE_PEER_FAILED_VERIFICATION;
+}
+
+#endif /* WANT_VERIFYHOST */
diff --git a/contrib/libs/curl/lib/vtls/x509asn1.h b/contrib/libs/curl/lib/vtls/x509asn1.h
new file mode 100644
index 0000000000..23a67b828a
--- /dev/null
+++ b/contrib/libs/curl/lib/vtls/x509asn1.h
@@ -0,0 +1,80 @@
+#ifndef HEADER_CURL_X509ASN1_H
+#define HEADER_CURL_X509ASN1_H
+
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if defined(USE_GNUTLS) || defined(USE_WOLFSSL) || \
+ defined(USE_SCHANNEL) || defined(USE_SECTRANSP)
+
+#include "cfilters.h"
+#include "urldata.h"
+
+/*
+ * Types.
+ */
+
+/* ASN.1 parsed element. */
+struct Curl_asn1Element {
+ const char *header; /* Pointer to header byte. */
+ const char *beg; /* Pointer to element data. */
+ const char *end; /* Pointer to 1st byte after element. */
+ unsigned char class; /* ASN.1 element class. */
+ unsigned char tag; /* ASN.1 element tag. */
+ bool constructed; /* Element is constructed. */
+};
+
+/* X509 certificate: RFC 5280. */
+struct Curl_X509certificate {
+ struct Curl_asn1Element certificate;
+ struct Curl_asn1Element version;
+ struct Curl_asn1Element serialNumber;
+ struct Curl_asn1Element signatureAlgorithm;
+ struct Curl_asn1Element signature;
+ struct Curl_asn1Element issuer;
+ struct Curl_asn1Element notBefore;
+ struct Curl_asn1Element notAfter;
+ struct Curl_asn1Element subject;
+ struct Curl_asn1Element subjectPublicKeyInfo;
+ struct Curl_asn1Element subjectPublicKeyAlgorithm;
+ struct Curl_asn1Element subjectPublicKey;
+ struct Curl_asn1Element issuerUniqueID;
+ struct Curl_asn1Element subjectUniqueID;
+ struct Curl_asn1Element extensions;
+};
+
+/*
+ * Prototypes.
+ */
+
+int Curl_parseX509(struct Curl_X509certificate *cert,
+ const char *beg, const char *end);
+CURLcode Curl_extract_certinfo(struct Curl_easy *data, int certnum,
+ const char *beg, const char *end);
+CURLcode Curl_verifyhost(struct Curl_cfilter *cf, struct Curl_easy *data,
+ const char *beg, const char *end);
+#endif /* USE_GNUTLS or USE_WOLFSSL or USE_SCHANNEL or USE_SECTRANSP */
+#endif /* HEADER_CURL_X509ASN1_H */
diff --git a/contrib/libs/curl/lib/warnless.h b/contrib/libs/curl/lib/warnless.h
index 6adf63a793..e5a02c8d94 100644
--- a/contrib/libs/curl/lib/warnless.h
+++ b/contrib/libs/curl/lib/warnless.h
@@ -77,6 +77,20 @@ ssize_t curlx_write(int fd, const void *buf, size_t count);
#endif /* _WIN32 */
+#if defined(__INTEL_COMPILER) && defined(__unix__)
+
+int curlx_FD_ISSET(int fd, fd_set *fdset);
+
+void curlx_FD_SET(int fd, fd_set *fdset);
+
+void curlx_FD_ZERO(fd_set *fdset);
+
+unsigned short curlx_htons(unsigned short usnum);
+
+unsigned short curlx_ntohs(unsigned short usnum);
+
+#endif /* __INTEL_COMPILER && __unix__ */
+
#endif /* HEADER_CURL_WARNLESS_H */
#ifndef HEADER_CURL_WARNLESS_H_REDEFS
diff --git a/contrib/libs/curl/lib/ws.c b/contrib/libs/curl/lib/ws.c
index 670694470a..adde531f5e 100644
--- a/contrib/libs/curl/lib/ws.c
+++ b/contrib/libs/curl/lib/ws.c
@@ -24,7 +24,7 @@
#include "curl_setup.h"
#include <curl/curl.h>
-#if defined(USE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP)
+#ifdef USE_WEBSOCKETS
#include "urldata.h"
#include "bufq.h"
@@ -37,7 +37,6 @@
#include "ws.h"
#include "easyif.h"
#include "transfer.h"
-#include "select.h"
#include "nonblock.h"
/* The last 3 #include files should be in this order */
@@ -103,7 +102,7 @@ static unsigned char ws_frame_flags2op(int flags)
size_t i;
for(i = 0; i < sizeof(WS_FRAMES)/sizeof(WS_FRAMES[0]); ++i) {
if(WS_FRAMES[i].flags & flags)
- return (unsigned char)WS_FRAMES[i].proto_opcode;
+ return WS_FRAMES[i].proto_opcode;
}
return 0;
}
@@ -115,31 +114,28 @@ static void ws_dec_info(struct ws_decoder *dec, struct Curl_easy *data,
case 0:
break;
case 1:
- CURL_TRC_WRITE(data, "websocket, decoded %s [%s%s]", msg,
- ws_frame_name_of_op(dec->head[0]),
- (dec->head[0] & WSBIT_FIN)? "" : " NON-FINAL");
+ infof(data, "WS-DEC: %s [%s%s]", msg,
+ ws_frame_name_of_op(dec->head[0]),
+ (dec->head[0] & WSBIT_FIN)? "" : " NON-FINAL");
break;
default:
if(dec->head_len < dec->head_total) {
- CURL_TRC_WRITE(data, "websocket, decoded %s [%s%s](%d/%d)", msg,
- ws_frame_name_of_op(dec->head[0]),
- (dec->head[0] & WSBIT_FIN)? "" : " NON-FINAL",
- dec->head_len, dec->head_total);
+ infof(data, "WS-DEC: %s [%s%s](%d/%d)", msg,
+ ws_frame_name_of_op(dec->head[0]),
+ (dec->head[0] & WSBIT_FIN)? "" : " NON-FINAL",
+ dec->head_len, dec->head_total);
}
else {
- CURL_TRC_WRITE(data, "websocket, decoded %s [%s%s payload=%"
- FMT_OFF_T "/%" FMT_OFF_T "]",
- msg, ws_frame_name_of_op(dec->head[0]),
- (dec->head[0] & WSBIT_FIN)? "" : " NON-FINAL",
- dec->payload_offset, dec->payload_len);
+ infof(data, "WS-DEC: %s [%s%s payload=%" CURL_FORMAT_CURL_OFF_T
+ "/%" CURL_FORMAT_CURL_OFF_T "]",
+ msg, ws_frame_name_of_op(dec->head[0]),
+ (dec->head[0] & WSBIT_FIN)? "" : " NON-FINAL",
+ dec->payload_offset, dec->payload_len);
}
break;
}
}
-static CURLcode ws_send_raw_blocking(CURL *data, struct websocket *ws,
- const char *buffer, size_t buflen);
-
typedef ssize_t ws_write_payload(const unsigned char *buf, size_t buflen,
int frame_age, int frame_flags,
curl_off_t payload_offset,
@@ -175,7 +171,7 @@ static CURLcode ws_dec_read_head(struct ws_decoder *dec,
dec->head[0] = *inbuf;
Curl_bufq_skip(inraw, 1);
- dec->frame_flags = ws_frame_op2flags(dec->head[0]);
+ dec->frame_flags = ws_frame_op2flags(dec->head[0]);
if(!dec->frame_flags) {
failf(data, "WS: unknown opcode: %x", dec->head[0]);
ws_dec_reset(dec);
@@ -229,10 +225,6 @@ static CURLcode ws_dec_read_head(struct ws_decoder *dec,
dec->payload_len = (dec->head[2] << 8) | dec->head[3];
break;
case 10:
- if(dec->head[2] > 127) {
- failf(data, "WS: frame length longer than 64 signed not supported");
- return CURLE_RECV_ERROR;
- }
dec->payload_len = ((curl_off_t)dec->head[2] << 56) |
(curl_off_t)dec->head[3] << 48 |
(curl_off_t)dec->head[4] << 40 |
@@ -281,8 +273,9 @@ static CURLcode ws_dec_pass_payload(struct ws_decoder *dec,
Curl_bufq_skip(inraw, (size_t)nwritten);
dec->payload_offset += (curl_off_t)nwritten;
remain = dec->payload_len - dec->payload_offset;
- CURL_TRC_WRITE(data, "websocket, passed %zd bytes payload, %"
- FMT_OFF_T " remain", nwritten, remain);
+ /* infof(data, "WS-DEC: passed %zd bytes payload, %"
+ CURL_FORMAT_CURL_OFF_T " remain",
+ nwritten, remain); */
}
return remain? CURLE_AGAIN : CURLE_OK;
@@ -303,7 +296,7 @@ static CURLcode ws_dec_pass(struct ws_decoder *dec,
case WS_DEC_INIT:
ws_dec_reset(dec);
dec->state = WS_DEC_HEAD;
- FALLTHROUGH();
+ /* FALLTHROUGH */
case WS_DEC_HEAD:
result = ws_dec_read_head(dec, data, inraw);
if(result) {
@@ -328,7 +321,7 @@ static CURLcode ws_dec_pass(struct ws_decoder *dec,
dec->state = WS_DEC_INIT;
break;
}
- FALLTHROUGH();
+ /* FALLTHROUGH */
case WS_DEC_PAYLOAD:
result = ws_dec_pass_payload(dec, data, inraw, write_payload, write_ctx);
ws_dec_info(dec, data, "passing");
@@ -357,142 +350,11 @@ static void update_meta(struct websocket *ws,
ws->frame.bytesleft = (payload_len - payload_offset - cur_len);
}
-/* WebSockets decoding client writer */
-struct ws_cw_ctx {
- struct Curl_cwriter super;
- struct bufq buf;
-};
-
-static CURLcode ws_cw_init(struct Curl_easy *data,
- struct Curl_cwriter *writer)
-{
- struct ws_cw_ctx *ctx = writer->ctx;
- (void)data;
- Curl_bufq_init2(&ctx->buf, WS_CHUNK_SIZE, 1, BUFQ_OPT_SOFT_LIMIT);
- return CURLE_OK;
-}
-
-static void ws_cw_close(struct Curl_easy *data, struct Curl_cwriter *writer)
-{
- struct ws_cw_ctx *ctx = writer->ctx;
- (void) data;
- Curl_bufq_free(&ctx->buf);
-}
-
-struct ws_cw_dec_ctx {
- struct Curl_easy *data;
- struct websocket *ws;
- struct Curl_cwriter *next_writer;
- int cw_type;
-};
-
-static ssize_t ws_cw_dec_next(const unsigned char *buf, size_t buflen,
- int frame_age, int frame_flags,
- curl_off_t payload_offset,
- curl_off_t payload_len,
- void *user_data,
- CURLcode *err)
-{
- struct ws_cw_dec_ctx *ctx = user_data;
- struct Curl_easy *data = ctx->data;
- struct websocket *ws = ctx->ws;
- curl_off_t remain = (payload_len - (payload_offset + buflen));
-
- (void)frame_age;
- if((frame_flags & CURLWS_PING) && !remain) {
- /* auto-respond to PINGs, only works for single-frame payloads atm */
- size_t bytes;
- infof(data, "WS: auto-respond to PING with a PONG");
- /* send back the exact same content as a PONG */
- *err = curl_ws_send(data, buf, buflen, &bytes, 0, CURLWS_PONG);
- if(*err)
- return -1;
- }
- else if(buflen || !remain) {
- /* forward the decoded frame to the next client writer. */
- update_meta(ws, frame_age, frame_flags, payload_offset,
- payload_len, buflen);
-
- *err = Curl_cwriter_write(data, ctx->next_writer, ctx->cw_type,
- (const char *)buf, buflen);
- if(*err)
- return -1;
- }
- *err = CURLE_OK;
- return (ssize_t)buflen;
-}
-
-static CURLcode ws_cw_write(struct Curl_easy *data,
- struct Curl_cwriter *writer, int type,
- const char *buf, size_t nbytes)
-{
- struct ws_cw_ctx *ctx = writer->ctx;
- struct websocket *ws;
- CURLcode result;
-
- if(!(type & CLIENTWRITE_BODY) || data->set.ws_raw_mode)
- return Curl_cwriter_write(data, writer->next, type, buf, nbytes);
-
- ws = data->conn->proto.ws;
- if(!ws) {
- failf(data, "WS: not a websocket transfer");
- return CURLE_FAILED_INIT;
- }
-
- if(nbytes) {
- ssize_t nwritten;
- nwritten = Curl_bufq_write(&ctx->buf, (const unsigned char *)buf,
- nbytes, &result);
- if(nwritten < 0) {
- infof(data, "WS: error adding data to buffer %d", result);
- return result;
- }
- }
-
- while(!Curl_bufq_is_empty(&ctx->buf)) {
- struct ws_cw_dec_ctx pass_ctx;
- pass_ctx.data = data;
- pass_ctx.ws = ws;
- pass_ctx.next_writer = writer->next;
- pass_ctx.cw_type = type;
- result = ws_dec_pass(&ws->dec, data, &ctx->buf,
- ws_cw_dec_next, &pass_ctx);
- if(result == CURLE_AGAIN) {
- /* insufficient amount of data, keep it for later.
- * we pretend to have written all since we have a copy */
- CURL_TRC_WRITE(data, "websocket, buffered incomplete frame head");
- return CURLE_OK;
- }
- else if(result) {
- infof(data, "WS: decode error %d", (int)result);
- return result;
- }
- }
-
- if((type & CLIENTWRITE_EOS) && !Curl_bufq_is_empty(&ctx->buf)) {
- infof(data, "WS: decode ending with %zd frame bytes remaining",
- Curl_bufq_len(&ctx->buf));
- return CURLE_RECV_ERROR;
- }
-
- return CURLE_OK;
-}
-
-/* WebSocket payload decoding client writer. */
-static const struct Curl_cwtype ws_cw_decode = {
- "ws-decode",
- NULL,
- ws_cw_init,
- ws_cw_write,
- ws_cw_close,
- sizeof(struct ws_cw_ctx)
-};
-
-
static void ws_enc_info(struct ws_encoder *enc, struct Curl_easy *data,
const char *msg)
{
- infof(data, "WS-ENC: %s [%s%s%s payload=%" FMT_OFF_T "/%" FMT_OFF_T "]",
+ infof(data, "WS-ENC: %s [%s%s%s payload=%" CURL_FORMAT_CURL_OFF_T
+ "/%" CURL_FORMAT_CURL_OFF_T "]",
msg, ws_frame_name_of_op(enc->firstbyte),
(enc->firstbyte & WSBIT_OPCODE_MASK) == WSBIT_OPCODE_CONT ?
" CONT" : "",
@@ -548,22 +410,15 @@ static ssize_t ws_enc_write_head(struct Curl_easy *data,
size_t hlen;
ssize_t n;
- if(payload_len < 0) {
- failf(data, "WS: starting new frame with negative payload length %"
- FMT_OFF_T, payload_len);
- *err = CURLE_SEND_ERROR;
- return -1;
- }
-
if(enc->payload_remain > 0) {
/* trying to write a new frame before the previous one is finished */
- failf(data, "WS: starting new frame with %zd bytes from last one "
+ failf(data, "WS: starting new frame with %zd bytes from last one"
"remaining to be sent", (ssize_t)enc->payload_remain);
*err = CURLE_SEND_ERROR;
return -1;
}
- opcode = ws_frame_flags2op((int)flags & ~CURLWS_CONT);
+ opcode = ws_frame_flags2op(flags);
if(!opcode) {
failf(data, "WS: provided flags not recognized '%x'", flags);
*err = CURLE_SEND_ERROR;
@@ -582,7 +437,7 @@ static ssize_t ws_enc_write_head(struct Curl_easy *data,
enc->contfragment = FALSE;
}
else if(enc->contfragment) {
- /* the previous fragment was not a final one and this is not either, keep a
+ /* the previous fragment was not a final one and this isn't either, keep a
CONT opcode and no FIN bit */
firstbyte |= WSBIT_OPCODE_CONT;
}
@@ -721,10 +576,8 @@ CURLcode Curl_ws_request(struct Curl_easy *data, REQTYPE *req)
if(result)
return result;
DEBUGASSERT(randlen < sizeof(keyval));
- if(randlen >= sizeof(keyval)) {
- free(randstr);
+ if(randlen >= sizeof(keyval))
return CURLE_FAILED_INIT;
- }
strcpy(keyval, randstr);
free(randstr);
for(i = 0; !result && (i < sizeof(heads)/sizeof(heads[0])); i++) {
@@ -754,32 +607,17 @@ CURLcode Curl_ws_accept(struct Curl_easy *data,
{
struct SingleRequest *k = &data->req;
struct websocket *ws;
- struct Curl_cwriter *ws_dec_writer;
CURLcode result;
DEBUGASSERT(data->conn);
ws = data->conn->proto.ws;
if(!ws) {
- size_t chunk_size = WS_CHUNK_SIZE;
ws = calloc(1, sizeof(*ws));
if(!ws)
return CURLE_OUT_OF_MEMORY;
data->conn->proto.ws = ws;
-#ifdef DEBUGBUILD
- {
- char *p = getenv("CURL_WS_CHUNK_SIZE");
- if(p) {
- long l = strtol(p, NULL, 10);
- if(l > 0 && l <= (1*1024*1024)) {
- chunk_size = (size_t)l;
- }
- }
- }
-#endif
- CURL_TRC_WS(data, "WS, using chunk size %zu", chunk_size);
- Curl_bufq_init2(&ws->recvbuf, chunk_size, WS_CHUNK_COUNT,
- BUFQ_OPT_SOFT_LIMIT);
- Curl_bufq_init2(&ws->sendbuf, chunk_size, WS_CHUNK_COUNT,
+ Curl_bufq_init(&ws->recvbuf, WS_CHUNK_SIZE, WS_CHUNK_COUNT);
+ Curl_bufq_init2(&ws->sendbuf, WS_CHUNK_SIZE, WS_CHUNK_COUNT,
BUFQ_OPT_SOFT_LIMIT);
ws_dec_init(&ws->dec);
ws_enc_init(&ws->enc);
@@ -817,18 +655,6 @@ CURLcode Curl_ws_accept(struct Curl_easy *data,
infof(data, "Received 101, switch to WebSocket; mask %02x%02x%02x%02x",
ws->enc.mask[0], ws->enc.mask[1], ws->enc.mask[2], ws->enc.mask[3]);
- /* Install our client writer that decodes WS frames payload */
- result = Curl_cwriter_create(&ws_dec_writer, data, &ws_cw_decode,
- CURL_CW_CONTENT_DECODE);
- if(result)
- return result;
-
- result = Curl_cwriter_add(data, ws_dec_writer);
- if(result) {
- Curl_cwriter_free(data, ws_dec_writer);
- return result;
- }
-
if(data->set.connect_only) {
ssize_t nwritten;
/* In CONNECT_ONLY setup, the payloads from `mem` need to be received
@@ -840,20 +666,110 @@ CURLcode Curl_ws_accept(struct Curl_easy *data,
return result;
infof(data, "%zu bytes websocket payload", nread);
}
- else { /* !connect_only */
- /* And pass any additional data to the writers */
- if(nread) {
- result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)mem, nread);
- }
- }
k->upgr101 = UPGR101_RECEIVED;
return result;
}
+static ssize_t ws_client_write(const unsigned char *buf, size_t buflen,
+ int frame_age, int frame_flags,
+ curl_off_t payload_offset,
+ curl_off_t payload_len,
+ void *userp,
+ CURLcode *err)
+{
+ struct Curl_easy *data = userp;
+ struct websocket *ws;
+ size_t wrote;
+ curl_off_t remain = (payload_len - (payload_offset + buflen));
+
+ (void)frame_age;
+ if(!data->conn || !data->conn->proto.ws) {
+ *err = CURLE_FAILED_INIT;
+ return -1;
+ }
+ ws = data->conn->proto.ws;
+
+ if((frame_flags & CURLWS_PING) && !remain) {
+ /* auto-respond to PINGs, only works for single-frame payloads atm */
+ size_t bytes;
+ infof(data, "WS: auto-respond to PING with a PONG");
+ /* send back the exact same content as a PONG */
+ *err = curl_ws_send(data, buf, buflen, &bytes, 0, CURLWS_PONG);
+ if(*err)
+ return -1;
+ }
+ else if(buflen || !remain) {
+ /* deliver the decoded frame to the user callback. The application
+ * may invoke curl_ws_meta() to access frame information. */
+ update_meta(ws, frame_age, frame_flags, payload_offset,
+ payload_len, buflen);
+ Curl_set_in_callback(data, true);
+ wrote = data->set.fwrite_func((char *)buf, 1,
+ buflen, data->set.out);
+ Curl_set_in_callback(data, false);
+ if(wrote != buflen) {
+ *err = CURLE_RECV_ERROR;
+ return -1;
+ }
+ }
+ *err = CURLE_OK;
+ return (ssize_t)buflen;
+}
+
+/* Curl_ws_writecb() is the write callback for websocket traffic. The
+ websocket data is provided to this raw, in chunks. This function should
+ handle/decode the data and call the "real" underlying callback accordingly.
+*/
+size_t Curl_ws_writecb(char *buffer, size_t size /* 1 */,
+ size_t nitems, void *userp)
+{
+ struct Curl_easy *data = userp;
+
+ if(data->set.ws_raw_mode)
+ return data->set.fwrite_func(buffer, size, nitems, data->set.out);
+ else if(nitems) {
+ struct websocket *ws;
+ CURLcode result;
+
+ if(!data->conn || !data->conn->proto.ws) {
+ failf(data, "WS: not a websocket transfer");
+ return nitems - 1;
+ }
+ ws = data->conn->proto.ws;
+
+ if(buffer) {
+ ssize_t nwritten;
+
+ nwritten = Curl_bufq_write(&ws->recvbuf, (const unsigned char *)buffer,
+ nitems, &result);
+ if(nwritten < 0) {
+ infof(data, "WS: error adding data to buffer %d", (int)result);
+ return nitems - 1;
+ }
+ buffer = NULL;
+ }
+
+ while(!Curl_bufq_is_empty(&ws->recvbuf)) {
+
+ result = ws_dec_pass(&ws->dec, data, &ws->recvbuf,
+ ws_client_write, data);
+ if(result == CURLE_AGAIN)
+ /* insufficient amount of data, keep it for later.
+ * we pretend to have written all since we have a copy */
+ return nitems;
+ else if(result) {
+ infof(data, "WS: decode error %d", (int)result);
+ return nitems - 1;
+ }
+ }
+ }
+ return nitems;
+}
+
struct ws_collect {
struct Curl_easy *data;
- unsigned char *buffer;
+ void *buffer;
size_t buflen;
size_t bufidx;
int frame_age;
@@ -905,7 +821,7 @@ static ssize_t ws_client_collect(const unsigned char *buf, size_t buflen,
return -1;
}
*err = CURLE_OK;
- memcpy(ctx->buffer + ctx->bufidx, buf, nwritten);
+ memcpy(ctx->buffer, buf, nwritten);
ctx->bufidx += nwritten;
}
return nwritten;
@@ -955,6 +871,10 @@ CURL_EXTERN CURLcode curl_ws_recv(struct Curl_easy *data, void *buffer,
*nread = 0;
*metap = NULL;
+ /* get a download buffer */
+ result = Curl_preconnect(data);
+ if(result)
+ return result;
memset(&ctx, 0, sizeof(ctx));
ctx.data = data;
@@ -973,8 +893,8 @@ CURL_EXTERN CURLcode curl_ws_recv(struct Curl_easy *data, void *buffer,
infof(data, "connection expectedly closed?");
return CURLE_GOT_NOTHING;
}
- CURL_TRC_WS(data, "curl_ws_recv, added %zu bytes from network",
- Curl_bufq_len(&ws->recvbuf));
+ DEBUGF(infof(data, "curl_ws_recv, added %zu bytes from network",
+ Curl_bufq_len(&ws->recvbuf)));
}
result = ws_dec_pass(&ws->dec, data, &ws->recvbuf,
@@ -1004,182 +924,111 @@ CURL_EXTERN CURLcode curl_ws_recv(struct Curl_easy *data, void *buffer,
ctx.payload_len, ctx.bufidx);
*metap = &ws->frame;
*nread = ws->frame.len;
- CURL_TRC_WS(data, "curl_ws_recv(len=%zu) -> %zu bytes (frame at %"
- FMT_OFF_T ", %" FMT_OFF_T " left)",
- buflen, *nread, ws->frame.offset, ws->frame.bytesleft);
+ /* infof(data, "curl_ws_recv(len=%zu) -> %zu bytes (frame at %"
+ CURL_FORMAT_CURL_OFF_T ", %" CURL_FORMAT_CURL_OFF_T " left)",
+ buflen, *nread, ws->frame.offset, ws->frame.bytesleft); */
return CURLE_OK;
}
static CURLcode ws_flush(struct Curl_easy *data, struct websocket *ws,
- bool blocking)
+ bool complete)
{
if(!Curl_bufq_is_empty(&ws->sendbuf)) {
CURLcode result;
const unsigned char *out;
- size_t outlen, n;
+ size_t outlen;
+ ssize_t n;
while(Curl_bufq_peek(&ws->sendbuf, &out, &outlen)) {
- if(blocking) {
- result = ws_send_raw_blocking(data, ws, (char *)out, outlen);
- n = result? 0 : outlen;
- }
- else if(data->set.connect_only || Curl_is_in_callback(data))
+ if(data->set.connect_only)
result = Curl_senddata(data, out, outlen, &n);
- else {
- result = Curl_xfer_send(data, out, outlen, FALSE, &n);
- if(!result && !n && outlen)
- result = CURLE_AGAIN;
- }
-
- if(result == CURLE_AGAIN) {
- CURL_TRC_WS(data, "flush EAGAIN, %zu bytes remain in buffer",
- Curl_bufq_len(&ws->sendbuf));
- return result;
- }
- else if(result) {
- failf(data, "WS: flush, write error %d", result);
- return result;
+ else
+ result = Curl_write(data, data->conn->writesockfd, out, outlen, &n);
+ if(result) {
+ if(result == CURLE_AGAIN) {
+ if(!complete) {
+ infof(data, "WS: flush EAGAIN, %zu bytes remain in buffer",
+ Curl_bufq_len(&ws->sendbuf));
+ return result;
+ }
+ /* TODO: the current design does not allow for buffered writes.
+ * We need to flush the buffer now. There is no ws_flush() later */
+ n = 0;
+ continue;
+ }
+ else if(result) {
+ failf(data, "WS: flush, write error %d", result);
+ return result;
+ }
}
else {
- infof(data, "WS: flushed %zu bytes", n);
- Curl_bufq_skip(&ws->sendbuf, n);
+ infof(data, "WS: flushed %zu bytes", (size_t)n);
+ Curl_bufq_skip(&ws->sendbuf, (size_t)n);
}
}
}
return CURLE_OK;
}
-static CURLcode ws_send_raw_blocking(CURL *data, struct websocket *ws,
- const char *buffer, size_t buflen)
-{
- CURLcode result = CURLE_OK;
- size_t nwritten;
-
- (void)ws;
- while(buflen) {
- result = Curl_xfer_send(data, buffer, buflen, FALSE, &nwritten);
- if(result)
- return result;
- DEBUGASSERT(nwritten <= buflen);
- buffer += nwritten;
- buflen -= nwritten;
- if(buflen) {
- curl_socket_t sock = data->conn->sock[FIRSTSOCKET];
- timediff_t left_ms;
- int ev;
-
- CURL_TRC_WS(data, "ws_send_raw_blocking() partial, %zu left to send",
- buflen);
- left_ms = Curl_timeleft(data, NULL, FALSE);
- if(left_ms < 0) {
- failf(data, "Timeout waiting for socket becoming writable");
- return CURLE_SEND_ERROR;
- }
-
- /* POLLOUT socket */
- if(sock == CURL_SOCKET_BAD)
- return CURLE_SEND_ERROR;
- ev = Curl_socket_check(CURL_SOCKET_BAD, CURL_SOCKET_BAD, sock,
- left_ms? left_ms : 500);
- if(ev < 0) {
- failf(data, "Error while waiting for socket becoming writable");
- return CURLE_SEND_ERROR;
- }
- }
- }
- return result;
-}
-
-static CURLcode ws_send_raw(CURL *data, const void *buffer,
- size_t buflen, size_t *pnwritten)
-{
- struct websocket *ws = data->conn->proto.ws;
- CURLcode result;
-
- if(!ws) {
- failf(data, "Not a websocket transfer");
- return CURLE_SEND_ERROR;
- }
- if(!buflen)
- return CURLE_OK;
-
- if(Curl_is_in_callback(data)) {
- /* When invoked from inside callbacks, we do a blocking send as the
- * callback will probably not implement partial writes that may then
- * mess up the ws framing subsequently.
- * We need any pending data to be flushed before sending. */
- result = ws_flush(data, ws, TRUE);
- if(result)
- return result;
- result = ws_send_raw_blocking(data, ws, buffer, buflen);
- }
- else {
- /* We need any pending data to be sent or EAGAIN this call. */
- result = ws_flush(data, ws, FALSE);
- if(result)
- return result;
- result = Curl_senddata(data, buffer, buflen, pnwritten);
- }
-
- CURL_TRC_WS(data, "ws_send_raw(len=%zu) -> %d, %zu",
- buflen, result, *pnwritten);
- return result;
-}
-
CURL_EXTERN CURLcode curl_ws_send(CURL *data, const void *buffer,
size_t buflen, size_t *sent,
curl_off_t fragsize,
unsigned int flags)
{
struct websocket *ws;
- ssize_t n;
- size_t space, payload_added;
+ ssize_t nwritten, n;
+ size_t space;
CURLcode result;
- CURL_TRC_WS(data, "curl_ws_send(len=%zu, fragsize=%" FMT_OFF_T
- ", flags=%x), raw=%d",
- buflen, fragsize, flags, data->set.ws_raw_mode);
*sent = 0;
if(!data->conn && data->set.connect_only) {
result = Curl_connect_only_attach(data);
if(result)
- goto out;
+ return result;
}
if(!data->conn) {
failf(data, "No associated connection");
- result = CURLE_SEND_ERROR;
- goto out;
+ return CURLE_SEND_ERROR;
}
if(!data->conn->proto.ws) {
failf(data, "Not a websocket transfer");
- result = CURLE_SEND_ERROR;
- goto out;
+ return CURLE_SEND_ERROR;
}
ws = data->conn->proto.ws;
- /* try flushing any content still waiting to be sent. */
- result = ws_flush(data, ws, FALSE);
- if(result)
- goto out;
-
if(data->set.ws_raw_mode) {
- /* In raw mode, we write directly to the connection */
- if(fragsize || flags) {
- failf(data, "ws_send, raw mode: fragsize and flags cannot be non-zero");
+ if(fragsize || flags)
return CURLE_BAD_FUNCTION_ARGUMENT;
+ if(!buflen)
+ /* nothing to do */
+ return CURLE_OK;
+ /* raw mode sends exactly what was requested, and this is from within
+ the write callback */
+ if(Curl_is_in_callback(data)) {
+ result = Curl_write(data, data->conn->writesockfd, buffer, buflen,
+ &nwritten);
}
- result = ws_send_raw(data, buffer, buflen, sent);
- goto out;
+ else
+ result = Curl_senddata(data, buffer, buflen, &nwritten);
+
+ infof(data, "WS: wanted to send %zu bytes, sent %zu bytes",
+ buflen, nwritten);
+ *sent = (nwritten >= 0)? (size_t)nwritten : 0;
+ return result;
}
/* Not RAW mode, buf we do the frame encoding */
+ result = ws_flush(data, ws, FALSE);
+ if(result)
+ return result;
+
+ /* TODO: the current design does not allow partial writes, afaict.
+ * It is not clear who the application is supposed to react. */
space = Curl_bufq_space(&ws->sendbuf);
- CURL_TRC_WS(data, "curl_ws_send(len=%zu), sendbuf=%zu space_left=%zu",
- buflen, Curl_bufq_len(&ws->sendbuf), space);
- if(space < 14) {
- result = CURLE_AGAIN;
- goto out;
- }
+ DEBUGF(infof(data, "curl_ws_send(len=%zu), sendbuf len=%zu space %zu",
+ buflen, Curl_bufq_len(&ws->sendbuf), space));
+ if(space < 14)
+ return CURLE_AGAIN;
if(flags & CURLWS_OFFSET) {
if(fragsize) {
@@ -1187,12 +1036,12 @@ CURL_EXTERN CURLcode curl_ws_send(CURL *data, const void *buffer,
n = ws_enc_write_head(data, &ws->enc, flags, fragsize,
&ws->sendbuf, &result);
if(n < 0)
- goto out;
+ return result;
}
else {
if((curl_off_t)buflen > ws->enc.payload_remain) {
infof(data, "WS: unaligned frame size (sending %zu instead of %"
- FMT_OFF_T ")",
+ CURL_FORMAT_CURL_OFF_T ")",
buflen, ws->enc.payload_remain);
}
}
@@ -1201,66 +1050,16 @@ CURL_EXTERN CURLcode curl_ws_send(CURL *data, const void *buffer,
n = ws_enc_write_head(data, &ws->enc, flags, (curl_off_t)buflen,
&ws->sendbuf, &result);
if(n < 0)
- goto out;
+ return result;
}
n = ws_enc_write_payload(&ws->enc, data,
buffer, buflen, &ws->sendbuf, &result);
if(n < 0)
- goto out;
- payload_added = (size_t)n;
-
- while(!result && (buflen || !Curl_bufq_is_empty(&ws->sendbuf))) {
- /* flush, blocking when in callback */
- result = ws_flush(data, ws, Curl_is_in_callback(data));
- if(!result) {
- DEBUGASSERT(payload_added <= buflen);
- /* all buffered data sent. Try sending the rest if there is any. */
- *sent += payload_added;
- buffer = (const char *)buffer + payload_added;
- buflen -= payload_added;
- payload_added = 0;
- if(buflen) {
- n = ws_enc_write_payload(&ws->enc, data,
- buffer, buflen, &ws->sendbuf, &result);
- if(n < 0)
- goto out;
- payload_added = Curl_bufq_len(&ws->sendbuf);
- }
- }
- else if(result == CURLE_AGAIN) {
- /* partially sent. how much of the call data has been part of it? what
- * should we report to out caller so it can retry/send the rest? */
- if(payload_added < buflen) {
- /* We did not add everything the caller wanted. Return just
- * the partial write to our buffer. */
- *sent = payload_added;
- result = CURLE_OK;
- goto out;
- }
- else if(!buflen) {
- /* We have no payload to report a partial write. EAGAIN would make
- * the caller repeat this and add the frame again.
- * Flush blocking seems the only way out of this. */
- *sent = (size_t)n;
- result = ws_flush(data, ws, TRUE);
- goto out;
- }
- /* We added the complete data to our sendbuf. Report one byte less as
- * sent. This parital success should make the caller invoke us again
- * with the last byte. */
- *sent = payload_added - 1;
- result = Curl_bufq_unwrite(&ws->sendbuf, 1);
- if(!result)
- result = CURLE_AGAIN;
- }
- }
+ return result;
-out:
- CURL_TRC_WS(data, "curl_ws_send(len=%zu, fragsize=%" FMT_OFF_T
- ", flags=%x, raw=%d) -> %d, %zu",
- buflen, fragsize, flags, data->set.ws_raw_mode, result, *sent);
- return result;
+ *sent = (size_t)n;
+ return ws_flush(data, ws, TRUE);
}
static void ws_free(struct connectdata *conn)
@@ -1272,18 +1071,14 @@ static void ws_free(struct connectdata *conn)
}
}
-static CURLcode ws_setup_conn(struct Curl_easy *data,
- struct connectdata *conn)
+void Curl_ws_done(struct Curl_easy *data)
{
- /* WebSockets is 1.1 only (for now) */
- data->state.httpwant = CURL_HTTP_VERSION_1_1;
- return Curl_http_setup_conn(data, conn);
+ (void)data;
}
-
-static CURLcode ws_disconnect(struct Curl_easy *data,
- struct connectdata *conn,
- bool dead_connection)
+CURLcode Curl_ws_disconnect(struct Curl_easy *data,
+ struct connectdata *conn,
+ bool dead_connection)
{
(void)data;
(void)dead_connection;
@@ -1301,59 +1096,6 @@ CURL_EXTERN const struct curl_ws_frame *curl_ws_meta(struct Curl_easy *data)
return NULL;
}
-const struct Curl_handler Curl_handler_ws = {
- "WS", /* scheme */
- ws_setup_conn, /* setup_connection */
- Curl_http, /* do_it */
- Curl_http_done, /* done */
- ZERO_NULL, /* do_more */
- Curl_http_connect, /* connect_it */
- ZERO_NULL, /* connecting */
- ZERO_NULL, /* doing */
- ZERO_NULL, /* proto_getsock */
- Curl_http_getsock_do, /* doing_getsock */
- ZERO_NULL, /* domore_getsock */
- ZERO_NULL, /* perform_getsock */
- ws_disconnect, /* disconnect */
- Curl_http_write_resp, /* write_resp */
- Curl_http_write_resp_hd, /* write_resp_hd */
- ZERO_NULL, /* connection_check */
- ZERO_NULL, /* attach connection */
- PORT_HTTP, /* defport */
- CURLPROTO_WS, /* protocol */
- CURLPROTO_HTTP, /* family */
- PROTOPT_CREDSPERREQUEST | /* flags */
- PROTOPT_USERPWDCTRL
-};
-
-#ifdef USE_SSL
-const struct Curl_handler Curl_handler_wss = {
- "WSS", /* scheme */
- ws_setup_conn, /* setup_connection */
- Curl_http, /* do_it */
- Curl_http_done, /* done */
- ZERO_NULL, /* do_more */
- Curl_http_connect, /* connect_it */
- NULL, /* connecting */
- ZERO_NULL, /* doing */
- NULL, /* proto_getsock */
- Curl_http_getsock_do, /* doing_getsock */
- ZERO_NULL, /* domore_getsock */
- ZERO_NULL, /* perform_getsock */
- ws_disconnect, /* disconnect */
- Curl_http_write_resp, /* write_resp */
- Curl_http_write_resp_hd, /* write_resp_hd */
- ZERO_NULL, /* connection_check */
- ZERO_NULL, /* attach connection */
- PORT_HTTPS, /* defport */
- CURLPROTO_WSS, /* protocol */
- CURLPROTO_HTTP, /* family */
- PROTOPT_SSL | PROTOPT_CREDSPERREQUEST | /* flags */
- PROTOPT_USERPWDCTRL
-};
-#endif
-
-
#else
CURL_EXTERN CURLcode curl_ws_recv(CURL *curl, void *buffer, size_t buflen,
diff --git a/contrib/libs/curl/lib/ws.h b/contrib/libs/curl/lib/ws.h
index 398900cc3f..0308a42545 100644
--- a/contrib/libs/curl/lib/ws.h
+++ b/contrib/libs/curl/lib/ws.h
@@ -25,7 +25,7 @@
***************************************************************************/
#include "curl_setup.h"
-#if defined(USE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP)
+#ifdef USE_WEBSOCKETS
#ifdef USE_HYPER
#define REQTYPE void
@@ -57,7 +57,7 @@ struct ws_encoder {
curl_off_t payload_len; /* payload length of current frame */
curl_off_t payload_remain; /* remaining payload of current */
unsigned int xori; /* xor index */
- unsigned char mask[4]; /* 32-bit mask for this connection */
+ unsigned char mask[4]; /* 32 bit mask for this connection */
unsigned char firstbyte; /* first byte of frame we encode */
bool contfragment; /* set TRUE if the previous fragment sent was not final */
};
@@ -75,15 +75,14 @@ struct websocket {
CURLcode Curl_ws_request(struct Curl_easy *data, REQTYPE *req);
CURLcode Curl_ws_accept(struct Curl_easy *data, const char *mem, size_t len);
-
-extern const struct Curl_handler Curl_handler_ws;
-#ifdef USE_SSL
-extern const struct Curl_handler Curl_handler_wss;
-#endif
-
-
+size_t Curl_ws_writecb(char *buffer, size_t size, size_t nitems, void *userp);
+void Curl_ws_done(struct Curl_easy *data);
+CURLcode Curl_ws_disconnect(struct Curl_easy *data,
+ struct connectdata *conn,
+ bool dead_connection);
#else
#define Curl_ws_request(x,y) CURLE_OK
+#define Curl_ws_done(x) Curl_nop_stmt
#define Curl_ws_free(x) Curl_nop_stmt
#endif
diff --git a/contrib/libs/curl/patches/pr12562-nghttp2-segfault-fix.patch b/contrib/libs/curl/patches/pr12562-nghttp2-segfault-fix.patch
new file mode 100644
index 0000000000..e60c53fff2
--- /dev/null
+++ b/contrib/libs/curl/patches/pr12562-nghttp2-segfault-fix.patch
@@ -0,0 +1,120 @@
+From 35380273b9311cf0741e386284310fa7ca4d005e Mon Sep 17 00:00:00 2001
+From: Stefan Eissing <stefan@eissing.org>
+Date: Tue, 19 Dec 2023 12:57:40 +0100
+Subject: [PATCH] http2: improved on_stream_close/data_done handling
+
+- there seems to be a code path that cleans up easy handles without
+ triggering DONE or DETACH events to the connection filters. This
+ would explain wh nghttp2 still holds stream user data
+- add GOOD check to easy handle used in on_close_callback to
+ prevent crashes, ASSERTs in debug builds.
+- NULL the stream user data early before submitting RST
+- add checks in on_stream_close() to identify UNGOOD easy handles
+
+Reported-by: Hans-Christian Egtvedt
+Fixes #10936
+Closes #12562
+---
+ lib/http2.c | 50 ++++++++++++++++++++++++------------
+ tests/http/test_07_upload.py | 17 ++++++++++++
+ tests/http/testenv/curl.py | 2 +-
+ 3 files changed, 51 insertions(+), 18 deletions(-)
+
+diff --git a/lib/http2.c b/lib/http2.c
+index 59903cfa72d250..dcc24ea102302c 100644
+--- a/lib/http2.c
++++ b/lib/http2.c
+@@ -283,13 +283,20 @@ static void http2_data_done(struct Curl_cfilter *cf,
+ return;
+
+ if(ctx->h2) {
++ bool flush_egress = FALSE;
++ /* returns error if stream not known, which is fine here */
++ (void)nghttp2_session_set_stream_user_data(ctx->h2, stream->id, NULL);
++
+ if(!stream->closed && stream->id > 0) {
+ /* RST_STREAM */
+ CURL_TRC_CF(data, cf, "[%d] premature DATA_DONE, RST stream",
+ stream->id);
+- if(!nghttp2_submit_rst_stream(ctx->h2, NGHTTP2_FLAG_NONE,
+- stream->id, NGHTTP2_STREAM_CLOSED))
+- (void)nghttp2_session_send(ctx->h2);
++ stream->closed = TRUE;
++ stream->reset = TRUE;
++ stream->send_closed = TRUE;
++ nghttp2_submit_rst_stream(ctx->h2, NGHTTP2_FLAG_NONE,
++ stream->id, NGHTTP2_STREAM_CLOSED);
++ flush_egress = TRUE;
+ }
+ if(!Curl_bufq_is_empty(&stream->recvbuf)) {
+ /* Anything in the recvbuf is still being counted
+@@ -299,19 +306,11 @@ static void http2_data_done(struct Curl_cfilter *cf,
+ nghttp2_session_consume(ctx->h2, stream->id,
+ Curl_bufq_len(&stream->recvbuf));
+ /* give WINDOW_UPATE a chance to be sent, but ignore any error */
+- (void)h2_progress_egress(cf, data);
++ flush_egress = TRUE;
+ }
+
+- /* -1 means unassigned and 0 means cleared */
+- if(nghttp2_session_get_stream_user_data(ctx->h2, stream->id)) {
+- int rv = nghttp2_session_set_stream_user_data(ctx->h2,
+- stream->id, 0);
+- if(rv) {
+- infof(data, "http/2: failed to clear user_data for stream %u",
+- stream->id);
+- DEBUGASSERT(0);
+- }
+- }
++ if(flush_egress)
++ nghttp2_session_send(ctx->h2);
+ }
+
+ Curl_bufq_free(&stream->sendbuf);
+@@ -1316,26 +1315,43 @@ static int on_stream_close(nghttp2_session *session, int32_t stream_id,
+ uint32_t error_code, void *userp)
+ {
+ struct Curl_cfilter *cf = userp;
+- struct Curl_easy *data_s;
++ struct Curl_easy *data_s, *call_data = CF_DATA_CURRENT(cf);
+ struct stream_ctx *stream;
+ int rv;
+ (void)session;
+
++ DEBUGASSERT(call_data);
+ /* get the stream from the hash based on Stream ID, stream ID zero is for
+ connection-oriented stuff */
+ data_s = stream_id?
+ nghttp2_session_get_stream_user_data(session, stream_id) : NULL;
+ if(!data_s) {
++ CURL_TRC_CF(call_data, cf,
++ "[%d] on_stream_close, no easy set on stream", stream_id);
+ return 0;
+ }
++ if(!GOOD_EASY_HANDLE(data_s)) {
++ /* nghttp2 still has an easy registered for the stream which has
++ * been freed be libcurl. This points to a code path that does not
++ * trigger DONE or DETACH events as it must. */
++ CURL_TRC_CF(call_data, cf,
++ "[%d] on_stream_close, not a GOOD easy on stream", stream_id);
++ (void)nghttp2_session_set_stream_user_data(session, stream_id, 0);
++ return NGHTTP2_ERR_CALLBACK_FAILURE;
++ }
+ stream = H2_STREAM_CTX(data_s);
+- if(!stream)
++ if(!stream) {
++ CURL_TRC_CF(data_s, cf,
++ "[%d] on_stream_close, GOOD easy but no stream", stream_id);
+ return NGHTTP2_ERR_CALLBACK_FAILURE;
++ }
+
+ stream->closed = TRUE;
+ stream->error = error_code;
+- if(stream->error)
++ if(stream->error) {
+ stream->reset = TRUE;
++ stream->send_closed = TRUE;
++ }
+
+ if(stream->error)
+ CURL_TRC_CF(data_s, cf, "[%d] RESET: %s (err %d)",
diff --git a/contrib/libs/curl/patches/pr12633-fix-mpd-streaming.patch b/contrib/libs/curl/patches/pr12633-fix-mpd-streaming.patch
new file mode 100644
index 0000000000..a57512b2a2
--- /dev/null
+++ b/contrib/libs/curl/patches/pr12633-fix-mpd-streaming.patch
@@ -0,0 +1,74 @@
+From 3a24ef09af5fe7fdd672dee72ff760f871105a03 Mon Sep 17 00:00:00 2001
+From: Stefan Eissing <stefan@eissing.org>
+Date: Thu, 4 Jan 2024 10:06:17 +0100
+Subject: [PATCH] adjust_pollset fix
+
+- do not add a socket for POLLIN when the transfer does not
+ want to send (for example is paused).
+- refs #12632
+---
+ lib/cf-socket.c | 2 +-
+ lib/http2.c | 4 ++--
+ lib/vquic/curl_ngtcp2.c | 7 ++++---
+ lib/vquic/curl_quiche.c | 2 +-
+ 4 files changed, 8 insertions(+), 7 deletions(-)
+
+diff --git a/lib/cf-socket.c b/lib/cf-socket.c
+index bd4f0d1e97e2d3..c86aa7e7c2a969 100644
+--- a/lib/cf-socket.c
++++ b/lib/cf-socket.c
+@@ -1243,7 +1243,7 @@ static void cf_socket_adjust_pollset(struct Curl_cfilter *cf,
+ if(ctx->sock != CURL_SOCKET_BAD) {
+ if(!cf->connected)
+ Curl_pollset_set_out_only(data, ps, ctx->sock);
+- else
++ else if(CURL_WANT_RECV(data))
+ Curl_pollset_add_in(data, ps, ctx->sock);
+ CURL_TRC_CF(data, cf, "adjust_pollset -> %d socks", ps->num);
+ }
+diff --git a/lib/http2.c b/lib/http2.c
+index dcc24ea102302c..b7a08607945357 100644
+--- a/lib/http2.c
++++ b/lib/http2.c
+@@ -2341,8 +2341,8 @@ static void cf_h2_adjust_pollset(struct Curl_cfilter *cf,
+ bool c_exhaust, s_exhaust;
+
+ CF_DATA_SAVE(save, cf, data);
+- c_exhaust = !nghttp2_session_get_remote_window_size(ctx->h2);
+- s_exhaust = stream && stream->id >= 0 &&
++ c_exhaust = want_send && !nghttp2_session_get_remote_window_size(ctx->h2);
++ s_exhaust = want_send && stream && stream->id >= 0 &&
+ !nghttp2_session_get_stream_remote_window_size(ctx->h2,
+ stream->id);
+ want_recv = (want_recv || c_exhaust || s_exhaust);
+diff --git a/lib/vquic/curl_ngtcp2.c b/lib/vquic/curl_ngtcp2.c
+index f4edf2d636ef93..89f690462d640b 100644
+--- a/lib/vquic/curl_ngtcp2.c
++++ b/lib/vquic/curl_ngtcp2.c
+@@ -1166,9 +1166,10 @@ static void cf_ngtcp2_adjust_pollset(struct Curl_cfilter *cf,
+ bool c_exhaust, s_exhaust;
+
+ CF_DATA_SAVE(save, cf, data);
+- c_exhaust = !ngtcp2_conn_get_cwnd_left(ctx->qconn) ||
+- !ngtcp2_conn_get_max_data_left(ctx->qconn);
+- s_exhaust = stream && stream->id >= 0 && stream->quic_flow_blocked;
++ c_exhaust = want_send && (!ngtcp2_conn_get_cwnd_left(ctx->qconn) ||
++ !ngtcp2_conn_get_max_data_left(ctx->qconn));
++ s_exhaust = want_send && stream && stream->id >= 0 &&
++ stream->quic_flow_blocked;
+ want_recv = (want_recv || c_exhaust || s_exhaust);
+ want_send = (!s_exhaust && want_send) ||
+ !Curl_bufq_is_empty(&ctx->q.sendbuf);
+diff --git a/lib/vquic/curl_quiche.c b/lib/vquic/curl_quiche.c
+index 33c2621dc8bf63..9c4df2df0f6955 100644
+--- a/lib/vquic/curl_quiche.c
++++ b/lib/vquic/curl_quiche.c
+@@ -1189,7 +1189,7 @@ static void cf_quiche_adjust_pollset(struct Curl_cfilter *cf,
+
+ c_exhaust = FALSE; /* Have not found any call in quiche that tells
+ us if the connection itself is blocked */
+- s_exhaust = stream && stream->id >= 0 &&
++ s_exhaust = want_send && stream && stream->id >= 0 &&
+ (stream->quic_flow_blocked || !stream_is_writeable(cf, data));
+ want_recv = (want_recv || c_exhaust || s_exhaust);
+ want_send = (!s_exhaust && want_send) ||
diff --git a/contrib/libs/curl/src/terminal.c b/contrib/libs/curl/src/terminal.c
deleted file mode 100644
index 7ba991d3e5..0000000000
--- a/contrib/libs/curl/src/terminal.c
+++ /dev/null
@@ -1,91 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at https://curl.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * SPDX-License-Identifier: curl
- *
- ***************************************************************************/
-#include "tool_setup.h"
-
-#ifdef HAVE_SYS_IOCTL_H
-#include <sys/ioctl.h>
-#endif
-
-#include "terminal.h"
-
-#include "memdebug.h" /* keep this as LAST include */
-
-#ifdef HAVE_TERMIOS_H
-# include <termios.h>
-#elif defined(HAVE_TERMIO_H)
-# include <termio.h>
-#endif
-
-/*
- * get_terminal_columns() returns the number of columns in the current
- * terminal. It will return 79 on failure. Also, the number can be very big.
- */
-
-unsigned int get_terminal_columns(void)
-{
- unsigned int width = 0;
- char *colp = curl_getenv("COLUMNS");
- if(colp) {
- char *endptr;
- long num = strtol(colp, &endptr, 10);
- if((endptr != colp) && (endptr == colp + strlen(colp)) && (num > 20) &&
- (num < 10000))
- width = (unsigned int)num;
- curl_free(colp);
- }
-
- if(!width) {
- int cols = 0;
-
-#ifdef TIOCGSIZE
- struct ttysize ts;
- if(!ioctl(STDIN_FILENO, TIOCGSIZE, &ts))
- cols = ts.ts_cols;
-#elif defined(TIOCGWINSZ)
- struct winsize ts;
- if(!ioctl(STDIN_FILENO, TIOCGWINSZ, &ts))
- cols = (int)ts.ws_col;
-#elif defined(_WIN32) && !defined(CURL_WINDOWS_APP)
- {
- HANDLE stderr_hnd = GetStdHandle(STD_ERROR_HANDLE);
- CONSOLE_SCREEN_BUFFER_INFO console_info;
-
- if((stderr_hnd != INVALID_HANDLE_VALUE) &&
- GetConsoleScreenBufferInfo(stderr_hnd, &console_info)) {
- /*
- * Do not use +1 to get the true screen-width since writing a
- * character at the right edge will cause a line wrap.
- */
- cols = (int)
- (console_info.srWindow.Right - console_info.srWindow.Left);
- }
- }
-#endif /* TIOCGSIZE */
- if(cols >= 0 && cols < 10000)
- width = (unsigned int)cols;
- }
- if(!width)
- width = 79;
- return width; /* 79 for unknown, might also be very small or very big */
-}
diff --git a/contrib/libs/curl/src/terminal.h b/contrib/libs/curl/src/terminal.h
deleted file mode 100644
index dbd4abe281..0000000000
--- a/contrib/libs/curl/src/terminal.h
+++ /dev/null
@@ -1,30 +0,0 @@
-#ifndef HEADER_CURL_TERMINAL_H
-#define HEADER_CURL_TERMINAL_H
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at https://curl.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * SPDX-License-Identifier: curl
- *
- ***************************************************************************/
-#include "tool_setup.h"
-
-unsigned int get_terminal_columns(void);
-
-#endif /* HEADER_CURL_TERMINAL_H */
diff --git a/contrib/libs/curl/src/tool_ca_embed.c b/contrib/libs/curl/src/tool_ca_embed.c
deleted file mode 100644
index 9b7b593f80..0000000000
--- a/contrib/libs/curl/src/tool_ca_embed.c
+++ /dev/null
@@ -1 +0,0 @@
-extern const void *curl_ca_embed; const void *curl_ca_embed;
diff --git a/contrib/libs/curl/src/tool_cb_dbg.c b/contrib/libs/curl/src/tool_cb_dbg.c
index 6d2a617835..ce5e25e92c 100644
--- a/contrib/libs/curl/src/tool_cb_dbg.c
+++ b/contrib/libs/curl/src/tool_cb_dbg.c
@@ -23,6 +23,8 @@
***************************************************************************/
#include "tool_setup.h"
+#define ENABLE_CURLX_PRINTF
+/* use our own printf() functions */
#include "curlx.h"
#include "tool_cfgable.h"
@@ -57,7 +59,7 @@ static const char *hms_for_sec(time_t tv_sec)
}
secs = epoch_offset + tv_sec;
/* !checksrc! disable BANNEDFUNC 1 */
- now = localtime(&secs); /* not thread safe but we do not care */
+ now = localtime(&secs); /* not thread safe but we don't care */
msnprintf(hms_buf, sizeof(hms_buf), "%02d:%02d:%02d",
now->tm_hour, now->tm_min, now->tm_sec);
cached_tv_sec = tv_sec;
@@ -97,7 +99,7 @@ int tool_debug_cb(CURL *handle, curl_infotype type,
const char *text;
struct timeval tv;
char timebuf[20];
- /* largest signed 64-bit is: 9,223,372,036,854,775,807
+ /* largest signed 64bit is: 9,223,372,036,854,775,807
* max length in decimal: 1 + (6*3) = 19
* formatted via TRC_IDS_FORMAT_IDS_2 this becomes 2 + 19 + 1 + 19 + 2 = 43
* negative xfer-id are not printed, negative conn-ids use TRC_IDS_FORMAT_1
@@ -189,8 +191,8 @@ int tool_debug_cb(CURL *handle, curl_infotype type,
case CURLINFO_SSL_DATA_IN:
case CURLINFO_SSL_DATA_OUT:
if(!traced_data) {
- /* if the data is output to a tty and we are sending this debug trace
- to stderr or stdout, we do not display the alert about the data not
+ /* if the data is output to a tty and we're sending this debug trace
+ to stderr or stdout, we don't display the alert about the data not
being shown as the data _is_ shown then just not via this
function */
if(!config->isatty ||
@@ -215,7 +217,7 @@ int tool_debug_cb(CURL *handle, curl_infotype type,
switch(type) {
case CURLINFO_TEXT:
fprintf(output, "%s%s== Info: %.*s", timebuf, idsbuf, (int)size, data);
- FALLTHROUGH();
+ /* FALLTHROUGH */
default: /* in case a new one is introduced to shock us */
return 0;
@@ -284,7 +286,7 @@ static void dump(const char *timebuf, const char *idsbuf, const char *text,
(void)infotype;
fprintf(stream, "%c", ((ptr[i + c] >= 0x20) && (ptr[i + c] < 0x7F)) ?
ptr[i + c] : UNPRINTABLE_CHAR);
- /* check again for 0D0A, to avoid an extra \n if it is at width */
+ /* check again for 0D0A, to avoid an extra \n if it's at width */
if((tracetype == TRACE_ASCII) &&
(i + c + 2 < size) && (ptr[i + c + 1] == 0x0D) &&
(ptr[i + c + 2] == 0x0A)) {
diff --git a/contrib/libs/curl/src/tool_cb_hdr.c b/contrib/libs/curl/src/tool_cb_hdr.c
index 969acac1e4..198a8d050c 100644
--- a/contrib/libs/curl/src/tool_cb_hdr.c
+++ b/contrib/libs/curl/src/tool_cb_hdr.c
@@ -24,10 +24,9 @@
#include "tool_setup.h"
#include "strcase.h"
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
+#define ENABLE_CURLX_PRINTF
+/* use our own printf() functions */
#include "curlx.h"
#include "tool_cfgable.h"
@@ -48,7 +47,7 @@ static char *parse_filename(const char *ptr, size_t len);
#else
#define BOLD "\x1b[1m"
/* Switch off bold by setting "all attributes off" since the explicit
- bold-off code (21) is not supported everywhere - like in the mac
+ bold-off code (21) isn't supported everywhere - like in the mac
Terminal. */
#define BOLDOFF "\x1b[0m"
/* OSC 8 hyperlink escape sequence */
@@ -103,29 +102,15 @@ size_t tool_header_cb(char *ptr, size_t size, size_t nmemb, void *userdata)
if(rc != cb)
return rc;
/* flush the stream to send off what we got earlier */
- if(fflush(heads->stream)) {
- errorf(per->config->global, "Failed writing headers to %s",
- per->config->headerfile);
- return CURL_WRITEFUNC_ERROR;
- }
+ (void)fflush(heads->stream);
}
- curl_easy_getinfo(per->curl, CURLINFO_SCHEME, &scheme);
- scheme = proto_token(scheme);
- if((scheme == proto_http || scheme == proto_https)) {
- long response = 0;
- curl_easy_getinfo(per->curl, CURLINFO_RESPONSE_CODE, &response);
-
- if((response/100 != 2) && (response/100 != 3))
- /* only care about etag and content-disposition headers in 2xx and 3xx
- responses */
- ;
- /*
- * Write etag to file when --etag-save option is given.
- */
- else if(per->config->etag_save_file && etag_save->stream &&
- /* match only header that start with etag (case insensitive) */
- checkprefix("etag:", str)) {
+ /*
+ * Write etag to file when --etag-save option is given.
+ */
+ if(per->config->etag_save_file && etag_save->stream) {
+ /* match only header that start with etag (case insensitive) */
+ if(curl_strnequal(str, "etag:", 5)) {
const char *etag_h = &str[5];
const char *eot = end - 1;
if(*eot == '\n') {
@@ -136,19 +121,6 @@ size_t tool_header_cb(char *ptr, size_t size, size_t nmemb, void *userdata)
if(eot >= etag_h) {
size_t etag_length = eot - etag_h + 1;
- /*
- * Truncate the etag save stream, it can have an existing etag value.
- */
-#ifdef HAVE_FTRUNCATE
- if(ftruncate(fileno(etag_save->stream), 0)) {
- return CURL_WRITEFUNC_ERROR;
- }
-#else
- if(fseek(etag_save->stream, 0, SEEK_SET)) {
- return CURL_WRITEFUNC_ERROR;
- }
-#endif
-
fwrite(etag_h, size, etag_length, etag_save->stream);
/* terminate with newline */
fputc('\n', etag_save->stream);
@@ -156,72 +128,69 @@ size_t tool_header_cb(char *ptr, size_t size, size_t nmemb, void *userdata)
}
}
}
+ }
- /*
- * This callback sets the filename where output shall be written when
- * curl options --remote-name (-O) and --remote-header-name (-J) have
- * been simultaneously given and additionally server returns an HTTP
- * Content-Disposition header specifying a filename property.
- */
-
- else if(hdrcbdata->honor_cd_filename &&
- (cb > 20) && checkprefix("Content-disposition:", str)) {
- const char *p = str + 20;
+ /*
+ * This callback sets the filename where output shall be written when
+ * curl options --remote-name (-O) and --remote-header-name (-J) have
+ * been simultaneously given and additionally server returns an HTTP
+ * Content-Disposition header specifying a filename property.
+ */
- /* look for the 'filename=' parameter
- (encoded filenames (*=) are not supported) */
- for(;;) {
- char *filename;
- size_t len;
+ curl_easy_getinfo(per->curl, CURLINFO_SCHEME, &scheme);
+ scheme = proto_token(scheme);
+ if(hdrcbdata->honor_cd_filename &&
+ (cb > 20) && checkprefix("Content-disposition:", str) &&
+ (scheme == proto_http || scheme == proto_https)) {
+ const char *p = str + 20;
+
+ /* look for the 'filename=' parameter
+ (encoded filenames (*=) are not supported) */
+ for(;;) {
+ char *filename;
+ size_t len;
+
+ while((p < end) && *p && !ISALPHA(*p))
+ p++;
+ if(p > end - 9)
+ break;
- while((p < end) && *p && !ISALPHA(*p))
+ if(memcmp(p, "filename=", 9)) {
+ /* no match, find next parameter */
+ while((p < end) && *p && (*p != ';'))
p++;
- if(p > end - 9)
+ if((p < end) && *p)
+ continue;
+ else
break;
-
- if(memcmp(p, "filename=", 9)) {
- /* no match, find next parameter */
- while((p < end) && *p && (*p != ';'))
- p++;
- if((p < end) && *p)
- continue;
- else
- break;
- }
- p += 9;
-
- len = cb - (size_t)(p - str);
- filename = parse_filename(p, len);
- if(filename) {
- if(outs->stream) {
- /* indication of problem, get out! */
- free(filename);
- return CURL_WRITEFUNC_ERROR;
- }
-
- if(per->config->output_dir) {
- outs->filename = aprintf("%s/%s", per->config->output_dir,
- filename);
- free(filename);
- if(!outs->filename)
- return CURL_WRITEFUNC_ERROR;
- }
- else
- outs->filename = filename;
-
- outs->is_cd_filename = TRUE;
- outs->s_isreg = TRUE;
- outs->fopened = FALSE;
- outs->alloc_filename = TRUE;
- hdrcbdata->honor_cd_filename = FALSE; /* done now! */
- if(!tool_create_output_file(outs, per->config))
- return CURL_WRITEFUNC_ERROR;
+ }
+ p += 9;
+
+ /* this expression below typecasts 'cb' only to avoid
+ warning: signed and unsigned type in conditional expression
+ */
+ len = (ssize_t)cb - (p - str);
+ filename = parse_filename(p, len);
+ if(filename) {
+ if(outs->stream) {
+ /* indication of problem, get out! */
+ free(filename);
+ return CURL_WRITEFUNC_ERROR;
}
- break;
+
+ outs->is_cd_filename = TRUE;
+ outs->s_isreg = TRUE;
+ outs->fopened = FALSE;
+ outs->filename = filename;
+ outs->alloc_filename = TRUE;
+ hdrcbdata->honor_cd_filename = FALSE; /* done now! */
+ if(!tool_create_output_file(outs, per->config))
+ return CURL_WRITEFUNC_ERROR;
}
- if(!outs->stream && !tool_create_output_file(outs, per->config))
- return CURL_WRITEFUNC_ERROR;
+ break;
}
+ if(!outs->stream && !tool_create_output_file(outs, per->config))
+ return CURL_WRITEFUNC_ERROR;
}
if(hdrcbdata->config->writeout) {
char *value = memchr(ptr, ':', cb);
@@ -271,7 +240,7 @@ size_t tool_header_cb(char *ptr, size_t size, size_t nmemb, void *userdata)
}
/*
- * Copies a filename part and returns an ALLOCATED data buffer.
+ * Copies a file name part and returns an ALLOCATED data buffer.
*/
static char *parse_filename(const char *ptr, size_t len)
{
@@ -312,7 +281,7 @@ static char *parse_filename(const char *ptr, size_t len)
}
/* If the filename contains a backslash, only use filename portion. The idea
- is that even systems that do not handle backslashes as path separators
+ is that even systems that don't handle backslashes as path separators
probably want the path removed for convenience. */
q = strrchr(p, '\\');
if(q) {
@@ -323,7 +292,7 @@ static char *parse_filename(const char *ptr, size_t len)
}
}
- /* make sure the filename does not end in \r or \n */
+ /* make sure the file name doesn't end in \r or \n */
q = strchr(p, '\r');
if(q)
*q = '\0';
@@ -347,17 +316,17 @@ static char *parse_filename(const char *ptr, size_t len)
#endif /* _WIN32 || MSDOS */
/* in case we built debug enabled, we allow an environment variable
- * named CURL_TESTDIR to prefix the given filename to put it into a
+ * named CURL_TESTDIR to prefix the given file name to put it into a
* specific directory
*/
#ifdef DEBUGBUILD
{
- char *tdir = curl_getenv("CURL_TESTDIR");
+ char *tdir = curlx_getenv("CURL_TESTDIR");
if(tdir) {
char buffer[512]; /* suitably large */
msnprintf(buffer, sizeof(buffer), "%s/%s", tdir, copy);
Curl_safefree(copy);
- copy = strdup(buffer); /* clone the buffer, we do not use the libcurl
+ copy = strdup(buffer); /* clone the buffer, we don't use the libcurl
aprintf() or similar since we want to use the
same memory code as the "real" parse_filename
function */
@@ -374,9 +343,9 @@ static char *parse_filename(const char *ptr, size_t len)
* Treat the Location: header specially, by writing a special escape
* sequence that adds a hyperlink to the displayed text. This makes
* the absolute URL of the redirect clickable in supported terminals,
- * which could not happen otherwise for relative URLs. The Location:
+ * which couldn't happen otherwise for relative URLs. The Location:
* header is supposed to always be absolute so this theoretically
- * should not be needed but the real world returns plenty of relative
+ * shouldn't be needed but the real world returns plenty of relative
* URLs here.
*/
static
@@ -448,7 +417,7 @@ void write_linked_location(CURL *curl, const char *location, size_t loclen,
goto locdone;
}
- /* Not a "safe" URL: do not linkify it */
+ /* Not a "safe" URL: don't linkify it */
locout:
/* Write the normal output in case of error or unsafe */
diff --git a/contrib/libs/curl/src/tool_cb_prg.c b/contrib/libs/curl/src/tool_cb_prg.c
index 5acd3fcc78..ef47b42da0 100644
--- a/contrib/libs/curl/src/tool_cb_prg.c
+++ b/contrib/libs/curl/src/tool_cb_prg.c
@@ -23,18 +23,28 @@
***************************************************************************/
#include "tool_setup.h"
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+
+#define ENABLE_CURLX_PRINTF
+/* use our own printf() functions */
#include "curlx.h"
#include "tool_cfgable.h"
#include "tool_cb_prg.h"
#include "tool_util.h"
#include "tool_operate.h"
-#include "terminal.h"
#include "memdebug.h" /* keep this as LAST include */
-#define MAX_BARLENGTH 400
-#define MIN_BARLENGTH 20
+#define MAX_BARLENGTH 256
+
+#ifdef HAVE_TERMIOS_H
+# include <termios.h>
+#elif defined(HAVE_TERMIO_H)
+# include <termio.h>
+#endif
/* 200 values generated by this perl code:
@@ -43,7 +53,7 @@
printf "%d, ", sin($i/200 * 2 * $pi) * 500000 + 500000;
}
*/
-static const int sinus[] = {
+static const unsigned int sinus[] = {
515704, 531394, 547052, 562664, 578214, 593687, 609068, 624341, 639491,
654504, 669364, 684057, 698568, 712883, 726989, 740870, 754513, 767906,
781034, 793885, 806445, 818704, 830647, 842265, 853545, 864476, 875047,
@@ -76,19 +86,19 @@ static void fly(struct ProgressData *bar, bool moved)
/* bar->width is range checked when assigned */
DEBUGASSERT(bar->width <= MAX_BARLENGTH);
- buf[0] = '\r';
- memset(&buf[1], ' ', bar->width);
+ memset(buf, ' ', bar->width);
+ buf[bar->width] = '\r';
buf[bar->width + 1] = '\0';
- memcpy(&buf[bar->bar + 1], "-=O=-", 5);
+ memcpy(&buf[bar->bar], "-=O=-", 5);
- pos = sinus[bar->tick%200] / (1000000 / check) + 1;
+ pos = sinus[bar->tick%200] / (1000000 / check);
buf[pos] = '#';
- pos = sinus[(bar->tick + 5)%200] / (1000000 / check) + 1;
+ pos = sinus[(bar->tick + 5)%200] / (1000000 / check);
buf[pos] = '#';
- pos = sinus[(bar->tick + 10)%200] / (1000000 / check) + 1;
+ pos = sinus[(bar->tick + 10)%200] / (1000000 / check);
buf[pos] = '#';
- pos = sinus[(bar->tick + 15)%200] / (1000000 / check) + 1;
+ pos = sinus[(bar->tick + 15)%200] / (1000000 / check);
buf[pos] = '#';
fputs(buf, bar->out);
@@ -118,17 +128,6 @@ static void fly(struct ProgressData *bar, bool moved)
# define CURL_OFF_T_MAX CURL_OFF_T_C(0x7FFFFFFFFFFFFFFF)
#endif
-static void update_width(struct ProgressData *bar)
-{
- int cols = get_terminal_columns();
- if(cols > MAX_BARLENGTH)
- bar->width = MAX_BARLENGTH;
- else if(cols > MIN_BARLENGTH)
- bar->width = (int)cols;
- else
- bar->width = MIN_BARLENGTH;
-}
-
int tool_progress_cb(void *clientp,
curl_off_t dltotal, curl_off_t dlnow,
curl_off_t ultotal, curl_off_t ulnow)
@@ -171,10 +170,10 @@ int tool_progress_cb(void *clientp,
if(total) {
/* we know the total data to get... */
if(bar->prev == point)
- /* progress did not change since last invoke */
+ /* progress didn't change since last invoke */
return 0;
else if((tvdiff(now, bar->prevtime) < 100L) && point < total)
- /* limit progress-bar updating to 10 Hz except when we are at 100% */
+ /* limit progress-bar updating to 10 Hz except when we're at 100% */
return 0;
}
else {
@@ -182,7 +181,6 @@ int tool_progress_cb(void *clientp,
if(tvdiff(now, bar->prevtime) < 100L)
/* limit progress-bar updating to 10 Hz */
return 0;
- update_width(bar);
fly(bar, point != bar->prev);
}
}
@@ -190,14 +188,13 @@ int tool_progress_cb(void *clientp,
/* simply count invokes */
bar->calls++;
- update_width(bar);
if((total > 0) && (point != bar->prev)) {
char line[MAX_BARLENGTH + 1];
char format[40];
double frac;
double percent;
int barwidth;
- size_t num;
+ int num;
if(point > total)
/* we have got more than the expected total! */
total = point;
@@ -205,20 +202,13 @@ int tool_progress_cb(void *clientp,
frac = (double)point / (double)total;
percent = frac * 100.0;
barwidth = bar->width - 7;
- num = (size_t) (((double)barwidth) * frac);
+ num = (int) (((double)barwidth) * frac);
if(num > MAX_BARLENGTH)
num = MAX_BARLENGTH;
memset(line, '#', num);
line[num] = '\0';
msnprintf(format, sizeof(format), "\r%%-%ds %%5.1f%%%%", barwidth);
-#ifdef __clang__
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wformat-nonliteral"
-#endif
fprintf(bar->out, format, line, percent);
-#ifdef __clang__
-#pragma clang diagnostic pop
-#endif
}
fflush(bar->out);
bar->prev = point;
@@ -235,14 +225,59 @@ int tool_progress_cb(void *clientp,
void progressbarinit(struct ProgressData *bar,
struct OperationConfig *config)
{
+ char *colp;
memset(bar, 0, sizeof(struct ProgressData));
/* pass the resume from value through to the progress function so it can
- * display progress towards total file not just the part that is left. */
+ * display progress towards total file not just the part that's left. */
if(config->use_resume)
bar->initial_size = config->resume_from;
- update_width(bar);
+ colp = curlx_getenv("COLUMNS");
+ if(colp) {
+ char *endptr;
+ long num = strtol(colp, &endptr, 10);
+ if((endptr != colp) && (endptr == colp + strlen(colp)) && (num > 20) &&
+ (num < 10000))
+ bar->width = (int)num;
+ curl_free(colp);
+ }
+
+ if(!bar->width) {
+ int cols = 0;
+
+#ifdef TIOCGSIZE
+ struct ttysize ts;
+ if(!ioctl(STDIN_FILENO, TIOCGSIZE, &ts))
+ cols = ts.ts_cols;
+#elif defined(TIOCGWINSZ)
+ struct winsize ts;
+ if(!ioctl(STDIN_FILENO, TIOCGWINSZ, &ts))
+ cols = ts.ws_col;
+#elif defined(_WIN32)
+ {
+ HANDLE stderr_hnd = GetStdHandle(STD_ERROR_HANDLE);
+ CONSOLE_SCREEN_BUFFER_INFO console_info;
+
+ if((stderr_hnd != INVALID_HANDLE_VALUE) &&
+ GetConsoleScreenBufferInfo(stderr_hnd, &console_info)) {
+ /*
+ * Do not use +1 to get the true screen-width since writing a
+ * character at the right edge will cause a line wrap.
+ */
+ cols = (int)
+ (console_info.srWindow.Right - console_info.srWindow.Left);
+ }
+ }
+#endif /* TIOCGSIZE */
+ if(cols > 20)
+ bar->width = cols;
+ }
+
+ if(!bar->width)
+ bar->width = 79;
+ else if(bar->width > MAX_BARLENGTH)
+ bar->width = MAX_BARLENGTH;
bar->out = tool_stderr;
bar->tick = 150;
diff --git a/contrib/libs/curl/src/tool_cb_prg.h b/contrib/libs/curl/src/tool_cb_prg.h
index dc10f2a5cc..565ad565a9 100644
--- a/contrib/libs/curl/src/tool_cb_prg.h
+++ b/contrib/libs/curl/src/tool_cb_prg.h
@@ -40,8 +40,6 @@ struct ProgressData {
int barmove;
};
-struct OperationConfig;
-
void progressbarinit(struct ProgressData *bar,
struct OperationConfig *config);
diff --git a/contrib/libs/curl/src/tool_cb_rea.c b/contrib/libs/curl/src/tool_cb_rea.c
index 0fe4014300..8cb5bbe8ac 100644
--- a/contrib/libs/curl/src/tool_cb_rea.c
+++ b/contrib/libs/curl/src/tool_cb_rea.c
@@ -27,6 +27,8 @@
#include <sys/select.h>
#endif
+#define ENABLE_CURLX_PRINTF
+/* use our own printf() functions */
#include "curlx.h"
#include "tool_cfgable.h"
@@ -34,7 +36,6 @@
#include "tool_operate.h"
#include "tool_util.h"
#include "tool_msgs.h"
-#include "tool_sleep.h"
#include "memdebug.h" /* keep this as LAST include */
@@ -88,7 +89,7 @@ size_t tool_read_cb(char *buffer, size_t sz, size_t nmemb, void *userdata)
config->readbusy = TRUE;
return CURL_READFUNC_PAUSE;
}
- /* since size_t is unsigned we cannot return negative values fine */
+ /* since size_t is unsigned we can't return negative values fine */
rc = 0;
}
if((per->uploadfilesize != -1) &&
@@ -123,33 +124,8 @@ int tool_readbusy_cb(void *clientp,
(void)ulnow; /* unused */
if(config->readbusy) {
- /* lame code to keep the rate down because the input might not deliver
- anything, get paused again and come back here immediately */
- static long rate = 500;
- static struct timeval prev;
- static curl_off_t ulprev;
-
- if(ulprev == ulnow) {
- /* it did not upload anything since last call */
- struct timeval now = tvnow();
- if(prev.tv_sec)
- /* get a rolling average rate */
- /* rate = rate - rate/4 + tvdiff(now, prev)/4; */
- rate -= rate/4 - tvdiff(now, prev)/4;
- prev = now;
- }
- else {
- rate = 50;
- ulprev = ulnow;
- }
- if(rate >= 50) {
- /* keeps the looping down to 20 times per second in the crazy case */
- config->readbusy = FALSE;
- curl_easy_pause(per->curl, CURLPAUSE_CONT);
- }
- else
- /* sleep half a period */
- tool_go_sleep(25);
+ config->readbusy = FALSE;
+ curl_easy_pause(per->curl, CURLPAUSE_CONT);
}
return per->noprogress? 0 : CURL_PROGRESSFUNC_CONTINUE;
diff --git a/contrib/libs/curl/src/tool_cb_see.c b/contrib/libs/curl/src/tool_cb_see.c
index a425ebe9de..bce57bb281 100644
--- a/contrib/libs/curl/src/tool_cb_see.c
+++ b/contrib/libs/curl/src/tool_cb_see.c
@@ -23,6 +23,8 @@
***************************************************************************/
#include "tool_setup.h"
+#define ENABLE_CURLX_PRINTF
+/* use our own printf() functions */
#include "curlx.h"
#include "tool_cfgable.h"
@@ -52,27 +54,27 @@ int tool_seek_cb(void *userdata, curl_off_t offset, int whence)
#if(SIZEOF_CURL_OFF_T > SIZEOF_OFF_T) && !defined(USE_WIN32_LARGE_FILES)
/* The offset check following here is only interesting if curl_off_t is
- larger than off_t and we are not using the Win32 large file support
- macros that provide the support to do 64-bit seeks correctly */
+ larger than off_t and we are not using the WIN32 large file support
+ macros that provide the support to do 64bit seeks correctly */
if(offset > OUR_MAX_SEEK_O) {
/* Some precaution code to work around problems with different data sizes
- to allow seeking >32-bit even if off_t is 32-bit. Should be very rare
- and is really valid on weirdo-systems. */
+ to allow seeking >32bit even if off_t is 32bit. Should be very rare and
+ is really valid on weirdo-systems. */
curl_off_t left = offset;
if(whence != SEEK_SET)
- /* this code path does not support other types */
+ /* this code path doesn't support other types */
return CURL_SEEKFUNC_FAIL;
if(LSEEK_ERROR == lseek(per->infd, 0, SEEK_SET))
- /* could not rewind to beginning */
+ /* couldn't rewind to beginning */
return CURL_SEEKFUNC_FAIL;
while(left) {
long step = (left > OUR_MAX_SEEK_O) ? OUR_MAX_SEEK_L : (long)left;
if(LSEEK_ERROR == lseek(per->infd, step, SEEK_CUR))
- /* could not seek forwards the desired amount */
+ /* couldn't seek forwards the desired amount */
return CURL_SEEKFUNC_FAIL;
left -= step;
}
@@ -81,10 +83,39 @@ int tool_seek_cb(void *userdata, curl_off_t offset, int whence)
#endif
if(LSEEK_ERROR == lseek(per->infd, offset, whence))
- /* could not rewind, the reason is in errno but errno is just not portable
- enough and we do not actually care that much why we failed. We will let
+ /* couldn't rewind, the reason is in errno but errno is just not portable
+ enough and we don't actually care that much why we failed. We'll let
libcurl know that it may try other means if it wants to. */
return CURL_SEEKFUNC_CANTSEEK;
return CURL_SEEKFUNC_OK;
}
+
+#ifdef USE_TOOL_FTRUNCATE
+
+#ifdef _WIN32_WCE
+/* 64-bit lseek-like function unavailable */
+# undef _lseeki64
+# define _lseeki64(hnd,ofs,whence) lseek(hnd,ofs,whence)
+# undef _get_osfhandle
+# define _get_osfhandle(fd) (fd)
+#endif
+
+/*
+ * Truncate a file handle at a 64-bit position 'where'.
+ */
+
+int tool_ftruncate64(int fd, curl_off_t where)
+{
+ intptr_t handle = _get_osfhandle(fd);
+
+ if(_lseeki64(fd, where, SEEK_SET) < 0)
+ return -1;
+
+ if(!SetEndOfFile((HANDLE)handle))
+ return -1;
+
+ return 0;
+}
+
+#endif /* USE_TOOL_FTRUNCATE */
diff --git a/contrib/libs/curl/src/tool_cb_see.h b/contrib/libs/curl/src/tool_cb_see.h
index e7b30a765d..b5d7bf985e 100644
--- a/contrib/libs/curl/src/tool_cb_see.h
+++ b/contrib/libs/curl/src/tool_cb_see.h
@@ -25,6 +25,18 @@
***************************************************************************/
#include "tool_setup.h"
+#if defined(_WIN32) && !defined(HAVE_FTRUNCATE)
+
+int tool_ftruncate64(int fd, curl_off_t where);
+
+#undef ftruncate
+#define ftruncate(fd,where) tool_ftruncate64(fd,where)
+
+#define HAVE_FTRUNCATE 1
+#define USE_TOOL_FTRUNCATE 1
+
+#endif /* _WIN32 && ! HAVE_FTRUNCATE */
+
/*
** callback for CURLOPT_SEEKFUNCTION
*/
diff --git a/contrib/libs/curl/src/tool_cb_soc.c b/contrib/libs/curl/src/tool_cb_soc.c
deleted file mode 100644
index 22048ee6bb..0000000000
--- a/contrib/libs/curl/src/tool_cb_soc.c
+++ /dev/null
@@ -1,58 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at https://curl.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * SPDX-License-Identifier: curl
- *
- ***************************************************************************/
-#include "tool_setup.h"
-
-#ifdef HAVE_NETINET_IN_H
-#include <netinet/in.h> /* IPPROTO_TCP */
-#endif
-
-#include "tool_cb_soc.h"
-
-/*
-** callback for CURLOPT_OPENSOCKETFUNCTION
-**
-** Notice that only Linux is supported for the moment.
-*/
-
-curl_socket_t tool_socket_open_mptcp_cb(void *clientp,
- curlsocktype purpose,
- struct curl_sockaddr *addr)
-{
- int protocol = addr->protocol;
-
- (void)clientp;
- (void)purpose;
-
- if(protocol == IPPROTO_TCP)
-#if defined(__linux__)
-# ifndef IPPROTO_MPTCP
-# define IPPROTO_MPTCP 262
-# endif
- protocol = IPPROTO_MPTCP;
-#else
- return CURL_SOCKET_BAD;
-#endif
-
- return socket(addr->family, addr->socktype, protocol);
-}
diff --git a/contrib/libs/curl/src/tool_cb_soc.h b/contrib/libs/curl/src/tool_cb_soc.h
deleted file mode 100644
index f02150aa82..0000000000
--- a/contrib/libs/curl/src/tool_cb_soc.h
+++ /dev/null
@@ -1,36 +0,0 @@
-#ifndef HEADER_CURL_TOOL_CB_SOC_H
-#define HEADER_CURL_TOOL_CB_SOC_H
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at https://curl.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * SPDX-License-Identifier: curl
- *
- ***************************************************************************/
-#include "tool_setup.h"
-
-/*
-** callback for CURLOPT_OPENSOCKETFUNCTION
-*/
-
-curl_socket_t tool_socket_open_mptcp_cb(void *clientp,
- curlsocktype purpose,
- struct curl_sockaddr *addr);
-
-#endif /* HEADER_CURL_TOOL_CB_SOC_H */
diff --git a/contrib/libs/curl/src/tool_cb_wrt.c b/contrib/libs/curl/src/tool_cb_wrt.c
index e35489a39f..98063c39c2 100644
--- a/contrib/libs/curl/src/tool_cb_wrt.c
+++ b/contrib/libs/curl/src/tool_cb_wrt.c
@@ -30,6 +30,8 @@
#include <sys/stat.h>
+#define ENABLE_CURLX_PRINTF
+/* use our own printf() functions */
#include "curlx.h"
#include "tool_cfgable.h"
@@ -54,11 +56,24 @@ bool tool_create_output_file(struct OutStruct *outs,
{
struct GlobalConfig *global;
FILE *file = NULL;
- const char *fname = outs->filename;
+ char *fname = outs->filename;
+ char *aname = NULL;
DEBUGASSERT(outs);
DEBUGASSERT(config);
global = config->global;
- DEBUGASSERT(fname && *fname);
+ if(!fname || !*fname) {
+ warnf(global, "Remote filename has no length");
+ return FALSE;
+ }
+
+ if(config->output_dir && outs->is_cd_filename) {
+ aname = aprintf("%s/%s", config->output_dir, fname);
+ if(!aname) {
+ errorf(global, "out of memory");
+ return FALSE;
+ }
+ fname = aname;
+ }
if(config->file_clobber_mode == CLOBBER_ALWAYS ||
(config->file_clobber_mode == CLOBBER_DEFAULT &&
@@ -70,7 +85,7 @@ bool tool_create_output_file(struct OutStruct *outs,
int fd;
do {
fd = open(fname, O_CREAT | O_WRONLY | O_EXCL | O_BINARY, OPENMODE);
- /* Keep retrying in the hope that it is not interrupted sometime */
+ /* Keep retrying in the hope that it isn't interrupted sometime */
} while(fd == -1 && errno == EINTR);
if(config->file_clobber_mode == CLOBBER_NEVER && fd == -1) {
int next_num = 1;
@@ -79,25 +94,27 @@ bool tool_create_output_file(struct OutStruct *outs,
char *newname;
/* Guard against wraparound in new filename */
if(newlen < len) {
+ free(aname);
errorf(global, "overflow in filename generation");
return FALSE;
}
newname = malloc(newlen);
if(!newname) {
errorf(global, "out of memory");
+ free(aname);
return FALSE;
}
memcpy(newname, fname, len);
newname[len] = '.';
- while(fd == -1 && /* have not successfully opened a file */
+ while(fd == -1 && /* haven't successfully opened a file */
(errno == EEXIST || errno == EISDIR) &&
/* because we keep having files that already exist */
- next_num < 100 /* and we have not reached the retry limit */ ) {
- msnprintf(newname + len + 1, 12, "%d", next_num);
+ next_num < 100 /* and we haven't reached the retry limit */ ) {
+ curlx_msnprintf(newname + len + 1, 12, "%d", next_num);
next_num++;
do {
fd = open(newname, O_CREAT | O_WRONLY | O_EXCL | O_BINARY, OPENMODE);
- /* Keep retrying in the hope that it is not interrupted sometime */
+ /* Keep retrying in the hope that it isn't interrupted sometime */
} while(fd == -1 && errno == EINTR);
}
outs->filename = newname; /* remember the new one */
@@ -118,8 +135,10 @@ bool tool_create_output_file(struct OutStruct *outs,
if(!file) {
warnf(global, "Failed to open the file %s: %s", fname,
strerror(errno));
+ free(aname);
return FALSE;
}
+ free(aname);
outs->s_isreg = TRUE;
outs->fopened = TRUE;
outs->stream = file;
@@ -147,7 +166,7 @@ size_t tool_write_cb(char *buffer, size_t sz, size_t nmemb, void *userdata)
#ifdef DEBUGBUILD
{
- char *tty = curl_getenv("CURL_ISATTY");
+ char *tty = curlx_getenv("CURL_ISATTY");
if(tty) {
is_tty = TRUE;
curl_free(tty);
@@ -214,7 +233,7 @@ size_t tool_write_cb(char *buffer, size_t sz, size_t nmemb, void *userdata)
#ifdef _WIN32
fhnd = _get_osfhandle(fileno(outs->stream));
- /* if Windows console then UTF-8 must be converted to UTF-16 */
+ /* if windows console then UTF-8 must be converted to UTF-16 */
if(isatty(fileno(outs->stream)) &&
GetConsoleScreenBufferInfo((HANDLE)fhnd, &console_info)) {
wchar_t *wc_buf;
@@ -313,8 +332,7 @@ size_t tool_write_cb(char *buffer, size_t sz, size_t nmemb, void *userdata)
if(rlen) {
/* calculate buffer size for wide characters */
- wc_len = (DWORD)MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)rbuf, (int)rlen,
- NULL, 0);
+ wc_len = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)rbuf, rlen, NULL, 0);
if(!wc_len)
return CURL_WRITEFUNC_ERROR;
@@ -322,8 +340,8 @@ size_t tool_write_cb(char *buffer, size_t sz, size_t nmemb, void *userdata)
if(!wc_buf)
return CURL_WRITEFUNC_ERROR;
- wc_len = (DWORD)MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)rbuf, (int)rlen,
- wc_buf, (int)wc_len);
+ wc_len = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)rbuf, rlen, wc_buf,
+ wc_len);
if(!wc_len) {
free(wc_buf);
return CURL_WRITEFUNC_ERROR;
diff --git a/contrib/libs/curl/src/tool_cfgable.c b/contrib/libs/curl/src/tool_cfgable.c
index 5564e250d3..906e23e141 100644
--- a/contrib/libs/curl/src/tool_cfgable.c
+++ b/contrib/libs/curl/src/tool_cfgable.c
@@ -25,7 +25,6 @@
#include "tool_cfgable.h"
#include "tool_formparse.h"
-#include "tool_paramhlp.h"
#include "tool_main.h"
#include "memdebug.h" /* keep this as LAST include */
@@ -34,6 +33,7 @@ void config_init(struct OperationConfig *config)
{
memset(config, 0, sizeof(struct OperationConfig));
+ config->postfieldsize = -1;
config->use_httpget = FALSE;
config->create_dirs = FALSE;
config->maxredirs = DEFAULT_MAXREDIRS;
@@ -45,7 +45,6 @@ void config_init(struct OperationConfig *config)
config->http09_allowed = FALSE;
config->ftp_skip_ip = TRUE;
config->file_clobber_mode = CLOBBER_DEFAULT;
- curlx_dyn_init(&config->postdata, MAX_FILE2MEMORY);
}
static void free_config_fields(struct OperationConfig *config)
@@ -60,7 +59,7 @@ static void free_config_fields(struct OperationConfig *config)
Curl_safefree(config->cookiejar);
curl_slist_free_all(config->cookiefiles);
- Curl_dyn_free(&config->postdata);
+ Curl_safefree(config->postfields);
Curl_safefree(config->query);
Curl_safefree(config->referer);
@@ -114,8 +113,6 @@ static void free_config_fields(struct OperationConfig *config)
Curl_safefree(config->doh_url);
Curl_safefree(config->cipher_list);
Curl_safefree(config->proxy_cipher_list);
- Curl_safefree(config->cipher13_list);
- Curl_safefree(config->proxy_cipher13_list);
Curl_safefree(config->cert);
Curl_safefree(config->proxy_cert);
Curl_safefree(config->cert_type);
@@ -178,14 +175,6 @@ static void free_config_fields(struct OperationConfig *config)
Curl_safefree(config->aws_sigv4);
Curl_safefree(config->proto_str);
Curl_safefree(config->proto_redir_str);
-#ifdef USE_ECH
- Curl_safefree(config->ech);
- config->ech = NULL;
- Curl_safefree(config->ech_config);
- config->ech_config = NULL;
- Curl_safefree(config->ech_public);
- config->ech_public = NULL;
-#endif
}
void config_free(struct OperationConfig *config)
diff --git a/contrib/libs/curl/src/tool_cfgable.h b/contrib/libs/curl/src/tool_cfgable.h
index 729cd5241a..57e8fce527 100644
--- a/contrib/libs/curl/src/tool_cfgable.h
+++ b/contrib/libs/curl/src/tool_cfgable.h
@@ -50,8 +50,8 @@ struct OperationConfig {
struct curl_slist *cookies; /* cookies to serialize into a single line */
char *cookiejar; /* write to this file */
struct curl_slist *cookiefiles; /* file(s) to load cookies from */
- char *altsvc; /* alt-svc cache filename */
- char *hsts; /* HSTS cache filename */
+ char *altsvc; /* alt-svc cache file name */
+ char *hsts; /* HSTS cache file name */
bool cookiesession; /* new session? */
bool encoding; /* Accept-Encoding please */
bool tr_encoding; /* Transfer-Encoding please */
@@ -68,7 +68,7 @@ struct OperationConfig {
char *proto_default;
curl_off_t resume_from;
char *postfields;
- struct curlx_dynbuf postdata;
+ curl_off_t postfieldsize;
char *referer;
char *query;
long timeout_ms;
@@ -85,8 +85,6 @@ struct OperationConfig {
char *range;
long low_speed_limit;
long low_speed_time;
- long ip_tos; /* IP Type of Service */
- long vlan_priority; /* VLAN priority */
char *dns_servers; /* dot notation: 1.1.1.1;2.2.2.2 */
char *dns_interface; /* interface name */
char *dns_ipv4_addr; /* dot notation */
@@ -111,12 +109,12 @@ struct OperationConfig {
bool sasl_ir; /* Enable/disable SASL initial response */
bool proxytunnel;
bool ftp_append; /* APPE on ftp */
- bool use_ascii; /* select ASCII or text transfer */
+ bool use_ascii; /* select ascii or text transfer */
bool autoreferer; /* automatically set referer */
bool failonerror; /* fail on (HTTP) errors */
bool failwithbody; /* fail on (HTTP) errors but still store body */
bool show_headers; /* show headers to data output */
- bool no_body; /* do not get the body */
+ bool no_body; /* don't get the body */
bool dirlistonly; /* only get the FTP dir list */
bool followlocation; /* follow http redirects */
bool unrestricted_auth; /* Continue to send authentication (user+password)
@@ -249,8 +247,7 @@ struct OperationConfig {
bool post302;
bool post303;
bool nokeepalive; /* for keepalive needs */
- long alivetime; /* keepalive-time */
- long alivecnt; /* keepalive-cnt */
+ long alivetime;
bool content_disposition; /* use Content-disposition filename */
int default_node_flags; /* default flags to search for each 'node', which
@@ -295,28 +292,19 @@ struct OperationConfig {
CLOBBER_NEVER, /* If the file exists, always fail */
CLOBBER_ALWAYS /* If the file exists, always overwrite it */
} file_clobber_mode;
- bool mptcp; /* enable MPTCP support */
struct GlobalConfig *global;
struct OperationConfig *prev;
struct OperationConfig *next; /* Always last in the struct */
struct State state; /* for create_transfer() */
bool rm_partial; /* on error, remove partially written output
files */
- bool skip_existing;
-#ifdef USE_ECH
- char *ech; /* Config set by --ech keywords */
- char *ech_config; /* Config set by "--ech esl:" option */
- char *ech_public; /* Config set by "--ech pn:" option */
-#endif
-
};
struct GlobalConfig {
bool showerror; /* show errors when silent */
- bool silent; /* do not show messages, --silent given */
- bool noprogress; /* do not show progress bar */
+ bool silent; /* don't show messages, --silent given */
+ bool noprogress; /* don't show progress bar */
bool isatty; /* Updated internally if output is a tty */
- unsigned char verbosity; /* How verbose we should be */
char *trace_dump; /* file to dump the network trace to */
FILE *trace_stream;
bool trace_fopened;
@@ -324,12 +312,12 @@ struct GlobalConfig {
bool tracetime; /* include timestamp? */
bool traceids; /* include xfer-/conn-id? */
int progressmode; /* CURL_PROGRESS_BAR / CURL_PROGRESS_STATS */
- char *libcurl; /* Output libcurl code to this filename */
+ char *libcurl; /* Output libcurl code to this file name */
bool fail_early; /* exit on first transfer error */
bool styled_output; /* enable fancy output style detection */
long ms_per_transfer; /* start next transfer after (at least) this
many milliseconds */
-#ifdef DEBUGBUILD
+#ifdef CURLDEBUG
bool test_event_based;
#endif
bool parallel;
diff --git a/contrib/libs/curl/src/tool_dirhie.c b/contrib/libs/curl/src/tool_dirhie.c
index 772664c5fb..1cadbd0beb 100644
--- a/contrib/libs/curl/src/tool_dirhie.c
+++ b/contrib/libs/curl/src/tool_dirhie.c
@@ -29,6 +29,8 @@
# include <direct.h>
#endif
+#define ENABLE_CURLX_PRINTF
+/* use our own printf() functions */
#include "curlx.h"
#include "tool_dirhie.h"
@@ -48,7 +50,7 @@ static void show_dir_errno(struct GlobalConfig *global, const char *name)
switch(errno) {
#ifdef EACCES
case EACCES:
- errorf(global, "You do not have permission to create %s", name);
+ errorf(global, "You don't have permission to create %s", name);
break;
#endif
#ifdef ENAMETOOLONG
@@ -115,7 +117,7 @@ CURLcode create_dir_hierarchy(const char *outfile, struct GlobalConfig *global)
}
dirbuildup[0] = '\0';
- /* Allow strtok() here since this is not used threaded */
+ /* Allow strtok() here since this isn't used threaded */
/* !checksrc! disable BANNEDFUNC 2 */
tempdir = strtok(outdup, PATH_DELIMITERS);
@@ -135,13 +137,13 @@ CURLcode create_dir_hierarchy(const char *outfile, struct GlobalConfig *global)
It may seem as though that would harmlessly fail but it could be
a corner case if X: did not exist, since we would be creating it
erroneously.
- eg if outfile is X:\foo\bar\filename then do not mkdir X:
+ eg if outfile is X:\foo\bar\filename then don't mkdir X:
This logic takes into account unsupported drives !:, 1:, etc. */
char *p = strchr(tempdir, ':');
if(p && !p[1])
skip = true;
#endif
- /* the output string does not start with a separator */
+ /* the output string doesn't start with a separator */
strcpy(dirbuildup, tempdir);
}
else
diff --git a/contrib/libs/curl/src/tool_doswin.c b/contrib/libs/curl/src/tool_doswin.c
index 321e44f9c0..db2b8b78ac 100644
--- a/contrib/libs/curl/src/tool_doswin.c
+++ b/contrib/libs/curl/src/tool_doswin.c
@@ -56,9 +56,9 @@
#endif
#ifdef _WIN32
-# define _use_lfn(f) (1) /* long filenames always available */
+# define _use_lfn(f) (1) /* long file names always available */
#elif !defined(__DJGPP__) || (__DJGPP__ < 2) /* DJGPP 2.0 has _use_lfn() */
-# define _use_lfn(f) (0) /* long filenames never available */
+# define _use_lfn(f) (0) /* long file names never available */
#elif defined(__DJGPP__)
# include <fcntl.h> /* _use_lfn(f) prototype */
#endif
@@ -98,8 +98,8 @@ SANITIZE_ALLOW_PATH: Allow path separators and colons.
Without this flag path separators and colons are sanitized.
SANITIZE_ALLOW_RESERVED: Allow reserved device names.
-Without this flag a reserved device name is renamed (COM1 => _COM1) unless it
-is in a UNC prefixed path.
+Without this flag a reserved device name is renamed (COM1 => _COM1) unless it's
+in a UNC prefixed path.
SANITIZE_ALLOW_TRUNCATE: Allow truncating a long filename.
Without this flag if the sanitized filename or path will be too long an error
@@ -136,9 +136,9 @@ SANITIZEcode sanitize_file_name(char **const sanitized, const char *file_name,
max_sanitized_len = PATH_MAX-1;
}
else
- /* The maximum length of a filename. FILENAME_MAX is often the same as
- PATH_MAX, in other words it is 260 and does not discount the path
- information therefore we should not use it. */
+ /* The maximum length of a filename.
+ FILENAME_MAX is often the same as PATH_MAX, in other words it is 260 and
+ does not discount the path information therefore we shouldn't use it. */
max_sanitized_len = (PATH_MAX-1 > 255) ? 255 : PATH_MAX-1;
len = strlen(file_name);
@@ -237,7 +237,7 @@ SANITIZEcode sanitize_file_name(char **const sanitized, const char *file_name,
/*
Test if truncating a path to a file will leave at least a single character in
-the filename. Filenames suffixed by an alternate data stream cannot be
+the filename. Filenames suffixed by an alternate data stream can't be
truncated. This performs a dry run, nothing is modified.
Good truncate_pos 9: C:\foo\bar => C:\foo\ba
@@ -253,7 +253,7 @@ Error truncate_pos 7: C:\foo => (pos out of range)
Bad truncate_pos 1: C:\foo\ => C
* C:foo is ambiguous, C could end up being a drive or file therefore something
- like C:superlongfilename cannot be truncated.
+ like C:superlongfilename can't be truncated.
Returns
SANITIZE_ERR_OK: Good -- 'path' can be truncated
@@ -278,7 +278,7 @@ SANITIZEcode truncate_dryrun(const char *path, const size_t truncate_pos)
if(strpbrk(&path[truncate_pos - 1], "\\/:"))
return SANITIZE_ERR_INVALID_PATH;
- /* C:\foo can be truncated but C:\foo:ads cannot */
+ /* C:\foo can be truncated but C:\foo:ads can't */
if(truncate_pos > 1) {
const char *p = &path[truncate_pos - 1];
do {
@@ -297,11 +297,11 @@ SANITIZEcode truncate_dryrun(const char *path, const size_t truncate_pos)
*/
/*
-Extra sanitization MS-DOS for file_name.
+Extra sanitization MSDOS for file_name.
This is a supporting function for sanitize_file_name.
-Warning: This is an MS-DOS legacy function and was purposely written in a way
+Warning: This is an MSDOS legacy function and was purposely written in a way
that some path information may pass through. For example drive letter names
(C:, D:, etc) are allowed to pass through. For sanitizing a filename use
sanitize_file_name.
@@ -357,8 +357,8 @@ SANITIZEcode msdosify(char **const sanitized, const char *file_name,
*d = ':';
else if((flags & SANITIZE_ALLOW_PATH) && (*s == '/' || *s == '\\'))
*d = *s;
- /* Dots are special: DOS does not allow them as the leading character,
- and a filename cannot have more than a single dot. We leave the
+ /* Dots are special: DOS doesn't allow them as the leading character,
+ and a file name cannot have more than a single dot. We leave the
first non-leading dot alone, unless it comes too close to the
beginning of the name: we want sh.lex.c to become sh_lex.c, not
sh.lex-c. */
@@ -445,11 +445,11 @@ SANITIZEcode msdosify(char **const sanitized, const char *file_name,
#endif /* MSDOS || UNITTESTS */
/*
-Rename file_name if it is a reserved dos device name.
+Rename file_name if it's a reserved dos device name.
This is a supporting function for sanitize_file_name.
-Warning: This is an MS-DOS legacy function and was purposely written in a way
+Warning: This is an MSDOS legacy function and was purposely written in a way
that some path information may pass through. For example drive letter names
(C:, D:, etc) are allowed to pass through. For sanitizing a filename use
sanitize_file_name.
@@ -461,8 +461,8 @@ SANITIZEcode rename_if_reserved_dos_device_name(char **const sanitized,
const char *file_name,
int flags)
{
- /* We could have a file whose name is a device on MS-DOS. Trying to
- * retrieve such a file would fail at best and wedge us at worst. We need
+ /* We could have a file whose name is a device on MS-DOS. Trying to
+ * retrieve such a file would fail at best and wedge us at worst. We need
* to rename such files. */
char *p, *base;
char fname[PATH_MAX];
@@ -558,12 +558,11 @@ SANITIZEcode rename_if_reserved_dos_device_name(char **const sanitized,
}
/* This is the legacy portion from rename_if_dos_device_name that checks for
- reserved device names. It only works on MS-DOS. On Windows XP the stat
+ reserved device names. It only works on MSDOS. On Windows XP the stat
check errors with EINVAL if the device name is reserved. On Windows
- Vista/7/8 it sets mode S_IFREG (regular file or device). According to
- MSDN stat doc the latter behavior is correct, but that does not help us
- identify whether it is a reserved device name and not a regular
- filename. */
+ Vista/7/8 it sets mode S_IFREG (regular file or device). According to MSDN
+ stat doc the latter behavior is correct, but that doesn't help us identify
+ whether it's a reserved device name and not a regular file name. */
#ifdef MSDOS
if(base && ((stat(base, &st_buf)) == 0) && (S_ISCHR(st_buf.st_mode))) {
/* Prepend a '_' */
@@ -603,12 +602,12 @@ char **__crt0_glob_function(char *arg)
/*
* Function to find CACert bundle on a Win32 platform using SearchPath.
* (SearchPath is already declared via inclusions done in setup header file)
- * (Use the ASCII version instead of the Unicode one!)
+ * (Use the ASCII version instead of the unicode one!)
* The order of the directories it searches is:
* 1. application's directory
* 2. current working directory
- * 3. Windows System directory (e.g. C:\Windows\System32)
- * 4. Windows Directory (e.g. C:\Windows)
+ * 3. Windows System directory (e.g. C:\windows\system32)
+ * 4. Windows Directory (e.g. C:\windows)
* 5. all directories along %PATH%
*
* For WinXP and later search order actually depends on registry value:
@@ -621,11 +620,6 @@ CURLcode FindWin32CACert(struct OperationConfig *config,
{
CURLcode result = CURLE_OK;
-#ifdef CURL_WINDOWS_APP
- (void)config;
- (void)backend;
- (void)bundle_file;
-#else
/* Search and set cert file only if libcurl supports SSL.
*
* If Schannel is the selected SSL backend then these locations are
@@ -651,7 +645,6 @@ CURLcode FindWin32CACert(struct OperationConfig *config,
result = CURLE_OUT_OF_MEMORY;
}
}
-#endif
return result;
}
@@ -684,7 +677,7 @@ struct curl_slist *GetLoadedModulePaths(void)
#ifdef UNICODE
/* sizeof(mod.szExePath) is the max total bytes of wchars. the max total
- bytes of multibyte chars will not be more than twice that. */
+ bytes of multibyte chars won't be more than twice that. */
char buffer[sizeof(mod.szExePath) * 2];
if(!WideCharToMultiByte(CP_ACP, 0, mod.szExePath, -1,
buffer, sizeof(buffer), NULL, NULL))
@@ -710,9 +703,6 @@ cleanup:
return slist;
}
-bool tool_term_has_bold;
-
-#ifndef CURL_WINDOWS_APP
/* The terminal settings to restore on exit */
static struct TerminalSettings {
HANDLE hStdOut;
@@ -724,6 +714,8 @@ static struct TerminalSettings {
#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
#endif
+bool tool_term_has_bold;
+
static void restore_terminal(void)
{
if(InterlockedExchange(&TerminalSettings.valid, (LONG)FALSE))
@@ -778,7 +770,6 @@ static void init_terminal(void)
}
}
}
-#endif
LARGE_INTEGER tool_freq;
bool tool_isVistaOrGreater;
@@ -795,9 +786,7 @@ CURLcode win32_init(void)
QueryPerformanceFrequency(&tool_freq);
-#ifndef CURL_WINDOWS_APP
init_terminal();
-#endif
return CURLE_OK;
}
diff --git a/contrib/libs/curl/src/tool_easysrc.c b/contrib/libs/curl/src/tool_easysrc.c
index a623f19613..6ef2be721c 100644
--- a/contrib/libs/curl/src/tool_easysrc.c
+++ b/contrib/libs/curl/src/tool_easysrc.c
@@ -27,6 +27,8 @@
#ifndef CURL_DISABLE_LIBCURL_OPTION
+#define ENABLE_CURLX_PRINTF
+/* use our own printf() functions */
#include "curlx.h"
#include "tool_cfgable.h"
@@ -111,7 +113,7 @@ CURLcode easysrc_addf(struct slist_wc **plist, const char *fmt, ...)
char *bufp;
va_list ap;
va_start(ap, fmt);
- bufp = vaprintf(fmt, ap);
+ bufp = curlx_mvaprintf(fmt, ap);
va_end(ap);
if(!bufp) {
ret = CURLE_OUT_OF_MEMORY;
diff --git a/contrib/libs/curl/src/tool_easysrc.h b/contrib/libs/curl/src/tool_easysrc.h
index f698c8f5cc..8c8d131501 100644
--- a/contrib/libs/curl/src/tool_easysrc.h
+++ b/contrib/libs/curl/src/tool_easysrc.h
@@ -40,7 +40,7 @@ extern int easysrc_slist_count; /* Number of curl_slist variables */
extern CURLcode easysrc_init(void);
extern CURLcode easysrc_add(struct slist_wc **plist, const char *bupf);
extern CURLcode easysrc_addf(struct slist_wc **plist,
- const char *fmt, ...) CURL_PRINTF(2, 3);
+ const char *fmt, ...);
extern CURLcode easysrc_perform(void);
extern CURLcode easysrc_cleanup(void);
diff --git a/contrib/libs/curl/src/tool_filetime.c b/contrib/libs/curl/src/tool_filetime.c
index a80019f152..13113886e6 100644
--- a/contrib/libs/curl/src/tool_filetime.c
+++ b/contrib/libs/curl/src/tool_filetime.c
@@ -38,10 +38,10 @@ int getfiletime(const char *filename, struct GlobalConfig *global,
{
int rc = 1;
-/* Windows stat() may attempt to adjust the Unix GMT file time by a daylight
- saving time offset and since it is GMT that is bad behavior. When we have
+/* Windows stat() may attempt to adjust the unix GMT file time by a daylight
+ saving time offset and since it's GMT that is bad behavior. When we have
access to a 64-bit type we can bypass stat and get the times directly. */
-#if defined(_WIN32) && !defined(CURL_WINDOWS_APP)
+#if defined(_WIN32)
HANDLE hfile;
TCHAR *tchar_filename = curlx_convert_UTF8_to_tchar((char *)filename);
@@ -92,14 +92,14 @@ void setfiletime(curl_off_t filetime, const char *filename,
struct GlobalConfig *global)
{
if(filetime >= 0) {
-/* Windows utime() may attempt to adjust the Unix GMT file time by a daylight
- saving time offset and since it is GMT that is bad behavior. When we have
+/* Windows utime() may attempt to adjust the unix GMT file time by a daylight
+ saving time offset and since it's GMT that is bad behavior. When we have
access to a 64-bit type we can bypass utime and set the times directly. */
-#if defined(_WIN32) && !defined(CURL_WINDOWS_APP)
+#if defined(_WIN32)
HANDLE hfile;
TCHAR *tchar_filename = curlx_convert_UTF8_to_tchar((char *)filename);
- /* 910670515199 is the maximum Unix filetime that can be used as a
+ /* 910670515199 is the maximum unix filetime that can be used as a
Windows FILETIME without overflow: 30827-12-31T23:59:59. */
if(filetime > CURL_OFF_T_C(910670515199)) {
warnf(global, "Failed to set filetime %" CURL_FORMAT_CURL_OFF_T
diff --git a/contrib/libs/curl/src/tool_findfile.c b/contrib/libs/curl/src/tool_findfile.c
index 672fc7b992..a1544a5633 100644
--- a/contrib/libs/curl/src/tool_findfile.c
+++ b/contrib/libs/curl/src/tool_findfile.c
@@ -35,7 +35,7 @@
#include <fcntl.h>
#endif
-#include <curlx.h>
+#include <curl/mprintf.h>
#include "tool_findfile.h"
@@ -51,7 +51,7 @@ struct finder {
in the findfile() function */
static const struct finder conf_list[] = {
{ "CURL_HOME", NULL, FALSE },
- { "XDG_CONFIG_HOME", NULL, TRUE },
+ { "XDG_CONFIG_HOME", NULL, FALSE }, /* index == 1, used in the code */
{ "HOME", NULL, FALSE },
#ifdef _WIN32
{ "USERPROFILE", NULL, FALSE },
@@ -72,9 +72,9 @@ static char *checkhome(const char *home, const char *fname, bool dotscore)
for(i = 0; i < (dotscore ? 2 : 1); i++) {
char *c;
if(dotscore)
- c = aprintf("%s" DIR_CHAR "%c%s", home, pref[i], &fname[1]);
+ c = curl_maprintf("%s" DIR_CHAR "%c%s", home, pref[i], &fname[1]);
else
- c = aprintf("%s" DIR_CHAR "%s", home, fname);
+ c = curl_maprintf("%s" DIR_CHAR "%s", home, fname);
if(c) {
int fd = open(c, O_RDONLY);
if(fd >= 0) {
@@ -97,11 +97,12 @@ static char *checkhome(const char *home, const char *fname, bool dotscore)
*
* 1. Iterate over the environment variables in order, and if set, check for
* the given file to be accessed there, then it is a match.
- * 2. Non-Windows: try getpwuid
+ * 2. Non-windows: try getpwuid
*/
char *findfile(const char *fname, int dotscore)
{
int i;
+ bool xdg = FALSE;
DEBUGASSERT(fname && fname[0]);
DEBUGASSERT((dotscore != 1) || (fname[0] == '.'));
@@ -113,19 +114,21 @@ char *findfile(const char *fname, int dotscore)
if(home) {
char *path;
const char *filename = fname;
+ if(i == 1 /* XDG_CONFIG_HOME */)
+ xdg = TRUE;
if(!home[0]) {
curl_free(home);
continue;
}
if(conf_list[i].append) {
- char *c = aprintf("%s%s", home, conf_list[i].append);
+ char *c = curl_maprintf("%s%s", home, conf_list[i].append);
curl_free(home);
if(!c)
return NULL;
home = c;
}
if(conf_list[i].withoutdot) {
- if(!dotscore) {
+ if(!dotscore || xdg) {
/* this is not looking for .curlrc, or the XDG_CONFIG_HOME was
defined so we skip the extended check */
curl_free(home);
diff --git a/contrib/libs/curl/src/tool_formparse.c b/contrib/libs/curl/src/tool_formparse.c
index 15918d3ee5..fa38698d5e 100644
--- a/contrib/libs/curl/src/tool_formparse.c
+++ b/contrib/libs/curl/src/tool_formparse.c
@@ -25,6 +25,8 @@
#include "strcase.h"
+#define ENABLE_CURLX_PRINTF
+/* use our own printf() functions */
#include "curlx.h"
#include "tool_cfgable.h"
@@ -276,7 +278,7 @@ static CURLcode tool2curlparts(CURL *curl, struct tool_mime *m,
case TOOLMIME_STDIN:
if(!filename)
filename = "-";
- FALLTHROUGH();
+ /* FALLTHROUGH */
case TOOLMIME_STDINDATA:
ret = curl_mime_data_cb(part, m->size,
(curl_read_callback) tool_mime_stdin_read,
@@ -635,7 +637,7 @@ static int get_param_part(struct OperationConfig *config, char endchar,
*pfilename = filename;
else if(filename)
warnf(config->global,
- "Field filename not allowed here: %s", filename);
+ "Field file name not allowed here: %s", filename);
if(pencoder)
*pencoder = encoder;
@@ -691,7 +693,7 @@ static int get_param_part(struct OperationConfig *config, char endchar,
* 'name=foo;headers=@headerfile' or why not
* 'name=@filemame;headers=@headerfile'
*
- * To upload a file, but to fake the filename that will be included in the
+ * To upload a file, but to fake the file name that will be included in the
* formpost, do like this:
*
* 'name=@filename;filename=/dev/null' or quote the faked filename like:
@@ -718,7 +720,7 @@ int formparse(struct OperationConfig *config,
struct tool_mime **mimecurrent,
bool literal_value)
{
- /* input MUST be a string in the format 'name=contents' and we will
+ /* input MUST be a string in the format 'name=contents' and we'll
build a linked list with the info */
char *name = NULL;
char *contents = NULL;
@@ -777,7 +779,7 @@ int formparse(struct OperationConfig *config,
}
else if('@' == contp[0] && !literal_value) {
- /* we use the @-letter to indicate filename(s) */
+ /* we use the @-letter to indicate file name(s) */
struct tool_mime *subparts = NULL;
@@ -829,7 +831,7 @@ int formparse(struct OperationConfig *config,
SET_TOOL_MIME_PTR(part, encoder);
/* *contp could be '\0', so we just check with the delimiter */
- } while(sep); /* loop if there is another filename */
+ } while(sep); /* loop if there's another file name */
part = (*mimecurrent)->subparts; /* Set name on group. */
}
else {
diff --git a/contrib/libs/curl/src/tool_getparam.c b/contrib/libs/curl/src/tool_getparam.c
index be41aa35d5..5fa1ace10d 100644
--- a/contrib/libs/curl/src/tool_getparam.c
+++ b/contrib/libs/curl/src/tool_getparam.c
@@ -25,6 +25,8 @@
#include "strcase.h"
+#define ENABLE_CURLX_PRINTF
+/* use our own printf() functions */
#include "curlx.h"
#include "tool_binmode.h"
@@ -49,308 +51,320 @@
# define USE_WATT32
#endif
-#define ALLOW_BLANK TRUE
-#define DENY_BLANK FALSE
-
-static ParameterError getstr(char **str, const char *val, bool allowblank)
-{
- if(*str) {
- free(*str);
- *str = NULL;
- }
- if(val) {
- if(!allowblank && !val[0])
- return PARAM_BLANK_STRING;
-
- *str = strdup(val);
- if(!*str)
- return PARAM_NO_MEM;
- }
- return PARAM_OK;
-}
+#define GetStr(str,val) do { \
+ if(*(str)) { \
+ free(*(str)); \
+ *(str) = NULL; \
+ } \
+ if((val)) { \
+ *(str) = strdup((val)); \
+ if(!(*(str))) { \
+ err = PARAM_NO_MEM; \
+ goto error; \
+ } \
+ } \
+ } while(0)
+
+struct LongShort {
+ const char *letter; /* short name option */
+ const char *lname; /* long name option */
+ enum {
+ ARG_NONE, /* stand-alone but not a boolean */
+ ARG_BOOL, /* accepts a --no-[name] prefix */
+ ARG_STRING, /* requires an argument */
+ ARG_FILENAME /* requires an argument, usually a file name */
+ } desc;
+};
-/* this array MUST be alphasorted based on the 'lname' */
static const struct LongShort aliases[]= {
- {"abstract-unix-socket", ARG_FILE, ' ', C_ABSTRACT_UNIX_SOCKET},
- {"alpn", ARG_BOOL|ARG_NO, ' ', C_ALPN},
- {"alt-svc", ARG_STRG, ' ', C_ALT_SVC},
- {"anyauth", ARG_BOOL, ' ', C_ANYAUTH},
- {"append", ARG_BOOL, 'a', C_APPEND},
- {"aws-sigv4", ARG_STRG, ' ', C_AWS_SIGV4},
- {"basic", ARG_BOOL, ' ', C_BASIC},
- {"buffer", ARG_BOOL|ARG_NO, 'N', C_BUFFER},
- {"ca-native", ARG_BOOL, ' ', C_CA_NATIVE},
- {"cacert", ARG_FILE, ' ', C_CACERT},
- {"capath", ARG_FILE, ' ', C_CAPATH},
- {"cert", ARG_FILE, 'E', C_CERT},
- {"cert-status", ARG_BOOL, ' ', C_CERT_STATUS},
- {"cert-type", ARG_STRG, ' ', C_CERT_TYPE},
- {"ciphers", ARG_STRG, ' ', C_CIPHERS},
- {"clobber", ARG_BOOL|ARG_NO, ' ', C_CLOBBER},
- {"compressed", ARG_BOOL, ' ', C_COMPRESSED},
- {"compressed-ssh", ARG_BOOL, ' ', C_COMPRESSED_SSH},
- {"config", ARG_FILE, 'K', C_CONFIG},
- {"connect-timeout", ARG_STRG, ' ', C_CONNECT_TIMEOUT},
- {"connect-to", ARG_STRG, ' ', C_CONNECT_TO},
- {"continue-at", ARG_STRG, 'C', C_CONTINUE_AT},
- {"cookie", ARG_STRG, 'b', C_COOKIE},
- {"cookie-jar", ARG_STRG, 'c', C_COOKIE_JAR},
- {"create-dirs", ARG_BOOL, ' ', C_CREATE_DIRS},
- {"create-file-mode", ARG_STRG, ' ', C_CREATE_FILE_MODE},
- {"crlf", ARG_BOOL, ' ', C_CRLF},
- {"crlfile", ARG_FILE, ' ', C_CRLFILE},
- {"curves", ARG_STRG, ' ', C_CURVES},
- {"data", ARG_STRG, 'd', C_DATA},
- {"data-ascii", ARG_STRG, ' ', C_DATA_ASCII},
- {"data-binary", ARG_STRG, ' ', C_DATA_BINARY},
- {"data-raw", ARG_STRG, ' ', C_DATA_RAW},
- {"data-urlencode", ARG_STRG, ' ', C_DATA_URLENCODE},
- {"delegation", ARG_STRG, ' ', C_DELEGATION},
- {"digest", ARG_BOOL, ' ', C_DIGEST},
- {"disable", ARG_BOOL, 'q', C_DISABLE},
- {"disable-eprt", ARG_BOOL, ' ', C_DISABLE_EPRT},
- {"disable-epsv", ARG_BOOL, ' ', C_DISABLE_EPSV},
- {"disallow-username-in-url", ARG_BOOL, ' ', C_DISALLOW_USERNAME_IN_URL},
- {"dns-interface", ARG_STRG, ' ', C_DNS_INTERFACE},
- {"dns-ipv4-addr", ARG_STRG, ' ', C_DNS_IPV4_ADDR},
- {"dns-ipv6-addr", ARG_STRG, ' ', C_DNS_IPV6_ADDR},
- {"dns-servers", ARG_STRG, ' ', C_DNS_SERVERS},
- {"doh-cert-status", ARG_BOOL, ' ', C_DOH_CERT_STATUS},
- {"doh-insecure", ARG_BOOL, ' ', C_DOH_INSECURE},
- {"doh-url" , ARG_STRG, ' ', C_DOH_URL},
- {"dump-ca-embed", ARG_NONE, ' ', C_DUMP_CA_EMBED},
- {"dump-header", ARG_FILE, 'D', C_DUMP_HEADER},
- {"ech", ARG_STRG, ' ', C_ECH},
- {"egd-file", ARG_STRG, ' ', C_EGD_FILE},
- {"engine", ARG_STRG, ' ', C_ENGINE},
- {"eprt", ARG_BOOL, ' ', C_EPRT},
- {"epsv", ARG_BOOL, ' ', C_EPSV},
- {"etag-compare", ARG_FILE, ' ', C_ETAG_COMPARE},
- {"etag-save", ARG_FILE, ' ', C_ETAG_SAVE},
- {"expect100-timeout", ARG_STRG, ' ', C_EXPECT100_TIMEOUT},
- {"fail", ARG_BOOL, 'f', C_FAIL},
- {"fail-early", ARG_BOOL, ' ', C_FAIL_EARLY},
- {"fail-with-body", ARG_BOOL, ' ', C_FAIL_WITH_BODY},
- {"false-start", ARG_BOOL, ' ', C_FALSE_START},
- {"form", ARG_STRG, 'F', C_FORM},
- {"form-escape", ARG_BOOL, ' ', C_FORM_ESCAPE},
- {"form-string", ARG_STRG, ' ', C_FORM_STRING},
- {"ftp-account", ARG_STRG, ' ', C_FTP_ACCOUNT},
- {"ftp-alternative-to-user", ARG_STRG, ' ', C_FTP_ALTERNATIVE_TO_USER},
- {"ftp-create-dirs", ARG_BOOL, ' ', C_FTP_CREATE_DIRS},
- {"ftp-method", ARG_STRG, ' ', C_FTP_METHOD},
- {"ftp-pasv", ARG_BOOL, ' ', C_FTP_PASV},
- {"ftp-port", ARG_STRG, 'P', C_FTP_PORT},
- {"ftp-pret", ARG_BOOL, ' ', C_FTP_PRET},
- {"ftp-skip-pasv-ip", ARG_BOOL, ' ', C_FTP_SKIP_PASV_IP},
- {"ftp-ssl", ARG_BOOL, ' ', C_FTP_SSL},
- {"ftp-ssl-ccc", ARG_BOOL, ' ', C_FTP_SSL_CCC},
- {"ftp-ssl-ccc-mode", ARG_STRG, ' ', C_FTP_SSL_CCC_MODE},
- {"ftp-ssl-control", ARG_BOOL, ' ', C_FTP_SSL_CONTROL},
- {"ftp-ssl-reqd", ARG_BOOL, ' ', C_FTP_SSL_REQD},
- {"get", ARG_BOOL, 'G', C_GET},
- {"globoff", ARG_BOOL, 'g', C_GLOBOFF},
- {"happy-eyeballs-timeout-ms", ARG_STRG, ' ', C_HAPPY_EYEBALLS_TIMEOUT_MS},
- {"haproxy-clientip", ARG_STRG, ' ', C_HAPROXY_CLIENTIP},
- {"haproxy-protocol", ARG_BOOL, ' ', C_HAPROXY_PROTOCOL},
- {"head", ARG_BOOL, 'I', C_HEAD},
- {"header", ARG_STRG, 'H', C_HEADER},
- {"help", ARG_BOOL, 'h', C_HELP},
- {"hostpubmd5", ARG_STRG, ' ', C_HOSTPUBMD5},
- {"hostpubsha256", ARG_STRG, ' ', C_HOSTPUBSHA256},
- {"hsts", ARG_STRG, ' ', C_HSTS},
- {"http0.9", ARG_BOOL, ' ', C_HTTP0_9},
- {"http1.0", ARG_NONE, '0', C_HTTP1_0},
- {"http1.1", ARG_NONE, ' ', C_HTTP1_1},
- {"http2", ARG_NONE, ' ', C_HTTP2},
- {"http2-prior-knowledge", ARG_NONE, ' ', C_HTTP2_PRIOR_KNOWLEDGE},
- {"http3", ARG_NONE, ' ', C_HTTP3},
- {"http3-only", ARG_NONE, ' ', C_HTTP3_ONLY},
- {"ignore-content-length", ARG_BOOL, ' ', C_IGNORE_CONTENT_LENGTH},
- {"include", ARG_BOOL, ' ', C_INCLUDE},
- {"insecure", ARG_BOOL, 'k', C_INSECURE},
- {"interface", ARG_STRG, ' ', C_INTERFACE},
- {"ip-tos", ARG_STRG, ' ', C_IP_TOS},
- {"ipfs-gateway", ARG_STRG, ' ', C_IPFS_GATEWAY},
- {"ipv4", ARG_NONE, '4', C_IPV4},
- {"ipv6", ARG_NONE, '6', C_IPV6},
- {"json", ARG_STRG, ' ', C_JSON},
- {"junk-session-cookies", ARG_BOOL, 'j', C_JUNK_SESSION_COOKIES},
- {"keepalive", ARG_BOOL|ARG_NO, ' ', C_KEEPALIVE},
- {"keepalive-cnt", ARG_STRG, ' ', C_KEEPALIVE_CNT},
- {"keepalive-time", ARG_STRG, ' ', C_KEEPALIVE_TIME},
- {"key", ARG_FILE, ' ', C_KEY},
- {"key-type", ARG_STRG, ' ', C_KEY_TYPE},
- {"krb", ARG_STRG, ' ', C_KRB},
- {"krb4", ARG_STRG, ' ', C_KRB4},
- {"libcurl", ARG_STRG, ' ', C_LIBCURL},
- {"limit-rate", ARG_STRG, ' ', C_LIMIT_RATE},
- {"list-only", ARG_BOOL, 'l', C_LIST_ONLY},
- {"local-port", ARG_STRG, ' ', C_LOCAL_PORT},
- {"location", ARG_BOOL, 'L', C_LOCATION},
- {"location-trusted", ARG_BOOL, ' ', C_LOCATION_TRUSTED},
- {"login-options", ARG_STRG, ' ', C_LOGIN_OPTIONS},
- {"mail-auth", ARG_STRG, ' ', C_MAIL_AUTH},
- {"mail-from", ARG_STRG, ' ', C_MAIL_FROM},
- {"mail-rcpt", ARG_STRG, ' ', C_MAIL_RCPT},
- {"mail-rcpt-allowfails", ARG_BOOL, ' ', C_MAIL_RCPT_ALLOWFAILS},
- {"manual", ARG_BOOL, 'M', C_MANUAL},
- {"max-filesize", ARG_STRG, ' ', C_MAX_FILESIZE},
- {"max-redirs", ARG_STRG, ' ', C_MAX_REDIRS},
- {"max-time", ARG_STRG, 'm', C_MAX_TIME},
- {"metalink", ARG_BOOL, ' ', C_METALINK},
- {"mptcp", ARG_BOOL, ' ', C_MPTCP},
- {"negotiate", ARG_BOOL, ' ', C_NEGOTIATE},
- {"netrc", ARG_BOOL, 'n', C_NETRC},
- {"netrc-file", ARG_FILE, ' ', C_NETRC_FILE},
- {"netrc-optional", ARG_BOOL, ' ', C_NETRC_OPTIONAL},
- {"next", ARG_NONE, ':', C_NEXT},
- {"noproxy", ARG_STRG, ' ', C_NOPROXY},
- {"npn", ARG_BOOL|ARG_NO, ' ', C_NPN},
- {"ntlm", ARG_BOOL, ' ', C_NTLM},
- {"ntlm-wb", ARG_BOOL, ' ', C_NTLM_WB},
- {"oauth2-bearer", ARG_STRG, ' ', C_OAUTH2_BEARER},
- {"output", ARG_FILE, 'o', C_OUTPUT},
- {"output-dir", ARG_STRG, ' ', C_OUTPUT_DIR},
- {"parallel", ARG_BOOL, 'Z', C_PARALLEL},
- {"parallel-immediate", ARG_BOOL, ' ', C_PARALLEL_IMMEDIATE},
- {"parallel-max", ARG_STRG, ' ', C_PARALLEL_MAX},
- {"pass", ARG_STRG, ' ', C_PASS},
- {"path-as-is", ARG_BOOL, ' ', C_PATH_AS_IS},
- {"pinnedpubkey", ARG_STRG, ' ', C_PINNEDPUBKEY},
- {"post301", ARG_BOOL, ' ', C_POST301},
- {"post302", ARG_BOOL, ' ', C_POST302},
- {"post303", ARG_BOOL, ' ', C_POST303},
- {"preproxy", ARG_STRG, ' ', C_PREPROXY},
- {"progress-bar", ARG_BOOL, '#', C_PROGRESS_BAR},
- {"progress-meter", ARG_BOOL|ARG_NO, ' ', C_PROGRESS_METER},
- {"proto", ARG_STRG, ' ', C_PROTO},
- {"proto-default", ARG_STRG, ' ', C_PROTO_DEFAULT},
- {"proto-redir", ARG_STRG, ' ', C_PROTO_REDIR},
- {"proxy", ARG_STRG, 'x', C_PROXY},
- {"proxy-anyauth", ARG_BOOL, ' ', C_PROXY_ANYAUTH},
- {"proxy-basic", ARG_BOOL, ' ', C_PROXY_BASIC},
- {"proxy-ca-native", ARG_BOOL, ' ', C_PROXY_CA_NATIVE},
- {"proxy-cacert", ARG_FILE, ' ', C_PROXY_CACERT},
- {"proxy-capath", ARG_FILE, ' ', C_PROXY_CAPATH},
- {"proxy-cert", ARG_FILE, ' ', C_PROXY_CERT},
- {"proxy-cert-type", ARG_STRG, ' ', C_PROXY_CERT_TYPE},
- {"proxy-ciphers", ARG_STRG, ' ', C_PROXY_CIPHERS},
- {"proxy-crlfile", ARG_FILE, ' ', C_PROXY_CRLFILE},
- {"proxy-digest", ARG_BOOL, ' ', C_PROXY_DIGEST},
- {"proxy-header", ARG_STRG, ' ', C_PROXY_HEADER},
- {"proxy-http2", ARG_BOOL, ' ', C_PROXY_HTTP2},
- {"proxy-insecure", ARG_BOOL, ' ', C_PROXY_INSECURE},
- {"proxy-key", ARG_FILE, ' ', C_PROXY_KEY},
- {"proxy-key-type", ARG_STRG, ' ', C_PROXY_KEY_TYPE},
- {"proxy-negotiate", ARG_BOOL, ' ', C_PROXY_NEGOTIATE},
- {"proxy-ntlm", ARG_BOOL, ' ', C_PROXY_NTLM},
- {"proxy-pass", ARG_STRG, ' ', C_PROXY_PASS},
- {"proxy-pinnedpubkey", ARG_STRG, ' ', C_PROXY_PINNEDPUBKEY},
- {"proxy-service-name", ARG_STRG, ' ', C_PROXY_SERVICE_NAME},
- {"proxy-ssl-allow-beast", ARG_BOOL, ' ', C_PROXY_SSL_ALLOW_BEAST},
- {"proxy-ssl-auto-client-cert", ARG_BOOL, ' ', C_PROXY_SSL_AUTO_CLIENT_CERT},
- {"proxy-tls13-ciphers", ARG_STRG, ' ', C_PROXY_TLS13_CIPHERS},
- {"proxy-tlsauthtype", ARG_STRG, ' ', C_PROXY_TLSAUTHTYPE},
- {"proxy-tlspassword", ARG_STRG, ' ', C_PROXY_TLSPASSWORD},
- {"proxy-tlsuser", ARG_STRG, ' ', C_PROXY_TLSUSER},
- {"proxy-tlsv1", ARG_NONE, ' ', C_PROXY_TLSV1},
- {"proxy-user", ARG_STRG, 'U', C_PROXY_USER},
- {"proxy1.0", ARG_STRG, ' ', C_PROXY1_0},
- {"proxytunnel", ARG_BOOL, 'p', C_PROXYTUNNEL},
- {"pubkey", ARG_STRG, ' ', C_PUBKEY},
- {"quote", ARG_STRG, 'Q', C_QUOTE},
- {"random-file", ARG_FILE, ' ', C_RANDOM_FILE},
- {"range", ARG_STRG, 'r', C_RANGE},
- {"rate", ARG_STRG, ' ', C_RATE},
- {"raw", ARG_BOOL, ' ', C_RAW},
- {"referer", ARG_STRG, 'e', C_REFERER},
- {"remote-header-name", ARG_BOOL, 'J', C_REMOTE_HEADER_NAME},
- {"remote-name", ARG_BOOL, 'O', C_REMOTE_NAME},
- {"remote-name-all", ARG_BOOL, ' ', C_REMOTE_NAME_ALL},
- {"remote-time", ARG_BOOL, 'R', C_REMOTE_TIME},
- {"remove-on-error", ARG_BOOL, ' ', C_REMOVE_ON_ERROR},
- {"request", ARG_STRG, 'X', C_REQUEST},
- {"request-target", ARG_STRG, ' ', C_REQUEST_TARGET},
- {"resolve", ARG_STRG, ' ', C_RESOLVE},
- {"retry", ARG_STRG, ' ', C_RETRY},
- {"retry-all-errors", ARG_BOOL, ' ', C_RETRY_ALL_ERRORS},
- {"retry-connrefused", ARG_BOOL, ' ', C_RETRY_CONNREFUSED},
- {"retry-delay", ARG_STRG, ' ', C_RETRY_DELAY},
- {"retry-max-time", ARG_STRG, ' ', C_RETRY_MAX_TIME},
- {"sasl-authzid", ARG_STRG, ' ', C_SASL_AUTHZID},
- {"sasl-ir", ARG_BOOL, ' ', C_SASL_IR},
- {"service-name", ARG_STRG, ' ', C_SERVICE_NAME},
- {"sessionid", ARG_BOOL|ARG_NO, ' ', C_SESSIONID},
- {"show-error", ARG_BOOL, 'S', C_SHOW_ERROR},
- {"show-headers", ARG_BOOL, 'i', C_SHOW_HEADERS},
- {"silent", ARG_BOOL, 's', C_SILENT},
- {"skip-existing", ARG_BOOL, ' ', C_SKIP_EXISTING},
- {"socks4", ARG_STRG, ' ', C_SOCKS4},
- {"socks4a", ARG_STRG, ' ', C_SOCKS4A},
- {"socks5", ARG_STRG, ' ', C_SOCKS5},
- {"socks5-basic", ARG_BOOL, ' ', C_SOCKS5_BASIC},
- {"socks5-gssapi", ARG_BOOL, ' ', C_SOCKS5_GSSAPI},
- {"socks5-gssapi-nec", ARG_BOOL, ' ', C_SOCKS5_GSSAPI_NEC},
- {"socks5-gssapi-service", ARG_STRG, ' ', C_SOCKS5_GSSAPI_SERVICE},
- {"socks5-hostname", ARG_STRG, ' ', C_SOCKS5_HOSTNAME},
- {"speed-limit", ARG_STRG, 'Y', C_SPEED_LIMIT},
- {"speed-time", ARG_STRG, 'y', C_SPEED_TIME},
- {"ssl", ARG_BOOL, ' ', C_SSL},
- {"ssl-allow-beast", ARG_BOOL, ' ', C_SSL_ALLOW_BEAST},
- {"ssl-auto-client-cert", ARG_BOOL, ' ', C_SSL_AUTO_CLIENT_CERT},
- {"ssl-no-revoke", ARG_BOOL, ' ', C_SSL_NO_REVOKE},
- {"ssl-reqd", ARG_BOOL, ' ', C_SSL_REQD},
- {"ssl-revoke-best-effort", ARG_BOOL, ' ', C_SSL_REVOKE_BEST_EFFORT},
- {"sslv2", ARG_NONE, '2', C_SSLV2},
- {"sslv3", ARG_NONE, '3', C_SSLV3},
- {"stderr", ARG_FILE, ' ', C_STDERR},
- {"styled-output", ARG_BOOL, ' ', C_STYLED_OUTPUT},
- {"suppress-connect-headers", ARG_BOOL, ' ', C_SUPPRESS_CONNECT_HEADERS},
- {"tcp-fastopen", ARG_BOOL, ' ', C_TCP_FASTOPEN},
- {"tcp-nodelay", ARG_BOOL, ' ', C_TCP_NODELAY},
- {"telnet-option", ARG_STRG, 't', C_TELNET_OPTION},
- {"test-event", ARG_BOOL, ' ', C_TEST_EVENT},
- {"tftp-blksize", ARG_STRG, ' ', C_TFTP_BLKSIZE},
- {"tftp-no-options", ARG_BOOL, ' ', C_TFTP_NO_OPTIONS},
- {"time-cond", ARG_STRG, 'z', C_TIME_COND},
- {"tls-max", ARG_STRG, ' ', C_TLS_MAX},
- {"tls13-ciphers", ARG_STRG, ' ', C_TLS13_CIPHERS},
- {"tlsauthtype", ARG_STRG, ' ', C_TLSAUTHTYPE},
- {"tlspassword", ARG_STRG, ' ', C_TLSPASSWORD},
- {"tlsuser", ARG_STRG, ' ', C_TLSUSER},
- {"tlsv1", ARG_NONE, '1', C_TLSV1},
- {"tlsv1.0", ARG_NONE, ' ', C_TLSV1_0},
- {"tlsv1.1", ARG_NONE, ' ', C_TLSV1_1},
- {"tlsv1.2", ARG_NONE, ' ', C_TLSV1_2},
- {"tlsv1.3", ARG_NONE, ' ', C_TLSV1_3},
- {"tr-encoding", ARG_BOOL, ' ', C_TR_ENCODING},
- {"trace", ARG_FILE, ' ', C_TRACE},
- {"trace-ascii", ARG_FILE, ' ', C_TRACE_ASCII},
- {"trace-config", ARG_STRG, ' ', C_TRACE_CONFIG},
- {"trace-ids", ARG_BOOL, ' ', C_TRACE_IDS},
- {"trace-time", ARG_BOOL, ' ', C_TRACE_TIME},
- {"unix-socket", ARG_FILE, ' ', C_UNIX_SOCKET},
- {"upload-file", ARG_FILE, 'T', C_UPLOAD_FILE},
- {"url", ARG_STRG, ' ', C_URL},
- {"url-query", ARG_STRG, ' ', C_URL_QUERY},
- {"use-ascii", ARG_BOOL, 'B', C_USE_ASCII},
- {"user", ARG_STRG, 'u', C_USER},
- {"user-agent", ARG_STRG, 'A', C_USER_AGENT},
- {"variable", ARG_STRG, ' ', C_VARIABLE},
- {"verbose", ARG_BOOL, 'v', C_VERBOSE},
- {"version", ARG_BOOL, 'V', C_VERSION},
- {"vlan-priority", ARG_STRG, ' ', C_VLAN_PRIORITY},
+ /* 'letter' strings with more than one character have *no* short option to
+ mention. */
+ {"*@", "url", ARG_STRING},
+ {"*4", "dns-ipv4-addr", ARG_STRING},
+ {"*6", "dns-ipv6-addr", ARG_STRING},
+ {"*a", "random-file", ARG_FILENAME},
+ {"*b", "egd-file", ARG_STRING},
+ {"*B", "oauth2-bearer", ARG_STRING},
+ {"*c", "connect-timeout", ARG_STRING},
+ {"*C", "doh-url" , ARG_STRING},
+ {"*d", "ciphers", ARG_STRING},
+ {"*D", "dns-interface", ARG_STRING},
+ {"*e", "disable-epsv", ARG_BOOL},
+ {"*f", "disallow-username-in-url", ARG_BOOL},
+ {"*E", "epsv", ARG_BOOL},
+ /* 'epsv' made like this to make --no-epsv and --epsv to work
+ although --disable-epsv is the documented option */
+ {"*F", "dns-servers", ARG_STRING},
+ {"*g", "trace", ARG_FILENAME},
+ {"*G", "npn", ARG_BOOL},
+ {"*h", "trace-ascii", ARG_FILENAME},
+ {"*H", "alpn", ARG_BOOL},
+ {"*i", "limit-rate", ARG_STRING},
+ {"*I", "rate", ARG_STRING},
+ {"*j", "compressed", ARG_BOOL},
+ {"*J", "tr-encoding", ARG_BOOL},
+ {"*k", "digest", ARG_BOOL},
+ {"*l", "negotiate", ARG_BOOL},
+ {"*m", "ntlm", ARG_BOOL},
+ {"*M", "ntlm-wb", ARG_BOOL},
+ {"*n", "basic", ARG_BOOL},
+ {"*o", "anyauth", ARG_BOOL},
#ifdef USE_WATT32
- {"wdebug", ARG_BOOL, ' ', C_WDEBUG},
+ {"*p", "wdebug", ARG_BOOL},
#endif
- {"write-out", ARG_STRG, 'w', C_WRITE_OUT},
- {"xattr", ARG_BOOL, ' ', C_XATTR},
+ {"*q", "ftp-create-dirs", ARG_BOOL},
+ {"*r", "create-dirs", ARG_BOOL},
+ {"*R", "create-file-mode", ARG_STRING},
+ {"*s", "max-redirs", ARG_STRING},
+ {"*S", "ipfs-gateway", ARG_STRING},
+ {"*t", "proxy-ntlm", ARG_BOOL},
+ {"*u", "crlf", ARG_BOOL},
+ {"*v", "stderr", ARG_FILENAME},
+ {"*V", "aws-sigv4", ARG_STRING},
+ {"*w", "interface", ARG_STRING},
+ {"*x", "krb", ARG_STRING},
+ {"*x", "krb4", ARG_STRING},
+ /* 'krb4' is the previous name */
+ {"*X", "haproxy-protocol", ARG_BOOL},
+ {"*P", "haproxy-clientip", ARG_STRING},
+ {"*y", "max-filesize", ARG_STRING},
+ {"*z", "disable-eprt", ARG_BOOL},
+ {"*Z", "eprt", ARG_BOOL},
+ /* 'eprt' made like this to make --no-eprt and --eprt to work
+ although --disable-eprt is the documented option */
+ {"*~", "xattr", ARG_BOOL},
+ {"$a", "ftp-ssl", ARG_BOOL},
+ /* 'ftp-ssl' deprecated name since 7.20.0 */
+ {"$a", "ssl", ARG_BOOL},
+ /* 'ssl' new option name in 7.20.0, previously this was ftp-ssl */
+ {"$b", "ftp-pasv", ARG_BOOL},
+ {"$c", "socks5", ARG_STRING},
+ {"$d", "tcp-nodelay", ARG_BOOL},
+ {"$e", "proxy-digest", ARG_BOOL},
+ {"$f", "proxy-basic", ARG_BOOL},
+ {"$g", "retry", ARG_STRING},
+ {"$V", "retry-connrefused", ARG_BOOL},
+ {"$h", "retry-delay", ARG_STRING},
+ {"$i", "retry-max-time", ARG_STRING},
+ {"$k", "proxy-negotiate", ARG_BOOL},
+ {"$l", "form-escape", ARG_BOOL},
+ {"$m", "ftp-account", ARG_STRING},
+ {"$n", "proxy-anyauth", ARG_BOOL},
+ {"$o", "trace-time", ARG_BOOL},
+ {"$p", "ignore-content-length", ARG_BOOL},
+ {"$q", "ftp-skip-pasv-ip", ARG_BOOL},
+ {"$r", "ftp-method", ARG_STRING},
+ {"$s", "local-port", ARG_STRING},
+ {"$t", "socks4", ARG_STRING},
+ {"$T", "socks4a", ARG_STRING},
+ {"$u", "ftp-alternative-to-user", ARG_STRING},
+ {"$v", "ftp-ssl-reqd", ARG_BOOL},
+ /* 'ftp-ssl-reqd' deprecated name since 7.20.0 */
+ {"$v", "ssl-reqd", ARG_BOOL},
+ /* 'ssl-reqd' new in 7.20.0, previously this was ftp-ssl-reqd */
+ {"$w", "sessionid", ARG_BOOL},
+ /* 'sessionid' listed as --no-sessionid in the help */
+ {"$x", "ftp-ssl-control", ARG_BOOL},
+ {"$y", "ftp-ssl-ccc", ARG_BOOL},
+ {"$j", "ftp-ssl-ccc-mode", ARG_STRING},
+ {"$z", "libcurl", ARG_STRING},
+ {"$#", "raw", ARG_BOOL},
+ {"$0", "post301", ARG_BOOL},
+ {"$1", "keepalive", ARG_BOOL},
+ /* 'keepalive' listed as --no-keepalive in the help */
+ {"$2", "socks5-hostname", ARG_STRING},
+ {"$3", "keepalive-time", ARG_STRING},
+ {"$4", "post302", ARG_BOOL},
+ {"$5", "noproxy", ARG_STRING},
+ {"$7", "socks5-gssapi-nec", ARG_BOOL},
+ {"$8", "proxy1.0", ARG_STRING},
+ {"$9", "tftp-blksize", ARG_STRING},
+ {"$A", "mail-from", ARG_STRING},
+ {"$B", "mail-rcpt", ARG_STRING},
+ {"$C", "ftp-pret", ARG_BOOL},
+ {"$D", "proto", ARG_STRING},
+ {"$E", "proto-redir", ARG_STRING},
+ {"$F", "resolve", ARG_STRING},
+ {"$G", "delegation", ARG_STRING},
+ {"$H", "mail-auth", ARG_STRING},
+ {"$I", "post303", ARG_BOOL},
+ {"$J", "metalink", ARG_BOOL},
+ {"$6", "sasl-authzid", ARG_STRING},
+ {"$K", "sasl-ir", ARG_BOOL },
+ {"$L", "test-event", ARG_BOOL},
+ {"$M", "unix-socket", ARG_FILENAME},
+ {"$N", "path-as-is", ARG_BOOL},
+ {"$O", "socks5-gssapi-service", ARG_STRING},
+ /* 'socks5-gssapi-service' merged with'proxy-service-name' and
+ deprecated since 7.49.0 */
+ {"$O", "proxy-service-name", ARG_STRING},
+ {"$P", "service-name", ARG_STRING},
+ {"$Q", "proto-default", ARG_STRING},
+ {"$R", "expect100-timeout", ARG_STRING},
+ {"$S", "tftp-no-options", ARG_BOOL},
+ {"$U", "connect-to", ARG_STRING},
+ {"$W", "abstract-unix-socket", ARG_FILENAME},
+ {"$X", "tls-max", ARG_STRING},
+ {"$Y", "suppress-connect-headers", ARG_BOOL},
+ {"$Z", "compressed-ssh", ARG_BOOL},
+ {"$~", "happy-eyeballs-timeout-ms", ARG_STRING},
+ {"$!", "retry-all-errors", ARG_BOOL},
+ {"$%", "trace-ids", ARG_BOOL},
+ {"$&", "trace-config", ARG_STRING},
+ {"0", "http1.0", ARG_NONE},
+ {"01", "http1.1", ARG_NONE},
+ {"02", "http2", ARG_NONE},
+ {"03", "http2-prior-knowledge", ARG_NONE},
+ {"04", "http3", ARG_NONE},
+ {"05", "http3-only", ARG_NONE},
+ {"09", "http0.9", ARG_BOOL},
+ {"0a", "proxy-http2", ARG_BOOL},
+ {"1", "tlsv1", ARG_NONE},
+ {"10", "tlsv1.0", ARG_NONE},
+ {"11", "tlsv1.1", ARG_NONE},
+ {"12", "tlsv1.2", ARG_NONE},
+ {"13", "tlsv1.3", ARG_NONE},
+ {"1A", "tls13-ciphers", ARG_STRING},
+ {"1B", "proxy-tls13-ciphers", ARG_STRING},
+ {"2", "sslv2", ARG_NONE},
+ {"3", "sslv3", ARG_NONE},
+ {"4", "ipv4", ARG_NONE},
+ {"6", "ipv6", ARG_NONE},
+ {"a", "append", ARG_BOOL},
+ {"A", "user-agent", ARG_STRING},
+ {"b", "cookie", ARG_STRING},
+ {"ba", "alt-svc", ARG_STRING},
+ {"bb", "hsts", ARG_STRING},
+ {"B", "use-ascii", ARG_BOOL},
+ {"c", "cookie-jar", ARG_STRING},
+ {"C", "continue-at", ARG_STRING},
+ {"d", "data", ARG_STRING},
+ {"dr", "data-raw", ARG_STRING},
+ {"da", "data-ascii", ARG_STRING},
+ {"db", "data-binary", ARG_STRING},
+ {"de", "data-urlencode", ARG_STRING},
+ {"df", "json", ARG_STRING},
+ {"dg", "url-query", ARG_STRING},
+ {"D", "dump-header", ARG_FILENAME},
+ {"e", "referer", ARG_STRING},
+ {"E", "cert", ARG_FILENAME},
+ {"Ea", "cacert", ARG_FILENAME},
+ {"Eb", "cert-type", ARG_STRING},
+ {"Ec", "key", ARG_FILENAME},
+ {"Ed", "key-type", ARG_STRING},
+ {"Ee", "pass", ARG_STRING},
+ {"Ef", "engine", ARG_STRING},
+ {"EG", "ca-native", ARG_BOOL},
+ {"EH", "proxy-ca-native", ARG_BOOL},
+ {"Eg", "capath", ARG_FILENAME},
+ {"Eh", "pubkey", ARG_STRING},
+ {"Ei", "hostpubmd5", ARG_STRING},
+ {"EF", "hostpubsha256", ARG_STRING},
+ {"Ej", "crlfile", ARG_FILENAME},
+ {"Ek", "tlsuser", ARG_STRING},
+ {"El", "tlspassword", ARG_STRING},
+ {"Em", "tlsauthtype", ARG_STRING},
+ {"En", "ssl-allow-beast", ARG_BOOL},
+ {"Eo", "ssl-auto-client-cert", ARG_BOOL},
+ {"EO", "proxy-ssl-auto-client-cert", ARG_BOOL},
+ {"Ep", "pinnedpubkey", ARG_STRING},
+ {"EP", "proxy-pinnedpubkey", ARG_STRING},
+ {"Eq", "cert-status", ARG_BOOL},
+ {"EQ", "doh-cert-status", ARG_BOOL},
+ {"Er", "false-start", ARG_BOOL},
+ {"Es", "ssl-no-revoke", ARG_BOOL},
+ {"ES", "ssl-revoke-best-effort", ARG_BOOL},
+ {"Et", "tcp-fastopen", ARG_BOOL},
+ {"Eu", "proxy-tlsuser", ARG_STRING},
+ {"Ev", "proxy-tlspassword", ARG_STRING},
+ {"Ew", "proxy-tlsauthtype", ARG_STRING},
+ {"Ex", "proxy-cert", ARG_FILENAME},
+ {"Ey", "proxy-cert-type", ARG_STRING},
+ {"Ez", "proxy-key", ARG_FILENAME},
+ {"E0", "proxy-key-type", ARG_STRING},
+ {"E1", "proxy-pass", ARG_STRING},
+ {"E2", "proxy-ciphers", ARG_STRING},
+ {"E3", "proxy-crlfile", ARG_FILENAME},
+ {"E4", "proxy-ssl-allow-beast", ARG_BOOL},
+ {"E5", "login-options", ARG_STRING},
+ {"E6", "proxy-cacert", ARG_FILENAME},
+ {"E7", "proxy-capath", ARG_FILENAME},
+ {"E8", "proxy-insecure", ARG_BOOL},
+ {"E9", "proxy-tlsv1", ARG_NONE},
+ {"EA", "socks5-basic", ARG_BOOL},
+ {"EB", "socks5-gssapi", ARG_BOOL},
+ {"EC", "etag-save", ARG_FILENAME},
+ {"ED", "etag-compare", ARG_FILENAME},
+ {"EE", "curves", ARG_STRING},
+ {"f", "fail", ARG_BOOL},
+ {"fa", "fail-early", ARG_BOOL},
+ {"fb", "styled-output", ARG_BOOL},
+ {"fc", "mail-rcpt-allowfails", ARG_BOOL},
+ {"fd", "fail-with-body", ARG_BOOL},
+ {"fe", "remove-on-error", ARG_BOOL},
+ {"F", "form", ARG_STRING},
+ {"Fs", "form-string", ARG_STRING},
+ {"g", "globoff", ARG_BOOL},
+ {"G", "get", ARG_BOOL},
+ {"Ga", "request-target", ARG_STRING},
+ {"h", "help", ARG_BOOL},
+ {"H", "header", ARG_STRING},
+ {"Hp", "proxy-header", ARG_STRING},
+ {"i", "include", ARG_BOOL},
+ {"I", "head", ARG_BOOL},
+ {"j", "junk-session-cookies", ARG_BOOL},
+ {"J", "remote-header-name", ARG_BOOL},
+ {"k", "insecure", ARG_BOOL},
+ {"kd", "doh-insecure", ARG_BOOL},
+ {"K", "config", ARG_FILENAME},
+ {"l", "list-only", ARG_BOOL},
+ {"L", "location", ARG_BOOL},
+ {"Lt", "location-trusted", ARG_BOOL},
+ {"m", "max-time", ARG_STRING},
+ {"M", "manual", ARG_BOOL},
+ {"n", "netrc", ARG_BOOL},
+ {"no", "netrc-optional", ARG_BOOL},
+ {"ne", "netrc-file", ARG_FILENAME},
+ {"N", "buffer", ARG_BOOL},
+ /* 'buffer' listed as --no-buffer in the help */
+ {"o", "output", ARG_FILENAME},
+ {"O", "remote-name", ARG_BOOL},
+ {"Oa", "remote-name-all", ARG_BOOL},
+ {"Ob", "output-dir", ARG_STRING},
+ {"Oc", "clobber", ARG_BOOL},
+ {"p", "proxytunnel", ARG_BOOL},
+ {"P", "ftp-port", ARG_STRING},
+ {"q", "disable", ARG_BOOL},
+ {"Q", "quote", ARG_STRING},
+ {"r", "range", ARG_STRING},
+ {"R", "remote-time", ARG_BOOL},
+ {"s", "silent", ARG_BOOL},
+ {"S", "show-error", ARG_BOOL},
+ {"t", "telnet-option", ARG_STRING},
+ {"T", "upload-file", ARG_FILENAME},
+ {"u", "user", ARG_STRING},
+ {"U", "proxy-user", ARG_STRING},
+ {"v", "verbose", ARG_BOOL},
+ {"V", "version", ARG_BOOL},
+ {"w", "write-out", ARG_STRING},
+ {"x", "proxy", ARG_STRING},
+ {"xa", "preproxy", ARG_STRING},
+ {"X", "request", ARG_STRING},
+ {"Y", "speed-limit", ARG_STRING},
+ {"y", "speed-time", ARG_STRING},
+ {"z", "time-cond", ARG_STRING},
+ {"Z", "parallel", ARG_BOOL},
+ {"Zb", "parallel-max", ARG_STRING},
+ {"Zc", "parallel-immediate", ARG_BOOL},
+ {"#", "progress-bar", ARG_BOOL},
+ {"#m", "progress-meter", ARG_BOOL},
+ {":", "next", ARG_NONE},
+ {":a", "variable", ARG_STRING},
};
/* Split the argument of -E to 'certname' and 'passphrase' separated by colon.
* We allow ':' and '\' to be escaped by '\' so that we can use certificate
- * nicknames containing ':'. See <https://sourceforge.net/p/curl/bugs/1196/>
+ * nicknames containing ':'. See <https://sourceforge.net/p/curl/bugs/1196/>
* for details. */
#ifndef UNITTESTS
static
@@ -391,7 +405,7 @@ void parse_cert_parameter(const char *cert_parameter,
strncpy(certname_place, param_place, span);
param_place += span;
certname_place += span;
- /* we just ate all the non-special chars. now we are on either a special
+ /* we just ate all the non-special chars. now we're on either a special
* char or the end of the string. */
switch(*param_place) {
case '\0':
@@ -418,11 +432,11 @@ void parse_cert_parameter(const char *cert_parameter,
}
break;
case ':':
- /* Since we live in a world of weirdness and confusion, the Windows
+ /* Since we live in a world of weirdness and confusion, the win32
dudes can use : when using drive letters and thus c:\file:password
needs to work. In order not to break compatibility, we still use : as
- separator, but we try to detect when it is used for a filename! On
- Windows. */
+ separator, but we try to detect when it is used for a file name! On
+ windows. */
#ifdef _WIN32
if((param_place == &cert_parameter[1]) &&
(cert_parameter[2] == '\\' || cert_parameter[2] == '/') &&
@@ -437,7 +451,7 @@ void parse_cert_parameter(const char *cert_parameter,
}
#endif
/* escaped colons and Windows drive letter colons were handled
- * above; if we are still here, this is a separating colon */
+ * above; if we're still here, this is a separating colon */
param_place++;
if(*param_place) {
*passphrase = strdup(param_place);
@@ -481,14 +495,12 @@ static void
GetFileAndPassword(char *nextarg, char **file, char **password)
{
char *certname, *passphrase;
- if(nextarg) {
- parse_cert_parameter(nextarg, &certname, &passphrase);
- Curl_safefree(*file);
- *file = certname;
- if(passphrase) {
- Curl_safefree(*password);
- *password = passphrase;
- }
+ parse_cert_parameter(nextarg, &certname, &passphrase);
+ Curl_safefree(*file);
+ *file = certname;
+ if(passphrase) {
+ Curl_safefree(*password);
+ *password = passphrase;
}
}
@@ -547,8 +559,8 @@ static ParameterError GetSizeParameter(struct GlobalConfig *global,
#ifdef HAVE_WRITABLE_ARGV
static void cleanarg(argv_item_t str)
{
- /* now that getstr has copied the contents of nextarg, wipe the next
- * argument out so that the username:password is not displayed in the
+ /* now that GetStr has copied the contents of nextarg, wipe the next
+ * argument out so that the username:password isn't displayed in the
* system process list */
if(str) {
size_t len = strlen(str);
@@ -559,9 +571,6 @@ static void cleanarg(argv_item_t str)
#define cleanarg(x)
#endif
-/* the maximum size we allow the dynbuf generated string */
-#define MAX_DATAURLENCODE (500*1024*1024)
-
/* --data-urlencode */
static ParameterError data_urlencode(struct GlobalConfig *global,
char *nextarg,
@@ -569,7 +578,7 @@ static ParameterError data_urlencode(struct GlobalConfig *global,
size_t *lenp)
{
/* [name]=[content], we encode the content part only
- * [name]@[filename]
+ * [name]@[file name]
*
* Case 2: we first load the file using that name and then encode
* the content.
@@ -588,14 +597,13 @@ static ParameterError data_urlencode(struct GlobalConfig *global,
is_file = *p++; /* pass the separator */
}
else {
- /* neither @ nor =, so no name and it is not a file */
- nlen = 0;
- is_file = 0;
+ /* neither @ nor =, so no name and it isn't a file */
+ nlen = is_file = 0;
p = nextarg;
}
if('@' == is_file) {
FILE *file;
- /* a '@' letter, it means that a filename or - (stdin) follows */
+ /* a '@' letter, it means that a file name or - (stdin) follows */
if(!strcmp("-", p)) {
file = stdin;
set_binmode(stdin);
@@ -616,10 +624,9 @@ static ParameterError data_urlencode(struct GlobalConfig *global,
return err;
}
else {
- err = getstr(&postdata, p, ALLOW_BLANK);
- if(err)
- goto error;
- size = strlen(postdata);
+ GetStr(&postdata, p);
+ if(postdata)
+ size = strlen(postdata);
}
if(!postdata) {
@@ -634,25 +641,25 @@ static ParameterError data_urlencode(struct GlobalConfig *global,
char *enc = curl_easy_escape(NULL, postdata, (int)size);
Curl_safefree(postdata); /* no matter if it worked or not */
if(enc) {
- char *n;
- replace_url_encoded_space_by_plus(enc);
- if(nlen > 0) { /* only append '=' if we have a name */
- struct curlx_dynbuf dyn;
- curlx_dyn_init(&dyn, MAX_DATAURLENCODE);
- if(curlx_dyn_addn(&dyn, nextarg, nlen) ||
- curlx_dyn_addn(&dyn, "=", 1) ||
- curlx_dyn_add(&dyn, enc)) {
- curl_free(enc);
- return PARAM_NO_MEM;
- }
+ /* replace (in-place) '%20' by '+' according to RFC1866 */
+ size_t enclen = replace_url_encoded_space_by_plus(enc);
+ /* now make a string with the name from above and append the
+ encoded string */
+ size_t outlen = nlen + enclen + 2;
+ char *n = malloc(outlen);
+ if(!n) {
curl_free(enc);
- n = curlx_dyn_ptr(&dyn);
- size = curlx_dyn_len(&dyn);
+ return PARAM_NO_MEM;
+ }
+ if(nlen > 0) { /* only append '=' if we have a name */
+ msnprintf(n, outlen, "%.*s=%s", (int)nlen, nextarg, enc);
+ size = outlen-1;
}
else {
- n = enc;
- size = strlen(n);
+ strcpy(n, enc);
+ size = outlen-2; /* since no '=' was inserted */
}
+ curl_free(enc);
postdata = n;
}
else
@@ -687,7 +694,7 @@ static CURLcode set_trace_config(struct GlobalConfig *global,
if(!tmp)
return CURLE_OUT_OF_MEMORY;
- /* Allow strtok() here since this is not used threaded */
+ /* Allow strtok() here since this isn't used threaded */
/* !checksrc! disable BANNEDFUNC 2 */
token = strtok(tmp, ", ");
while(token) {
@@ -731,289 +738,6 @@ out:
return result;
}
-static int findarg(const void *a, const void *b)
-{
- const struct LongShort *aa = a;
- const struct LongShort *bb = b;
- return strcmp(aa->lname, bb->lname);
-}
-
-const struct LongShort *findshortopt(char letter)
-{
- static const struct LongShort *singles[128 - ' ']; /* ASCII => pointer */
- static bool singles_done = FALSE;
- if((letter >= 127) || (letter <= ' '))
- return NULL;
-
- if(!singles_done) {
- unsigned int j;
- for(j = 0; j < sizeof(aliases)/sizeof(aliases[0]); j++) {
- if(aliases[j].letter != ' ') {
- unsigned char l = (unsigned char)aliases[j].letter;
- singles[l - ' '] = &aliases[j];
- }
- }
- singles_done = TRUE;
- }
- return singles[letter - ' '];
-}
-
-struct TOSEntry {
- const char *name;
- unsigned char value;
-};
-
-static const struct TOSEntry tos_entries[] = {
- {"AF11", 0x28},
- {"AF12", 0x30},
- {"AF13", 0x38},
- {"AF21", 0x48},
- {"AF22", 0x50},
- {"AF23", 0x58},
- {"AF31", 0x68},
- {"AF32", 0x70},
- {"AF33", 0x78},
- {"AF41", 0x88},
- {"AF42", 0x90},
- {"AF43", 0x98},
- {"CE", 0x03},
- {"CS0", 0x00},
- {"CS1", 0x20},
- {"CS2", 0x40},
- {"CS3", 0x60},
- {"CS4", 0x80},
- {"CS5", 0xa0},
- {"CS6", 0xc0},
- {"CS7", 0xe0},
- {"ECT0", 0x02},
- {"ECT1", 0x01},
- {"EF", 0xb8},
- {"LE", 0x04},
- {"LOWCOST", 0x02},
- {"LOWDELAY", 0x10},
- {"MINCOST", 0x02},
- {"RELIABILITY", 0x04},
- {"THROUGHPUT", 0x08},
- {"VOICE-ADMIT", 0xb0}
-};
-
-static int find_tos(const void *a, const void *b)
-{
- const struct TOSEntry *aa = a;
- const struct TOSEntry *bb = b;
- return strcmp(aa->name, bb->name);
-}
-
-#define MAX_QUERY_LEN 100000 /* larger is not likely to ever work */
-static ParameterError url_query(char *nextarg,
- struct GlobalConfig *global,
- struct OperationConfig *config)
-{
- size_t size = 0;
- ParameterError err = PARAM_OK;
- char *query;
- struct curlx_dynbuf dyn;
- curlx_dyn_init(&dyn, MAX_QUERY_LEN);
-
- if(*nextarg == '+') {
- /* use without encoding */
- query = strdup(&nextarg[1]);
- if(!query)
- err = PARAM_NO_MEM;
- }
- else
- err = data_urlencode(global, nextarg, &query, &size);
-
- if(!err) {
- if(config->query) {
- CURLcode result = curlx_dyn_addf(&dyn, "%s&%s", config->query, query);
- free(query);
- if(result)
- err = PARAM_NO_MEM;
- else {
- free(config->query);
- config->query = curlx_dyn_ptr(&dyn);
- }
- }
- else
- config->query = query;
- }
- return err;
-}
-
-static ParameterError set_data(cmdline_t cmd,
- char *nextarg,
- struct GlobalConfig *global,
- struct OperationConfig *config)
-{
- char *postdata = NULL;
- FILE *file;
- size_t size = 0;
- ParameterError err = PARAM_OK;
-
- if(cmd == C_DATA_URLENCODE) { /* --data-urlencode */
- err = data_urlencode(global, nextarg, &postdata, &size);
- if(err)
- return err;
- }
- else if('@' == *nextarg && (cmd != C_DATA_RAW)) {
- /* the data begins with a '@' letter, it means that a filename
- or - (stdin) follows */
- nextarg++; /* pass the @ */
-
- if(!strcmp("-", nextarg)) {
- file = stdin;
- if(cmd == C_DATA_BINARY) /* forced data-binary */
- set_binmode(stdin);
- }
- else {
- file = fopen(nextarg, "rb");
- if(!file) {
- errorf(global, "Failed to open %s", nextarg);
- return PARAM_READ_ERROR;
- }
- }
-
- if((cmd == C_DATA_BINARY) || /* --data-binary */
- (cmd == C_JSON) /* --json */)
- /* forced binary */
- err = file2memory(&postdata, &size, file);
- else {
- err = file2string(&postdata, file);
- if(postdata)
- size = strlen(postdata);
- }
-
- if(file && (file != stdin))
- fclose(file);
- if(err)
- return err;
-
- if(!postdata) {
- /* no data from the file, point to a zero byte string to make this
- get sent as a POST anyway */
- postdata = strdup("");
- if(!postdata)
- return PARAM_NO_MEM;
- }
- }
- else {
- err = getstr(&postdata, nextarg, ALLOW_BLANK);
- if(err)
- return err;
- size = strlen(postdata);
- }
- if(cmd == C_JSON)
- config->jsoned = TRUE;
-
- if(curlx_dyn_len(&config->postdata)) {
- /* skip separator append for --json */
- if(!err && (cmd != C_JSON) &&
- curlx_dyn_addn(&config->postdata, "&", 1))
- err = PARAM_NO_MEM;
- }
-
- if(!err && curlx_dyn_addn(&config->postdata, postdata, size))
- err = PARAM_NO_MEM;
-
- Curl_safefree(postdata);
-
- config->postfields = curlx_dyn_ptr(&config->postdata);
- return err;
-}
-
-static ParameterError set_rate(struct GlobalConfig *global,
- char *nextarg)
-{
- /* --rate */
- /* support a few different suffixes, extract the suffix first, then
- get the number and convert to per hour.
- /s == per second
- /m == per minute
- /h == per hour (default)
- /d == per day (24 hours)
- */
- ParameterError err = PARAM_OK;
- char *div = strchr(nextarg, '/');
- char number[26];
- long denominator;
- long numerator = 60*60*1000; /* default per hour */
- size_t numlen = div ? (size_t)(div - nextarg) : strlen(nextarg);
- if(numlen > sizeof(number) -1)
- return PARAM_NUMBER_TOO_LARGE;
-
- strncpy(number, nextarg, numlen);
- number[numlen] = 0;
- err = str2unum(&denominator, number);
- if(err)
- return err;
-
- if(denominator < 1)
- return PARAM_BAD_USE;
-
- if(div) {
- char unit = div[1];
- curl_off_t numunits;
- char *endp;
-
- if(curlx_strtoofft(&div[1], &endp, 10, &numunits)) {
- /* if it fails, there is no legit number specified */
- if(endp == &div[1])
- /* if endp did not move, accept it as a 1 */
- numunits = 1;
- else
- return PARAM_BAD_USE;
- }
- else
- unit = *endp;
-
- switch(unit) {
- case 's': /* per second */
- numerator = 1000;
- break;
- case 'm': /* per minute */
- numerator = 60*1000;
- break;
- case 'h': /* per hour */
- break;
- case 'd': /* per day */
- numerator = 24*60*60*1000;
- break;
- default:
- errorf(global, "unsupported --rate unit");
- err = PARAM_BAD_USE;
- break;
- }
-
- if((LONG_MAX / numerator) < numunits) {
- /* overflow, too large number */
- errorf(global, "too large --rate unit");
- err = PARAM_NUMBER_TOO_LARGE;
- }
- /* this typecast is okay based on the check above */
- numerator *= (long)numunits;
- }
-
- if(err)
- ;
- else if(denominator > numerator)
- err = PARAM_NUMBER_TOO_LARGE;
- else
- global->ms_per_transfer = numerator/denominator;
-
- return err;
-}
-
-const struct LongShort *findlongopt(const char *opt)
-{
- struct LongShort key;
- key.lname = opt;
-
- return bsearch(&key, aliases, sizeof(aliases)/sizeof(aliases[0]),
- sizeof(aliases[0]), findarg);
-}
-
-
ParameterError getparameter(const char *flag, /* f or -long-flag */
char *nextarg, /* NULL if unset */
argv_item_t cleararg,
@@ -1022,17 +746,19 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
struct GlobalConfig *global,
struct OperationConfig *config)
{
+ char letter;
+ char subletter = '\0'; /* subletters can only occur on long options */
int rc;
const char *parse = NULL;
+ unsigned int j;
time_t now;
+ int hit = -1;
bool longopt = FALSE;
bool singleopt = FALSE; /* when true means '-o foo' used '-ofoo' */
- size_t nopts = 0; /* options processed in `flag`*/
ParameterError err = PARAM_OK;
bool toggle = TRUE; /* how to switch boolean options, on or off. Controlled
by using --OPTION or --no-OPTION */
bool nextalloc = FALSE; /* if nextarg is allocated */
- struct getout *url;
static const char *redir_protos[] = {
"http",
"https",
@@ -1040,19 +766,19 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
"ftps",
NULL
};
- const struct LongShort *a = NULL;
- curl_off_t value;
#ifdef HAVE_WRITABLE_ARGV
argv_item_t clearthis = NULL;
#else
(void)cleararg;
#endif
- *usedarg = FALSE; /* default is that we do not use the arg */
+ *usedarg = FALSE; /* default is that we don't use the arg */
if(('-' != flag[0]) || ('-' == flag[1])) {
/* this should be a long name */
const char *word = ('-' == flag[0]) ? flag + 2 : flag;
+ size_t fnam = strlen(word);
+ int numhits = 0;
bool noflagged = FALSE;
bool expand = FALSE;
@@ -1068,26 +794,41 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
expand = TRUE;
}
- a = findlongopt(word);
- if(a) {
- longopt = TRUE;
+ for(j = 0; j < sizeof(aliases)/sizeof(aliases[0]); j++) {
+ if(curl_strnequal(aliases[j].lname, word, fnam)) {
+ longopt = TRUE;
+ numhits++;
+ if(curl_strequal(aliases[j].lname, word)) {
+ parse = aliases[j].letter;
+ hit = j;
+ numhits = 1; /* a single unique hit */
+ break;
+ }
+ parse = aliases[j].letter;
+ hit = j;
+ }
}
- else {
+ if(numhits > 1) {
+ /* this is at least the second match! */
+ err = PARAM_OPTION_AMBIGUOUS;
+ goto error;
+ }
+ else if(hit < 0) {
err = PARAM_OPTION_UNKNOWN;
goto error;
}
- if(noflagged && (ARGTYPE(a->desc) != ARG_BOOL)) {
- /* --no- prefixed an option that is not boolean! */
+ else if(noflagged && (aliases[hit].desc != ARG_BOOL)) {
+ /* --no- prefixed an option that isn't boolean! */
err = PARAM_NO_NOT_BOOLEAN;
goto error;
}
- else if(expand && nextarg) {
+ else if(expand) {
struct curlx_dynbuf nbuf;
bool replaced;
- if((ARGTYPE(a->desc) != ARG_STRG) &&
- (ARGTYPE(a->desc) != ARG_FILE)) {
- /* --expand on an option that is not a string or a filename */
+ if((aliases[hit].desc != ARG_STRING) &&
+ (aliases[hit].desc != ARG_FILENAME)) {
+ /* --expand on an option that isn't a string or a filename */
err = PARAM_EXPAND_ERROR;
goto error;
}
@@ -1104,28 +845,40 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
}
else {
flag++; /* prefixed with one dash, pass it */
+ hit = -1;
parse = flag;
}
do {
/* we can loop here if we have multiple single-letters */
- char letter;
- cmdline_t cmd;
- if(!longopt && !a) {
- a = findshortopt(*parse);
- if(!a) {
+ if(!longopt) {
+ letter = (char)*parse;
+ subletter = '\0';
+ }
+ else {
+ letter = parse[0];
+ subletter = parse[1];
+ }
+
+ if(hit < 0) {
+ for(j = 0; j < sizeof(aliases)/sizeof(aliases[0]); j++) {
+ if(letter == aliases[j].letter[0]) {
+ hit = j;
+ break;
+ }
+ }
+ if(hit < 0) {
err = PARAM_OPTION_UNKNOWN;
break;
}
}
- letter = a->letter;
- cmd = (cmdline_t)a->cmd;
- if(ARGTYPE(a->desc) >= ARG_STRG) {
+
+ if(aliases[hit].desc >= ARG_STRING) {
/* this option requires an extra parameter */
if(!longopt && parse[1]) {
nextarg = (char *)&parse[1]; /* this is the actual extra parameter */
- singleopt = TRUE; /* do not loop anymore after this */
+ singleopt = TRUE; /* don't loop anymore after this */
}
else if(!nextarg) {
err = PARAM_REQUIRES_PARAMETER;
@@ -1138,704 +891,819 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
*usedarg = TRUE; /* mark it as used */
}
- if((ARGTYPE(a->desc) == ARG_FILE) &&
+ if((aliases[hit].desc == ARG_FILENAME) &&
(nextarg[0] == '-') && nextarg[1]) {
- /* if the filename looks like a command line option */
- warnf(global, "The filename argument '%s' looks like a flag.",
- nextarg);
- }
- else if(!strncmp("\xe2\x80\x9c", nextarg, 3)) {
- warnf(global, "The argument '%s' starts with a Unicode quote where "
- "maybe an ASCII \" was intended?",
+ /* if the file name looks like a command line option */
+ warnf(global, "The file name argument '%s' looks like a flag.",
nextarg);
}
}
- else if((ARGTYPE(a->desc) == ARG_NONE) && !toggle) {
+ else if((aliases[hit].desc == ARG_NONE) && !toggle) {
err = PARAM_NO_PREFIX;
break;
}
- if(!nextarg)
- /* this is a precaution mostly to please scan-build, as all arguments
- that use nextarg should be marked as such and they will check that
- nextarg is set before continuing, but code analyzers are not always
- that aware of that state */
- nextarg = (char *)"";
-
- switch(cmd) {
- case C_RANDOM_FILE: /* --random-file */
- case C_EGD_FILE: /* --egd-file */
- case C_NTLM_WB: /* --ntlm-wb */
- warnf(global, "--%s is deprecated and has no function anymore",
- a->lname);
- break;
- case C_DNS_IPV4_ADDR: /* --dns-ipv4-addr */
- if(!curlinfo->ares_num) /* c-ares is needed for this */
- err = PARAM_LIBCURL_DOESNT_SUPPORT;
- else
+ switch(letter) {
+ case '*': /* options without a short option */
+ switch(subletter) {
+ case '4': /* --dns-ipv4-addr */
+ if(!curlinfo->ares_num) { /* c-ares is needed for this */
+ err = PARAM_LIBCURL_DOESNT_SUPPORT;
+ break;
+ }
/* addr in dot notation */
- err = getstr(&config->dns_ipv4_addr, nextarg, DENY_BLANK);
- break;
- case C_DNS_IPV6_ADDR: /* --dns-ipv6-addr */
- if(!curlinfo->ares_num) /* c-ares is needed for this */
- err = PARAM_LIBCURL_DOESNT_SUPPORT;
- else
+ GetStr(&config->dns_ipv4_addr, nextarg);
+ break;
+ case '6': /* --dns-ipv6-addr */
+ if(!curlinfo->ares_num) { /* c-ares is needed for this */
+ err = PARAM_LIBCURL_DOESNT_SUPPORT;
+ break;
+ }
/* addr in dot notation */
- err = getstr(&config->dns_ipv6_addr, nextarg, DENY_BLANK);
- break;
- case C_OAUTH2_BEARER: /* --oauth2-bearer */
- err = getstr(&config->oauth_bearer, nextarg, DENY_BLANK);
- if(!err) {
+ GetStr(&config->dns_ipv6_addr, nextarg);
+ break;
+ case 'a': /* random-file */
+ break;
+ case 'b': /* egd-file */
+ break;
+ case 'B': /* OAuth 2.0 bearer token */
+ GetStr(&config->oauth_bearer, nextarg);
cleanarg(clearthis);
config->authtype |= CURLAUTH_BEARER;
- }
- break;
- case C_CONNECT_TIMEOUT: /* --connect-timeout */
- err = secs2ms(&config->connecttimeout_ms, nextarg);
- break;
- case C_DOH_URL: /* --doh-url */
- err = getstr(&config->doh_url, nextarg, ALLOW_BLANK);
- if(!err && config->doh_url && !config->doh_url[0])
- /* if given a blank string, make it NULL again */
- Curl_safefree(config->doh_url);
- break;
- case C_CIPHERS: /* -- ciphers */
- err = getstr(&config->cipher_list, nextarg, DENY_BLANK);
- break;
- case C_DNS_INTERFACE: /* --dns-interface */
- if(!curlinfo->ares_num) /* c-ares is needed for this */
- err = PARAM_LIBCURL_DOESNT_SUPPORT;
- else
- /* interface name */
- err = getstr(&config->dns_interface, nextarg, DENY_BLANK);
- break;
- case C_DISABLE_EPSV: /* --disable-epsv */
- config->disable_epsv = toggle;
- break;
- case C_DISALLOW_USERNAME_IN_URL: /* --disallow-username-in-url */
- config->disallow_username_in_url = toggle;
- break;
- case C_EPSV: /* --epsv */
- config->disable_epsv = (!toggle)?TRUE:FALSE;
- break;
- case C_DNS_SERVERS: /* --dns-servers */
- if(!curlinfo->ares_num) /* c-ares is needed for this */
- err = PARAM_LIBCURL_DOESNT_SUPPORT;
- else
- /* IP addrs of DNS servers */
- err = getstr(&config->dns_servers, nextarg, DENY_BLANK);
- break;
- case C_TRACE: /* --trace */
- err = getstr(&global->trace_dump, nextarg, DENY_BLANK);
- if(!err) {
+ break;
+ case 'c': /* connect-timeout */
+ err = secs2ms(&config->connecttimeout_ms, nextarg);
+ break;
+ case 'C': /* doh-url */
+ GetStr(&config->doh_url, nextarg);
+ if(config->doh_url && !config->doh_url[0])
+ /* if given a blank string, we make it NULL again */
+ Curl_safefree(config->doh_url);
+ break;
+ case 'd': /* ciphers */
+ GetStr(&config->cipher_list, nextarg);
+ break;
+ case 'D': /* --dns-interface */
+ if(!curlinfo->ares_num) /* c-ares is needed for this */
+ err = PARAM_LIBCURL_DOESNT_SUPPORT;
+ else
+ /* interface name */
+ GetStr(&config->dns_interface, nextarg);
+ break;
+ case 'e': /* --disable-epsv */
+ config->disable_epsv = toggle;
+ break;
+ case 'f': /* --disallow-username-in-url */
+ config->disallow_username_in_url = toggle;
+ break;
+ case 'E': /* --epsv */
+ config->disable_epsv = (!toggle)?TRUE:FALSE;
+ break;
+ case 'F': /* --dns-servers */
+ if(!curlinfo->ares_num) /* c-ares is needed for this */
+ err = PARAM_LIBCURL_DOESNT_SUPPORT;
+ else
+ /* IP addrs of DNS servers */
+ GetStr(&config->dns_servers, nextarg);
+ break;
+ case 'g': /* --trace */
+ GetStr(&global->trace_dump, nextarg);
if(global->tracetype && (global->tracetype != TRACE_BIN))
warnf(global, "--trace overrides an earlier trace/verbose option");
global->tracetype = TRACE_BIN;
- }
- break;
- case C_NPN: /* --npn */
- warnf(global, "--npn is no longer supported");
- break;
- case C_TRACE_ASCII: /* --trace-ascii */
- err = getstr(&global->trace_dump, nextarg, DENY_BLANK);
- if(!err) {
+ break;
+ case 'G': /* --npn */
+ warnf(global, "--npn is no longer supported");
+ break;
+ case 'h': /* --trace-ascii */
+ GetStr(&global->trace_dump, nextarg);
if(global->tracetype && (global->tracetype != TRACE_ASCII))
warnf(global,
"--trace-ascii overrides an earlier trace/verbose option");
global->tracetype = TRACE_ASCII;
- }
- break;
- case C_ALPN: /* --alpn */
- config->noalpn = (!toggle)?TRUE:FALSE;
- break;
- case C_LIMIT_RATE: /* --limit-rate */
- err = GetSizeParameter(global, nextarg, "rate", &value);
- if(!err) {
+ break;
+ case 'H': /* --alpn */
+ config->noalpn = (!toggle)?TRUE:FALSE;
+ break;
+ case 'i': /* --limit-rate */
+ {
+ curl_off_t value;
+ err = GetSizeParameter(global, nextarg, "rate", &value);
+ if(err)
+ break;
config->recvpersecond = value;
config->sendpersecond = value;
}
break;
- case C_RATE:
- err = set_rate(global, nextarg);
+ case 'I': /* --rate (request rate) */
+ {
+ /* support a few different suffixes, extract the suffix first, then
+ get the number and convert to per hour.
+ /s == per second
+ /m == per minute
+ /h == per hour (default)
+ /d == per day (24 hours)
+ */
+ char *div = strchr(nextarg, '/');
+ char number[26];
+ long denominator;
+ long numerator = 60*60*1000; /* default per hour */
+ size_t numlen = div ? (size_t)(div - nextarg) : strlen(nextarg);
+ if(numlen > sizeof(number)-1) {
+ err = PARAM_NUMBER_TOO_LARGE;
+ break;
+ }
+ strncpy(number, nextarg, numlen);
+ number[numlen] = 0;
+ err = str2unum(&denominator, number);
+ if(err)
+ break;
+
+ if(denominator < 1) {
+ err = PARAM_BAD_USE;
+ break;
+ }
+ if(div) {
+ char unit = div[1];
+ switch(unit) {
+ case 's': /* per second */
+ numerator = 1000;
+ break;
+ case 'm': /* per minute */
+ numerator = 60*1000;
+ break;
+ case 'h': /* per hour */
+ break;
+ case 'd': /* per day */
+ numerator = 24*60*60*1000;
+ break;
+ default:
+ errorf(global, "unsupported --rate unit");
+ err = PARAM_BAD_USE;
+ break;
+ }
+ }
+
+ if(denominator > numerator) {
+ err = PARAM_NUMBER_TOO_LARGE;
+ break;
+ }
+
+ global->ms_per_transfer = numerator/denominator;
+ }
break;
- case C_COMPRESSED: /* --compressed */
- if(toggle && !(feature_libz || feature_brotli || feature_zstd))
- err = PARAM_LIBCURL_DOESNT_SUPPORT;
- else
+
+ case 'j': /* --compressed */
+ if(toggle && !(feature_libz || feature_brotli || feature_zstd)) {
+ err = PARAM_LIBCURL_DOESNT_SUPPORT;
+ break;
+ }
config->encoding = toggle;
- break;
- case C_TR_ENCODING: /* --tr-encoding */
- config->tr_encoding = toggle;
- break;
- case C_DIGEST: /* --digest */
- if(toggle)
- config->authtype |= CURLAUTH_DIGEST;
- else
- config->authtype &= ~CURLAUTH_DIGEST;
- break;
- case C_NEGOTIATE: /* --negotiate */
- if(!toggle)
- config->authtype &= ~CURLAUTH_NEGOTIATE;
- else if(feature_spnego)
- config->authtype |= CURLAUTH_NEGOTIATE;
- else
- err = PARAM_LIBCURL_DOESNT_SUPPORT;
- break;
- case C_NTLM: /* --ntlm */
- if(!toggle)
- config->authtype &= ~CURLAUTH_NTLM;
- else if(feature_ntlm)
- config->authtype |= CURLAUTH_NTLM;
- else
- err = PARAM_LIBCURL_DOESNT_SUPPORT;
- break;
- case C_BASIC: /* --basic */
- if(toggle)
- config->authtype |= CURLAUTH_BASIC;
- else
- config->authtype &= ~CURLAUTH_BASIC;
- break;
- case C_ANYAUTH: /* --anyauth */
- if(toggle)
- config->authtype = CURLAUTH_ANY;
- /* --no-anyauth simply does not touch it */
- break;
+ break;
+
+ case 'J': /* --tr-encoding */
+ config->tr_encoding = toggle;
+ break;
+
+ case 'k': /* --digest */
+ if(toggle)
+ config->authtype |= CURLAUTH_DIGEST;
+ else
+ config->authtype &= ~CURLAUTH_DIGEST;
+ break;
+
+ case 'l': /* --negotiate */
+ if(!toggle)
+ config->authtype &= ~CURLAUTH_NEGOTIATE;
+ else if(feature_spnego)
+ config->authtype |= CURLAUTH_NEGOTIATE;
+ else {
+ err = PARAM_LIBCURL_DOESNT_SUPPORT;
+ break;
+ }
+ break;
+
+ case 'm': /* --ntlm */
+ if(!toggle)
+ config->authtype &= ~CURLAUTH_NTLM;
+ else if(feature_ntlm)
+ config->authtype |= CURLAUTH_NTLM;
+ else {
+ err = PARAM_LIBCURL_DOESNT_SUPPORT;
+ break;
+ }
+ break;
+
+ case 'M': /* --ntlm-wb */
+ if(!toggle)
+ config->authtype &= ~CURLAUTH_NTLM_WB;
+ else if(feature_ntlm_wb)
+ config->authtype |= CURLAUTH_NTLM_WB;
+ else {
+ err = PARAM_LIBCURL_DOESNT_SUPPORT;
+ break;
+ }
+ break;
+
+ case 'n': /* --basic for completeness */
+ if(toggle)
+ config->authtype |= CURLAUTH_BASIC;
+ else
+ config->authtype &= ~CURLAUTH_BASIC;
+ break;
+
+ case 'o': /* --anyauth, let libcurl pick it */
+ if(toggle)
+ config->authtype = CURLAUTH_ANY;
+ /* --no-anyauth simply doesn't touch it */
+ break;
+
#ifdef USE_WATT32
- case C_WDEBUG: /* --wdebug */
- dbug_init();
- break;
+ case 'p': /* --wdebug */
+ dbug_init();
+ break;
#endif
- case C_FTP_CREATE_DIRS: /* --ftp-create-dirs */
- config->ftp_create_dirs = toggle;
- break;
- case C_CREATE_DIRS: /* --create-dirs */
- config->create_dirs = toggle;
- break;
- case C_CREATE_FILE_MODE: /* --create-file-mode */
- err = oct2nummax(&config->create_file_mode, nextarg, 0777);
- break;
- case C_MAX_REDIRS: /* --max-redirs */
- /* specified max no of redirects (http(s)), this accepts -1 as a
- special condition */
- err = str2num(&config->maxredirs, nextarg);
- if(!err && (config->maxredirs < -1))
- err = PARAM_BAD_NUMERIC;
- break;
- case C_IPFS_GATEWAY: /* --ipfs-gateway */
- err = getstr(&config->ipfs_gateway, nextarg, DENY_BLANK);
- break;
- case C_PROXY_NTLM: /* --proxy-ntlm */
- if(!feature_ntlm)
- err = PARAM_LIBCURL_DOESNT_SUPPORT;
- else
+ case 'q': /* --ftp-create-dirs */
+ config->ftp_create_dirs = toggle;
+ break;
+
+ case 'r': /* --create-dirs */
+ config->create_dirs = toggle;
+ break;
+
+ case 'R': /* --create-file-mode */
+ err = oct2nummax(&config->create_file_mode, nextarg, 0777);
+ break;
+
+ case 's': /* --max-redirs */
+ /* specified max no of redirects (http(s)), this accepts -1 as a
+ special condition */
+ err = str2num(&config->maxredirs, nextarg);
+ if(err)
+ break;
+ if(config->maxredirs < -1)
+ err = PARAM_BAD_NUMERIC;
+ break;
+
+ case 'S': /* ipfs gateway url */
+ GetStr(&config->ipfs_gateway, nextarg);
+ break;
+
+ case 't': /* --proxy-ntlm */
+ if(!feature_ntlm) {
+ err = PARAM_LIBCURL_DOESNT_SUPPORT;
+ break;
+ }
config->proxyntlm = toggle;
- break;
- case C_CRLF: /* --crlf */
- /* LF -> CRLF conversion? */
- config->crlf = toggle;
- break;
- case C_AWS_SIGV4: /* --aws-sigv4 */
- config->authtype |= CURLAUTH_AWS_SIGV4;
- err = getstr(&config->aws_sigv4, nextarg, DENY_BLANK);
- break;
- case C_STDERR: /* --stderr */
- tool_set_stderr_file(global, nextarg);
- break;
- case C_INTERFACE: /* --interface */
- /* interface */
- err = getstr(&config->iface, nextarg, DENY_BLANK);
- break;
- case C_KRB: /* --krb */
- /* kerberos level string */
- if(!feature_spnego)
- err = PARAM_LIBCURL_DOESNT_SUPPORT;
- else
- err = getstr(&config->krblevel, nextarg, DENY_BLANK);
- break;
- case C_HAPROXY_PROTOCOL: /* --haproxy-protocol */
- config->haproxy_protocol = toggle;
- break;
- case C_HAPROXY_CLIENTIP: /* --haproxy-clientip */
- err = getstr(&config->haproxy_clientip, nextarg, DENY_BLANK);
- break;
- case C_MAX_FILESIZE: /* --max-filesize */
- err = GetSizeParameter(global, nextarg, "max-filesize", &value);
- if(!err)
- config->max_filesize = value;
- break;
- case C_DISABLE_EPRT: /* --disable-eprt */
- config->disable_eprt = toggle;
- break;
- case C_EPRT: /* --eprt */
- config->disable_eprt = (!toggle)?TRUE:FALSE;
- break;
- case C_XATTR: /* --xattr */
- config->xattr = toggle;
- break;
- case C_URL: /* --url */
- if(!config->url_get)
- config->url_get = config->url_list;
+ break;
- if(config->url_get) {
- /* there is a node here, if it already is filled-in continue to find
- an "empty" node */
- while(config->url_get && (config->url_get->flags & GETOUT_URL))
- config->url_get = config->url_get->next;
- }
+ case 'u': /* --crlf */
+ /* LF -> CRLF conversion? */
+ config->crlf = toggle;
+ break;
- /* now there might or might not be an available node to fill in! */
+ case 'V': /* --aws-sigv4 */
+ config->authtype |= CURLAUTH_AWS_SIGV4;
+ GetStr(&config->aws_sigv4, nextarg);
+ break;
- if(config->url_get)
- /* existing node */
- url = config->url_get;
- else
- /* there was no free node, create one! */
- config->url_get = url = new_getout(config);
+ case 'v': /* --stderr */
+ tool_set_stderr_file(global, nextarg);
+ break;
+ case 'w': /* --interface */
+ /* interface */
+ GetStr(&config->iface, nextarg);
+ break;
+ case 'x': /* --krb */
+ /* kerberos level string */
+ if(!feature_spnego) {
+ err = PARAM_LIBCURL_DOESNT_SUPPORT;
+ break;
+ }
+ GetStr(&config->krblevel, nextarg);
+ break;
+ case 'X': /* --haproxy-protocol */
+ config->haproxy_protocol = toggle;
+ break;
+ case 'P': /* --haproxy-clientip */
+ GetStr(&config->haproxy_clientip, nextarg);
+ break;
+ case 'y': /* --max-filesize */
+ {
+ curl_off_t value;
+ err =
+ GetSizeParameter(global, nextarg, "max-filesize", &value);
+ if(err)
+ break;
+ config->max_filesize = value;
+ }
+ break;
+ case 'z': /* --disable-eprt */
+ config->disable_eprt = toggle;
+ break;
+ case 'Z': /* --eprt */
+ config->disable_eprt = (!toggle)?TRUE:FALSE;
+ break;
+ case '~': /* --xattr */
+ config->xattr = toggle;
+ break;
+ case '@': /* the URL! */
+ {
+ struct getout *url;
+
+ if(!config->url_get)
+ config->url_get = config->url_list;
+
+ if(config->url_get) {
+ /* there's a node here, if it already is filled-in continue to find
+ an "empty" node */
+ while(config->url_get && (config->url_get->flags & GETOUT_URL))
+ config->url_get = config->url_get->next;
+ }
+
+ /* now there might or might not be an available node to fill in! */
+
+ if(config->url_get)
+ /* existing node */
+ url = config->url_get;
+ else
+ /* there was no free node, create one! */
+ config->url_get = url = new_getout(config);
+
+ if(!url) {
+ err = PARAM_NO_MEM;
+ break;
+ }
- if(!url)
- err = PARAM_NO_MEM;
- else {
/* fill in the URL */
- err = getstr(&url->url, nextarg, DENY_BLANK);
+ GetStr(&url->url, nextarg);
url->flags |= GETOUT_URL;
}
+ }
break;
- case C_FTP_SSL: /* --ftp-ssl */
- case C_SSL: /* --ssl */
- if(toggle && !feature_ssl)
- err = PARAM_LIBCURL_DOESNT_SUPPORT;
- else {
+ case '$': /* more options without a short option */
+ switch(subletter) {
+ case 'a': /* --ssl */
+ if(toggle && !feature_ssl) {
+ err = PARAM_LIBCURL_DOESNT_SUPPORT;
+ break;
+ }
config->ftp_ssl = toggle;
if(config->ftp_ssl)
warnf(global,
- "--%s is an insecure option, consider --ssl-reqd instead",
- a->lname);
- }
- break;
- case C_FTP_PASV: /* --ftp-pasv */
- Curl_safefree(config->ftpport);
- break;
- case C_SOCKS5: /* --socks5 */
- /* socks5 proxy to use, and resolves the name locally and passes on the
- resolved address */
- err = getstr(&config->proxy, nextarg, DENY_BLANK);
- config->proxyver = CURLPROXY_SOCKS5;
- break;
- case C_SOCKS4: /* --socks4 */
- err = getstr(&config->proxy, nextarg, DENY_BLANK);
- config->proxyver = CURLPROXY_SOCKS4;
- break;
- case C_SOCKS4A: /* --socks4a */
- err = getstr(&config->proxy, nextarg, DENY_BLANK);
- config->proxyver = CURLPROXY_SOCKS4A;
- break;
- case C_SOCKS5_HOSTNAME: /* --socks5-hostname */
- err = getstr(&config->proxy, nextarg, DENY_BLANK);
- config->proxyver = CURLPROXY_SOCKS5_HOSTNAME;
- break;
- case C_TCP_NODELAY: /* --tcp-nodelay */
- config->tcp_nodelay = toggle;
- break;
- case C_IP_TOS: { /* --ip-tos */
- struct TOSEntry find;
- const struct TOSEntry *entry;
- find.name = nextarg;
- entry = bsearch(&find, tos_entries,
- sizeof(tos_entries)/sizeof(*tos_entries),
- sizeof(*tos_entries), find_tos);
- if(entry)
- config->ip_tos = entry->value;
- else /* numeric tos value */
- err = str2unummax(&config->ip_tos, nextarg, 0xFF);
- break;
- }
- case C_VLAN_PRIORITY: /* --vlan-priority */
- err = str2unummax(&config->vlan_priority, nextarg, 7);
- break;
- case C_PROXY_DIGEST: /* --proxy-digest */
- config->proxydigest = toggle;
- break;
- case C_PROXY_BASIC: /* --proxy-basic */
- config->proxybasic = toggle;
- break;
- case C_RETRY: /* --retry */
- err = str2unum(&config->req_retry, nextarg);
- break;
- case C_RETRY_CONNREFUSED: /* --retry-connrefused */
- config->retry_connrefused = toggle;
- break;
- case C_RETRY_DELAY: /* --retry-delay */
- err = str2unummax(&config->retry_delay, nextarg, LONG_MAX/1000);
- break;
- case C_RETRY_MAX_TIME: /* --retry-max-time */
- err = str2unummax(&config->retry_maxtime, nextarg, LONG_MAX/1000);
- break;
- case C_RETRY_ALL_ERRORS: /* --retry-all-errors */
- config->retry_all_errors = toggle;
- break;
- case C_PROXY_NEGOTIATE: /* --proxy-negotiate */
- if(!feature_spnego)
- err = PARAM_LIBCURL_DOESNT_SUPPORT;
- else
+ "--ssl is an insecure option, consider --ssl-reqd instead");
+ break;
+ case 'b': /* --ftp-pasv */
+ Curl_safefree(config->ftpport);
+ break;
+ case 'c': /* --socks5 specifies a socks5 proxy to use, and resolves
+ the name locally and passes on the resolved address */
+ GetStr(&config->proxy, nextarg);
+ config->proxyver = CURLPROXY_SOCKS5;
+ break;
+ case 't': /* --socks4 specifies a socks4 proxy to use */
+ GetStr(&config->proxy, nextarg);
+ config->proxyver = CURLPROXY_SOCKS4;
+ break;
+ case 'T': /* --socks4a specifies a socks4a proxy to use */
+ GetStr(&config->proxy, nextarg);
+ config->proxyver = CURLPROXY_SOCKS4A;
+ break;
+ case '2': /* --socks5-hostname specifies a socks5 proxy and enables name
+ resolving with the proxy */
+ GetStr(&config->proxy, nextarg);
+ config->proxyver = CURLPROXY_SOCKS5_HOSTNAME;
+ break;
+ case 'd': /* --tcp-nodelay option */
+ config->tcp_nodelay = toggle;
+ break;
+ case 'e': /* --proxy-digest */
+ config->proxydigest = toggle;
+ break;
+ case 'f': /* --proxy-basic */
+ config->proxybasic = toggle;
+ break;
+ case 'g': /* --retry */
+ err = str2unum(&config->req_retry, nextarg);
+ break;
+ case 'V': /* --retry-connrefused */
+ config->retry_connrefused = toggle;
+ break;
+ case 'h': /* --retry-delay */
+ err = str2unummax(&config->retry_delay, nextarg, LONG_MAX/1000);
+ break;
+ case 'i': /* --retry-max-time */
+ err = str2unummax(&config->retry_maxtime, nextarg, LONG_MAX/1000);
+ break;
+ case '!': /* --retry-all-errors */
+ config->retry_all_errors = toggle;
+ break;
+
+ case 'k': /* --proxy-negotiate */
+ if(!feature_spnego) {
+ err = PARAM_LIBCURL_DOESNT_SUPPORT;
+ break;
+ }
config->proxynegotiate = toggle;
- break;
- case C_FORM_ESCAPE: /* --form-escape */
- config->mime_options &= ~CURLMIMEOPT_FORMESCAPE;
- if(toggle)
- config->mime_options |= CURLMIMEOPT_FORMESCAPE;
- break;
- case C_FTP_ACCOUNT: /* --ftp-account */
- err = getstr(&config->ftp_account, nextarg, DENY_BLANK);
- break;
- case C_PROXY_ANYAUTH: /* --proxy-anyauth */
- config->proxyanyauth = toggle;
- break;
- case C_TRACE_TIME: /* --trace-time */
- global->tracetime = toggle;
- break;
- case C_IGNORE_CONTENT_LENGTH: /* --ignore-content-length */
- config->ignorecl = toggle;
- break;
- case C_FTP_SKIP_PASV_IP: /* --ftp-skip-pasv-ip */
- config->ftp_skip_ip = toggle;
- break;
- case C_FTP_METHOD: /* --ftp-method */
- config->ftp_filemethod = ftpfilemethod(config, nextarg);
- break;
- case C_LOCAL_PORT: { /* --local-port */
- /* 16bit base 10 is 5 digits, but we allow 6 so that this catches
- overflows, not just truncates */
- char lrange[7]="";
- char *p = nextarg;
- while(ISDIGIT(*p))
- p++;
- if(*p) {
- /* if there is anything more than a plain decimal number */
- rc = sscanf(p, " - %6s", lrange);
- *p = 0; /* null-terminate to make str2unum() work below */
- }
- else
- rc = 0;
+ break;
- err = str2unum(&config->localport, nextarg);
- if(err || (config->localport > 65535)) {
- err = PARAM_BAD_USE;
+ case 'l': /* --form-escape */
+ config->mime_options &= ~CURLMIMEOPT_FORMESCAPE;
+ if(toggle)
+ config->mime_options |= CURLMIMEOPT_FORMESCAPE;
break;
- }
- if(!rc)
- config->localportrange = 1; /* default number of ports to try */
- else {
- err = str2unum(&config->localportrange, lrange);
- if(err || (config->localportrange > 65535))
+
+ case 'm': /* --ftp-account */
+ GetStr(&config->ftp_account, nextarg);
+ break;
+ case 'n': /* --proxy-anyauth */
+ config->proxyanyauth = toggle;
+ break;
+ case 'o': /* --trace-time */
+ global->tracetime = toggle;
+ break;
+ case 'p': /* --ignore-content-length */
+ config->ignorecl = toggle;
+ break;
+ case 'q': /* --ftp-skip-pasv-ip */
+ config->ftp_skip_ip = toggle;
+ break;
+ case 'r': /* --ftp-method (undocumented at this point) */
+ config->ftp_filemethod = ftpfilemethod(config, nextarg);
+ break;
+ case 's': { /* --local-port */
+ /* 16bit base 10 is 5 digits, but we allow 6 so that this catches
+ overflows, not just truncates */
+ char lrange[7]="";
+ char *p = nextarg;
+ while(ISDIGIT(*p))
+ p++;
+ if(*p) {
+ /* if there's anything more than a plain decimal number */
+ rc = sscanf(p, " - %6s", lrange);
+ *p = 0; /* null-terminate to make str2unum() work below */
+ }
+ else
+ rc = 0;
+
+ err = str2unum(&config->localport, nextarg);
+ if(err || (config->localport > 65535)) {
err = PARAM_BAD_USE;
+ break;
+ }
+ if(!rc)
+ config->localportrange = 1; /* default number of ports to try */
else {
- config->localportrange -= (config->localport-1);
- if(config->localportrange < 1)
+ err = str2unum(&config->localportrange, lrange);
+ if(err || (config->localportrange > 65535))
err = PARAM_BAD_USE;
+ else {
+ config->localportrange -= (config->localport-1);
+ if(config->localportrange < 1)
+ err = PARAM_BAD_USE;
+ }
}
- }
- break;
- }
- case C_FTP_ALTERNATIVE_TO_USER: /* --ftp-alternative-to-user */
- err = getstr(&config->ftp_alternative_to_user, nextarg, DENY_BLANK);
- break;
- case C_FTP_SSL_REQD: /* --ftp-ssl-reqd */
- case C_SSL_REQD: /* --ssl-reqd */
- if(toggle && !feature_ssl) {
- err = PARAM_LIBCURL_DOESNT_SUPPORT;
break;
}
- config->ftp_ssl_reqd = toggle;
- break;
- case C_SESSIONID: /* --sessionid */
- config->disable_sessionid = (!toggle)?TRUE:FALSE;
- break;
- case C_FTP_SSL_CONTROL: /* --ftp-ssl-control */
- if(toggle && !feature_ssl)
- err = PARAM_LIBCURL_DOESNT_SUPPORT;
- else
+ case 'u': /* --ftp-alternative-to-user */
+ GetStr(&config->ftp_alternative_to_user, nextarg);
+ break;
+ case 'v': /* --ssl-reqd */
+ if(toggle && !feature_ssl) {
+ err = PARAM_LIBCURL_DOESNT_SUPPORT;
+ break;
+ }
+ config->ftp_ssl_reqd = toggle;
+ break;
+ case 'w': /* --no-sessionid */
+ config->disable_sessionid = (!toggle)?TRUE:FALSE;
+ break;
+ case 'x': /* --ftp-ssl-control */
+ if(toggle && !feature_ssl) {
+ err = PARAM_LIBCURL_DOESNT_SUPPORT;
+ break;
+ }
config->ftp_ssl_control = toggle;
- break;
- case C_FTP_SSL_CCC: /* --ftp-ssl-ccc */
- config->ftp_ssl_ccc = toggle;
- if(!config->ftp_ssl_ccc_mode)
- config->ftp_ssl_ccc_mode = CURLFTPSSL_CCC_PASSIVE;
- break;
- case C_FTP_SSL_CCC_MODE: /* --ftp-ssl-ccc-mode */
- config->ftp_ssl_ccc = TRUE;
- config->ftp_ssl_ccc_mode = ftpcccmethod(config, nextarg);
- break;
- case C_LIBCURL: /* --libcurl */
+ break;
+ case 'y': /* --ftp-ssl-ccc */
+ config->ftp_ssl_ccc = toggle;
+ if(!config->ftp_ssl_ccc_mode)
+ config->ftp_ssl_ccc_mode = CURLFTPSSL_CCC_PASSIVE;
+ break;
+ case 'j': /* --ftp-ssl-ccc-mode */
+ config->ftp_ssl_ccc = TRUE;
+ config->ftp_ssl_ccc_mode = ftpcccmethod(config, nextarg);
+ break;
+ case 'z': /* --libcurl */
#ifdef CURL_DISABLE_LIBCURL_OPTION
- warnf(global,
- "--libcurl option was disabled at build-time");
- err = PARAM_OPTION_UNKNOWN;
+ warnf(global,
+ "--libcurl option was disabled at build-time");
+ err = PARAM_OPTION_UNKNOWN;
+ break;
#else
- err = getstr(&global->libcurl, nextarg, DENY_BLANK);
+ GetStr(&global->libcurl, nextarg);
+ break;
#endif
- break;
- case C_RAW: /* --raw */
- config->raw = toggle;
- break;
- case C_KEEPALIVE: /* --keepalive */
- config->nokeepalive = (!toggle)?TRUE:FALSE;
- break;
- case C_KEEPALIVE_TIME: /* --keepalive-time */
- err = str2unum(&config->alivetime, nextarg);
- break;
- case C_KEEPALIVE_CNT: /* --keepalive-cnt */
- err = str2unum(&config->alivecnt, nextarg);
- break;
- case C_POST301: /* --post301 */
- config->post301 = toggle;
- break;
- case C_POST302: /* --post302 */
- config->post302 = toggle;
- break;
- case C_POST303: /* --post303 */
- config->post303 = toggle;
- break;
- case C_NOPROXY: /* --noproxy */
- /* This specifies the noproxy list */
- err = getstr(&config->noproxy, nextarg, ALLOW_BLANK);
- break;
- case C_SOCKS5_GSSAPI_NEC: /* --socks5-gssapi-nec */
- config->socks5_gssapi_nec = toggle;
- break;
- case C_PROXY1_0: /* --proxy1.0 */
- /* http 1.0 proxy */
- err = getstr(&config->proxy, nextarg, DENY_BLANK);
- config->proxyver = CURLPROXY_HTTP_1_0;
- break;
- case C_TFTP_BLKSIZE: /* --tftp-blksize */
- err = str2unum(&config->tftp_blksize, nextarg);
- break;
- case C_MAIL_FROM: /* --mail-from */
- err = getstr(&config->mail_from, nextarg, DENY_BLANK);
- break;
- case C_MAIL_RCPT: /* --mail-rcpt */
- /* append receiver to a list */
- err = add2list(&config->mail_rcpt, nextarg);
- break;
- case C_FTP_PRET: /* --ftp-pret */
- config->ftp_pret = toggle;
- break;
- case C_PROTO: /* --proto */
- config->proto_present = TRUE;
- err = proto2num(config, built_in_protos, &config->proto_str, nextarg);
- break;
- case C_PROTO_REDIR: /* --proto-redir */
- config->proto_redir_present = TRUE;
- if(proto2num(config, redir_protos, &config->proto_redir_str,
- nextarg))
+ case '#': /* --raw */
+ config->raw = toggle;
+ break;
+ case '0': /* --post301 */
+ config->post301 = toggle;
+ break;
+ case '1': /* --no-keepalive */
+ config->nokeepalive = (!toggle)?TRUE:FALSE;
+ break;
+ case '3': /* --keepalive-time */
+ err = str2unum(&config->alivetime, nextarg);
+ break;
+ case '4': /* --post302 */
+ config->post302 = toggle;
+ break;
+ case 'I': /* --post303 */
+ config->post303 = toggle;
+ break;
+ case '5': /* --noproxy */
+ /* This specifies the noproxy list */
+ GetStr(&config->noproxy, nextarg);
+ break;
+ case '7': /* --socks5-gssapi-nec */
+ config->socks5_gssapi_nec = toggle;
+ break;
+ case '8': /* --proxy1.0 */
+ /* http 1.0 proxy */
+ GetStr(&config->proxy, nextarg);
+ config->proxyver = CURLPROXY_HTTP_1_0;
+ break;
+ case '9': /* --tftp-blksize */
+ err = str2unum(&config->tftp_blksize, nextarg);
+ break;
+ case 'A': /* --mail-from */
+ GetStr(&config->mail_from, nextarg);
+ break;
+ case 'B': /* --mail-rcpt */
+ /* append receiver to a list */
+ err = add2list(&config->mail_rcpt, nextarg);
+ break;
+ case 'C': /* --ftp-pret */
+ config->ftp_pret = toggle;
+ break;
+ case 'D': /* --proto */
+ config->proto_present = TRUE;
+ err = proto2num(config, built_in_protos, &config->proto_str, nextarg);
+ break;
+ case 'E': /* --proto-redir */
+ config->proto_redir_present = TRUE;
+ if(proto2num(config, redir_protos, &config->proto_redir_str,
+ nextarg)) {
+ err = PARAM_BAD_USE;
+ break;
+ }
+ break;
+ case 'F': /* --resolve */
+ err = add2list(&config->resolve, nextarg);
+ break;
+ case 'G': /* --delegation LEVEL */
+ config->gssapi_delegation = delegation(config, nextarg);
+ break;
+ case 'H': /* --mail-auth */
+ GetStr(&config->mail_auth, nextarg);
+ break;
+ case 'J': /* --metalink */
+ errorf(global, "--metalink is disabled");
err = PARAM_BAD_USE;
- break;
- case C_RESOLVE: /* --resolve */
- err = add2list(&config->resolve, nextarg);
- break;
- case C_DELEGATION: /* --delegation */
- config->gssapi_delegation = delegation(config, nextarg);
- break;
- case C_MAIL_AUTH: /* --mail-auth */
- err = getstr(&config->mail_auth, nextarg, DENY_BLANK);
- break;
- case C_METALINK: /* --metalink */
- errorf(global, "--metalink is disabled");
- err = PARAM_BAD_USE;
- break;
- case C_SASL_AUTHZID: /* --sasl-authzid */
- err = getstr(&config->sasl_authzid, nextarg, DENY_BLANK);
- break;
- case C_SASL_IR: /* --sasl-ir */
- config->sasl_ir = toggle;
- break;
- case C_TEST_EVENT: /* --test-event */
-#ifdef DEBUGBUILD
- global->test_event_based = toggle;
+ break;
+ case '6': /* --sasl-authzid */
+ GetStr(&config->sasl_authzid, nextarg);
+ break;
+ case 'K': /* --sasl-ir */
+ config->sasl_ir = toggle;
+ break;
+ case 'L': /* --test-event */
+#ifdef CURLDEBUG
+ global->test_event_based = toggle;
#else
- warnf(global, "--test-event is ignored unless a debug build");
+ warnf(global, "--test-event is ignored unless a debug build");
#endif
- break;
- case C_UNIX_SOCKET: /* --unix-socket */
- config->abstract_unix_socket = FALSE;
- err = getstr(&config->unix_socket_path, nextarg, DENY_BLANK);
- break;
- case C_PATH_AS_IS: /* --path-as-is */
- config->path_as_is = toggle;
- break;
- case C_PROXY_SERVICE_NAME: /* --proxy-service-name */
- err = getstr(&config->proxy_service_name, nextarg, DENY_BLANK);
- break;
- case C_SERVICE_NAME: /* --service-name */
- err = getstr(&config->service_name, nextarg, DENY_BLANK);
- break;
- case C_PROTO_DEFAULT: /* --proto-default */
- err = getstr(&config->proto_default, nextarg, DENY_BLANK);
- if(!err)
+ break;
+ case 'M': /* --unix-socket */
+ config->abstract_unix_socket = FALSE;
+ GetStr(&config->unix_socket_path, nextarg);
+ break;
+ case 'N': /* --path-as-is */
+ config->path_as_is = toggle;
+ break;
+ case 'O': /* --proxy-service-name */
+ GetStr(&config->proxy_service_name, nextarg);
+ break;
+ case 'P': /* --service-name */
+ GetStr(&config->service_name, nextarg);
+ break;
+ case 'Q': /* --proto-default */
+ GetStr(&config->proto_default, nextarg);
err = check_protocol(config->proto_default);
+ break;
+ case 'R': /* --expect100-timeout */
+ err = secs2ms(&config->expect100timeout_ms, nextarg);
+ break;
+ case 'S': /* --tftp-no-options */
+ config->tftp_no_options = toggle;
+ break;
+ case 'U': /* --connect-to */
+ err = add2list(&config->connect_to, nextarg);
+ break;
+ case 'W': /* --abstract-unix-socket */
+ config->abstract_unix_socket = TRUE;
+ GetStr(&config->unix_socket_path, nextarg);
+ break;
+ case 'X': /* --tls-max */
+ err = str2tls_max(&config->ssl_version_max, nextarg);
+ break;
+ case 'Y': /* --suppress-connect-headers */
+ config->suppress_connect_headers = toggle;
+ break;
+ case 'Z': /* --compressed-ssh */
+ config->ssh_compression = toggle;
+ break;
+ case '~': /* --happy-eyeballs-timeout-ms */
+ err = str2unum(&config->happy_eyeballs_timeout_ms, nextarg);
+ /* 0 is a valid value for this timeout */
+ break;
+ case '%': /* --trace-ids */
+ global->traceids = toggle;
+ break;
+ case '&': /* --trace-config */
+ if(set_trace_config(global, nextarg)) {
+ err = PARAM_NO_MEM;
+ }
+ break;
+ }
break;
- case C_EXPECT100_TIMEOUT: /* --expect100-timeout */
- err = secs2ms(&config->expect100timeout_ms, nextarg);
- break;
- case C_TFTP_NO_OPTIONS: /* --tftp-no-options */
- config->tftp_no_options = toggle;
- break;
- case C_CONNECT_TO: /* --connect-to */
- err = add2list(&config->connect_to, nextarg);
- break;
- case C_ABSTRACT_UNIX_SOCKET: /* --abstract-unix-socket */
- config->abstract_unix_socket = TRUE;
- err = getstr(&config->unix_socket_path, nextarg, DENY_BLANK);
- break;
- case C_TLS_MAX: /* --tls-max */
- err = str2tls_max(&config->ssl_version_max, nextarg);
- break;
- case C_SUPPRESS_CONNECT_HEADERS: /* --suppress-connect-headers */
- config->suppress_connect_headers = toggle;
- break;
- case C_COMPRESSED_SSH: /* --compressed-ssh */
- config->ssh_compression = toggle;
- break;
- case C_HAPPY_EYEBALLS_TIMEOUT_MS: /* --happy-eyeballs-timeout-ms */
- err = str2unum(&config->happy_eyeballs_timeout_ms, nextarg);
- /* 0 is a valid value for this timeout */
- break;
- case C_TRACE_IDS: /* --trace-ids */
- global->traceids = toggle;
- break;
- case C_TRACE_CONFIG: /* --trace-config */
- if(set_trace_config(global, nextarg))
- err = PARAM_NO_MEM;
- break;
- case C_PROGRESS_METER: /* --progress-meter */
- global->noprogress = !toggle;
- break;
- case C_PROGRESS_BAR: /* --progress-bar */
- global->progressmode = toggle ? CURL_PROGRESS_BAR : CURL_PROGRESS_STATS;
- break;
- case C_VARIABLE: /* --variable */
- err = setvariable(global, nextarg);
- break;
- case C_NEXT: /* --next */
- err = PARAM_NEXT_OPERATION;
- break;
- case C_HTTP1_0: /* --http1.0 */
- /* HTTP version 1.0 */
- sethttpver(global, config, CURL_HTTP_VERSION_1_0);
- break;
- case C_HTTP1_1: /* --http1.1 */
- /* HTTP version 1.1 */
- sethttpver(global, config, CURL_HTTP_VERSION_1_1);
- break;
- case C_HTTP2: /* --http2 */
- /* HTTP version 2.0 */
- if(!feature_http2)
- return PARAM_LIBCURL_DOESNT_SUPPORT;
- sethttpver(global, config, CURL_HTTP_VERSION_2_0);
+ case '#':
+ switch(subletter) {
+ case 'm': /* --progress-meter */
+ global->noprogress = !toggle;
+ break;
+ default: /* --progress-bar */
+ global->progressmode =
+ toggle ? CURL_PROGRESS_BAR : CURL_PROGRESS_STATS;
+ break;
+ }
break;
- case C_HTTP2_PRIOR_KNOWLEDGE: /* --http2-prior-knowledge */
- /* HTTP version 2.0 over clean TCP */
- if(!feature_http2)
- return PARAM_LIBCURL_DOESNT_SUPPORT;
- sethttpver(global, config, CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE);
+ case ':':
+ switch(subletter) {
+ case 'a': /* --variable */
+ err = setvariable(global, nextarg);
+ break;
+ default: /* --next */
+ err = PARAM_NEXT_OPERATION;
+ break;
+ }
break;
- case C_HTTP3: /* --http3: */
- /* Try HTTP/3, allow fallback */
- if(!feature_http3)
- err = PARAM_LIBCURL_DOESNT_SUPPORT;
- else
+ case '0': /* --http* options */
+ switch(subletter) {
+ case '\0':
+ /* HTTP version 1.0 */
+ sethttpver(global, config, CURL_HTTP_VERSION_1_0);
+ break;
+ case '1':
+ /* HTTP version 1.1 */
+ sethttpver(global, config, CURL_HTTP_VERSION_1_1);
+ break;
+ case '2':
+ /* HTTP version 2.0 */
+ if(!feature_http2)
+ return PARAM_LIBCURL_DOESNT_SUPPORT;
+ sethttpver(global, config, CURL_HTTP_VERSION_2_0);
+ break;
+ case '3': /* --http2-prior-knowledge */
+ /* HTTP version 2.0 over clean TCP */
+ if(!feature_http2)
+ return PARAM_LIBCURL_DOESNT_SUPPORT;
+ sethttpver(global, config, CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE);
+ break;
+ case '4': /* --http3 */
+ /* Try HTTP/3, allow fallback */
+ if(!feature_http3) {
+ err = PARAM_LIBCURL_DOESNT_SUPPORT;
+ break;
+ }
sethttpver(global, config, CURL_HTTP_VERSION_3);
- break;
- case C_HTTP3_ONLY: /* --http3-only */
- /* Try HTTP/3 without fallback */
- if(!feature_http3)
- err = PARAM_LIBCURL_DOESNT_SUPPORT;
- else
+ break;
+ case '5': /* --http3-only */
+ /* Try HTTP/3 without fallback */
+ if(!feature_http3) {
+ err = PARAM_LIBCURL_DOESNT_SUPPORT;
+ break;
+ }
sethttpver(global, config, CURL_HTTP_VERSION_3ONLY);
- break;
- case C_HTTP0_9: /* --http0.9 */
- /* Allow HTTP/0.9 responses! */
- config->http09_allowed = toggle;
- break;
- case C_PROXY_HTTP2: /* --proxy-http2 */
- if(!feature_httpsproxy || !feature_http2)
- err = PARAM_LIBCURL_DOESNT_SUPPORT;
- else
+ break;
+ case '9':
+ /* Allow HTTP/0.9 responses! */
+ config->http09_allowed = toggle;
+ break;
+ case 'a':
+ /* --proxy-http2 */
+ if(!feature_httpsproxy || !feature_http2)
+ return PARAM_LIBCURL_DOESNT_SUPPORT;
config->proxyver = CURLPROXY_HTTPS2;
+ break;
+ }
break;
- case C_TLSV1: /* --tlsv1 */
- config->ssl_version = CURL_SSLVERSION_TLSv1;
- break;
- case C_TLSV1_0: /* --tlsv1.0 */
- config->ssl_version = CURL_SSLVERSION_TLSv1_0;
- break;
- case C_TLSV1_1: /* --tlsv1.1 */
- config->ssl_version = CURL_SSLVERSION_TLSv1_1;
- break;
- case C_TLSV1_2: /* --tlsv1.2 */
- config->ssl_version = CURL_SSLVERSION_TLSv1_2;
- break;
- case C_TLSV1_3: /* --tlsv1.3 */
- config->ssl_version = CURL_SSLVERSION_TLSv1_3;
- break;
- case C_TLS13_CIPHERS: /* --tls13-ciphers */
- err = getstr(&config->cipher13_list, nextarg, DENY_BLANK);
- break;
- case C_PROXY_TLS13_CIPHERS: /* --proxy-tls13-ciphers */
- err = getstr(&config->proxy_cipher13_list, nextarg, DENY_BLANK);
+ case '1': /* --tlsv1* options */
+ switch(subletter) {
+ case '\0':
+ /* TLS version 1.x */
+ config->ssl_version = CURL_SSLVERSION_TLSv1;
+ break;
+ case '0':
+ /* TLS version 1.0 */
+ config->ssl_version = CURL_SSLVERSION_TLSv1_0;
+ break;
+ case '1':
+ /* TLS version 1.1 */
+ config->ssl_version = CURL_SSLVERSION_TLSv1_1;
+ break;
+ case '2':
+ /* TLS version 1.2 */
+ config->ssl_version = CURL_SSLVERSION_TLSv1_2;
+ break;
+ case '3':
+ /* TLS version 1.3 */
+ config->ssl_version = CURL_SSLVERSION_TLSv1_3;
+ break;
+ case 'A': /* --tls13-ciphers */
+ GetStr(&config->cipher13_list, nextarg);
+ break;
+ case 'B': /* --proxy-tls13-ciphers */
+ GetStr(&config->proxy_cipher13_list, nextarg);
+ break;
+ }
break;
- case C_SSLV2: /* --sslv2 */
+ case '2':
+ /* SSL version 2 */
warnf(global, "Ignores instruction to use SSLv2");
break;
- case C_SSLV3: /* --sslv3 */
+ case '3':
+ /* SSL version 3 */
warnf(global, "Ignores instruction to use SSLv3");
break;
- case C_IPV4: /* --ipv4 */
+ case '4':
+ /* IPv4 */
config->ip_version = CURL_IPRESOLVE_V4;
break;
- case C_IPV6: /* --ipv6 */
+ case '6':
+ /* IPv6 */
config->ip_version = CURL_IPRESOLVE_V6;
break;
- case C_APPEND: /* --append */
+ case 'a':
/* This makes the FTP sessions use APPE instead of STOR */
config->ftp_append = toggle;
break;
- case C_USER_AGENT: /* --user-agent */
- err = getstr(&config->useragent, nextarg, ALLOW_BLANK);
- break;
- case C_ALT_SVC: /* --alt-svc */
- if(!feature_altsvc)
- err = PARAM_LIBCURL_DOESNT_SUPPORT;
- else
- err = getstr(&config->altsvc, nextarg, ALLOW_BLANK);
- break;
- case C_HSTS: /* --hsts */
- if(!feature_hsts)
- err = PARAM_LIBCURL_DOESNT_SUPPORT;
- else
- err = getstr(&config->hsts, nextarg, ALLOW_BLANK);
+ case 'A':
+ /* This specifies the User-Agent name */
+ GetStr(&config->useragent, nextarg);
break;
- case C_COOKIE: /* --cookie */
- if(strchr(nextarg, '=')) {
- /* A cookie string must have a =-letter */
- err = add2list(&config->cookies, nextarg);
+ case 'b':
+ switch(subletter) {
+ case 'a': /* --alt-svc */
+ if(!feature_altsvc)
+ err = PARAM_LIBCURL_DOESNT_SUPPORT;
+ else
+ GetStr(&config->altsvc, nextarg);
break;
- }
- else {
+ case 'b': /* --hsts */
+ if(!feature_hsts)
+ err = PARAM_LIBCURL_DOESNT_SUPPORT;
+ else
+ GetStr(&config->hsts, nextarg);
+ break;
+ default: /* --cookie string coming up: */
+ if(nextarg[0] == '@') {
+ nextarg++;
+ }
+ else if(strchr(nextarg, '=')) {
+ /* A cookie string must have a =-letter */
+ err = add2list(&config->cookies, nextarg);
+ break;
+ }
/* We have a cookie file to read from! */
err = add2list(&config->cookiefiles, nextarg);
}
break;
- case C_USE_ASCII: /* --use-ascii */
+ case 'B':
+ /* use ASCII/text when transferring */
config->use_ascii = toggle;
break;
- case C_COOKIE_JAR: /* --cookie-jar */
- err = getstr(&config->cookiejar, nextarg, DENY_BLANK);
+ case 'c':
+ /* get the file name to dump all cookies in */
+ GetStr(&config->cookiejar, nextarg);
break;
- case C_CONTINUE_AT: /* --continue-at */
+ case 'C':
/* This makes us continue an ftp transfer at given position */
if(strcmp(nextarg, "-")) {
err = str2offset(&config->resume_from, nextarg);
+ if(err)
+ break;
config->resume_from_current = FALSE;
}
else {
@@ -1844,24 +1712,158 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
}
config->use_resume = TRUE;
break;
- case C_DATA: /* --data */
- case C_DATA_ASCII: /* --data-ascii */
- case C_DATA_BINARY: /* --data-binary */
- case C_DATA_URLENCODE: /* --data-urlencode */
- case C_JSON: /* --json */
- case C_DATA_RAW: /* --data-raw */
- err = set_data(cmd, nextarg, global, config);
- break;
- case C_URL_QUERY: /* --url-query */
- err = url_query(nextarg, global, config);
- break;
- case C_DUMP_CA_EMBED: /* --dump-ca-embed */
- err = PARAM_CA_EMBED_REQUESTED;
- break;
- case C_DUMP_HEADER: /* --dump-header */
- err = getstr(&config->headerfile, nextarg, DENY_BLANK);
+ case 'd':
+ /* postfield data */
+ {
+ char *postdata = NULL;
+ FILE *file;
+ size_t size = 0;
+ bool raw_mode = (subletter == 'r');
+
+ if(subletter == 'g') { /* --url-query */
+#define MAX_QUERY_LEN 100000 /* larger is not likely to ever work */
+ char *query;
+ struct curlx_dynbuf dyn;
+ curlx_dyn_init(&dyn, MAX_QUERY_LEN);
+
+ if(*nextarg == '+') {
+ /* use without encoding */
+ query = strdup(&nextarg[1]);
+ if(!query) {
+ err = PARAM_NO_MEM;
+ break;
+ }
+ }
+ else {
+ err = data_urlencode(global, nextarg, &query, &size);
+ if(err)
+ break;
+ }
+
+ if(config->query) {
+ CURLcode result =
+ curlx_dyn_addf(&dyn, "%s&%s", config->query, query);
+ free(query);
+ if(result) {
+ err = PARAM_NO_MEM;
+ break;
+ }
+ free(config->query);
+ config->query = curlx_dyn_ptr(&dyn);
+ }
+ else
+ config->query = query;
+
+ break; /* this is not a POST argument at all */
+ }
+ else if(subletter == 'e') { /* --data-urlencode */
+ err = data_urlencode(global, nextarg, &postdata, &size);
+ if(err)
+ break;
+ }
+ else if('@' == *nextarg && !raw_mode) {
+ /* the data begins with a '@' letter, it means that a file name
+ or - (stdin) follows */
+ nextarg++; /* pass the @ */
+
+ if(!strcmp("-", nextarg)) {
+ file = stdin;
+ if(subletter == 'b') /* forced data-binary */
+ set_binmode(stdin);
+ }
+ else {
+ file = fopen(nextarg, "rb");
+ if(!file) {
+ errorf(global, "Failed to open %s", nextarg);
+ err = PARAM_READ_ERROR;
+ break;
+ }
+ }
+
+ if((subletter == 'b') || /* --data-binary */
+ (subletter == 'f') /* --json */)
+ /* forced binary */
+ err = file2memory(&postdata, &size, file);
+ else {
+ err = file2string(&postdata, file);
+ if(postdata)
+ size = strlen(postdata);
+ }
+
+ if(file && (file != stdin))
+ fclose(file);
+ if(err)
+ break;
+
+ if(!postdata) {
+ /* no data from the file, point to a zero byte string to make this
+ get sent as a POST anyway */
+ postdata = strdup("");
+ if(!postdata) {
+ err = PARAM_NO_MEM;
+ break;
+ }
+ }
+ }
+ else {
+ GetStr(&postdata, nextarg);
+ if(postdata)
+ size = strlen(postdata);
+ }
+ if(subletter == 'f')
+ config->jsoned = TRUE;
+
+ if(config->postfields) {
+ /* we already have a string, we append this one with a separating
+ &-letter */
+ char *oldpost = config->postfields;
+ curl_off_t oldlen = config->postfieldsize;
+ curl_off_t newlen = oldlen + curlx_uztoso(size) + 2;
+ config->postfields = malloc((size_t)newlen);
+ if(!config->postfields) {
+ Curl_safefree(oldpost);
+ Curl_safefree(postdata);
+ err = PARAM_NO_MEM;
+ break;
+ }
+ memcpy(config->postfields, oldpost, (size_t)oldlen);
+ if(subletter != 'f') {
+ /* skip this treatment for --json */
+ /* use byte value 0x26 for '&' to accommodate non-ASCII platforms */
+ config->postfields[oldlen] = '\x26';
+ memcpy(&config->postfields[oldlen + 1], postdata, size);
+ config->postfields[oldlen + 1 + size] = '\0';
+ config->postfieldsize += size + 1;
+ }
+ else {
+ memcpy(&config->postfields[oldlen], postdata, size);
+ config->postfields[oldlen + size] = '\0';
+ config->postfieldsize += size;
+ }
+ Curl_safefree(oldpost);
+ Curl_safefree(postdata);
+ }
+ else {
+ config->postfields = postdata;
+ config->postfieldsize = curlx_uztoso(size);
+ }
+ }
+ /*
+ We can't set the request type here, as this data might be used in
+ a simple GET if -G is used. Already or soon.
+
+ if(SetHTTPrequest(HTTPREQ_SIMPLEPOST, &config->httpreq)) {
+ Curl_safefree(postdata);
+ return PARAM_BAD_USE;
+ }
+ */
+ break;
+ case 'D':
+ /* dump-header to given file name */
+ GetStr(&config->headerfile, nextarg);
break;
- case C_REFERER: { /* --referer */
+ case 'e':
+ {
char *ptr = strstr(nextarg, ";auto");
if(ptr) {
/* Automatic referer requested, this may be combined with a
@@ -1872,314 +1874,322 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
else
config->autoreferer = FALSE;
ptr = *nextarg ? nextarg : NULL;
- err = getstr(&config->referer, ptr, ALLOW_BLANK);
- }
- break;
- case C_CERT: /* --cert */
- cleanarg(clearthis);
- GetFileAndPassword(nextarg, &config->cert, &config->key_passwd);
- break;
- case C_CACERT: /* --cacert */
- err = getstr(&config->cacert, nextarg, DENY_BLANK);
- break;
- case C_CA_NATIVE: /* --ca-native */
- config->native_ca_store = toggle;
- break;
- case C_PROXY_CA_NATIVE: /* --proxy-ca-native */
- config->proxy_native_ca_store = toggle;
- break;
- case C_CERT_TYPE: /* --cert-type */
- err = getstr(&config->cert_type, nextarg, DENY_BLANK);
- break;
- case C_KEY: /* --key */
- err = getstr(&config->key, nextarg, DENY_BLANK);
- break;
- case C_KEY_TYPE: /* --key-type */
- err = getstr(&config->key_type, nextarg, DENY_BLANK);
- break;
- case C_PASS: /* --pass */
- err = getstr(&config->key_passwd, nextarg, DENY_BLANK);
- cleanarg(clearthis);
- break;
- case C_ENGINE: /* --engine */
- err = getstr(&config->engine, nextarg, DENY_BLANK);
- if(!err &&
- config->engine && !strcmp(config->engine, "list")) {
- err = PARAM_ENGINES_REQUESTED;
- }
- break;
-#ifndef USE_ECH
- case C_ECH: /* --ech, not implemented by default */
- err = PARAM_LIBCURL_DOESNT_SUPPORT;
- break;
-#else
- case C_ECH: /* --ech */
- if(strlen(nextarg) > 4 && strncasecompare("pn:", nextarg, 3)) {
- /* a public_name */
- err = getstr(&config->ech_public, nextarg, DENY_BLANK);
- }
- else if(strlen(nextarg) > 5 && strncasecompare("ecl:", nextarg, 4)) {
- /* an ECHConfigList */
- if('@' != *(nextarg + 4)) {
- err = getstr(&config->ech_config, nextarg, DENY_BLANK);
- }
- else {
- /* Indirect case: @filename or @- for stdin */
- char *tmpcfg = NULL;
- FILE *file;
-
- nextarg++; /* skip over '@' */
- if(!strcmp("-", nextarg)) {
- file = stdin;
- }
- else {
- file = fopen(nextarg, FOPEN_READTEXT);
- }
- if(!file) {
- warnf(global,
- "Couldn't read file \"%s\" "
- "specified for \"--ech ecl:\" option",
- nextarg);
- return PARAM_BAD_USE; /* */
- }
- err = file2string(&tmpcfg, file);
- if(file != stdin)
- fclose(file);
- if(err)
- return err;
- config->ech_config = aprintf("ecl:%s",tmpcfg);
- if(!config->ech_config)
- return PARAM_NO_MEM;
- free(tmpcfg);
- } /* file done */
- }
- else {
- /* Simple case: just a string, with a keyword */
- err = getstr(&config->ech, nextarg, DENY_BLANK);
+ GetStr(&config->referer, ptr);
}
break;
-#endif
- case C_CAPATH: /* --capath */
- err = getstr(&config->capath, nextarg, DENY_BLANK);
- break;
- case C_PUBKEY: /* --pubkey */
- err = getstr(&config->pubkey, nextarg, DENY_BLANK);
- break;
- case C_HOSTPUBMD5: /* --hostpubmd5 */
- err = getstr(&config->hostpubmd5, nextarg, DENY_BLANK);
- if(!err) {
- if(!config->hostpubmd5 || strlen(config->hostpubmd5) != 32)
+ case 'E':
+ switch(subletter) {
+ case '\0': /* certificate file */
+ cleanarg(clearthis);
+ GetFileAndPassword(nextarg, &config->cert, &config->key_passwd);
+ break;
+ case 'a': /* --cacert CA info PEM file */
+ GetStr(&config->cacert, nextarg);
+ break;
+ case 'G': /* --ca-native */
+ config->native_ca_store = toggle;
+ break;
+ case 'H': /* --proxy-ca-native */
+ config->proxy_native_ca_store = toggle;
+ break;
+ case 'b': /* cert file type */
+ GetStr(&config->cert_type, nextarg);
+ break;
+ case 'c': /* private key file */
+ GetStr(&config->key, nextarg);
+ break;
+ case 'd': /* private key file type */
+ GetStr(&config->key_type, nextarg);
+ break;
+ case 'e': /* private key passphrase */
+ GetStr(&config->key_passwd, nextarg);
+ cleanarg(clearthis);
+ break;
+ case 'f': /* crypto engine */
+ GetStr(&config->engine, nextarg);
+ if(config->engine && curl_strequal(config->engine, "list")) {
+ err = PARAM_ENGINES_REQUESTED;
+ break;
+ }
+ break;
+ case 'g': /* CA cert directory */
+ GetStr(&config->capath, nextarg);
+ break;
+ case 'h': /* --pubkey public key file */
+ GetStr(&config->pubkey, nextarg);
+ break;
+ case 'i': /* --hostpubmd5 md5 of the host public key */
+ GetStr(&config->hostpubmd5, nextarg);
+ if(!config->hostpubmd5 || strlen(config->hostpubmd5) != 32) {
err = PARAM_BAD_USE;
- }
- break;
- case C_HOSTPUBSHA256: /* --hostpubsha256 */
- err = getstr(&config->hostpubsha256, nextarg, DENY_BLANK);
- break;
- case C_CRLFILE: /* --crlfile */
- err = getstr(&config->crlfile, nextarg, DENY_BLANK);
- break;
- case C_TLSUSER: /* --tlsuser */
- if(!feature_tls_srp)
- err = PARAM_LIBCURL_DOESNT_SUPPORT;
- else
- err = getstr(&config->tls_username, nextarg, DENY_BLANK);
- cleanarg(clearthis);
- break;
- case C_TLSPASSWORD: /* --tlspassword */
- if(!feature_tls_srp)
- err = PARAM_LIBCURL_DOESNT_SUPPORT;
- else
- err = getstr(&config->tls_password, nextarg, ALLOW_BLANK);
- cleanarg(clearthis);
- break;
- case C_TLSAUTHTYPE: /* --tlsauthtype */
- if(!feature_tls_srp)
- err = PARAM_LIBCURL_DOESNT_SUPPORT;
- else {
- err = getstr(&config->tls_authtype, nextarg, DENY_BLANK);
- if(!err && strcmp(config->tls_authtype, "SRP"))
+ break;
+ }
+ break;
+ case 'F': /* --hostpubsha256 sha256 of the host public key */
+ GetStr(&config->hostpubsha256, nextarg);
+ break;
+ case 'j': /* CRL file */
+ GetStr(&config->crlfile, nextarg);
+ break;
+ case 'k': /* TLS username */
+ if(!feature_tls_srp) {
+ cleanarg(clearthis);
+ err = PARAM_LIBCURL_DOESNT_SUPPORT;
+ break;
+ }
+ GetStr(&config->tls_username, nextarg);
+ cleanarg(clearthis);
+ break;
+ case 'l': /* TLS password */
+ if(!feature_tls_srp) {
+ cleanarg(clearthis);
+ err = PARAM_LIBCURL_DOESNT_SUPPORT;
+ break;
+ }
+ GetStr(&config->tls_password, nextarg);
+ cleanarg(clearthis);
+ break;
+ case 'm': /* TLS authentication type */
+ if(!feature_tls_srp) {
+ err = PARAM_LIBCURL_DOESNT_SUPPORT;
+ break;
+ }
+ GetStr(&config->tls_authtype, nextarg);
+ if(!curl_strequal(config->tls_authtype, "SRP")) {
err = PARAM_LIBCURL_DOESNT_SUPPORT; /* only support TLS-SRP */
- }
- break;
- case C_SSL_ALLOW_BEAST: /* --ssl-allow-beast */
- if(feature_ssl)
- config->ssl_allow_beast = toggle;
- break;
- case C_SSL_AUTO_CLIENT_CERT: /* --ssl-auto-client-cert */
- if(feature_ssl)
- config->ssl_auto_client_cert = toggle;
- break;
- case C_PROXY_SSL_AUTO_CLIENT_CERT: /* --proxy-ssl-auto-client-cert */
- if(feature_ssl)
- config->proxy_ssl_auto_client_cert = toggle;
- break;
- case C_PINNEDPUBKEY: /* --pinnedpubkey */
- err = getstr(&config->pinnedpubkey, nextarg, DENY_BLANK);
- break;
- case C_PROXY_PINNEDPUBKEY: /* --proxy-pinnedpubkey */
- err = getstr(&config->proxy_pinnedpubkey, nextarg, DENY_BLANK);
- break;
- case C_CERT_STATUS: /* --cert-status */
- config->verifystatus = TRUE;
- break;
- case C_DOH_CERT_STATUS: /* --doh-cert-status */
- config->doh_verifystatus = TRUE;
- break;
- case C_FALSE_START: /* --false-start */
- config->falsestart = TRUE;
- break;
- case C_SSL_NO_REVOKE: /* --ssl-no-revoke */
- if(feature_ssl)
- config->ssl_no_revoke = TRUE;
- break;
- case C_SSL_REVOKE_BEST_EFFORT: /* --ssl-revoke-best-effort */
- if(feature_ssl)
- config->ssl_revoke_best_effort = TRUE;
- break;
- case C_TCP_FASTOPEN: /* --tcp-fastopen */
- config->tcp_fastopen = TRUE;
- break;
- case C_PROXY_TLSUSER: /* --proxy-tlsuser */
- cleanarg(clearthis);
- if(!feature_tls_srp)
- err = PARAM_LIBCURL_DOESNT_SUPPORT;
- else
- err = getstr(&config->proxy_tls_username, nextarg, ALLOW_BLANK);
- break;
- case C_PROXY_TLSPASSWORD: /* --proxy-tlspassword */
- cleanarg(clearthis);
- if(!feature_tls_srp)
- err = PARAM_LIBCURL_DOESNT_SUPPORT;
- else
- err = getstr(&config->proxy_tls_password, nextarg, DENY_BLANK);
- break;
- case C_PROXY_TLSAUTHTYPE: /* --proxy-tlsauthtype */
- if(!feature_tls_srp)
- err = PARAM_LIBCURL_DOESNT_SUPPORT;
- else {
- err = getstr(&config->proxy_tls_authtype, nextarg, DENY_BLANK);
- if(!err && strcmp(config->proxy_tls_authtype, "SRP"))
+ break;
+ }
+ break;
+ case 'n': /* no empty SSL fragments, --ssl-allow-beast */
+ if(feature_ssl)
+ config->ssl_allow_beast = toggle;
+ break;
+
+ case 'o': /* --ssl-auto-client-cert */
+ if(feature_ssl)
+ config->ssl_auto_client_cert = toggle;
+ break;
+
+ case 'O': /* --proxy-ssl-auto-client-cert */
+ if(feature_ssl)
+ config->proxy_ssl_auto_client_cert = toggle;
+ break;
+
+ case 'p': /* Pinned public key DER file */
+ GetStr(&config->pinnedpubkey, nextarg);
+ break;
+
+ case 'P': /* proxy pinned public key */
+ GetStr(&config->proxy_pinnedpubkey, nextarg);
+ break;
+
+ case 'q': /* --cert-status */
+ config->verifystatus = TRUE;
+ break;
+
+ case 'Q': /* --doh-cert-status */
+ config->doh_verifystatus = TRUE;
+ break;
+
+ case 'r': /* --false-start */
+ config->falsestart = TRUE;
+ break;
+
+ case 's': /* --ssl-no-revoke */
+ if(feature_ssl)
+ config->ssl_no_revoke = TRUE;
+ break;
+
+ case 'S': /* --ssl-revoke-best-effort */
+ if(feature_ssl)
+ config->ssl_revoke_best_effort = TRUE;
+ break;
+
+ case 't': /* --tcp-fastopen */
+ config->tcp_fastopen = TRUE;
+ break;
+
+ case 'u': /* TLS username for proxy */
+ cleanarg(clearthis);
+ if(!feature_tls_srp) {
+ err = PARAM_LIBCURL_DOESNT_SUPPORT;
+ break;
+ }
+ GetStr(&config->proxy_tls_username, nextarg);
+ break;
+
+ case 'v': /* TLS password for proxy */
+ cleanarg(clearthis);
+ if(!feature_tls_srp) {
+ err = PARAM_LIBCURL_DOESNT_SUPPORT;
+ break;
+ }
+ GetStr(&config->proxy_tls_password, nextarg);
+ break;
+
+ case 'w': /* TLS authentication type for proxy */
+ if(!feature_tls_srp) {
+ err = PARAM_LIBCURL_DOESNT_SUPPORT;
+ break;
+ }
+ GetStr(&config->proxy_tls_authtype, nextarg);
+ if(!curl_strequal(config->proxy_tls_authtype, "SRP")) {
err = PARAM_LIBCURL_DOESNT_SUPPORT; /* only support TLS-SRP */
+ break;
+ }
+ break;
+
+ case 'x': /* certificate file for proxy */
+ cleanarg(clearthis);
+ GetFileAndPassword(nextarg, &config->proxy_cert,
+ &config->proxy_key_passwd);
+ break;
+
+ case 'y': /* cert file type for proxy */
+ GetStr(&config->proxy_cert_type, nextarg);
+ break;
+
+ case 'z': /* private key file for proxy */
+ GetStr(&config->proxy_key, nextarg);
+ break;
+
+ case '0': /* private key file type for proxy */
+ GetStr(&config->proxy_key_type, nextarg);
+ break;
+
+ case '1': /* private key passphrase for proxy */
+ GetStr(&config->proxy_key_passwd, nextarg);
+ cleanarg(clearthis);
+ break;
+
+ case '2': /* ciphers for proxy */
+ GetStr(&config->proxy_cipher_list, nextarg);
+ break;
+
+ case '3': /* CRL file for proxy */
+ GetStr(&config->proxy_crlfile, nextarg);
+ break;
+
+ case '4': /* no empty SSL fragments for proxy */
+ if(feature_ssl)
+ config->proxy_ssl_allow_beast = toggle;
+ break;
+
+ case '5': /* --login-options */
+ GetStr(&config->login_options, nextarg);
+ break;
+
+ case '6': /* CA info PEM file for proxy */
+ GetStr(&config->proxy_cacert, nextarg);
+ break;
+
+ case '7': /* CA cert directory for proxy */
+ GetStr(&config->proxy_capath, nextarg);
+ break;
+
+ case '8': /* allow insecure SSL connects for proxy */
+ config->proxy_insecure_ok = toggle;
+ break;
+
+ case '9': /* --proxy-tlsv1 */
+ /* TLS version 1 for proxy */
+ config->proxy_ssl_version = CURL_SSLVERSION_TLSv1;
+ break;
+
+ case 'A':
+ /* --socks5-basic */
+ if(toggle)
+ config->socks5_auth |= CURLAUTH_BASIC;
+ else
+ config->socks5_auth &= ~CURLAUTH_BASIC;
+ break;
+
+ case 'B':
+ /* --socks5-gssapi */
+ if(toggle)
+ config->socks5_auth |= CURLAUTH_GSSAPI;
+ else
+ config->socks5_auth &= ~CURLAUTH_GSSAPI;
+ break;
+
+ case 'C':
+ GetStr(&config->etag_save_file, nextarg);
+ break;
+
+ case 'D':
+ GetStr(&config->etag_compare_file, nextarg);
+ break;
+
+ case 'E':
+ GetStr(&config->ssl_ec_curves, nextarg);
+ break;
+
+ default: /* unknown flag */
+ err = PARAM_OPTION_UNKNOWN;
+ break;
}
break;
- case C_PROXY_CERT: /* --proxy-cert */
- cleanarg(clearthis);
- GetFileAndPassword(nextarg, &config->proxy_cert,
- &config->proxy_key_passwd);
- break;
- case C_PROXY_CERT_TYPE: /* --proxy-cert-type */
- err = getstr(&config->proxy_cert_type, nextarg, DENY_BLANK);
- break;
- case C_PROXY_KEY: /* --proxy-key */
- err = getstr(&config->proxy_key, nextarg, ALLOW_BLANK);
- break;
- case C_PROXY_KEY_TYPE: /* --proxy-key-type */
- err = getstr(&config->proxy_key_type, nextarg, DENY_BLANK);
- break;
- case C_PROXY_PASS: /* --proxy-pass */
- err = getstr(&config->proxy_key_passwd, nextarg, ALLOW_BLANK);
- cleanarg(clearthis);
- break;
- case C_PROXY_CIPHERS: /* --proxy-ciphers */
- err = getstr(&config->proxy_cipher_list, nextarg, DENY_BLANK);
- break;
- case C_PROXY_CRLFILE: /* --proxy-crlfile */
- err = getstr(&config->proxy_crlfile, nextarg, DENY_BLANK);
- break;
- case C_PROXY_SSL_ALLOW_BEAST: /* --proxy-ssl-allow-beast */
- if(feature_ssl)
- config->proxy_ssl_allow_beast = toggle;
- break;
- case C_LOGIN_OPTIONS: /* --login-options */
- err = getstr(&config->login_options, nextarg, ALLOW_BLANK);
- break;
- case C_PROXY_CACERT: /* --proxy-cacert */
- err = getstr(&config->proxy_cacert, nextarg, DENY_BLANK);
- break;
- case C_PROXY_CAPATH: /* --proxy-capath */
- err = getstr(&config->proxy_capath, nextarg, DENY_BLANK);
- break;
- case C_PROXY_INSECURE: /* --proxy-insecure */
- config->proxy_insecure_ok = toggle;
- break;
- case C_PROXY_TLSV1: /* --proxy-tlsv1 */
- /* TLS version 1 for proxy */
- config->proxy_ssl_version = CURL_SSLVERSION_TLSv1;
- break;
- case C_SOCKS5_BASIC: /* --socks5-basic */
- if(toggle)
- config->socks5_auth |= CURLAUTH_BASIC;
- else
- config->socks5_auth &= ~CURLAUTH_BASIC;
- break;
- case C_SOCKS5_GSSAPI: /* --socks5-gssapi */
- if(toggle)
- config->socks5_auth |= CURLAUTH_GSSAPI;
- else
- config->socks5_auth &= ~CURLAUTH_GSSAPI;
- break;
- case C_ETAG_SAVE: /* --etag-save */
- err = getstr(&config->etag_save_file, nextarg, DENY_BLANK);
- break;
- case C_ETAG_COMPARE: /* --etag-compare */
- err = getstr(&config->etag_compare_file, nextarg, DENY_BLANK);
- break;
- case C_CURVES: /* --curves */
- err = getstr(&config->ssl_ec_curves, nextarg, DENY_BLANK);
- break;
- case C_FAIL_EARLY: /* --fail-early */
- global->fail_early = toggle;
- break;
- case C_STYLED_OUTPUT: /* --styled-output */
- global->styled_output = toggle;
- break;
- case C_MAIL_RCPT_ALLOWFAILS: /* --mail-rcpt-allowfails */
- config->mail_rcpt_allowfails = toggle;
- break;
- case C_FAIL_WITH_BODY: /* --fail-with-body */
- config->failwithbody = toggle;
- if(config->failonerror && config->failwithbody) {
- errorf(config->global, "You must select either --fail or "
- "--fail-with-body, not both.");
- err = PARAM_BAD_USE;
+ case 'f':
+ switch(subletter) {
+ case 'a': /* --fail-early */
+ global->fail_early = toggle;
+ break;
+ case 'b': /* --styled-output */
+ global->styled_output = toggle;
+ break;
+ case 'c': /* --mail-rcpt-allowfails */
+ config->mail_rcpt_allowfails = toggle;
+ break;
+ case 'd': /* --fail-with-body */
+ config->failwithbody = toggle;
+ break;
+ case 'e': /* --remove-on-error */
+ config->rm_partial = toggle;
+ break;
+ default: /* --fail (hard on errors) */
+ config->failonerror = toggle;
+ break;
}
- break;
- case C_REMOVE_ON_ERROR: /* --remove-on-error */
- config->rm_partial = toggle;
- break;
- case C_FAIL: /* --fail */
- config->failonerror = toggle;
if(config->failonerror && config->failwithbody) {
errorf(config->global, "You must select either --fail or "
"--fail-with-body, not both.");
err = PARAM_BAD_USE;
+ break;
}
break;
- case C_FORM: /* --form */
- case C_FORM_STRING: /* --form-string */
+ case 'F':
/* "form data" simulation, this is a little advanced so lets do our best
to sort this out slowly and carefully */
if(formparse(config,
nextarg,
&config->mimeroot,
&config->mimecurrent,
- (cmd == C_FORM_STRING)?TRUE:FALSE)) /* literal string */
+ (subletter == 's')?TRUE:FALSE)) { /* 's' is literal
+ string */
err = PARAM_BAD_USE;
- else if(SetHTTPrequest(config, TOOL_HTTPREQ_MIMEPOST, &config->httpreq))
+ break;
+ }
+ if(SetHTTPrequest(config, HTTPREQ_MIMEPOST, &config->httpreq)) {
err = PARAM_BAD_USE;
+ break;
+ }
break;
- case C_GLOBOFF: /* --globoff */
+
+ case 'g': /* g disables URLglobbing */
config->globoff = toggle;
break;
- case C_GET: /* --get */
- config->use_httpget = toggle;
- break;
- case C_REQUEST_TARGET: /* --request-target */
- err = getstr(&config->request_target, nextarg, DENY_BLANK);
+
+ case 'G': /* HTTP GET */
+ if(subletter == 'a') { /* --request-target */
+ GetStr(&config->request_target, nextarg);
+ }
+ else
+ config->use_httpget = toggle;
break;
- case C_HELP: /* --help */
+
+ case 'h': /* h for help */
if(toggle) {
- if(*nextarg) {
+ if(nextarg) {
global->help_category = strdup(nextarg);
if(!global->help_category) {
err = PARAM_NO_MEM;
@@ -2187,11 +2197,11 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
}
}
err = PARAM_HELP_REQUESTED;
+ break;
}
/* we now actually support --no-help too! */
break;
- case C_HEADER: /* --header */
- case C_PROXY_HEADER: /* --proxy-header */
+ case 'H':
/* A custom header to append to a list */
if(nextarg[0] == '@') {
/* read many headers from a file or stdin */
@@ -2202,15 +2212,16 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
if(!file) {
errorf(global, "Failed to open %s", &nextarg[1]);
err = PARAM_READ_ERROR;
+ break;
}
else {
err = file2memory(&string, &len, file);
if(!err && string) {
- /* Allow strtok() here since this is not used threaded */
+ /* Allow strtok() here since this isn't used threaded */
/* !checksrc! disable BANNEDFUNC 2 */
char *h = strtok(string, "\r\n");
while(h) {
- if(cmd == C_PROXY_HEADER) /* --proxy-header */
+ if(subletter == 'p') /* --proxy-header */
err = add2list(&config->proxyheaders, h);
else
err = add2list(&config->headers, h);
@@ -2222,102 +2233,119 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
}
if(!use_stdin)
fclose(file);
+ if(err)
+ break;
}
}
else {
- if(cmd == C_PROXY_HEADER) /* --proxy-header */
+ if(subletter == 'p') /* --proxy-header */
err = add2list(&config->proxyheaders, nextarg);
else
err = add2list(&config->headers, nextarg);
}
break;
- case C_INCLUDE: /* --include */
- case C_SHOW_HEADERS: /* --show-headers */
+ case 'i':
config->show_headers = toggle; /* show the headers as well in the
general output stream */
break;
- case C_JUNK_SESSION_COOKIES: /* --junk-session-cookies */
+ case 'j':
config->cookiesession = toggle;
break;
- case C_HEAD: /* --head */
+ case 'I': /* --head */
config->no_body = toggle;
config->show_headers = toggle;
if(SetHTTPrequest(config,
- (config->no_body)?TOOL_HTTPREQ_HEAD:TOOL_HTTPREQ_GET,
- &config->httpreq))
+ (config->no_body)?HTTPREQ_HEAD:HTTPREQ_GET,
+ &config->httpreq)) {
err = PARAM_BAD_USE;
+ break;
+ }
break;
- case C_REMOTE_HEADER_NAME: /* --remote-header-name */
+ case 'J': /* --remote-header-name */
config->content_disposition = toggle;
break;
- case C_INSECURE: /* --insecure */
- config->insecure_ok = toggle;
- break;
- case C_DOH_INSECURE: /* --doh-insecure */
- config->doh_insecure_ok = toggle;
+ case 'k': /* allow insecure SSL connects */
+ if(subletter == 'd') /* --doh-insecure */
+ config->doh_insecure_ok = toggle;
+ else
+ config->insecure_ok = toggle;
break;
- case C_CONFIG: /* --config */
+ case 'K': /* parse config file */
if(parseconfig(nextarg, global)) {
errorf(global, "cannot read config from '%s'", nextarg);
err = PARAM_READ_ERROR;
+ break;
}
break;
- case C_LIST_ONLY: /* --list-only */
+ case 'l':
config->dirlistonly = toggle; /* only list the names of the FTP dir */
break;
- case C_LOCATION_TRUSTED: /* --location-trusted */
- /* Continue to send authentication (user+password) when following
- * locations, even when hostname changed */
- config->unrestricted_auth = toggle;
- FALLTHROUGH();
- case C_LOCATION: /* --location */
+ case 'L':
config->followlocation = toggle; /* Follow Location: HTTP headers */
+ switch(subletter) {
+ case 't':
+ /* Continue to send authentication (user+password) when following
+ * locations, even when hostname changed */
+ config->unrestricted_auth = toggle;
+ break;
+ }
break;
- case C_MAX_TIME: /* --max-time */
+ case 'm':
/* specified max time */
err = secs2ms(&config->timeout_ms, nextarg);
break;
- case C_MANUAL: /* --manual */
+ case 'M': /* M for manual, huge help */
if(toggle) { /* --no-manual shows no manual... */
#ifndef USE_MANUAL
warnf(global,
"built-in manual was disabled at build-time");
#endif
err = PARAM_MANUAL_REQUESTED;
+ break;
}
break;
- case C_NETRC_OPTIONAL: /* --netrc-optional */
- config->netrc_opt = toggle;
- break;
- case C_NETRC_FILE: /* --netrc-file */
- err = getstr(&config->netrc_file, nextarg, DENY_BLANK);
- break;
- case C_NETRC: /* --netrc */
- /* pick info from .netrc, if this is used for http, curl will
- automatically enforce user+password with the request */
- config->netrc = toggle;
+ case 'n':
+ switch(subletter) {
+ case 'o': /* use .netrc or URL */
+ config->netrc_opt = toggle;
+ break;
+ case 'e': /* netrc-file */
+ GetStr(&config->netrc_file, nextarg);
+ break;
+ default:
+ /* pick info from .netrc, if this is used for http, curl will
+ automatically enforce user+password with the request */
+ config->netrc = toggle;
+ break;
+ }
break;
- case C_BUFFER: /* --buffer */
+ case 'N':
/* disable the output I/O buffering. note that the option is called
--buffer but is mostly used in the negative form: --no-buffer */
config->nobuffer = longopt ? !toggle : TRUE;
break;
- case C_REMOTE_NAME_ALL: /* --remote-name-all */
- config->default_node_flags = toggle?GETOUT_USEREMOTE:0;
- break;
- case C_OUTPUT_DIR: /* --output-dir */
- err = getstr(&config->output_dir, nextarg, DENY_BLANK);
- break;
- case C_CLOBBER: /* --clobber */
- config->file_clobber_mode = toggle ? CLOBBER_ALWAYS : CLOBBER_NEVER;
- break;
- case C_OUTPUT: /* --output */
- case C_REMOTE_NAME: /* --remote-name */
+ case 'O': /* --remote-name */
+ if(subletter == 'a') { /* --remote-name-all */
+ config->default_node_flags = toggle?GETOUT_USEREMOTE:0;
+ break;
+ }
+ else if(subletter == 'b') { /* --output-dir */
+ GetStr(&config->output_dir, nextarg);
+ break;
+ }
+ else if(subletter == 'c') { /* --clobber / --no-clobber */
+ config->file_clobber_mode = toggle ? CLOBBER_ALWAYS : CLOBBER_NEVER;
+ break;
+ }
+ /* FALLTHROUGH */
+ case 'o': /* --output */
/* output file */
+ {
+ struct getout *url;
if(!config->url_out)
config->url_out = config->url_list;
if(config->url_out) {
- /* there is a node here, if it already is filled-in continue to find
+ /* there's a node here, if it already is filled-in continue to find
an "empty" node */
while(config->url_out && (config->url_out->flags & GETOUT_OUTFILE))
config->url_out = config->url_out->next;
@@ -2342,7 +2370,12 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
/* fill in the outfile */
if('o' == letter) {
- err = getstr(&url->outfile, nextarg, DENY_BLANK);
+ if(!*nextarg) {
+ warnf(global, "output file name has no length");
+ err = PARAM_BAD_USE;
+ break;
+ }
+ GetStr(&url->outfile, nextarg);
url->flags &= ~GETOUT_USEREMOTE; /* switch off */
}
else {
@@ -2353,25 +2386,25 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
url->flags &= ~GETOUT_USEREMOTE; /* switch off */
}
url->flags |= GETOUT_OUTFILE;
- break;
- case C_FTP_PORT: /* --ftp-port */
+ }
+ break;
+ case 'P':
/* This makes the FTP sessions use PORT instead of PASV */
/* use <eth0> or <192.168.10.10> style addresses. Anything except
this will make us try to get the "default" address.
NOTE: this is a changed behavior since the released 4.1!
*/
- err = getstr(&config->ftpport, nextarg, DENY_BLANK);
+ GetStr(&config->ftpport, nextarg);
break;
- case C_PROXYTUNNEL: /* --proxytunnel */
+ case 'p':
/* proxy tunnel for non-http protocols */
config->proxytunnel = toggle;
break;
- case C_DISABLE: /* --disable */
- /* if used first, already taken care of, we do it like this so we do not
- cause an error! */
+ case 'q': /* if used first, already taken care of, we do it like
+ this so we don't cause an error! */
break;
- case C_QUOTE: /* --quote */
+ case 'Q':
/* QUOTE command to send to FTP server */
switch(nextarg[0]) {
case '-':
@@ -2389,33 +2422,34 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
break;
}
break;
- case C_RANGE: /* --range */
+ case 'r':
/* Specifying a range WITHOUT A DASH will create an illegal HTTP range
- (and will not actually be range by definition). The manpage
- previously claimed that to be a good way, why this code is added to
- work-around it. */
+ (and won't actually be range by definition). The man page previously
+ claimed that to be a good way, why this code is added to work-around
+ it. */
if(ISDIGIT(*nextarg) && !strchr(nextarg, '-')) {
char buffer[32];
- if(curlx_strtoofft(nextarg, NULL, 10, &value)) {
+ curl_off_t off;
+ if(curlx_strtoofft(nextarg, NULL, 10, &off)) {
warnf(global, "unsupported range point");
err = PARAM_BAD_USE;
+ break;
}
- else {
- warnf(global,
- "A specified range MUST include at least one dash (-). "
- "Appending one for you");
- msnprintf(buffer, sizeof(buffer), "%" CURL_FORMAT_CURL_OFF_T "-",
- value);
- Curl_safefree(config->range);
- config->range = strdup(buffer);
- if(!config->range)
- err = PARAM_NO_MEM;
+ warnf(global,
+ "A specified range MUST include at least one dash (-). "
+ "Appending one for you");
+ msnprintf(buffer, sizeof(buffer), "%" CURL_FORMAT_CURL_OFF_T "-", off);
+ Curl_safefree(config->range);
+ config->range = strdup(buffer);
+ if(!config->range) {
+ err = PARAM_NO_MEM;
+ break;
}
}
else {
/* byte range requested */
const char *tmp_range = nextarg;
- while(*tmp_range) {
+ while(*tmp_range != '\0') {
if(!ISDIGIT(*tmp_range) && *tmp_range != '-' && *tmp_range != ',') {
warnf(global, "Invalid character is found in given range. "
"A specified range MUST have only digits in "
@@ -2425,32 +2459,31 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
}
tmp_range++;
}
- err = getstr(&config->range, nextarg, DENY_BLANK);
+ GetStr(&config->range, nextarg);
}
break;
- case C_REMOTE_TIME: /* --remote-time */
+ case 'R':
/* use remote file's time */
config->remote_time = toggle;
break;
- case C_SILENT: /* --silent */
+ case 's': /* --silent */
global->silent = toggle;
break;
- case C_SKIP_EXISTING: /* --skip-existing */
- config->skip_existing = toggle;
- break;
- case C_SHOW_ERROR: /* --show-error */
+ case 'S': /* --show-error */
global->showerror = toggle;
break;
- case C_TELNET_OPTION: /* --telnet-option */
+ case 't':
/* Telnet options */
err = add2list(&config->telnet_options, nextarg);
break;
- case C_UPLOAD_FILE: /* --upload-file */
+ case 'T':
/* we are uploading */
+ {
+ struct getout *url;
if(!config->url_ul)
config->url_ul = config->url_list;
if(config->url_ul) {
- /* there is a node here, if it already is filled-in continue to find
+ /* there's a node here, if it already is filled-in continue to find
an "empty" node */
while(config->url_ul && (config->url_ul->flags & GETOUT_UPLOAD))
config->url_ul = config->url_ul->next;
@@ -2475,81 +2508,49 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
url->flags |= GETOUT_NOUPLOAD;
else {
/* "-" equals stdin, but keep the string around for now */
- err = getstr(&url->infile, nextarg, DENY_BLANK);
+ GetStr(&url->infile, nextarg);
}
- break;
- case C_USER: /* --user */
+ }
+ break;
+ case 'u':
/* user:password */
- err = getstr(&config->userpwd, nextarg, ALLOW_BLANK);
+ GetStr(&config->userpwd, nextarg);
cleanarg(clearthis);
break;
- case C_PROXY_USER: /* --proxy-user */
+ case 'U':
/* Proxy user:password */
- err = getstr(&config->proxyuserpwd, nextarg, ALLOW_BLANK);
+ GetStr(&config->proxyuserpwd, nextarg);
cleanarg(clearthis);
break;
- case C_VERBOSE: /* --verbose */
- /* This option is a super-boolean with side effect when applied
- * more than once in the same argument flag, like `-vvv`. */
- if(!toggle) {
- global->verbosity = 0;
- if(set_trace_config(global, "-all"))
- err = PARAM_NO_MEM;
- global->tracetype = TRACE_NONE;
- break;
- }
- else if(!nopts) {
- /* fist `-v` in an argument resets to base verbosity */
- global->verbosity = 0;
- if(set_trace_config(global, "-all")) {
- err = PARAM_NO_MEM;
- break;
- }
- }
- /* the '%' thing here will cause the trace get sent to stderr */
- switch(global->verbosity) {
- case 0:
- global->verbosity = 1;
+ case 'v':
+ if(toggle) {
+ /* the '%' thing here will cause the trace get sent to stderr */
Curl_safefree(global->trace_dump);
global->trace_dump = strdup("%");
- if(!global->trace_dump)
+ if(!global->trace_dump) {
err = PARAM_NO_MEM;
- else {
- if(global->tracetype && (global->tracetype != TRACE_PLAIN))
- warnf(global,
- "-v, --verbose overrides an earlier trace option");
- global->tracetype = TRACE_PLAIN;
+ break;
}
- break;
- case 1:
- global->verbosity = 2;
- if(set_trace_config(global, "ids,time,protocol"))
- err = PARAM_NO_MEM;
- break;
- case 2:
- global->verbosity = 3;
- global->tracetype = TRACE_ASCII;
- if(set_trace_config(global, "ssl,read,write"))
- err = PARAM_NO_MEM;
- break;
- case 3:
- global->verbosity = 4;
- if(set_trace_config(global, "network"))
- err = PARAM_NO_MEM;
- break;
- default:
- /* no effect for now */
- break;
+ if(global->tracetype && (global->tracetype != TRACE_PLAIN))
+ warnf(global,
+ "-v, --verbose overrides an earlier trace/verbose option");
+ global->tracetype = TRACE_PLAIN;
}
+ else
+ /* verbose is disabled here */
+ global->tracetype = TRACE_NONE;
break;
- case C_VERSION: /* --version */
- if(toggle) /* --no-version yields no output! */
+ case 'V':
+ if(toggle) { /* --no-version yields no output! */
err = PARAM_VERSION_INFO_REQUESTED;
+ break;
+ }
break;
- case C_WRITE_OUT: /* --write-out */
+
+ case 'w':
/* get the output string */
if('@' == *nextarg) {
- /* the data begins with a '@' letter, it means that a filename
+ /* the data begins with a '@' letter, it means that a file name
or - (stdin) follows */
FILE *file;
const char *fname;
@@ -2577,57 +2578,69 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
warnf(global, "Failed to read %s", fname);
}
else
- err = getstr(&config->writeout, nextarg, ALLOW_BLANK);
+ GetStr(&config->writeout, nextarg);
break;
- case C_PREPROXY: /* --preproxy */
- err = getstr(&config->preproxy, nextarg, DENY_BLANK);
- break;
- case C_PROXY: /* --proxy */
- /* --proxy */
- err = getstr(&config->proxy, nextarg, ALLOW_BLANK);
- if(config->proxyver != CURLPROXY_HTTPS2)
- config->proxyver = CURLPROXY_HTTP;
+ case 'x':
+ switch(subletter) {
+ case 'a': /* --preproxy */
+ GetStr(&config->preproxy, nextarg);
+ break;
+ default:
+ /* --proxy */
+ GetStr(&config->proxy, nextarg);
+ if(config->proxyver != CURLPROXY_HTTPS2)
+ config->proxyver = CURLPROXY_HTTP;
+ break;
+ }
break;
- case C_REQUEST: /* --request */
+ case 'X':
/* set custom request */
- err = getstr(&config->customrequest, nextarg, DENY_BLANK);
+ GetStr(&config->customrequest, nextarg);
break;
- case C_SPEED_TIME: /* --speed-time */
+ case 'y':
/* low speed time */
err = str2unum(&config->low_speed_time, nextarg);
- if(!err && !config->low_speed_limit)
+ if(err)
+ break;
+ if(!config->low_speed_limit)
config->low_speed_limit = 1;
break;
- case C_SPEED_LIMIT: /* --speed-limit */
+ case 'Y':
/* low speed limit */
err = str2unum(&config->low_speed_limit, nextarg);
- if(!err && !config->low_speed_time)
- config->low_speed_time = 30;
- break;
- case C_PARALLEL: /* --parallel */
- global->parallel = toggle;
- break;
- case C_PARALLEL_MAX: { /* --parallel-max */
- long val;
- err = str2unum(&val, nextarg);
if(err)
break;
- if(val > MAX_PARALLEL)
- global->parallel_max = MAX_PARALLEL;
- else if(val < 1)
- global->parallel_max = PARALLEL_DEFAULT;
- else
- global->parallel_max = (unsigned short)val;
+ if(!config->low_speed_time)
+ config->low_speed_time = 30;
break;
- }
- case C_PARALLEL_IMMEDIATE: /* --parallel-immediate */
- global->parallel_connect = toggle;
+ case 'Z':
+ switch(subletter) {
+ case '\0': /* --parallel */
+ global->parallel = toggle;
+ break;
+ case 'b': { /* --parallel-max */
+ long val;
+ err = str2unum(&val, nextarg);
+ if(err)
+ break;
+ if(val > MAX_PARALLEL)
+ global->parallel_max = MAX_PARALLEL;
+ else if(val < 1)
+ global->parallel_max = PARALLEL_DEFAULT;
+ else
+ global->parallel_max = (unsigned short)val;
+ break;
+ }
+ case 'c': /* --parallel-immediate */
+ global->parallel_connect = toggle;
+ break;
+ }
break;
- case C_TIME_COND: /* --time-cond */
+ case 'z': /* time condition coming up */
switch(*nextarg) {
case '+':
nextarg++;
- FALLTHROUGH();
+ /* FALLTHROUGH */
default:
/* If-Modified-Since: (section 14.28 in RFC2068) */
config->timecond = CURL_TIMECOND_IFMODSINCE;
@@ -2646,30 +2659,28 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
now = time(NULL);
config->condtime = (curl_off_t)curl_getdate(nextarg, &now);
if(-1 == config->condtime) {
- /* now let's see if it is a filename to get the time from instead! */
- rc = getfiletime(nextarg, global, &value);
+ /* now let's see if it is a file name to get the time from instead! */
+ curl_off_t filetime;
+ rc = getfiletime(nextarg, global, &filetime);
if(!rc)
/* pull the time out from the file */
- config->condtime = value;
+ config->condtime = filetime;
else {
/* failed, remove time condition */
config->timecond = CURL_TIMECOND_NONE;
warnf(global,
"Illegal date format for -z, --time-cond (and not "
- "a filename). Disabling time condition. "
+ "a file name). Disabling time condition. "
"See curl_getdate(3) for valid date syntax.");
}
}
break;
- case C_MPTCP: /* --mptcp */
- config->mptcp = TRUE;
- break;
default: /* unknown flag */
err = PARAM_OPTION_UNKNOWN;
break;
}
- a = NULL;
- ++nopts; /* processed one option from `flag` input, loop for more */
+ hit = -1;
+
} while(!longopt && !singleopt && *++parse && !*usedarg && !err);
error:
@@ -2745,7 +2756,7 @@ ParameterError parse_args(struct GlobalConfig *global, int argc,
}
}
else if(!result && passarg)
- i++; /* we are supposed to skip this */
+ i++; /* we're supposed to skip this */
}
}
else {
@@ -2769,8 +2780,7 @@ ParameterError parse_args(struct GlobalConfig *global, int argc,
if(result && result != PARAM_HELP_REQUESTED &&
result != PARAM_MANUAL_REQUESTED &&
result != PARAM_VERSION_INFO_REQUESTED &&
- result != PARAM_ENGINES_REQUESTED &&
- result != PARAM_CA_EMBED_REQUESTED) {
+ result != PARAM_ENGINES_REQUESTED) {
const char *reason = param2text(result);
if(orig_opt && strcmp(":", orig_opt))
diff --git a/contrib/libs/curl/src/tool_getparam.h b/contrib/libs/curl/src/tool_getparam.h
index 9d6c72ef82..a8a9d45975 100644
--- a/contrib/libs/curl/src/tool_getparam.h
+++ b/contrib/libs/curl/src/tool_getparam.h
@@ -25,302 +25,6 @@
***************************************************************************/
#include "tool_setup.h"
-/* one enum for every command line option. The name is the verbatim long
- option name, but in uppercase with periods and minuses replaced with
- underscores using a "C_" prefix. */
-typedef enum {
- C_ABSTRACT_UNIX_SOCKET,
- C_ALPN,
- C_ALT_SVC,
- C_ANYAUTH,
- C_APPEND,
- C_AWS_SIGV4,
- C_BASIC,
- C_BUFFER,
- C_CA_NATIVE,
- C_CACERT,
- C_CAPATH,
- C_CERT,
- C_CERT_STATUS,
- C_CERT_TYPE,
- C_CIPHERS,
- C_CLOBBER,
- C_COMPRESSED,
- C_COMPRESSED_SSH,
- C_CONFIG,
- C_CONNECT_TIMEOUT,
- C_CONNECT_TO,
- C_CONTINUE_AT,
- C_COOKIE,
- C_COOKIE_JAR,
- C_CREATE_DIRS,
- C_CREATE_FILE_MODE,
- C_CRLF,
- C_CRLFILE,
- C_CURVES,
- C_DATA,
- C_DATA_ASCII,
- C_DATA_BINARY,
- C_DATA_RAW,
- C_DATA_URLENCODE,
- C_DELEGATION,
- C_DIGEST,
- C_DISABLE,
- C_DISABLE_EPRT,
- C_DISABLE_EPSV,
- C_DISALLOW_USERNAME_IN_URL,
- C_DNS_INTERFACE,
- C_DNS_IPV4_ADDR,
- C_DNS_IPV6_ADDR,
- C_DNS_SERVERS,
- C_DOH_CERT_STATUS,
- C_DOH_INSECURE,
- C_DOH_URL,
- C_DUMP_CA_EMBED,
- C_DUMP_HEADER,
- C_ECH,
- C_EGD_FILE,
- C_ENGINE,
- C_EPRT,
- C_EPSV,
- C_ETAG_COMPARE,
- C_ETAG_SAVE,
- C_EXPECT100_TIMEOUT,
- C_FAIL,
- C_FAIL_EARLY,
- C_FAIL_WITH_BODY,
- C_FALSE_START,
- C_FORM,
- C_FORM_ESCAPE,
- C_FORM_STRING,
- C_FTP_ACCOUNT,
- C_FTP_ALTERNATIVE_TO_USER,
- C_FTP_CREATE_DIRS,
- C_FTP_METHOD,
- C_FTP_PASV,
- C_FTP_PORT,
- C_FTP_PRET,
- C_FTP_SKIP_PASV_IP,
- C_FTP_SSL,
- C_FTP_SSL_CCC,
- C_FTP_SSL_CCC_MODE,
- C_FTP_SSL_CONTROL,
- C_FTP_SSL_REQD,
- C_GET,
- C_GLOBOFF,
- C_HAPPY_EYEBALLS_TIMEOUT_MS,
- C_HAPROXY_CLIENTIP,
- C_HAPROXY_PROTOCOL,
- C_HEAD,
- C_HEADER,
- C_HELP,
- C_HOSTPUBMD5,
- C_HOSTPUBSHA256,
- C_HSTS,
- C_HTTP0_9,
- C_HTTP1_0,
- C_HTTP1_1,
- C_HTTP2,
- C_HTTP2_PRIOR_KNOWLEDGE,
- C_HTTP3,
- C_HTTP3_ONLY,
- C_IGNORE_CONTENT_LENGTH,
- C_INCLUDE,
- C_INSECURE,
- C_INTERFACE,
- C_IPFS_GATEWAY,
- C_IPV4,
- C_IPV6,
- C_JSON,
- C_JUNK_SESSION_COOKIES,
- C_KEEPALIVE,
- C_KEEPALIVE_CNT,
- C_KEEPALIVE_TIME,
- C_KEY,
- C_KEY_TYPE,
- C_KRB,
- C_KRB4,
- C_LIBCURL,
- C_LIMIT_RATE,
- C_LIST_ONLY,
- C_LOCAL_PORT,
- C_LOCATION,
- C_LOCATION_TRUSTED,
- C_LOGIN_OPTIONS,
- C_MAIL_AUTH,
- C_MAIL_FROM,
- C_MAIL_RCPT,
- C_MAIL_RCPT_ALLOWFAILS,
- C_MANUAL,
- C_MAX_FILESIZE,
- C_MAX_REDIRS,
- C_MAX_TIME,
- C_METALINK,
- C_MPTCP,
- C_NEGOTIATE,
- C_NETRC,
- C_NETRC_FILE,
- C_NETRC_OPTIONAL,
- C_NEXT,
- C_NOPROXY,
- C_NPN,
- C_NTLM,
- C_NTLM_WB,
- C_OAUTH2_BEARER,
- C_OUTPUT,
- C_OUTPUT_DIR,
- C_PARALLEL,
- C_PARALLEL_IMMEDIATE,
- C_PARALLEL_MAX,
- C_PASS,
- C_PATH_AS_IS,
- C_PINNEDPUBKEY,
- C_POST301,
- C_POST302,
- C_POST303,
- C_PREPROXY,
- C_PROGRESS_BAR,
- C_PROGRESS_METER,
- C_PROTO,
- C_PROTO_DEFAULT,
- C_PROTO_REDIR,
- C_PROXY,
- C_PROXY_ANYAUTH,
- C_PROXY_BASIC,
- C_PROXY_CA_NATIVE,
- C_PROXY_CACERT,
- C_PROXY_CAPATH,
- C_PROXY_CERT,
- C_PROXY_CERT_TYPE,
- C_PROXY_CIPHERS,
- C_PROXY_CRLFILE,
- C_PROXY_DIGEST,
- C_PROXY_HEADER,
- C_PROXY_HTTP2,
- C_PROXY_INSECURE,
- C_PROXY_KEY,
- C_PROXY_KEY_TYPE,
- C_PROXY_NEGOTIATE,
- C_PROXY_NTLM,
- C_PROXY_PASS,
- C_PROXY_PINNEDPUBKEY,
- C_PROXY_SERVICE_NAME,
- C_PROXY_SSL_ALLOW_BEAST,
- C_PROXY_SSL_AUTO_CLIENT_CERT,
- C_PROXY_TLS13_CIPHERS,
- C_PROXY_TLSAUTHTYPE,
- C_PROXY_TLSPASSWORD,
- C_PROXY_TLSUSER,
- C_PROXY_TLSV1,
- C_PROXY_USER,
- C_PROXY1_0,
- C_PROXYTUNNEL,
- C_PUBKEY,
- C_QUOTE,
- C_RANDOM_FILE,
- C_RANGE,
- C_RATE,
- C_RAW,
- C_REFERER,
- C_REMOTE_HEADER_NAME,
- C_REMOTE_NAME,
- C_REMOTE_NAME_ALL,
- C_REMOTE_TIME,
- C_REMOVE_ON_ERROR,
- C_REQUEST,
- C_REQUEST_TARGET,
- C_RESOLVE,
- C_RETRY,
- C_RETRY_ALL_ERRORS,
- C_RETRY_CONNREFUSED,
- C_RETRY_DELAY,
- C_RETRY_MAX_TIME,
- C_SASL_AUTHZID,
- C_SASL_IR,
- C_SERVICE_NAME,
- C_SESSIONID,
- C_SHOW_ERROR,
- C_SHOW_HEADERS,
- C_SILENT,
- C_SKIP_EXISTING,
- C_SOCKS4,
- C_SOCKS4A,
- C_SOCKS5,
- C_SOCKS5_BASIC,
- C_SOCKS5_GSSAPI,
- C_SOCKS5_GSSAPI_NEC,
- C_SOCKS5_GSSAPI_SERVICE,
- C_SOCKS5_HOSTNAME,
- C_SPEED_LIMIT,
- C_SPEED_TIME,
- C_SSL,
- C_SSL_ALLOW_BEAST,
- C_SSL_AUTO_CLIENT_CERT,
- C_SSL_NO_REVOKE,
- C_SSL_REQD,
- C_SSL_REVOKE_BEST_EFFORT,
- C_SSLV2,
- C_SSLV3,
- C_STDERR,
- C_STYLED_OUTPUT,
- C_SUPPRESS_CONNECT_HEADERS,
- C_TCP_FASTOPEN,
- C_TCP_NODELAY,
- C_TELNET_OPTION,
- C_TEST_EVENT,
- C_TFTP_BLKSIZE,
- C_TFTP_NO_OPTIONS,
- C_TIME_COND,
- C_TLS_MAX,
- C_TLS13_CIPHERS,
- C_TLSAUTHTYPE,
- C_TLSPASSWORD,
- C_TLSUSER,
- C_TLSV1,
- C_TLSV1_0,
- C_TLSV1_1,
- C_TLSV1_2,
- C_TLSV1_3,
- C_TR_ENCODING,
- C_TRACE,
- C_TRACE_ASCII,
- C_TRACE_CONFIG,
- C_TRACE_IDS,
- C_TRACE_TIME,
- C_IP_TOS,
- C_UNIX_SOCKET,
- C_UPLOAD_FILE,
- C_URL,
- C_URL_QUERY,
- C_USE_ASCII,
- C_USER,
- C_USER_AGENT,
- C_VARIABLE,
- C_VERBOSE,
- C_VERSION,
- C_VLAN_PRIORITY,
- C_WDEBUG,
- C_WRITE_OUT,
- C_XATTR
-} cmdline_t;
-
-#define ARG_NONE 0 /* stand-alone but not a boolean */
-#define ARG_BOOL 1 /* accepts a --no-[name] prefix */
-#define ARG_STRG 2 /* requires an argument */
-#define ARG_FILE 3 /* requires an argument, usually a filename */
-
-#define ARG_TYPEMASK 0x03
-#define ARGTYPE(x) ((x) & ARG_TYPEMASK)
-
-#define ARG_NO 0x80 /* set if the option is documented as --no-* */
-
-struct LongShort {
- const char *lname; /* long name option */
- unsigned char desc; /* type, see ARG_* */
- char letter; /* short name option or ' ' */
- unsigned short cmd;
-};
-
typedef enum {
PARAM_OK = 0,
PARAM_OPTION_AMBIGUOUS,
@@ -331,7 +35,6 @@ typedef enum {
PARAM_MANUAL_REQUESTED,
PARAM_VERSION_INFO_REQUESTED,
PARAM_ENGINES_REQUESTED,
- PARAM_CA_EMBED_REQUESTED,
PARAM_GOT_EXTRA_PARAMETER,
PARAM_BAD_NUMERIC,
PARAM_NEGATIVE_NUMERIC,
@@ -346,16 +49,12 @@ typedef enum {
PARAM_CONTDISP_RESUME_FROM, /* --continue-at and --remote-header-name */
PARAM_READ_ERROR,
PARAM_EXPAND_ERROR, /* --expand problem */
- PARAM_BLANK_STRING,
PARAM_LAST
} ParameterError;
struct GlobalConfig;
struct OperationConfig;
-const struct LongShort *findlongopt(const char *opt);
-const struct LongShort *findshortopt(char letter);
-
ParameterError getparameter(const char *flag, char *nextarg,
argv_item_t cleararg,
bool *usedarg,
diff --git a/contrib/libs/curl/src/tool_getpass.c b/contrib/libs/curl/src/tool_getpass.c
index 1bc82584d2..b8f0b23c48 100644
--- a/contrib/libs/curl/src/tool_getpass.c
+++ b/contrib/libs/curl/src/tool_getpass.c
@@ -64,8 +64,8 @@ char *getpass_r(const char *prompt, char *buffer, size_t buflen)
long sts;
short chan;
- /* MSK, 23-JAN-2004, iosbdef.h was not in VAX V7.2 or CC 6.4 */
- /* distribution so I created this. May revert back later to */
+ /* MSK, 23-JAN-2004, iosbdef.h wasn't in VAX V7.2 or CC 6.4 */
+ /* distribution so I created this. May revert back later to */
/* struct _iosb iosb; */
struct _iosb
{
@@ -115,7 +115,7 @@ char *getpass_r(const char *prompt, char *buffer, size_t buflen)
}
/* since echo is disabled, print a newline */
fputs("\n", tool_stderr);
- /* if user did not hit ENTER, terminate buffer */
+ /* if user didn't hit ENTER, terminate buffer */
if(i == buflen)
buffer[buflen-1] = '\0';
@@ -146,15 +146,15 @@ static bool ttyecho(bool enable, int fd)
#ifdef HAVE_TERMIOS_H
tcgetattr(fd, &withecho);
noecho = withecho;
- noecho.c_lflag &= ~(tcflag_t)ECHO;
+ noecho.c_lflag &= ~ECHO;
tcsetattr(fd, TCSANOW, &noecho);
#elif defined(HAVE_TERMIO_H)
ioctl(fd, TCGETA, &withecho);
noecho = withecho;
- noecho.c_lflag &= ~(tcflag_t)ECHO;
+ noecho.c_lflag &= ~ECHO;
ioctl(fd, TCSETA, &noecho);
#else
- /* neither HAVE_TERMIO_H nor HAVE_TERMIOS_H, we cannot disable echo! */
+ /* neither HAVE_TERMIO_H nor HAVE_TERMIOS_H, we can't disable echo! */
(void)fd;
return FALSE; /* not disabled */
#endif
@@ -180,7 +180,7 @@ char *getpass_r(const char *prompt, /* prompt to display */
bool disabled;
int fd = open("/dev/tty", O_RDONLY);
if(-1 == fd)
- fd = STDIN_FILENO; /* use stdin if the tty could not be used */
+ fd = STDIN_FILENO; /* use stdin if the tty couldn't be used */
disabled = ttyecho(FALSE, fd); /* disable terminal echo */
diff --git a/contrib/libs/curl/src/tool_getpass.h b/contrib/libs/curl/src/tool_getpass.h
index 0a4d6d5a83..b93585d94d 100644
--- a/contrib/libs/curl/src/tool_getpass.h
+++ b/contrib/libs/curl/src/tool_getpass.h
@@ -26,7 +26,7 @@
#include "tool_setup.h"
#ifndef HAVE_GETPASS_R
-/* If there is a system-provided function named like this, we trust it is
+/* If there's a system-provided function named like this, we trust it is
also found in one of the standard headers. */
/*
diff --git a/contrib/libs/curl/src/tool_help.c b/contrib/libs/curl/src/tool_help.c
index 8c655c4b2b..c8aea295d5 100644
--- a/contrib/libs/curl/src/tool_help.c
+++ b/contrib/libs/curl/src/tool_help.c
@@ -22,17 +22,14 @@
*
***************************************************************************/
#include "tool_setup.h"
-
+#define ENABLE_CURLX_PRINTF
+/* use our own printf() functions */
#include "curlx.h"
#include "tool_help.h"
#include "tool_libinfo.h"
#include "tool_util.h"
#include "tool_version.h"
-#include "tool_cb_prg.h"
-#include "tool_hugehelp.h"
-#include "tool_getparam.h"
-#include "terminal.h"
#include "memdebug.h" /* keep this as LAST include */
@@ -40,46 +37,44 @@
# define USE_WATT32
#endif
-#ifndef ARRAYSIZE
-#define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
-#endif
-
struct category_descriptors {
const char *opt;
const char *desc;
- unsigned int category;
+ curlhelp_t category;
};
static const struct category_descriptors categories[] = {
- /* important is left out because it is the default help page */
- {"auth", "Authentication methods", CURLHELP_AUTH},
- {"connection", "Manage connections", CURLHELP_CONNECTION},
+ {"auth", "Different types of authentication methods", CURLHELP_AUTH},
+ {"connection", "Low level networking operations",
+ CURLHELP_CONNECTION},
{"curl", "The command line tool itself", CURLHELP_CURL},
- {"deprecated", "Legacy", CURLHELP_DEPRECATED},
- {"dns", "Names and resolving", CURLHELP_DNS},
- {"file", "FILE protocol", CURLHELP_FILE},
- {"ftp", "FTP protocol", CURLHELP_FTP},
- {"global", "Global options", CURLHELP_GLOBAL},
- {"http", "HTTP and HTTPS protocol", CURLHELP_HTTP},
- {"imap", "IMAP protocol", CURLHELP_IMAP},
- {"ldap", "LDAP protocol", CURLHELP_LDAP},
+ {"dns", "General DNS options", CURLHELP_DNS},
+ {"file", "FILE protocol options", CURLHELP_FILE},
+ {"ftp", "FTP protocol options", CURLHELP_FTP},
+ {"http", "HTTP and HTTPS protocol options", CURLHELP_HTTP},
+ {"imap", "IMAP protocol options", CURLHELP_IMAP},
+ /* important is left out because it is the default help page */
+ {"misc", "Options that don't fit into any other category", CURLHELP_MISC},
{"output", "Filesystem output", CURLHELP_OUTPUT},
- {"pop3", "POP3 protocol", CURLHELP_POP3},
- {"post", "HTTP POST specific", CURLHELP_POST},
- {"proxy", "Options for proxies", CURLHELP_PROXY},
- {"scp", "SCP protocol", CURLHELP_SCP},
- {"sftp", "SFTP protocol", CURLHELP_SFTP},
- {"smtp", "SMTP protocol", CURLHELP_SMTP},
- {"ssh", "SSH protocol", CURLHELP_SSH},
- {"telnet", "TELNET protocol", CURLHELP_TELNET},
- {"tftp", "TFTP protocol", CURLHELP_TFTP},
- {"timeout", "Timeouts and delays", CURLHELP_TIMEOUT},
- {"tls", "TLS/SSL related", CURLHELP_TLS},
- {"upload", "Upload, sending data", CURLHELP_UPLOAD},
- {"verbose", "Tracing, logging etc", CURLHELP_VERBOSE}
+ {"pop3", "POP3 protocol options", CURLHELP_POP3},
+ {"post", "HTTP Post specific options", CURLHELP_POST},
+ {"proxy", "All options related to proxies", CURLHELP_PROXY},
+ {"scp", "SCP protocol options", CURLHELP_SCP},
+ {"sftp", "SFTP protocol options", CURLHELP_SFTP},
+ {"smtp", "SMTP protocol options", CURLHELP_SMTP},
+ {"ssh", "SSH protocol options", CURLHELP_SSH},
+ {"telnet", "TELNET protocol options", CURLHELP_TELNET},
+ {"tftp", "TFTP protocol options", CURLHELP_TFTP},
+ {"tls", "All TLS/SSL related options", CURLHELP_TLS},
+ {"upload", "All options for uploads",
+ CURLHELP_UPLOAD},
+ {"verbose", "Options related to any kind of command line output of curl",
+ CURLHELP_VERBOSE},
+ {NULL, NULL, CURLHELP_HIDDEN}
};
-static void print_category(unsigned int category, unsigned int cols)
+
+static void print_category(curlhelp_t category)
{
unsigned int i;
size_t longopt = 5;
@@ -96,31 +91,23 @@ static void print_category(unsigned int category, unsigned int cols)
if(len > longdesc)
longdesc = len;
}
- if(longopt + longdesc > cols)
- longopt = cols - longdesc;
+ if(longopt + longdesc > 80)
+ longopt = 80 - longdesc;
for(i = 0; helptext[i].opt; ++i)
if(helptext[i].categories & category) {
- size_t opt = longopt;
- size_t desclen = strlen(helptext[i].desc);
- if(opt + desclen >= (cols - 2)) {
- if(desclen < (cols - 2))
- opt = (cols - 3) - desclen;
- else
- opt = 0;
- }
- printf(" %-*s %s\n", (int)opt, helptext[i].opt, helptext[i].desc);
+ printf(" %-*s %s\n", (int)longopt, helptext[i].opt, helptext[i].desc);
}
}
/* Prints category if found. If not, it returns 1 */
-static int get_category_content(const char *category, unsigned int cols)
+static int get_category_content(const char *category)
{
unsigned int i;
- for(i = 0; i < ARRAYSIZE(categories); ++i)
+ for(i = 0; categories[i].opt; ++i)
if(curl_strequal(categories[i].opt, category)) {
printf("%s: %s\n", categories[i].opt, categories[i].desc);
- print_category(categories[i].category, cols);
+ print_category(categories[i].category);
return 0;
}
return 1;
@@ -130,178 +117,33 @@ static int get_category_content(const char *category, unsigned int cols)
static void get_categories(void)
{
unsigned int i;
- for(i = 0; i < ARRAYSIZE(categories); ++i)
+ for(i = 0; categories[i].opt; ++i)
printf(" %-11s %s\n", categories[i].opt, categories[i].desc);
}
-/* Prints all categories as a comma-separated list of given width */
-static void get_categories_list(unsigned int width)
-{
- unsigned int i;
- size_t col = 0;
- for(i = 0; i < ARRAYSIZE(categories); ++i) {
- size_t len = strlen(categories[i].opt);
- if(i == ARRAYSIZE(categories) - 1) {
- /* final category */
- if(col + len + 1 < width)
- printf("%s.\n", categories[i].opt);
- else
- /* start a new line first */
- printf("\n%s.\n", categories[i].opt);
- }
- else if(col + len + 2 < width) {
- printf("%s, ", categories[i].opt);
- col += len + 2;
- }
- else {
- /* start a new line first */
- printf("\n%s, ", categories[i].opt);
- col = len + 2;
- }
- }
-}
-
-#ifdef USE_MANUAL
-
-void inithelpscan(struct scan_ctx *ctx,
- const char *trigger,
- const char *arg,
- const char *endarg)
-{
- ctx->trigger = trigger;
- ctx->tlen = strlen(trigger);
- ctx->arg = arg;
- ctx->flen = strlen(arg);
- ctx->endarg = endarg;
- ctx->elen = strlen(endarg);
- DEBUGASSERT((ctx->elen < sizeof(ctx->rbuf)) ||
- (ctx->flen < sizeof(ctx->rbuf)));
- ctx->show = 0;
- ctx->olen = 0;
- memset(ctx->rbuf, 0, sizeof(ctx->rbuf));
-}
-
-bool helpscan(unsigned char *buf, size_t len, struct scan_ctx *ctx)
-{
- size_t i;
- for(i = 0; i < len; i++) {
- if(!ctx->show) {
- /* wait for the trigger */
- memmove(&ctx->rbuf[0], &ctx->rbuf[1], ctx->tlen - 1);
- ctx->rbuf[ctx->tlen - 1] = buf[i];
- if(!memcmp(ctx->rbuf, ctx->trigger, ctx->tlen))
- ctx->show++;
- continue;
- }
- /* past the trigger */
- if(ctx->show == 1) {
- memmove(&ctx->rbuf[0], &ctx->rbuf[1], ctx->flen - 1);
- ctx->rbuf[ctx->flen - 1] = buf[i];
- if(!memcmp(ctx->rbuf, ctx->arg, ctx->flen)) {
- /* match, now output until endarg */
- fputs(&ctx->arg[1], stdout);
- ctx->show++;
- }
- continue;
- }
- /* show until the end */
- memmove(&ctx->rbuf[0], &ctx->rbuf[1], ctx->elen - 1);
- ctx->rbuf[ctx->elen - 1] = buf[i];
- if(!memcmp(ctx->rbuf, ctx->endarg, ctx->elen))
- return FALSE;
-
- if(buf[i] == '\n') {
- DEBUGASSERT(ctx->olen < sizeof(ctx->obuf));
- if(ctx->olen == sizeof(ctx->obuf))
- return FALSE; /* bail out */
- ctx->obuf[ctx->olen++] = 0;
- ctx->olen = 0;
- puts(ctx->obuf);
- }
- else {
- DEBUGASSERT(ctx->olen < sizeof(ctx->obuf));
- if(ctx->olen == sizeof(ctx->obuf))
- return FALSE; /* bail out */
- ctx->obuf[ctx->olen++] = buf[i];
- }
- }
- return TRUE;
-}
-
-#endif
void tool_help(char *category)
{
- unsigned int cols = get_terminal_columns();
+ puts("Usage: curl [options...] <url>");
/* If no category was provided */
if(!category) {
- const char *category_note = "\nThis is not the full help; this "
- "menu is split into categories.\nUse \"--help category\" to get "
- "an overview of all categories, which are:";
- const char *category_note2 =
- "Use \"--help all\" to list all options"
-#ifdef USE_MANUAL
- "\nUse \"--help [option]\" to view documentation for a given option"
-#endif
- ;
- puts("Usage: curl [options...] <url>");
- print_category(CURLHELP_IMPORTANT, cols);
+ const char *category_note = "\nThis is not the full help, this "
+ "menu is stripped into categories.\nUse \"--help category\" to get "
+ "an overview of all categories.\nFor all options use the manual"
+ " or \"--help all\".";
+ print_category(CURLHELP_IMPORTANT);
puts(category_note);
- get_categories_list(cols);
- puts(category_note2);
}
/* Lets print everything if "all" was provided */
else if(curl_strequal(category, "all"))
- /* Print everything */
- print_category(CURLHELP_ALL, cols);
+ /* Print everything except hidden */
+ print_category(~(CURLHELP_HIDDEN));
/* Lets handle the string "category" differently to not print an errormsg */
else if(curl_strequal(category, "category"))
get_categories();
- else if(category[0] == '-') {
-#ifdef USE_MANUAL
- /* command line option help */
- const struct LongShort *a = NULL;
- if(category[1] == '-') {
- char *lookup = &category[2];
- bool noflagged = FALSE;
- if(!strncmp(lookup, "no-", 3)) {
- lookup += 3;
- noflagged = TRUE;
- }
- a = findlongopt(lookup);
- if(a && noflagged && (ARGTYPE(a->desc) != ARG_BOOL))
- /* a --no- prefix for a non-boolean is not specifying a proper
- option */
- a = NULL;
- }
- else if(!category[2])
- a = findshortopt(category[1]);
- if(!a) {
- fprintf(tool_stderr, "Incorrect option name to show help for,"
- " see curl -h\n");
- }
- else {
- char cmdbuf[80];
- if(a->letter != ' ')
- msnprintf(cmdbuf, sizeof(cmdbuf), "\n -%c, --", a->letter);
- else if(a->desc & ARG_NO)
- msnprintf(cmdbuf, sizeof(cmdbuf), "\n --no-%s", a->lname);
- else
- msnprintf(cmdbuf, sizeof(cmdbuf), "\n %s", category);
- if(a->cmd == C_XATTR)
- /* this is the last option, which then ends when FILES starts */
- showhelp("\nALL OPTIONS\n", cmdbuf, "\nFILES");
- else
- showhelp("\nALL OPTIONS\n", cmdbuf, "\n -");
- }
-#else
- fprintf(tool_stderr, "Cannot comply. "
- "This curl was built without built-in manual\n");
-#endif
- }
/* Otherwise print category and handle the case if the cat was not found */
- else if(get_category_content(category, cols)) {
- puts("Unknown category provided, here is a list of all categories:\n");
+ else if(get_category_content(category)) {
+ puts("Invalid category provided, here is a list of all categories:\n");
get_categories();
}
free(category);
@@ -331,56 +173,20 @@ void tool_version_info(void)
printf("Release-Date: %s\n", LIBCURL_TIMESTAMP);
#endif
if(built_in_protos[0]) {
- const char *insert = NULL;
- /* we have ipfs and ipns support if libcurl has http support */
- for(builtin = built_in_protos; *builtin; ++builtin) {
- if(insert) {
- /* update insertion so ipfs will be printed in alphabetical order */
- if(strcmp(*builtin, "ipfs") < 0)
- insert = *builtin;
- else
- break;
- }
- else if(!strcmp(*builtin, "http")) {
- insert = *builtin;
- }
- }
printf("Protocols:");
for(builtin = built_in_protos; *builtin; ++builtin) {
/* Special case: do not list rtmp?* protocols.
They may only appear together with "rtmp" */
if(!curl_strnequal(*builtin, "rtmp", 4) || !builtin[0][4])
printf(" %s", *builtin);
- if(insert && insert == *builtin) {
- printf(" ipfs ipns");
- insert = NULL;
- }
}
puts(""); /* newline */
}
if(feature_names[0]) {
- const char **feat_ext;
- size_t feat_ext_count = feature_count;
-#ifdef CURL_CA_EMBED
- ++feat_ext_count;
-#endif
- feat_ext = malloc(sizeof(*feature_names) * (feat_ext_count + 1));
- if(feat_ext) {
- memcpy((void *)feat_ext, feature_names,
- sizeof(*feature_names) * feature_count);
- feat_ext_count = feature_count;
-#ifdef CURL_CA_EMBED
- feat_ext[feat_ext_count++] = "CAcert";
-#endif
- feat_ext[feat_ext_count] = NULL;
- qsort((void *)feat_ext, feat_ext_count, sizeof(*feat_ext),
- struplocompare4sort);
- printf("Features:");
- for(builtin = feat_ext; *builtin; ++builtin)
- printf(" %s", *builtin);
- puts(""); /* newline */
- free((void *)feat_ext);
- }
+ printf("Features:");
+ for(builtin = feature_names; *builtin; ++builtin)
+ printf(" %s", *builtin);
+ puts(""); /* newline */
}
if(strcmp(CURL_VERSION, curlinfo->version)) {
printf("WARNING: curl and libcurl versions do not match. "
diff --git a/contrib/libs/curl/src/tool_help.h b/contrib/libs/curl/src/tool_help.h
index 4b40715375..a7906266e3 100644
--- a/contrib/libs/curl/src/tool_help.h
+++ b/contrib/libs/curl/src/tool_help.h
@@ -28,65 +28,47 @@
void tool_help(char *category);
void tool_list_engines(void);
void tool_version_info(void);
-struct scan_ctx {
- const char *trigger;
- size_t tlen;
- const char *arg;
- size_t flen;
- const char *endarg;
- size_t elen;
- size_t olen;
- char rbuf[40];
- char obuf[160];
- unsigned char show; /* start as at 0.
- trigger match moves it to 1
- arg match moves it to 2
- endarg stops the search */
-};
-void inithelpscan(struct scan_ctx *ctx, const char *trigger,
- const char *arg, const char *endarg);
-bool helpscan(unsigned char *buf, size_t len, struct scan_ctx *ctx);
+
+typedef unsigned int curlhelp_t;
struct helptxt {
const char *opt;
const char *desc;
- unsigned int categories;
+ curlhelp_t categories;
};
/*
* The bitmask output is generated with the following command
------------------------------------------------------------
- make -C docs/cmdline-opts listcats
+ cd $srcroot/docs/cmdline-opts
+ ./gen.pl listcats *.d
*/
-#define CURLHELP_AUTH (1u << 0u)
-#define CURLHELP_CONNECTION (1u << 1u)
-#define CURLHELP_CURL (1u << 2u)
-#define CURLHELP_DEPRECATED (1u << 3u)
-#define CURLHELP_DNS (1u << 4u)
-#define CURLHELP_FILE (1u << 5u)
-#define CURLHELP_FTP (1u << 6u)
-#define CURLHELP_GLOBAL (1u << 7u)
-#define CURLHELP_HTTP (1u << 8u)
-#define CURLHELP_IMAP (1u << 9u)
-#define CURLHELP_IMPORTANT (1u << 10u)
-#define CURLHELP_LDAP (1u << 11u)
-#define CURLHELP_OUTPUT (1u << 12u)
-#define CURLHELP_POP3 (1u << 13u)
-#define CURLHELP_POST (1u << 14u)
-#define CURLHELP_PROXY (1u << 15u)
-#define CURLHELP_SCP (1u << 16u)
-#define CURLHELP_SFTP (1u << 17u)
-#define CURLHELP_SMTP (1u << 18u)
-#define CURLHELP_SSH (1u << 19u)
-#define CURLHELP_TELNET (1u << 20u)
-#define CURLHELP_TFTP (1u << 21u)
-#define CURLHELP_TIMEOUT (1u << 22u)
-#define CURLHELP_TLS (1u << 23u)
-#define CURLHELP_UPLOAD (1u << 24u)
-#define CURLHELP_VERBOSE (1u << 25u)
-
-#define CURLHELP_ALL (0xfffffffu)
+#define CURLHELP_HIDDEN 1u << 0u
+#define CURLHELP_AUTH 1u << 1u
+#define CURLHELP_CONNECTION 1u << 2u
+#define CURLHELP_CURL 1u << 3u
+#define CURLHELP_DNS 1u << 4u
+#define CURLHELP_FILE 1u << 5u
+#define CURLHELP_FTP 1u << 6u
+#define CURLHELP_HTTP 1u << 7u
+#define CURLHELP_IMAP 1u << 8u
+#define CURLHELP_IMPORTANT 1u << 9u
+#define CURLHELP_IPFS 1u << 10u
+#define CURLHELP_MISC 1u << 11u
+#define CURLHELP_OUTPUT 1u << 12u
+#define CURLHELP_POP3 1u << 13u
+#define CURLHELP_POST 1u << 14u
+#define CURLHELP_PROXY 1u << 15u
+#define CURLHELP_SCP 1u << 16u
+#define CURLHELP_SFTP 1u << 17u
+#define CURLHELP_SMTP 1u << 18u
+#define CURLHELP_SSH 1u << 19u
+#define CURLHELP_TELNET 1u << 20u
+#define CURLHELP_TFTP 1u << 21u
+#define CURLHELP_TLS 1u << 22u
+#define CURLHELP_UPLOAD 1u << 23u
+#define CURLHELP_VERBOSE 1u << 24u
extern const struct helptxt helptext[];
diff --git a/contrib/libs/curl/src/tool_helpers.c b/contrib/libs/curl/src/tool_helpers.c
index 2e15144b7b..854bf777a0 100644
--- a/contrib/libs/curl/src/tool_helpers.c
+++ b/contrib/libs/curl/src/tool_helpers.c
@@ -25,6 +25,8 @@
#include "strcase.h"
+#define ENABLE_CURLX_PRINTF
+/* use our own printf() functions */
#include "curlx.h"
#include "tool_cfgable.h"
@@ -38,8 +40,9 @@
** Helper functions that are used from more than one source file.
*/
-const char *param2text(ParameterError error)
+const char *param2text(int res)
{
+ ParameterError error = (ParameterError)res;
switch(error) {
case PARAM_GOT_EXTRA_PARAMETER:
return "had unsupported trailing garbage";
@@ -56,17 +59,17 @@ const char *param2text(ParameterError error)
case PARAM_NEGATIVE_NUMERIC:
return "expected a positive numerical parameter";
case PARAM_LIBCURL_DOESNT_SUPPORT:
- return "the installed libcurl version does not support this";
+ return "the installed libcurl version doesn't support this";
case PARAM_LIBCURL_UNSUPPORTED_PROTOCOL:
return "a specified protocol is unsupported by libcurl";
case PARAM_NO_MEM:
return "out of memory";
case PARAM_NO_PREFIX:
- return "the given option cannot be reversed with a --no- prefix";
+ return "the given option can't be reversed with a --no- prefix";
case PARAM_NUMBER_TOO_LARGE:
return "too large number";
case PARAM_NO_NOT_BOOLEAN:
- return "used '--no-' for option that is not a boolean";
+ return "used '--no-' for option that isn't a boolean";
case PARAM_CONTDISP_SHOW_HEADER:
return "showing headers and --remote-header-name cannot be combined";
case PARAM_CONTDISP_RESUME_FROM:
@@ -75,8 +78,6 @@ const char *param2text(ParameterError error)
return "error encountered when reading a file";
case PARAM_EXPAND_ERROR:
return "variable expansion failure";
- case PARAM_BLANK_STRING:
- return "blank argument where content is expected";
default:
return "unknown error";
}
@@ -94,7 +95,7 @@ int SetHTTPrequest(struct OperationConfig *config, HttpReq req, HttpReq *store)
"PUT (-T, --upload-file)"
};
- if((*store == TOOL_HTTPREQ_UNSPEC) ||
+ if((*store == HTTPREQ_UNSPEC) ||
(*store == req)) {
*store = req;
return 0;
diff --git a/contrib/libs/curl/src/tool_helpers.h b/contrib/libs/curl/src/tool_helpers.h
index dd085e2cc7..2cfbad21a3 100644
--- a/contrib/libs/curl/src/tool_helpers.h
+++ b/contrib/libs/curl/src/tool_helpers.h
@@ -25,7 +25,7 @@
***************************************************************************/
#include "tool_setup.h"
-const char *param2text(ParameterError error);
+const char *param2text(int res);
int SetHTTPrequest(struct OperationConfig *config, HttpReq req,
HttpReq *store);
diff --git a/contrib/libs/curl/src/tool_hugehelp.h b/contrib/libs/curl/src/tool_hugehelp.h
index f00f88702b..ce9af0c545 100644
--- a/contrib/libs/curl/src/tool_hugehelp.h
+++ b/contrib/libs/curl/src/tool_hugehelp.h
@@ -25,8 +25,6 @@
***************************************************************************/
#include "tool_setup.h"
-void showhelp(const char *trigger, const char *arg, const char *endarg);
-
#ifdef USE_MANUAL
void hugehelp(void);
#else
diff --git a/contrib/libs/curl/src/tool_ipfs.c b/contrib/libs/curl/src/tool_ipfs.c
index 09bff49067..435d1697ce 100644
--- a/contrib/libs/curl/src/tool_ipfs.c
+++ b/contrib/libs/curl/src/tool_ipfs.c
@@ -23,6 +23,8 @@
***************************************************************************/
#include "tool_setup.h"
+#define ENABLE_CURLX_PRINTF
+/* use our own printf() functions */
#include "curlx.h"
#include "dynbuf.h"
@@ -63,7 +65,7 @@ static char *ipfs_gateway(void)
char *ipfs_path = NULL;
char *gateway_composed_file_path = NULL;
FILE *gateway_file = NULL;
- char *gateway = curl_getenv("IPFS_GATEWAY");
+ char *gateway = curlx_getenv("IPFS_GATEWAY");
/* Gateway is found from environment variable. */
if(gateway) {
@@ -73,13 +75,15 @@ static char *ipfs_gateway(void)
}
/* Try to find the gateway in the IPFS data folder. */
- ipfs_path = curl_getenv("IPFS_PATH");
+ ipfs_path = curlx_getenv("IPFS_PATH");
if(!ipfs_path) {
- char *home = getenv("HOME");
+ char *home = curlx_getenv("HOME");
if(home && *home)
ipfs_path = aprintf("%s/.ipfs/", home);
- /* fallback to "~/.ipfs", as that is the default location. */
+ /* fallback to "~/.ipfs", as that's the default location. */
+
+ Curl_safefree(home);
}
if(!ipfs_path || ensure_trailing_slash(&ipfs_path))
@@ -130,7 +134,7 @@ fail:
}
/*
- * Rewrite ipfs://<cid> and ipns://<cid> to an HTTP(S)
+ * Rewrite ipfs://<cid> and ipns://<cid> to a HTTP(S)
* URL that can be handled by an IPFS gateway.
*/
CURLcode ipfs_url_rewrite(CURLU *uh, const char *protocol, char **url,
@@ -160,7 +164,7 @@ CURLcode ipfs_url_rewrite(CURLU *uh, const char *protocol, char **url,
goto clean;
/* We might have a --ipfs-gateway argument. Check it first and use it. Error
- * if we do have something but if it is an invalid url.
+ * if we do have something but if it's an invalid url.
*/
if(config->ipfs_gateway) {
/* ensure the gateway ends in a trailing / */
@@ -271,19 +275,22 @@ clean:
curl_free(pathbuffer);
curl_url_cleanup(gatewayurl);
{
+ const char *msg = NULL;
switch(result) {
case CURLE_URL_MALFORMAT:
- helpf(tool_stderr, "malformed target URL");
+ msg = "malformed target URL";
break;
case CURLE_FILE_COULDNT_READ_FILE:
- helpf(tool_stderr, "IPFS automatic gateway detection failed");
+ msg = "IPFS automatic gateway detection failed";
break;
case CURLE_BAD_FUNCTION_ARGUMENT:
- helpf(tool_stderr, "--ipfs-gateway was given a malformed URL");
+ msg = "--ipfs-gateway was given a malformed URL";
break;
default:
break;
}
+ if(msg)
+ helpf(tool_stderr, msg);
}
return result;
}
diff --git a/contrib/libs/curl/src/tool_libinfo.c b/contrib/libs/curl/src/tool_libinfo.c
index 4bc22217f9..0bf3a90bf2 100644
--- a/contrib/libs/curl/src/tool_libinfo.c
+++ b/contrib/libs/curl/src/tool_libinfo.c
@@ -25,13 +25,15 @@
#include "strcase.h"
+#define ENABLE_CURLX_PRINTF
+/* use our own printf() functions */
#include "curlx.h"
#include "tool_libinfo.h"
#include "memdebug.h" /* keep this as LAST include */
-/* global variable definitions, for libcurl runtime info */
+/* global variable definitions, for libcurl run-time info */
static const char *no_protos = NULL;
@@ -122,11 +124,10 @@ static struct feature_name_presentp {
static const char *fnames[sizeof(maybe_feature) / sizeof(maybe_feature[0])];
const char * const *feature_names = fnames;
-size_t feature_count;
/*
- * libcurl_info_init: retrieves runtime information about libcurl,
- * setting a global pointer 'curlinfo' to libcurl's runtime info
+ * libcurl_info_init: retrieves run-time information about libcurl,
+ * setting a global pointer 'curlinfo' to libcurl's run-time info
* struct, count protocols and flag those we are interested in.
* Global pointer feature_names is set to the feature names array. If
* the latter is not returned by curl_version_info(), it is built from
@@ -138,7 +139,7 @@ CURLcode get_libcurl_info(void)
CURLcode result = CURLE_OK;
const char *const *builtin;
- /* Pointer to libcurl's runtime version information */
+ /* Pointer to libcurl's run-time version information */
curlinfo = curl_version_info(CURLVERSION_NOW);
if(!curlinfo)
return CURLE_FAILED_INIT;
@@ -181,7 +182,6 @@ CURLcode get_libcurl_info(void)
*p->feature_presentp = TRUE;
break;
}
- ++feature_count;
}
return CURLE_OK;
diff --git a/contrib/libs/curl/src/tool_libinfo.h b/contrib/libs/curl/src/tool_libinfo.h
index ad9c195dc0..46063ad1be 100644
--- a/contrib/libs/curl/src/tool_libinfo.h
+++ b/contrib/libs/curl/src/tool_libinfo.h
@@ -25,7 +25,7 @@
***************************************************************************/
#include "tool_setup.h"
-/* global variable declarations, for libcurl runtime info */
+/* global variable declarations, for libcurl run-time info */
extern curl_version_info_data *curlinfo;
@@ -34,7 +34,6 @@ extern const char * const *built_in_protos;
extern size_t proto_count;
extern const char * const *feature_names;
-extern size_t feature_count;
extern const char *proto_file;
extern const char *proto_ftp;
diff --git a/contrib/libs/curl/src/tool_listhelp.c b/contrib/libs/curl/src/tool_listhelp.c
index fa29a51c1f..4e7a6dd632 100644
--- a/contrib/libs/curl/src/tool_listhelp.c
+++ b/contrib/libs/curl/src/tool_listhelp.c
@@ -26,17 +26,17 @@
/*
* DO NOT edit tool_listhelp.c manually.
- * This source file is generated with the following command in an autotools
- * build:
- *
- * "make listhelp"
+ * This source file is generated with the following command:
+
+ cd $srcroot/docs/cmdline-opts
+ ./gen.pl listhelp *.d > $srcroot/src/tool_listhelp.c
*/
const struct helptxt helptext[] = {
{" --abstract-unix-socket <path>",
"Connect via abstract Unix domain socket",
CURLHELP_CONNECTION},
- {" --alt-svc <filename>",
+ {" --alt-svc <file name>",
"Enable alt-svc with this cache file",
CURLHELP_HTTP},
{" --anyauth",
@@ -45,14 +45,14 @@ const struct helptxt helptext[] = {
{"-a, --append",
"Append to target file when uploading",
CURLHELP_FTP | CURLHELP_SFTP},
- {" --aws-sigv4 <provider1[:prvdr2[:reg[:srv]]]>",
- "AWS V4 signature auth",
+ {" --aws-sigv4 <provider1[:provider2[:region[:service]]]>",
+ "Use AWS V4 signature authentication",
CURLHELP_AUTH | CURLHELP_HTTP},
{" --basic",
- "HTTP Basic Authentication",
+ "Use HTTP Basic Authentication",
CURLHELP_AUTH},
{" --ca-native",
- "Load CA certs from the OS",
+ "Use CA certificates from the native OS",
CURLHELP_TLS},
{" --cacert <file>",
"CA certificate to verify peer against",
@@ -64,13 +64,13 @@ const struct helptxt helptext[] = {
"Client certificate file and password",
CURLHELP_TLS},
{" --cert-status",
- "Verify server cert status OCSP-staple",
+ "Verify the status of the server cert via OCSP-staple",
CURLHELP_TLS},
{" --cert-type <type>",
"Certificate type (DER/PEM/ENG/P12)",
CURLHELP_TLS},
- {" --ciphers <list>",
- "TLS 1.2 (1.1, 1.0) ciphers to use",
+ {" --ciphers <list of ciphers>",
+ "SSL ciphers to use",
CURLHELP_TLS},
{" --compressed",
"Request compressed response",
@@ -81,24 +81,24 @@ const struct helptxt helptext[] = {
{"-K, --config <file>",
"Read config from a file",
CURLHELP_CURL},
- {" --connect-timeout <seconds>",
- "Maximum time allowed to connect",
- CURLHELP_CONNECTION | CURLHELP_TIMEOUT},
+ {" --connect-timeout <fractional seconds>",
+ "Maximum time allowed for connection",
+ CURLHELP_CONNECTION},
{" --connect-to <HOST1:PORT1:HOST2:PORT2>",
- "Connect to host2 instead of host1",
- CURLHELP_CONNECTION | CURLHELP_DNS},
+ "Connect to host",
+ CURLHELP_CONNECTION},
{"-C, --continue-at <offset>",
"Resumed transfer offset",
CURLHELP_CONNECTION},
{"-b, --cookie <data|filename>",
- "Send cookies from string/load from file",
+ "Send cookies from string/file",
CURLHELP_HTTP},
{"-c, --cookie-jar <filename>",
- "Save cookies to <filename> after operation",
+ "Write cookies to <filename> after operation",
CURLHELP_HTTP},
{" --create-dirs",
"Create necessary local directory hierarchy",
- CURLHELP_OUTPUT},
+ CURLHELP_CURL},
{" --create-file-mode <mode>",
"File mode for created files",
CURLHELP_SFTP | CURLHELP_SCP | CURLHELP_FILE | CURLHELP_UPLOAD},
@@ -106,10 +106,10 @@ const struct helptxt helptext[] = {
"Convert LF to CRLF in upload",
CURLHELP_FTP | CURLHELP_SMTP},
{" --crlfile <file>",
- "Certificate Revocation list",
+ "Use this CRL list",
CURLHELP_TLS},
- {" --curves <list>",
- "(EC) TLS key exchange algorithms to request",
+ {" --curves <algorithm list>",
+ "(EC) TLS key exchange algorithm(s) to request",
CURLHELP_TLS},
{"-d, --data <data>",
"HTTP POST data",
@@ -130,7 +130,7 @@ const struct helptxt helptext[] = {
"GSS-API delegation permission",
CURLHELP_AUTH},
{" --digest",
- "HTTP Digest Authentication",
+ "Use HTTP Digest Authentication",
CURLHELP_PROXY | CURLHELP_AUTH | CURLHELP_HTTP},
{"-q, --disable",
"Disable .curlrc",
@@ -143,7 +143,7 @@ const struct helptxt helptext[] = {
CURLHELP_FTP},
{" --disallow-username-in-url",
"Disallow username in URL",
- CURLHELP_CURL},
+ CURLHELP_CURL | CURLHELP_HTTP},
{" --dns-interface <interface>",
"Interface to use for DNS requests",
CURLHELP_DNS},
@@ -157,44 +157,38 @@ const struct helptxt helptext[] = {
"DNS server addrs to use",
CURLHELP_DNS},
{" --doh-cert-status",
- "Verify DoH server cert status OCSP-staple",
+ "Verify the status of the DoH server cert via OCSP-staple",
CURLHELP_DNS | CURLHELP_TLS},
{" --doh-insecure",
"Allow insecure DoH server connections",
CURLHELP_DNS | CURLHELP_TLS},
{" --doh-url <URL>",
- "Resolve hostnames over DoH",
+ "Resolve host names over DoH",
CURLHELP_DNS},
- {" --dump-ca-embed",
- "Write the embedded CA bundle to standard output",
- CURLHELP_HTTP | CURLHELP_PROXY | CURLHELP_TLS},
{"-D, --dump-header <filename>",
"Write the received headers to <filename>",
CURLHELP_HTTP | CURLHELP_FTP},
- {" --ech <config>",
- "Configure ECH",
- CURLHELP_TLS},
{" --egd-file <file>",
"EGD socket path for random data",
- CURLHELP_DEPRECATED},
+ CURLHELP_TLS},
{" --engine <name>",
"Crypto engine to use",
CURLHELP_TLS},
{" --etag-compare <file>",
- "Load ETag from file",
+ "Pass an ETag from a file as a custom header",
CURLHELP_HTTP},
{" --etag-save <file>",
- "Parse incoming ETag and save to a file",
+ "Parse ETag from a request and save it to a file",
CURLHELP_HTTP},
{" --expect100-timeout <seconds>",
"How long to wait for 100-continue",
- CURLHELP_HTTP | CURLHELP_TIMEOUT},
+ CURLHELP_HTTP},
{"-f, --fail",
"Fail fast with no output on HTTP errors",
CURLHELP_IMPORTANT | CURLHELP_HTTP},
{" --fail-early",
- "Fail on first transfer error",
- CURLHELP_CURL | CURLHELP_GLOBAL},
+ "Fail on first transfer error, do not continue",
+ CURLHELP_CURL},
{" --fail-with-body",
"Fail on HTTP errors but save the body",
CURLHELP_HTTP | CURLHELP_OUTPUT},
@@ -203,15 +197,13 @@ const struct helptxt helptext[] = {
CURLHELP_TLS},
{"-F, --form <name=content>",
"Specify multipart MIME data",
- CURLHELP_HTTP | CURLHELP_UPLOAD | CURLHELP_POST | CURLHELP_IMAP |
- CURLHELP_SMTP},
+ CURLHELP_HTTP | CURLHELP_UPLOAD},
{" --form-escape",
- "Escape form fields using backslash",
- CURLHELP_HTTP | CURLHELP_UPLOAD | CURLHELP_POST},
+ "Escape multipart form field/file names using backslash",
+ CURLHELP_HTTP | CURLHELP_UPLOAD},
{" --form-string <name=string>",
"Specify multipart MIME data",
- CURLHELP_HTTP | CURLHELP_UPLOAD | CURLHELP_POST | CURLHELP_SMTP |
- CURLHELP_IMAP},
+ CURLHELP_HTTP | CURLHELP_UPLOAD},
{" --ftp-account <data>",
"Account data string",
CURLHELP_FTP | CURLHELP_AUTH},
@@ -220,15 +212,15 @@ const struct helptxt helptext[] = {
CURLHELP_FTP},
{" --ftp-create-dirs",
"Create the remote dirs if not present",
- CURLHELP_FTP | CURLHELP_SFTP},
+ CURLHELP_FTP | CURLHELP_SFTP | CURLHELP_CURL},
{" --ftp-method <method>",
"Control CWD usage",
CURLHELP_FTP},
{" --ftp-pasv",
- "Send PASV/EPSV instead of PORT",
+ "Use PASV/EPSV instead of PORT",
CURLHELP_FTP},
{"-P, --ftp-port <address>",
- "Send PORT instead of PASV",
+ "Use PORT instead of PASV",
CURLHELP_FTP},
{" --ftp-pret",
"Send PRET before PASV",
@@ -243,19 +235,19 @@ const struct helptxt helptext[] = {
"Set CCC mode",
CURLHELP_FTP | CURLHELP_TLS},
{" --ftp-ssl-control",
- "Require TLS for login, clear for transfer",
+ "Require SSL/TLS for FTP login, clear for transfer",
CURLHELP_FTP | CURLHELP_TLS},
{"-G, --get",
"Put the post data in the URL and use GET",
- CURLHELP_HTTP},
+ CURLHELP_HTTP | CURLHELP_UPLOAD},
{"-g, --globoff",
- "Disable URL globbing with {} and []",
+ "Disable URL sequences and ranges using {} and []",
CURLHELP_CURL},
- {" --happy-eyeballs-timeout-ms <ms>",
- "Time for IPv6 before IPv4",
- CURLHELP_CONNECTION | CURLHELP_TIMEOUT},
- {" --haproxy-clientip <ip>",
- "Set address in HAProxy PROXY",
+ {" --happy-eyeballs-timeout-ms <milliseconds>",
+ "Time for IPv6 before trying IPv4",
+ CURLHELP_CONNECTION},
+ {" --haproxy-clientip",
+ "Sets client IP in HAProxy PROXY protocol v1 header",
CURLHELP_HTTP | CURLHELP_PROXY},
{" --haproxy-protocol",
"Send HAProxy PROXY protocol v1 header",
@@ -266,16 +258,16 @@ const struct helptxt helptext[] = {
{"-H, --header <header/@file>",
"Pass custom header(s) to server",
CURLHELP_HTTP | CURLHELP_IMAP | CURLHELP_SMTP},
- {"-h, --help <subject>",
+ {"-h, --help <category>",
"Get help for commands",
CURLHELP_IMPORTANT | CURLHELP_CURL},
{" --hostpubmd5 <md5>",
- "Acceptable MD5 hash of host public key",
- CURLHELP_SFTP | CURLHELP_SCP | CURLHELP_SSH},
+ "Acceptable MD5 hash of the host public key",
+ CURLHELP_SFTP | CURLHELP_SCP},
{" --hostpubsha256 <sha256>",
- "Acceptable SHA256 hash of host public key",
- CURLHELP_SFTP | CURLHELP_SCP | CURLHELP_SSH},
- {" --hsts <filename>",
+ "Acceptable SHA256 hash of the host public key",
+ CURLHELP_SFTP | CURLHELP_SCP},
+ {" --hsts <file name>",
"Enable HSTS with this cache file",
CURLHELP_HTTP},
{" --http0.9",
@@ -302,18 +294,18 @@ const struct helptxt helptext[] = {
{" --ignore-content-length",
"Ignore the size of the remote resource",
CURLHELP_HTTP | CURLHELP_FTP},
+ {"-i, --include",
+ "Include protocol response headers in the output",
+ CURLHELP_IMPORTANT | CURLHELP_VERBOSE},
{"-k, --insecure",
"Allow insecure server connections",
- CURLHELP_TLS | CURLHELP_SFTP | CURLHELP_SCP | CURLHELP_SSH},
+ CURLHELP_TLS | CURLHELP_SFTP | CURLHELP_SCP},
{" --interface <name>",
- "Use network interface",
- CURLHELP_CONNECTION},
- {" --ip-tos <string>",
- "Set IP Type of Service or Traffic Class",
+ "Use network INTERFACE (or address)",
CURLHELP_CONNECTION},
{" --ipfs-gateway <URL>",
"Gateway for IPFS",
- CURLHELP_CURL},
+ CURLHELP_IPFS},
{"-4, --ipv4",
"Resolve names to IPv4 addresses",
CURLHELP_CONNECTION | CURLHELP_DNS},
@@ -326,14 +318,11 @@ const struct helptxt helptext[] = {
{"-j, --junk-session-cookies",
"Ignore session cookies read from file",
CURLHELP_HTTP},
- {" --keepalive-cnt <integer>",
- "Maximum number of keepalive probes",
- CURLHELP_CONNECTION},
{" --keepalive-time <seconds>",
"Interval time for keepalive probes",
- CURLHELP_CONNECTION | CURLHELP_TIMEOUT},
+ CURLHELP_CONNECTION},
{" --key <key>",
- "Private key filename",
+ "Private key file name",
CURLHELP_TLS | CURLHELP_SSH},
{" --key-type <type>",
"Private key file type (DER/PEM/ENG)",
@@ -342,27 +331,26 @@ const struct helptxt helptext[] = {
"Enable Kerberos with security <level>",
CURLHELP_FTP},
{" --libcurl <file>",
- "Generate libcurl code for this command line",
- CURLHELP_CURL | CURLHELP_GLOBAL},
+ "Dump libcurl equivalent code of this command line",
+ CURLHELP_CURL},
{" --limit-rate <speed>",
"Limit transfer speed to RATE",
CURLHELP_CONNECTION},
{"-l, --list-only",
"List only mode",
- CURLHELP_FTP | CURLHELP_POP3 | CURLHELP_SFTP | CURLHELP_FILE},
- {" --local-port <range>",
- "Use a local port number within RANGE",
+ CURLHELP_FTP | CURLHELP_POP3 | CURLHELP_SFTP},
+ {" --local-port <num/range>",
+ "Force use of RANGE for local port numbers",
CURLHELP_CONNECTION},
{"-L, --location",
"Follow redirects",
CURLHELP_HTTP},
{" --location-trusted",
- "As --location, but send secrets to other hosts",
+ "Like --location, and send auth to other hosts",
CURLHELP_HTTP | CURLHELP_AUTH},
{" --login-options <options>",
"Server login options",
- CURLHELP_IMAP | CURLHELP_POP3 | CURLHELP_SMTP | CURLHELP_AUTH |
- CURLHELP_LDAP},
+ CURLHELP_IMAP | CURLHELP_POP3 | CURLHELP_SMTP | CURLHELP_AUTH},
{" --mail-auth <address>",
"Originator address of the original email",
CURLHELP_SMTP},
@@ -373,7 +361,7 @@ const struct helptxt helptext[] = {
"Mail to this address",
CURLHELP_SMTP},
{" --mail-rcpt-allowfails",
- "Allow RCPT TO command to fail",
+ "Allow RCPT TO command to fail for some recipients",
CURLHELP_SMTP},
{"-M, --manual",
"Display the full manual",
@@ -384,45 +372,42 @@ const struct helptxt helptext[] = {
{" --max-redirs <num>",
"Maximum number of redirects allowed",
CURLHELP_HTTP},
- {"-m, --max-time <seconds>",
+ {"-m, --max-time <fractional seconds>",
"Maximum time allowed for transfer",
- CURLHELP_CONNECTION | CURLHELP_TIMEOUT},
+ CURLHELP_CONNECTION},
{" --metalink",
"Process given URLs as metalink XML file",
- CURLHELP_DEPRECATED},
- {" --mptcp",
- "Enable Multipath TCP",
- CURLHELP_CONNECTION},
+ CURLHELP_MISC},
{" --negotiate",
"Use HTTP Negotiate (SPNEGO) authentication",
CURLHELP_AUTH | CURLHELP_HTTP},
{"-n, --netrc",
- "Must read .netrc for username and password",
- CURLHELP_AUTH},
+ "Must read .netrc for user name and password",
+ CURLHELP_CURL},
{" --netrc-file <filename>",
"Specify FILE for netrc",
- CURLHELP_AUTH},
+ CURLHELP_CURL},
{" --netrc-optional",
"Use either .netrc or URL",
- CURLHELP_AUTH},
+ CURLHELP_CURL},
{"-:, --next",
- "Make next URL use separate options",
+ "Make next URL use its separate set of options",
CURLHELP_CURL},
{" --no-alpn",
"Disable the ALPN TLS extension",
CURLHELP_TLS | CURLHELP_HTTP},
{"-N, --no-buffer",
"Disable buffering of the output stream",
- CURLHELP_OUTPUT},
+ CURLHELP_CURL},
{" --no-clobber",
"Do not overwrite files that already exist",
- CURLHELP_OUTPUT},
+ CURLHELP_CURL | CURLHELP_OUTPUT},
{" --no-keepalive",
"Disable TCP keepalive on the connection",
CURLHELP_CONNECTION},
{" --no-npn",
"Disable the NPN TLS extension",
- CURLHELP_DEPRECATED},
+ CURLHELP_TLS | CURLHELP_HTTP},
{" --no-progress-meter",
"Do not show the progress meter",
CURLHELP_VERBOSE},
@@ -433,54 +418,53 @@ const struct helptxt helptext[] = {
"List of hosts which do not use proxy",
CURLHELP_PROXY},
{" --ntlm",
- "HTTP NTLM authentication",
+ "Use HTTP NTLM authentication",
CURLHELP_AUTH | CURLHELP_HTTP},
{" --ntlm-wb",
- "HTTP NTLM authentication with winbind",
- CURLHELP_DEPRECATED},
+ "Use HTTP NTLM authentication with winbind",
+ CURLHELP_AUTH | CURLHELP_HTTP},
{" --oauth2-bearer <token>",
"OAuth 2 Bearer Token",
- CURLHELP_AUTH | CURLHELP_IMAP | CURLHELP_POP3 | CURLHELP_SMTP |
- CURLHELP_LDAP},
+ CURLHELP_AUTH},
{"-o, --output <file>",
"Write to file instead of stdout",
- CURLHELP_IMPORTANT | CURLHELP_OUTPUT},
+ CURLHELP_IMPORTANT | CURLHELP_CURL},
{" --output-dir <dir>",
"Directory to save files in",
- CURLHELP_OUTPUT},
+ CURLHELP_CURL},
{"-Z, --parallel",
"Perform transfers in parallel",
- CURLHELP_CONNECTION | CURLHELP_CURL | CURLHELP_GLOBAL},
+ CURLHELP_CONNECTION | CURLHELP_CURL},
{" --parallel-immediate",
- "Do not wait for multiplexing",
- CURLHELP_CONNECTION | CURLHELP_CURL | CURLHELP_GLOBAL},
+ "Do not wait for multiplexing (with --parallel)",
+ CURLHELP_CONNECTION | CURLHELP_CURL},
{" --parallel-max <num>",
"Maximum concurrency for parallel transfers",
- CURLHELP_CONNECTION | CURLHELP_CURL | CURLHELP_GLOBAL},
+ CURLHELP_CONNECTION | CURLHELP_CURL},
{" --pass <phrase>",
- "Passphrase for the private key",
+ "Pass phrase for the private key",
CURLHELP_SSH | CURLHELP_TLS | CURLHELP_AUTH},
{" --path-as-is",
"Do not squash .. sequences in URL path",
CURLHELP_CURL},
{" --pinnedpubkey <hashes>",
- "Public key to verify peer against",
+ "FILE/HASHES Public key to verify peer against",
CURLHELP_TLS},
{" --post301",
- "Do not switch to GET after a 301 redirect",
+ "Do not switch to GET after following a 301",
CURLHELP_HTTP | CURLHELP_POST},
{" --post302",
- "Do not switch to GET after a 302 redirect",
+ "Do not switch to GET after following a 302",
CURLHELP_HTTP | CURLHELP_POST},
{" --post303",
- "Do not switch to GET after a 303 redirect",
+ "Do not switch to GET after following a 303",
CURLHELP_HTTP | CURLHELP_POST},
{" --preproxy [protocol://]host[:port]",
"Use this proxy first",
CURLHELP_PROXY},
{"-#, --progress-bar",
"Display transfer progress as a bar",
- CURLHELP_VERBOSE | CURLHELP_GLOBAL},
+ CURLHELP_VERBOSE},
{" --proto <protocols>",
"Enable/disable PROTOCOLS",
CURLHELP_CONNECTION | CURLHELP_CURL},
@@ -500,13 +484,13 @@ const struct helptxt helptext[] = {
"Use Basic authentication on the proxy",
CURLHELP_PROXY | CURLHELP_AUTH},
{" --proxy-ca-native",
- "Load CA certs from the OS to verify proxy",
+ "Use CA certificates from the native OS for proxy",
CURLHELP_TLS},
{" --proxy-cacert <file>",
- "CA certificates to verify proxy against",
+ "CA certificate to verify peer against for proxy",
CURLHELP_PROXY | CURLHELP_TLS},
{" --proxy-capath <dir>",
- "CA directory to verify proxy against",
+ "CA directory to verify peer against for proxy",
CURLHELP_PROXY | CURLHELP_TLS},
{" --proxy-cert <cert[:passwd]>",
"Set client certificate for proxy",
@@ -515,13 +499,13 @@ const struct helptxt helptext[] = {
"Client certificate type for HTTPS proxy",
CURLHELP_PROXY | CURLHELP_TLS},
{" --proxy-ciphers <list>",
- "TLS 1.2 (1.1, 1.0) ciphers to use for proxy",
+ "SSL ciphers to use for proxy",
CURLHELP_PROXY | CURLHELP_TLS},
{" --proxy-crlfile <file>",
"Set a CRL list for proxy",
CURLHELP_PROXY | CURLHELP_TLS},
{" --proxy-digest",
- "Digest auth with the proxy",
+ "Use Digest authentication on the proxy",
CURLHELP_PROXY | CURLHELP_TLS},
{" --proxy-header <header/@file>",
"Pass custom header(s) to proxy",
@@ -530,7 +514,7 @@ const struct helptxt helptext[] = {
"Use HTTP/2 with HTTPS proxy",
CURLHELP_HTTP | CURLHELP_PROXY},
{" --proxy-insecure",
- "Skip HTTPS proxy cert verification",
+ "Do HTTPS proxy connections without verifying the proxy",
CURLHELP_PROXY | CURLHELP_TLS},
{" --proxy-key <key>",
"Private key for HTTPS proxy",
@@ -539,13 +523,13 @@ const struct helptxt helptext[] = {
"Private key file type for proxy",
CURLHELP_PROXY | CURLHELP_TLS},
{" --proxy-negotiate",
- "HTTP Negotiate (SPNEGO) auth with the proxy",
+ "Use HTTP Negotiate (SPNEGO) authentication on the proxy",
CURLHELP_PROXY | CURLHELP_AUTH},
{" --proxy-ntlm",
- "NTLM authentication with the proxy",
+ "Use NTLM authentication on the proxy",
CURLHELP_PROXY | CURLHELP_AUTH},
{" --proxy-pass <phrase>",
- "Passphrase for private key for HTTPS proxy",
+ "Pass phrase for the private key for HTTPS proxy",
CURLHELP_PROXY | CURLHELP_TLS | CURLHELP_AUTH},
{" --proxy-pinnedpubkey <hashes>",
"FILE/HASHES public key to verify proxy with",
@@ -554,12 +538,12 @@ const struct helptxt helptext[] = {
"SPNEGO proxy service name",
CURLHELP_PROXY | CURLHELP_TLS},
{" --proxy-ssl-allow-beast",
- "Allow this security flaw for HTTPS proxy",
+ "Allow security flaw for interop for HTTPS proxy",
CURLHELP_PROXY | CURLHELP_TLS},
{" --proxy-ssl-auto-client-cert",
- "Auto client certificate for proxy",
+ "Use auto client certificate for proxy (Schannel)",
CURLHELP_PROXY | CURLHELP_TLS},
- {" --proxy-tls13-ciphers <list>",
+ {" --proxy-tls13-ciphers <ciphersuite list>",
"TLS 1.3 proxy cipher suites",
CURLHELP_PROXY | CURLHELP_TLS},
{" --proxy-tlsauthtype <type>",
@@ -572,7 +556,7 @@ const struct helptxt helptext[] = {
"TLS username for HTTPS proxy",
CURLHELP_PROXY | CURLHELP_TLS | CURLHELP_AUTH},
{" --proxy-tlsv1",
- "TLSv1 for HTTPS proxy",
+ "Use TLSv1 for HTTPS proxy",
CURLHELP_PROXY | CURLHELP_TLS | CURLHELP_AUTH},
{"-U, --proxy-user <user:password>",
"Proxy user and password",
@@ -581,25 +565,25 @@ const struct helptxt helptext[] = {
"Use HTTP/1.0 proxy on given port",
CURLHELP_PROXY},
{"-p, --proxytunnel",
- "HTTP proxy tunnel (using CONNECT)",
+ "Operate through an HTTP proxy tunnel (using CONNECT)",
CURLHELP_PROXY},
{" --pubkey <key>",
- "SSH Public key filename",
- CURLHELP_SFTP | CURLHELP_SCP | CURLHELP_SSH | CURLHELP_AUTH},
+ "SSH Public key file name",
+ CURLHELP_SFTP | CURLHELP_SCP | CURLHELP_AUTH},
{"-Q, --quote <command>",
"Send command(s) to server before transfer",
CURLHELP_FTP | CURLHELP_SFTP},
{" --random-file <file>",
"File for reading random data from",
- CURLHELP_DEPRECATED},
+ CURLHELP_MISC},
{"-r, --range <range>",
"Retrieve only the bytes within RANGE",
CURLHELP_HTTP | CURLHELP_FTP | CURLHELP_SFTP | CURLHELP_FILE},
{" --rate <max request rate>",
"Request rate for serial transfers",
- CURLHELP_CONNECTION | CURLHELP_GLOBAL},
+ CURLHELP_CONNECTION},
{" --raw",
- "Do HTTP raw; no transfer decoding",
+ "Do HTTP \"raw\"; no transfer decoding",
CURLHELP_HTTP},
{"-e, --referer <URL>",
"Referrer URL",
@@ -608,63 +592,56 @@ const struct helptxt helptext[] = {
"Use the header-provided filename",
CURLHELP_OUTPUT},
{"-O, --remote-name",
- "Write output to file named as remote file",
+ "Write output to a file named as the remote file",
CURLHELP_IMPORTANT | CURLHELP_OUTPUT},
{" --remote-name-all",
- "Use the remote filename for all URLs",
+ "Use the remote file name for all URLs",
CURLHELP_OUTPUT},
{"-R, --remote-time",
- "Set remote file's time on local output",
+ "Set the remote file's time on the local output",
CURLHELP_OUTPUT},
{" --remove-on-error",
"Remove output file on errors",
- CURLHELP_OUTPUT},
+ CURLHELP_CURL},
{"-X, --request <method>",
"Specify request method to use",
- CURLHELP_CONNECTION | CURLHELP_POP3 | CURLHELP_FTP | CURLHELP_IMAP |
- CURLHELP_SMTP},
+ CURLHELP_CONNECTION},
{" --request-target <path>",
"Specify the target for this request",
CURLHELP_HTTP},
{" --resolve <[+]host:port:addr[,addr]...>",
- "Resolve host+port to address",
+ "Resolve the host+port to this address",
CURLHELP_CONNECTION | CURLHELP_DNS},
{" --retry <num>",
"Retry request if transient problems occur",
CURLHELP_CURL},
{" --retry-all-errors",
- "Retry all errors (with --retry)",
+ "Retry all errors (use with --retry)",
CURLHELP_CURL},
{" --retry-connrefused",
- "Retry on connection refused (with --retry)",
+ "Retry on connection refused (use with --retry)",
CURLHELP_CURL},
{" --retry-delay <seconds>",
"Wait time between retries",
- CURLHELP_CURL | CURLHELP_TIMEOUT},
+ CURLHELP_CURL},
{" --retry-max-time <seconds>",
"Retry only within this period",
- CURLHELP_CURL | CURLHELP_TIMEOUT},
+ CURLHELP_CURL},
{" --sasl-authzid <identity>",
"Identity for SASL PLAIN authentication",
CURLHELP_AUTH},
{" --sasl-ir",
- "Initial response in SASL authentication",
+ "Enable initial response in SASL authentication",
CURLHELP_AUTH},
{" --service-name <name>",
"SPNEGO service name",
- CURLHELP_AUTH},
+ CURLHELP_MISC},
{"-S, --show-error",
"Show error even when -s is used",
- CURLHELP_CURL | CURLHELP_GLOBAL},
- {"-i, --show-headers",
- "Show response headers in output",
- CURLHELP_IMPORTANT | CURLHELP_VERBOSE | CURLHELP_OUTPUT},
+ CURLHELP_CURL},
{"-s, --silent",
"Silent mode",
CURLHELP_IMPORTANT | CURLHELP_VERBOSE},
- {" --skip-existing",
- "Skip download if local file already exists",
- CURLHELP_CURL | CURLHELP_OUTPUT},
{" --socks4 <host[:port]>",
"SOCKS4 proxy on given host + port",
CURLHELP_PROXY},
@@ -675,7 +652,7 @@ const struct helptxt helptext[] = {
"SOCKS5 proxy on given host + port",
CURLHELP_PROXY},
{" --socks5-basic",
- "Username/password auth for SOCKS5 proxies",
+ "Enable username/password auth for SOCKS5 proxies",
CURLHELP_PROXY | CURLHELP_AUTH},
{" --socks5-gssapi",
"Enable GSS-API auth for SOCKS5 proxies",
@@ -687,18 +664,17 @@ const struct helptxt helptext[] = {
"SOCKS5 proxy service name for GSS-API",
CURLHELP_PROXY | CURLHELP_AUTH},
{" --socks5-hostname <host[:port]>",
- "SOCKS5 proxy, pass hostname to proxy",
+ "SOCKS5 proxy, pass host name to proxy",
CURLHELP_PROXY},
{"-Y, --speed-limit <speed>",
"Stop transfers slower than this",
CURLHELP_CONNECTION},
{"-y, --speed-time <seconds>",
"Trigger 'speed-limit' abort after this time",
- CURLHELP_CONNECTION | CURLHELP_TIMEOUT},
+ CURLHELP_CONNECTION},
{" --ssl",
- "Try enabling TLS",
- CURLHELP_TLS | CURLHELP_IMAP | CURLHELP_POP3 | CURLHELP_SMTP |
- CURLHELP_LDAP},
+ "Try SSL/TLS",
+ CURLHELP_TLS},
{" --ssl-allow-beast",
"Allow security flaw to improve interop",
CURLHELP_TLS},
@@ -710,23 +686,22 @@ const struct helptxt helptext[] = {
CURLHELP_TLS},
{" --ssl-reqd",
"Require SSL/TLS",
- CURLHELP_TLS | CURLHELP_IMAP | CURLHELP_POP3 | CURLHELP_SMTP |
- CURLHELP_LDAP},
+ CURLHELP_TLS},
{" --ssl-revoke-best-effort",
- "Ignore missing cert CRL dist points",
+ "Ignore missing/offline cert CRL dist points (Schannel)",
CURLHELP_TLS},
{"-2, --sslv2",
- "SSLv2",
- CURLHELP_DEPRECATED},
+ "Use SSLv2",
+ CURLHELP_TLS},
{"-3, --sslv3",
- "SSLv3",
- CURLHELP_DEPRECATED},
+ "Use SSLv3",
+ CURLHELP_TLS},
{" --stderr <file>",
"Where to redirect stderr",
- CURLHELP_VERBOSE | CURLHELP_GLOBAL},
+ CURLHELP_VERBOSE},
{" --styled-output",
"Enable styled output for HTTP headers",
- CURLHELP_VERBOSE | CURLHELP_GLOBAL},
+ CURLHELP_VERBOSE},
{" --suppress-connect-headers",
"Suppress proxy CONNECT response headers",
CURLHELP_PROXY},
@@ -734,7 +709,7 @@ const struct helptxt helptext[] = {
"Use TCP Fast Open",
CURLHELP_CONNECTION},
{" --tcp-nodelay",
- "Set TCP_NODELAY",
+ "Use the TCP_NODELAY option",
CURLHELP_CONNECTION},
{"-t, --telnet-option <opt=val>",
"Set telnet option",
@@ -749,9 +724,9 @@ const struct helptxt helptext[] = {
"Transfer based on a time condition",
CURLHELP_HTTP | CURLHELP_FTP},
{" --tls-max <VERSION>",
- "Maximum allowed TLS version",
+ "Set maximum allowed TLS version",
CURLHELP_TLS},
- {" --tls13-ciphers <list>",
+ {" --tls13-ciphers <ciphersuite list>",
"TLS 1.3 cipher suites to use",
CURLHELP_TLS},
{" --tlsauthtype <type>",
@@ -761,41 +736,41 @@ const struct helptxt helptext[] = {
"TLS password",
CURLHELP_TLS | CURLHELP_AUTH},
{" --tlsuser <name>",
- "TLS username",
+ "TLS user name",
CURLHELP_TLS | CURLHELP_AUTH},
{"-1, --tlsv1",
- "TLSv1.0 or greater",
+ "Use TLSv1.0 or greater",
CURLHELP_TLS},
{" --tlsv1.0",
- "TLSv1.0 or greater",
+ "Use TLSv1.0 or greater",
CURLHELP_TLS},
{" --tlsv1.1",
- "TLSv1.1 or greater",
+ "Use TLSv1.1 or greater",
CURLHELP_TLS},
{" --tlsv1.2",
- "TLSv1.2 or greater",
+ "Use TLSv1.2 or greater",
CURLHELP_TLS},
{" --tlsv1.3",
- "TLSv1.3 or greater",
+ "Use TLSv1.3 or greater",
CURLHELP_TLS},
{" --tr-encoding",
"Request compressed transfer encoding",
CURLHELP_HTTP},
{" --trace <file>",
"Write a debug trace to FILE",
- CURLHELP_VERBOSE | CURLHELP_GLOBAL},
+ CURLHELP_VERBOSE},
{" --trace-ascii <file>",
"Like --trace, but without hex output",
- CURLHELP_VERBOSE | CURLHELP_GLOBAL},
+ CURLHELP_VERBOSE},
{" --trace-config <string>",
"Details to log in trace/verbose output",
- CURLHELP_VERBOSE | CURLHELP_GLOBAL},
+ CURLHELP_VERBOSE},
{" --trace-ids",
- "Transfer + connection ids in verbose output",
- CURLHELP_VERBOSE | CURLHELP_GLOBAL},
+ "Add transfer and connection identifiers to trace/verbose output",
+ CURLHELP_VERBOSE},
{" --trace-time",
"Add time stamps to trace/verbose output",
- CURLHELP_VERBOSE | CURLHELP_GLOBAL},
+ CURLHELP_VERBOSE},
{" --unix-socket <path>",
"Connect through this Unix domain socket",
CURLHELP_CONNECTION},
@@ -810,7 +785,7 @@ const struct helptxt helptext[] = {
CURLHELP_HTTP | CURLHELP_POST | CURLHELP_UPLOAD},
{"-B, --use-ascii",
"Use ASCII/text transfer",
- CURLHELP_FTP | CURLHELP_OUTPUT | CURLHELP_LDAP},
+ CURLHELP_MISC},
{"-u, --user <user:password>",
"Server user and password",
CURLHELP_IMPORTANT | CURLHELP_AUTH},
@@ -822,18 +797,15 @@ const struct helptxt helptext[] = {
CURLHELP_CURL},
{"-v, --verbose",
"Make the operation more talkative",
- CURLHELP_IMPORTANT | CURLHELP_VERBOSE | CURLHELP_GLOBAL},
+ CURLHELP_IMPORTANT | CURLHELP_VERBOSE},
{"-V, --version",
"Show version number and quit",
CURLHELP_IMPORTANT | CURLHELP_CURL},
- {" --vlan-priority <priority>",
- "Set VLAN priority",
- CURLHELP_CONNECTION},
{"-w, --write-out <format>",
- "Output FORMAT after completion",
+ "Use output FORMAT after completion",
CURLHELP_VERBOSE},
{" --xattr",
"Store metadata in extended file attributes",
- CURLHELP_OUTPUT},
- { NULL, NULL, 0 }
+ CURLHELP_MISC},
+ { NULL, NULL, CURLHELP_HIDDEN }
};
diff --git a/contrib/libs/curl/src/tool_main.c b/contrib/libs/curl/src/tool_main.c
index 01993123e2..446806ecbd 100644
--- a/contrib/libs/curl/src/tool_main.c
+++ b/contrib/libs/curl/src/tool_main.c
@@ -35,6 +35,8 @@
#include <fcntl.h>
#endif
+#define ENABLE_CURLX_PRINTF
+/* use our own printf() functions */
#include "curlx.h"
#include "tool_cfgable.h"
@@ -79,7 +81,7 @@ int _CRT_glob = 0;
#if defined(HAVE_PIPE) && defined(HAVE_FCNTL)
/*
* Ensure that file descriptors 0, 1 and 2 (stdin, stdout, stderr) are
- * open before starting to run. Otherwise, the first three network
+ * open before starting to run. Otherwise, the first three network
* sockets opened by curl could be used for input sources, downloaded data
* or error logs as they will effectively be stdin, stdout and/or stderr.
*
@@ -106,9 +108,9 @@ static void memory_tracking_init(void)
{
char *env;
/* if CURL_MEMDEBUG is set, this starts memory tracking message logging */
- env = curl_getenv("CURL_MEMDEBUG");
+ env = curlx_getenv("CURL_MEMDEBUG");
if(env) {
- /* use the value as filename */
+ /* use the value as file name */
char fname[CURL_MT_LOGFNAME_BUFSIZE];
if(strlen(env) >= CURL_MT_LOGFNAME_BUFSIZE)
env[CURL_MT_LOGFNAME_BUFSIZE-1] = '\0';
@@ -120,7 +122,7 @@ static void memory_tracking_init(void)
without an alloc! */
}
/* if CURL_MEMLIMIT is set, this enables fail-on-alloc-number-N feature */
- env = curl_getenv("CURL_MEMLIMIT");
+ env = curlx_getenv("CURL_MEMLIMIT");
if(env) {
char *endptr;
long num = strtol(env, &endptr, 10);
@@ -217,7 +219,7 @@ static void main_free(struct GlobalConfig *config)
*/
#ifdef _UNICODE
#if defined(__GNUC__)
-/* GCC does not know about wmain() */
+/* GCC doesn't know about wmain() */
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wmissing-prototypes"
#pragma GCC diagnostic ignored "-Wmissing-declarations"
@@ -247,7 +249,7 @@ int main(int argc, char *argv[])
result = win32_init();
if(result) {
errorf(&global, "(%d) Windows-specific init failed", result);
- return (int)result;
+ return result;
}
#endif
diff --git a/contrib/libs/curl/src/tool_msgs.c b/contrib/libs/curl/src/tool_msgs.c
index 58b935e962..c914836db7 100644
--- a/contrib/libs/curl/src/tool_msgs.c
+++ b/contrib/libs/curl/src/tool_msgs.c
@@ -23,12 +23,12 @@
***************************************************************************/
#include "tool_setup.h"
+#define ENABLE_CURLX_PRINTF
+/* use our own printf() functions */
#include "curlx.h"
#include "tool_cfgable.h"
#include "tool_msgs.h"
-#include "tool_cb_prg.h"
-#include "terminal.h"
#include "memdebug.h" /* keep this as LAST include */
@@ -39,21 +39,16 @@
static void voutf(struct GlobalConfig *config,
const char *prefix,
const char *fmt,
- va_list ap) CURL_PRINTF(3, 0);
-
-static void voutf(struct GlobalConfig *config,
- const char *prefix,
- const char *fmt,
va_list ap)
{
- size_t width = (get_terminal_columns() - strlen(prefix));
+ size_t width = (79 - strlen(prefix));
DEBUGASSERT(!strchr(fmt, '\n'));
if(!config->silent) {
size_t len;
char *ptr;
char *print_buffer;
- print_buffer = vaprintf(fmt, ap);
+ print_buffer = curlx_mvaprintf(fmt, ap);
if(!print_buffer)
return;
len = strlen(print_buffer);
@@ -105,6 +100,7 @@ void notef(struct GlobalConfig *config, const char *fmt, ...)
* Emit warning formatted message on configured 'errors' stream unless
* mute (--silent) was selected.
*/
+
void warnf(struct GlobalConfig *config, const char *fmt, ...)
{
va_list ap;
@@ -112,7 +108,6 @@ void warnf(struct GlobalConfig *config, const char *fmt, ...)
voutf(config, WARN_PREFIX, fmt, ap);
va_end(ap);
}
-
/*
* Emit help formatted message on given stream. This is for errors with or
* related to command line arguments.
diff --git a/contrib/libs/curl/src/tool_msgs.h b/contrib/libs/curl/src/tool_msgs.h
index e963efaa0b..9458991c01 100644
--- a/contrib/libs/curl/src/tool_msgs.h
+++ b/contrib/libs/curl/src/tool_msgs.h
@@ -26,13 +26,9 @@
#include "tool_setup.h"
#include "tool_cfgable.h"
-void warnf(struct GlobalConfig *config, const char *fmt, ...)
- CURL_PRINTF(2, 3);
-void notef(struct GlobalConfig *config, const char *fmt, ...)
- CURL_PRINTF(2, 3);
-void helpf(FILE *errors, const char *fmt, ...)
- CURL_PRINTF(2, 3);
-void errorf(struct GlobalConfig *config, const char *fmt, ...)
- CURL_PRINTF(2, 3);
+void warnf(struct GlobalConfig *config, const char *fmt, ...);
+void notef(struct GlobalConfig *config, const char *fmt, ...);
+void helpf(FILE *errors, const char *fmt, ...);
+void errorf(struct GlobalConfig *config, const char *fmt, ...);
#endif /* HEADER_CURL_TOOL_MSGS_H */
diff --git a/contrib/libs/curl/src/tool_operate.c b/contrib/libs/curl/src/tool_operate.c
index 53f1bd82aa..097e7e0d08 100644
--- a/contrib/libs/curl/src/tool_operate.c
+++ b/contrib/libs/curl/src/tool_operate.c
@@ -45,21 +45,8 @@
# error #include <proto/dos.h>
#endif
-#ifdef HAVE_NETINET_IN_H
-# include <netinet/in.h>
-#endif
-
-#ifdef HAVE_UV_H
-/* Hack for Unity mode */
-#ifdef HEADER_CURL_MEMDEBUG_H
-#undef HEADER_CURL_MEMDEBUG_H
-#undef freeaddrinfo
-#undef getaddrinfo
-#endif
-/* this is for libuv-enabled debug builds only */
-#error #include <uv.h>
-#endif
-
+#define ENABLE_CURLX_PRINTF
+/* use our own printf() functions */
#include "curlx.h"
#include "tool_binmode.h"
@@ -69,7 +56,6 @@
#include "tool_cb_prg.h"
#include "tool_cb_rea.h"
#include "tool_cb_see.h"
-#include "tool_cb_soc.h"
#include "tool_cb_wrt.h"
#include "tool_dirhie.h"
#include "tool_doswin.h"
@@ -97,31 +83,25 @@
#include "tool_progress.h"
#include "tool_ipfs.h"
#include "dynbuf.h"
-#ifdef DEBUGBUILD
-#include "easyif.h" /* for libcurl's debug-only curl_easy_perform_ev() */
-#endif
#include "memdebug.h" /* keep this as LAST include */
-#ifdef CURL_CA_EMBED
-extern const unsigned char curl_ca_embed[];
+#ifdef CURLDEBUG
+/* libcurl's debug builds provide an extra function */
+CURLcode curl_easy_perform_ev(CURL *easy);
#endif
#ifndef O_BINARY
/* since O_BINARY as used in bitmasks, setting it to zero makes it usable in
- source code but yet it does not ruin anything */
+ source code but yet it doesn't ruin anything */
# define O_BINARY 0
#endif
-#ifndef SOL_IP
-# define SOL_IP IPPROTO_IP
-#endif
-
-#define CURL_CA_CERT_ERRORMSG \
- "More details here: https://curl.se/docs/sslcerts.html\n\n" \
- "curl failed to verify the legitimacy of the server and therefore " \
- "could not\nestablish a secure connection to it. To learn more about " \
- "this situation and\nhow to fix it, please visit the webpage mentioned " \
+#define CURL_CA_CERT_ERRORMSG \
+ "More details here: https://curl.se/docs/sslcerts.html\n\n" \
+ "curl failed to verify the legitimacy of the server and therefore " \
+ "could not\nestablish a secure connection to it. To learn more about " \
+ "this situation and\nhow to fix it, please visit the web page mentioned " \
"above.\n"
static CURLcode single_transfer(struct GlobalConfig *global,
@@ -164,67 +144,6 @@ static bool is_pkcs11_uri(const char *string)
}
}
-#ifdef IP_TOS
-static int get_address_family(curl_socket_t sockfd)
-{
- struct sockaddr addr;
- curl_socklen_t addrlen = sizeof(addr);
- if(getsockname(sockfd, (struct sockaddr *)&addr, &addrlen) == 0)
- return addr.sa_family;
- return AF_UNSPEC;
-}
-#endif
-
-#if defined(IP_TOS) || defined(IPV6_TCLASS) || defined(SO_PRIORITY)
-static int sockopt_callback(void *clientp, curl_socket_t curlfd,
- curlsocktype purpose)
-{
- struct OperationConfig *config = (struct OperationConfig *)clientp;
- if(purpose != CURLSOCKTYPE_IPCXN)
- return CURL_SOCKOPT_OK;
- (void)config;
- (void)curlfd;
-#if defined(IP_TOS) || defined(IPV6_TCLASS)
- if(config->ip_tos > 0) {
- int tos = (int)config->ip_tos;
- int result = 0;
- switch(get_address_family(curlfd)) {
- case AF_INET:
-#ifdef IP_TOS
- result = setsockopt(curlfd, SOL_IP, IP_TOS, (void *)&tos, sizeof(tos));
-#endif
- break;
-#if defined(IPV6_TCLASS) && defined(AF_INET6)
- case AF_INET6:
- result = setsockopt(curlfd, IPPROTO_IPV6, IPV6_TCLASS,
- (void *)&tos, sizeof(tos));
- break;
-#endif
- }
- if(result < 0) {
- int error = errno;
- warnf(config->global,
- "Setting type of service to %d failed with errno %d: %s;\n",
- tos, error, strerror(error));
- }
- }
-#endif
-#ifdef SO_PRIORITY
- if(config->vlan_priority > 0) {
- int priority = (int)config->vlan_priority;
- if(setsockopt(curlfd, SOL_SOCKET, SO_PRIORITY,
- (void *)&priority, sizeof(priority)) != 0) {
- int error = errno;
- warnf(config->global, "VLAN priority %d failed with errno %d: %s;\n",
- priority, error, strerror(error));
- }
- }
-#endif
- return CURL_SOCKOPT_OK;
-}
-#endif
-
-
#ifdef __VMS
/*
* get_vms_file_size does what it takes to get the real size of the file
@@ -352,7 +271,7 @@ static CURLcode pre_transfer(struct GlobalConfig *global,
if(per->uploadfile && !stdin_upload(per->uploadfile)) {
/* VMS Note:
*
- * Reading binary from files can be a problem... Only FIXED, VAR
+ * Reading binary from files can be a problem... Only FIXED, VAR
* etc WITHOUT implied CC will work. Others need a \n appended to
* a line
*
@@ -386,7 +305,7 @@ static CURLcode pre_transfer(struct GlobalConfig *global,
if((per->infd == -1) || fstat(per->infd, &fileinfo))
#endif
{
- helpf(tool_stderr, "cannot open '%s'", per->uploadfile);
+ helpf(tool_stderr, "Can't open '%s'", per->uploadfile);
if(per->infd != -1) {
close(per->infd);
per->infd = STDIN_FILENO;
@@ -424,6 +343,22 @@ static CURLcode pre_transfer(struct GlobalConfig *global,
return result;
}
+#ifdef __AMIGA__
+static void AmigaSetComment(struct per_transfer *per,
+ CURLcode result)
+{
+ struct OutStruct *outs = &per->outs;
+ if(!result && outs->s_isreg && outs->filename) {
+ /* Set the url (up to 80 chars) as comment for the file */
+ if(strlen(per->this_url) > 78)
+ per->this_url[79] = '\0';
+ SetComment(outs->filename, per->this_url);
+ }
+}
+#else
+#define AmigaSetComment(x,y) Curl_nop_stmt
+#endif
+
/* When doing serial transfers, we use a single fixed error area */
static char global_errorbuffer[CURL_ERROR_SIZE];
@@ -437,6 +372,7 @@ void single_transfer_cleanup(struct OperationConfig *config)
state->urls = NULL;
}
Curl_safefree(state->outfiles);
+ Curl_safefree(state->httpgetfields);
Curl_safefree(state->uploadfile);
if(state->inglob) {
/* Free list of globbed upload files */
@@ -460,18 +396,15 @@ static CURLcode post_per_transfer(struct GlobalConfig *global,
struct OperationConfig *config = per->config;
int rc;
- *retryp = FALSE;
- *delay = 0; /* for no retry, keep it zero */
-
if(!curl || !config)
return result;
+ *retryp = FALSE;
+ *delay = 0; /* for no retry, keep it zero */
+
if(per->infdopen)
close(per->infd);
- if(per->skip)
- goto skip;
-
#ifdef __VMS
if(is_vms_shell()) {
/* VMS DCL shell behavior */
@@ -536,9 +469,9 @@ static CURLcode post_per_transfer(struct GlobalConfig *global,
memset(outs->utf8seq, 0, sizeof(outs->utf8seq));
#endif
- /* if retry-max-time is non-zero, make sure we have not exceeded the
+ /* if retry-max-time is non-zero, make sure we haven't exceeded the
time */
- if(per->retry_remaining &&
+ if(per->retry_numretries &&
(!config->retry_maxtime ||
(tvdiff(tvnow(), per->retrystart) <
config->retry_maxtime*1000L)) ) {
@@ -610,7 +543,7 @@ static CURLcode post_per_transfer(struct GlobalConfig *global,
if((scheme == proto_ftp || scheme == proto_ftps) && response / 100 == 4)
/*
* This is typically when the FTP server only allows a certain
- * amount of users and we are not one of them. All 4xx codes
+ * amount of users and we are not one of them. All 4xx codes
* are transient.
*/
retry = RETRY_FTP;
@@ -635,10 +568,10 @@ static CURLcode post_per_transfer(struct GlobalConfig *global,
if(RETRY_HTTP == retry) {
curl_easy_getinfo(curl, CURLINFO_RETRY_AFTER, &retry_after);
if(retry_after) {
- /* store in a 'long', make sure it does not overflow */
+ /* store in a 'long', make sure it doesn't overflow */
if(retry_after > LONG_MAX/1000)
sleeptime = LONG_MAX;
- else if((retry_after * 1000) > sleeptime)
+ else
sleeptime = (long)retry_after * 1000; /* milliseconds */
/* if adding retry_after seconds to the process would exceed the
@@ -660,9 +593,9 @@ static CURLcode post_per_transfer(struct GlobalConfig *global,
warnf(config->global, "Problem %s. "
"Will retry in %ld seconds. "
"%ld retries left.",
- m[retry], sleeptime/1000L, per->retry_remaining);
+ m[retry], sleeptime/1000L, per->retry_numretries);
- per->retry_remaining--;
+ per->retry_numretries--;
if(!config->retry_delay) {
per->retry_sleep *= 2;
if(per->retry_sleep > RETRY_SLEEP_MAX)
@@ -678,7 +611,7 @@ static CURLcode post_per_transfer(struct GlobalConfig *global,
/* truncate file at the position where we started appending */
#ifdef HAVE_FTRUNCATE
if(ftruncate(fileno(outs->stream), outs->init)) {
- /* when truncate fails, we cannot just append as then we will
+ /* when truncate fails, we can't just append as then we'll
create something strange, bail out */
errorf(config->global, "Failed to truncate file");
return CURLE_WRITE_ERROR;
@@ -688,7 +621,7 @@ static CURLcode post_per_transfer(struct GlobalConfig *global,
rc = fseek(outs->stream, 0, SEEK_END);
#else
/* ftruncate is not available, so just reposition the file
- to the location we would have truncated it. This will not
+ to the location we would have truncated it. This won't
work properly with large files on 32-bit systems, but
most of those will have ftruncate. */
rc = fseek(outs->stream, (long)outs->init, SEEK_SET);
@@ -700,11 +633,10 @@ static CURLcode post_per_transfer(struct GlobalConfig *global,
outs->bytes = 0; /* clear for next round */
}
*retryp = TRUE;
- per->num_retries++;
*delay = sleeptime;
return CURLE_OK;
}
- } /* if retry_remaining */
+ } /* if retry_numretries */
noretry:
if((global->progressmode == CURL_PROGRESS_BAR) &&
@@ -722,20 +654,13 @@ noretry:
errorf(config->global, "curl: (%d) Failed writing body", result);
}
if(result && config->rm_partial) {
- struct_stat st;
- if(!stat(outs->filename, &st) &&
- S_ISREG(st.st_mode)) {
- if(!unlink(outs->filename))
- notef(global, "Removed output file: %s", outs->filename);
- else
- warnf(global, "Failed removing: %s", outs->filename);
- }
- else
- warnf(global, "Skipping removal; not a regular file: %s",
- outs->filename);
+ notef(global, "Removing output file: %s", outs->filename);
+ unlink(outs->filename);
}
}
+ AmigaSetComment(per, result);
+
/* File time can only be set _after_ the file has been closed */
if(!result && config->remote_time && outs->s_isreg && outs->filename) {
/* Ask libcurl if we got a remote file time */
@@ -743,7 +668,7 @@ noretry:
curl_easy_getinfo(curl, CURLINFO_FILETIME_T, &filetime);
setfiletime(filetime, outs->filename, global);
}
-skip:
+
/* Write the --write-out data before cleanup but after result is final */
if(config->writeout)
ourWriteOut(config, per, result);
@@ -796,7 +721,7 @@ static CURLcode url_proto(char **url,
if(curl_strequal(schemep, proto_ipfs) ||
curl_strequal(schemep, proto_ipns)) {
result = ipfs_url_rewrite(uh, schemep, url, config);
- /* short-circuit proto_token, we know it is ipfs or ipns */
+ /* short-circuit proto_token, we know it's ipfs or ipns */
if(curl_strequal(schemep, proto_ipfs))
proto = proto_ipfs;
else if(curl_strequal(schemep, proto_ipns))
@@ -837,17 +762,21 @@ static CURLcode single_transfer(struct GlobalConfig *global,
if(config->use_httpget) {
if(!httpgetfields) {
/* Use the postfields data for an HTTP get */
- httpgetfields = state->httpgetfields = config->postfields;
- config->postfields = NULL;
- if(SetHTTPrequest(config,
- (config->no_body?TOOL_HTTPREQ_HEAD:TOOL_HTTPREQ_GET),
- &config->httpreq)) {
+ httpgetfields = state->httpgetfields = strdup(config->postfields);
+ Curl_safefree(config->postfields);
+ if(!httpgetfields) {
+ errorf(global, "out of memory");
+ result = CURLE_OUT_OF_MEMORY;
+ }
+ else if(SetHTTPrequest(config,
+ (config->no_body?HTTPREQ_HEAD:HTTPREQ_GET),
+ &config->httpreq)) {
result = CURLE_FAILED_INIT;
}
}
}
else {
- if(SetHTTPrequest(config, TOOL_HTTPREQ_SIMPLEPOST, &config->httpreq))
+ if(SetHTTPrequest(config, HTTPREQ_SIMPLEPOST, &config->httpreq))
result = CURLE_FAILED_INIT;
}
if(result) {
@@ -949,7 +878,6 @@ static CURLcode single_transfer(struct GlobalConfig *global,
urlnum = state->urlnum;
if(state->up < state->infilenum) {
- char ssl_ver[80] = "no ssl";
struct per_transfer *per = NULL;
struct OutStruct *outs;
struct OutStruct *heads;
@@ -1011,7 +939,7 @@ static CURLcode single_transfer(struct GlobalConfig *global,
if(config->etag_save_file) {
/* open file for output: */
if(strcmp(config->etag_save_file, "-")) {
- FILE *newfile = fopen(config->etag_save_file, "ab");
+ FILE *newfile = fopen(config->etag_save_file, "wb");
if(!newfile) {
warnf(global, "Failed creating file for saving etags: \"%s\". "
"Skip this transfer", config->etag_save_file);
@@ -1051,7 +979,7 @@ static CURLcode single_transfer(struct GlobalConfig *global,
result = CURLE_OUT_OF_MEMORY;
break;
}
- if(SetHTTPrequest(config, TOOL_HTTPREQ_PUT, &config->httpreq)) {
+ if(SetHTTPrequest(config, HTTPREQ_PUT, &config->httpreq)) {
Curl_safefree(per->uploadfile);
curl_easy_cleanup(curl);
result = CURLE_FAILED_INIT;
@@ -1061,7 +989,7 @@ static CURLcode single_transfer(struct GlobalConfig *global,
*added = TRUE;
per->config = config;
per->curl = curl;
- per->urlnum = (unsigned int)urlnode->num;
+ per->urlnum = urlnode->num;
/* default headers output stream is stdout */
heads = &per->heads;
@@ -1070,12 +998,7 @@ static CURLcode single_transfer(struct GlobalConfig *global,
/* Single header file for all URLs */
if(config->headerfile) {
/* open file for output: */
- if(!strcmp(config->headerfile, "%")) {
- heads->stream = stderr;
- /* use binary mode for protocol header output */
- set_binmode(heads->stream);
- }
- else if(strcmp(config->headerfile, "-")) {
+ if(strcmp(config->headerfile, "-")) {
FILE *newfile;
/*
@@ -1152,18 +1075,23 @@ static CURLcode single_transfer(struct GlobalConfig *global,
(per->outfile && strcmp("-", per->outfile)))) {
/*
- * We have specified a filename to store the result in, or we have
- * decided we want to use the remote filename.
+ * We have specified a file name to store the result in, or we have
+ * decided we want to use the remote file name.
*/
if(!per->outfile) {
- /* extract the filename from the URL */
- result = get_url_file_name(global, &per->outfile, per->this_url);
+ /* extract the file name from the URL */
+ result = get_url_file_name(&per->outfile, per->this_url);
if(result) {
- errorf(global, "Failed to extract a filename"
+ errorf(global, "Failed to extract a sensible file name"
" from the URL to use for storage");
break;
}
+ if(!*per->outfile && !config->content_disposition) {
+ errorf(global, "Remote file name has no length");
+ result = CURLE_WRITE_ERROR;
+ break;
+ }
}
else if(state->urls) {
/* fill '#1' ... '#9' terms from URL pattern */
@@ -1181,7 +1109,6 @@ static CURLcode single_transfer(struct GlobalConfig *global,
break;
}
}
- DEBUGASSERT(per->outfile);
if(config->output_dir && *config->output_dir) {
char *d = aprintf("%s/%s", config->output_dir, per->outfile);
@@ -1202,15 +1129,6 @@ static CURLcode single_transfer(struct GlobalConfig *global,
break;
}
- if(config->skip_existing) {
- struct_stat fileinfo;
- if(!stat(per->outfile, &fileinfo)) {
- /* file is present */
- notef(global, "skips transfer, \"%s\" exists locally",
- per->outfile);
- per->skip = TRUE;
- }
- }
if((urlnode->flags & GETOUT_USEREMOTE)
&& config->content_disposition) {
/* Our header callback MIGHT set the filename */
@@ -1218,7 +1136,7 @@ static CURLcode single_transfer(struct GlobalConfig *global,
}
if(config->resume_from_current) {
- /* We are told to continue from where we are now. Get the size
+ /* We're told to continue from where we are now. Get the size
of the file as it is now and open it for append instead */
struct_stat fileinfo;
/* VMS -- Danger, the filesize is only valid for stream files */
@@ -1241,7 +1159,7 @@ static CURLcode single_transfer(struct GlobalConfig *global,
FILE *file = fopen(per->outfile, "ab");
#endif
if(!file) {
- errorf(global, "cannot open '%s'", per->outfile);
+ errorf(global, "Can't open '%s'", per->outfile);
result = CURLE_WRITE_ERROR;
break;
}
@@ -1258,7 +1176,7 @@ static CURLcode single_transfer(struct GlobalConfig *global,
if(per->uploadfile && !stdin_upload(per->uploadfile)) {
/*
- * We have specified a file to upload and it is not "-".
+ * We have specified a file to upload and it isn't "-".
*/
result = add_file_name_to_url(per->curl, &per->this_url,
per->uploadfile);
@@ -1274,7 +1192,7 @@ static CURLcode single_transfer(struct GlobalConfig *global,
if(config->authtype & (1UL << bitcheck++)) {
authbits++;
if(authbits > 1) {
- /* more than one, we are done! */
+ /* more than one, we're done! */
break;
}
}
@@ -1365,20 +1283,19 @@ static CURLcode single_transfer(struct GlobalConfig *global,
if(result)
break;
+ /* result is only used when for ipfs and ipns, ignored otherwise */
result = url_proto(&per->this_url, config, &use_proto);
- if(result)
+ if(result && (use_proto == proto_ipfs || use_proto == proto_ipns))
break;
-#ifndef DEBUGBUILD
/* On most modern OSes, exiting works thoroughly,
- we will clean everything up via exit(), so do not bother with
+ we'll clean everything up via exit(), so don't bother with
slow cleanups. Crappy ones might need to skip this.
Note: avoid having this setopt added to the --libcurl source
output. */
result = curl_easy_setopt(curl, CURLOPT_QUICK_EXIT, 1L);
if(result)
break;
-#endif
if(!config->tcp_nodelay)
my_setopt(curl, CURLOPT_TCP_NODELAY, 0L);
@@ -1386,10 +1303,6 @@ static CURLcode single_transfer(struct GlobalConfig *global,
if(config->tcp_fastopen)
my_setopt(curl, CURLOPT_TCP_FASTOPEN, 1L);
- if(config->mptcp)
- my_setopt(curl, CURLOPT_OPENSOCKETFUNCTION,
- tool_socket_open_mptcp_cb);
-
/* where to store */
my_setopt(curl, CURLOPT_WRITEDATA, per);
my_setopt(curl, CURLOPT_INTERLEAVEDATA, per);
@@ -1414,7 +1327,7 @@ static CURLcode single_transfer(struct GlobalConfig *global,
my_setopt(curl, CURLOPT_SEEKFUNCTION, tool_seek_cb);
{
-#ifdef DEBUGBUILD
+#ifdef CURLDEBUG
char *env = getenv("CURL_BUFFERSIZE");
if(env) {
long size = strtol(env, NULL, 10);
@@ -1513,19 +1426,19 @@ static CURLcode single_transfer(struct GlobalConfig *global,
my_setopt(curl, CURLOPT_TIMEOUT_MS, config->timeout_ms);
switch(config->httpreq) {
- case TOOL_HTTPREQ_SIMPLEPOST:
+ case HTTPREQ_SIMPLEPOST:
if(config->resume_from) {
errorf(global, "cannot mix --continue-at with --data");
result = CURLE_FAILED_INIT;
}
else {
my_setopt_str(curl, CURLOPT_POSTFIELDS,
- curlx_dyn_ptr(&config->postdata));
+ config->postfields);
my_setopt(curl, CURLOPT_POSTFIELDSIZE_LARGE,
- (curl_off_t)curlx_dyn_len(&config->postdata));
+ config->postfieldsize);
}
break;
- case TOOL_HTTPREQ_MIMEPOST:
+ case HTTPREQ_MIMEPOST:
/* free previous remainders */
curl_mime_free(config->mimepost);
config->mimepost = NULL;
@@ -1651,14 +1564,6 @@ static CURLcode single_transfer(struct GlobalConfig *global,
my_setopt(curl, CURLOPT_SSH_COMPRESSION, 1L);
}
- {
- /* get current SSL backend, chop off multissl */
- const char *v = curl_version_info(CURLVERSION_NOW)->ssl_version;
- if(v)
- msnprintf(ssl_ver, sizeof(ssl_ver),
- "%.*s", (int) strcspn(v, " "), v);
- }
-
if(config->cacert)
my_setopt_str(curl, CURLOPT_CAINFO, config->cacert);
if(config->proxy_cacert)
@@ -1667,10 +1572,9 @@ static CURLcode single_transfer(struct GlobalConfig *global,
if(config->capath) {
result = res_setopt_str(curl, CURLOPT_CAPATH, config->capath);
if(result == CURLE_NOT_BUILT_IN) {
- warnf(global, "ignoring %s, not supported by libcurl with %s",
- capath_from_env ?
- "SSL_CERT_DIR environment variable" : "--capath",
- ssl_ver);
+ warnf(global, "ignoring %s, not supported by libcurl",
+ capath_from_env?
+ "SSL_CERT_DIR environment variable":"--capath");
}
else if(result)
break;
@@ -1685,47 +1589,14 @@ static CURLcode single_transfer(struct GlobalConfig *global,
if((result == CURLE_NOT_BUILT_IN) ||
(result == CURLE_UNKNOWN_OPTION)) {
if(config->proxy_capath) {
- warnf(global, "ignoring %s, not supported by libcurl with %s",
- config->proxy_capath ?
- "--proxy-capath" : "--capath",
- ssl_ver);
+ warnf(global,
+ "ignoring --proxy-capath, not supported by libcurl");
}
}
else if(result)
break;
}
-#ifdef CURL_CA_EMBED
- if(!config->cacert && !config->capath) {
- struct curl_blob blob;
- blob.data = (void *)curl_ca_embed;
- blob.len = strlen((const char *)curl_ca_embed);
- blob.flags = CURL_BLOB_NOCOPY;
- notef(config->global,
- "Using embedded CA bundle (%zu bytes)",
- blob.len);
- result = curl_easy_setopt(curl, CURLOPT_CAINFO_BLOB, &blob);
- if(result == CURLE_NOT_BUILT_IN) {
- warnf(global, "ignoring %s, not supported by libcurl with %s",
- "embedded CA bundle", ssl_ver);
- }
- }
- if(!config->proxy_cacert && !config->proxy_capath) {
- struct curl_blob blob;
- blob.data = (void *)curl_ca_embed;
- blob.len = strlen((const char *)curl_ca_embed);
- blob.flags = CURL_BLOB_NOCOPY;
- notef(config->global,
- "Using embedded CA bundle, for proxies (%zu bytes)",
- blob.len);
- result = curl_easy_setopt(curl, CURLOPT_PROXY_CAINFO_BLOB, &blob);
- if(result == CURLE_NOT_BUILT_IN) {
- warnf(global, "ignoring %s, not supported by libcurl with %s",
- "embedded CA bundle", ssl_ver);
- }
- }
-#endif
-
if(config->crlfile)
my_setopt_str(curl, CURLOPT_CRLFILE, config->crlfile);
if(config->proxy_crlfile)
@@ -1733,20 +1604,8 @@ static CURLcode single_transfer(struct GlobalConfig *global,
else if(config->crlfile) /* CURLOPT_PROXY_CRLFILE default is crlfile */
my_setopt_str(curl, CURLOPT_PROXY_CRLFILE, config->crlfile);
- if(config->pinnedpubkey) {
- result = res_setopt_str(curl, CURLOPT_PINNEDPUBLICKEY,
- config->pinnedpubkey);
- if(result == CURLE_NOT_BUILT_IN)
- warnf(global, "ignoring %s, not supported by libcurl with %s",
- "--pinnedpubkey", ssl_ver);
- }
- if(config->proxy_pinnedpubkey) {
- result = res_setopt_str(curl, CURLOPT_PROXY_PINNEDPUBLICKEY,
- config->proxy_pinnedpubkey);
- if(result == CURLE_NOT_BUILT_IN)
- warnf(global, "ignoring %s, not supported by libcurl with %s",
- "--proxy-pinnedpubkey", ssl_ver);
- }
+ if(config->pinnedpubkey)
+ my_setopt_str(curl, CURLOPT_PINNEDPUBLICKEY, config->pinnedpubkey);
if(config->ssl_ec_curves)
my_setopt_str(curl, CURLOPT_SSL_EC_CURVES, config->ssl_ec_curves);
@@ -1800,7 +1659,7 @@ static CURLcode single_transfer(struct GlobalConfig *global,
* must do the same thing as classic:
* --cert <filename>:<password> --cert-type p12
* but is designed to test blob */
-#ifdef DEBUGBUILD
+#if defined(CURLDEBUG) || defined(DEBUGBUILD)
if(config->cert && (strlen(config->cert) > 8) &&
(memcmp(config->cert, "loadmem=",8) == 0)) {
FILE *fInCert = fopen(config->cert + 8, "rb");
@@ -1828,7 +1687,7 @@ static CURLcode single_transfer(struct GlobalConfig *global,
structblob.len = (size_t)filesize;
structblob.flags = CURL_BLOB_COPY;
my_setopt_str(curl, CURLOPT_SSLCERT_BLOB, &structblob);
- /* if test run well, we are sure we do not reuse
+ /* if test run well, we are sure we don't reuse
* original mem pointer */
memset(certdata, 0, (size_t)filesize);
}
@@ -1843,7 +1702,7 @@ static CURLcode single_transfer(struct GlobalConfig *global,
config->proxy_cert_type);
-#ifdef DEBUGBUILD
+#if defined(CURLDEBUG) || defined(DEBUGBUILD)
if(config->key && (strlen(config->key) > 8) &&
(memcmp(config->key, "loadmem=",8) == 0)) {
FILE *fInCert = fopen(config->key + 8, "rb");
@@ -1871,7 +1730,7 @@ static CURLcode single_transfer(struct GlobalConfig *global,
structblob.len = (size_t)filesize;
structblob.flags = CURL_BLOB_COPY;
my_setopt_str(curl, CURLOPT_SSLKEY_BLOB, &structblob);
- /* if test run well, we are sure we do not reuse
+ /* if test run well, we are sure we don't reuse
* original mem pointer */
memset(certdata, 0, (size_t)filesize);
}
@@ -1884,12 +1743,15 @@ static CURLcode single_transfer(struct GlobalConfig *global,
my_setopt_str(curl, CURLOPT_SSLKEYTYPE, config->key_type);
my_setopt_str(curl, CURLOPT_PROXY_SSLKEYTYPE,
config->proxy_key_type);
-
- /* libcurl default is strict verifyhost -> 1L, verifypeer -> 1L */
if(config->insecure_ok) {
my_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
my_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
}
+ else {
+ my_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L);
+ /* libcurl default is strict verifyhost -> 2L */
+ /* my_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2L); */
+ }
if(config->doh_insecure_ok) {
my_setopt(curl, CURLOPT_DOH_SSL_VERIFYPEER, 0L);
@@ -1900,6 +1762,9 @@ static CURLcode single_transfer(struct GlobalConfig *global,
my_setopt(curl, CURLOPT_PROXY_SSL_VERIFYPEER, 0L);
my_setopt(curl, CURLOPT_PROXY_SSL_VERIFYHOST, 0L);
}
+ else {
+ my_setopt(curl, CURLOPT_PROXY_SSL_VERIFYPEER, 1L);
+ }
if(config->verifystatus)
my_setopt(curl, CURLOPT_SSL_VERIFYSTATUS, 1L);
@@ -1910,11 +1775,11 @@ static CURLcode single_transfer(struct GlobalConfig *global,
if(config->falsestart)
my_setopt(curl, CURLOPT_SSL_FALSESTART, 1L);
- my_setopt_SSLVERSION(curl, CURLOPT_SSLVERSION,
- config->ssl_version | config->ssl_version_max);
+ my_setopt_enum(curl, CURLOPT_SSLVERSION,
+ config->ssl_version | config->ssl_version_max);
if(config->proxy)
- my_setopt_SSLVERSION(curl, CURLOPT_PROXY_SSLVERSION,
- config->proxy_ssl_version);
+ my_setopt_enum(curl, CURLOPT_PROXY_SSLVERSION,
+ config->proxy_ssl_version);
{
long mask =
@@ -2063,34 +1928,19 @@ static CURLcode single_transfer(struct GlobalConfig *global,
if(config->doh_url)
my_setopt_str(curl, CURLOPT_DOH_URL, config->doh_url);
- if(config->cipher_list) {
- result = res_setopt_str(curl, CURLOPT_SSL_CIPHER_LIST,
- config->cipher_list);
- if(result == CURLE_NOT_BUILT_IN)
- warnf(global, "ignoring %s, not supported by libcurl with %s",
- "--ciphers", ssl_ver);
- }
- if(config->proxy_cipher_list) {
- result = res_setopt_str(curl, CURLOPT_PROXY_SSL_CIPHER_LIST,
- config->proxy_cipher_list);
- if(result == CURLE_NOT_BUILT_IN)
- warnf(global, "ignoring %s, not supported by libcurl with %s",
- "--proxy-ciphers", ssl_ver);
- }
- if(config->cipher13_list) {
- result = res_setopt_str(curl, CURLOPT_TLS13_CIPHERS,
- config->cipher13_list);
- if(result == CURLE_NOT_BUILT_IN)
- warnf(global, "ignoring %s, not supported by libcurl with %s",
- "--tls13-ciphers", ssl_ver);
- }
- if(config->proxy_cipher13_list) {
- result = res_setopt_str(curl, CURLOPT_PROXY_TLS13_CIPHERS,
- config->proxy_cipher13_list);
- if(result == CURLE_NOT_BUILT_IN)
- warnf(global, "ignoring %s, not supported by libcurl with %s",
- "--proxy-tls13-ciphers", ssl_ver);
- }
+ if(config->cipher_list)
+ my_setopt_str(curl, CURLOPT_SSL_CIPHER_LIST, config->cipher_list);
+
+ if(config->proxy_cipher_list)
+ my_setopt_str(curl, CURLOPT_PROXY_SSL_CIPHER_LIST,
+ config->proxy_cipher_list);
+
+ if(config->cipher13_list)
+ my_setopt_str(curl, CURLOPT_TLS13_CIPHERS, config->cipher13_list);
+
+ if(config->proxy_cipher13_list)
+ my_setopt_str(curl, CURLOPT_PROXY_TLS13_CIPHERS,
+ config->proxy_cipher13_list);
/* new in libcurl 7.9.2: */
if(config->disable_epsv)
@@ -2205,8 +2055,6 @@ static CURLcode single_transfer(struct GlobalConfig *global,
my_setopt(curl, CURLOPT_TCP_KEEPIDLE, config->alivetime);
my_setopt(curl, CURLOPT_TCP_KEEPINTVL, config->alivetime);
}
- if(config->alivecnt)
- my_setopt(curl, CURLOPT_TCP_KEEPCNT, config->alivecnt);
}
else
my_setopt(curl, CURLOPT_TCP_KEEPALIVE, 0L);
@@ -2351,39 +2199,10 @@ static CURLcode single_transfer(struct GlobalConfig *global,
if(config->hsts)
my_setopt_str(curl, CURLOPT_HSTS, config->hsts);
-#ifdef USE_ECH
- /* only if enabled in configure */
- if(config->ech) /* only if set (optional) */
- my_setopt_str(curl, CURLOPT_ECH, config->ech);
- if(config->ech_public) /* only if set (optional) */
- my_setopt_str(curl, CURLOPT_ECH, config->ech_public);
- if(config->ech_config) /* only if set (optional) */
- my_setopt_str(curl, CURLOPT_ECH, config->ech_config);
-#endif
-
- /* new in 8.9.0 */
- if(config->ip_tos > 0 || config->vlan_priority > 0) {
-#if defined(IP_TOS) || defined(IPV6_TCLASS) || defined(SO_PRIORITY)
- my_setopt(curl, CURLOPT_SOCKOPTFUNCTION, sockopt_callback);
- my_setopt(curl, CURLOPT_SOCKOPTDATA, config);
-#else
- if(config->ip_tos > 0) {
- errorf(config->global,
- "Type of service is not supported in this build.");
- result = CURLE_NOT_BUILT_IN;
- }
- if(config->vlan_priority > 0) {
- errorf(config->global,
- "VLAN priority is not supported in this build.");
- result = CURLE_NOT_BUILT_IN;
- }
-#endif
- }
-
/* initialize retry vars for loop below */
per->retry_sleep_default = (config->retry_delay) ?
config->retry_delay*1000L : RETRY_SLEEP_DEFAULT; /* ms */
- per->retry_remaining = config->req_retry;
+ per->retry_numretries = config->req_retry;
per->retry_sleep = per->retry_sleep_default; /* ms */
per->retrystart = tvnow();
@@ -2477,7 +2296,7 @@ static CURLcode add_parallel_transfers(struct GlobalConfig *global,
if(!errorbuf)
return CURLE_OUT_OF_MEMORY;
- /* parallel connect means that we do not set PIPEWAIT since pipewait
+ /* parallel connect means that we don't set PIPEWAIT since pipewait
will make libcurl prefer multiplexing */
(void)curl_easy_setopt(per->curl, CURLOPT_PIPEWAIT,
global->parallel_connect ? 0L : 1L);
@@ -2485,10 +2304,6 @@ static CURLcode add_parallel_transfers(struct GlobalConfig *global,
(void)curl_easy_setopt(per->curl, CURLOPT_XFERINFOFUNCTION, xferinfo_cb);
(void)curl_easy_setopt(per->curl, CURLOPT_XFERINFODATA, per);
(void)curl_easy_setopt(per->curl, CURLOPT_NOPROGRESS, 0L);
-#ifdef DEBUGBUILD
- if(getenv("CURL_FORBID_REUSE"))
- (void)curl_easy_setopt(per->curl, CURLOPT_FORBID_REUSE, 1L);
-#endif
mcode = curl_multi_add_handle(multi, per->curl);
if(mcode) {
@@ -2513,386 +2328,136 @@ static CURLcode add_parallel_transfers(struct GlobalConfig *global,
return CURLE_OK;
}
-struct parastate {
- struct GlobalConfig *global;
+static CURLcode parallel_transfers(struct GlobalConfig *global,
+ CURLSH *share)
+{
CURLM *multi;
- CURLSH *share;
- CURLMcode mcode;
- CURLcode result;
- int still_running;
- struct timeval start;
+ CURLMcode mcode = CURLM_OK;
+ CURLcode result = CURLE_OK;
+ int still_running = 1;
+ struct timeval start = tvnow();
bool more_transfers;
bool added_transfers;
/* wrapitup is set TRUE after a critical error occurs to end all transfers */
- bool wrapitup;
+ bool wrapitup = FALSE;
/* wrapitup_processed is set TRUE after the per transfer abort flag is set */
- bool wrapitup_processed;
- time_t tick;
-};
-
-#if defined(DEBUGBUILD) && defined(USE_LIBUV)
-
-#define DEBUG_UV 0
-
-/* object to pass to the callbacks */
-struct datauv {
- uv_timer_t timeout;
- uv_loop_t *loop;
- struct parastate *s;
-};
-
-struct contextuv {
- uv_poll_t poll_handle;
- curl_socket_t sockfd;
- struct datauv *uv;
-};
-
-static CURLcode check_finished(struct parastate *s);
-
-static void check_multi_info(struct datauv *uv)
-{
- CURLcode result;
-
- result = check_finished(uv->s);
- if(result && !uv->s->result)
- uv->s->result = result;
-
- if(uv->s->more_transfers) {
- result = add_parallel_transfers(uv->s->global, uv->s->multi,
- uv->s->share,
- &uv->s->more_transfers,
- &uv->s->added_transfers);
- if(result && !uv->s->result)
- uv->s->result = result;
- if(result)
- uv_stop(uv->loop);
- }
-}
-
-/* callback from libuv on socket activity */
-static void on_uv_socket(uv_poll_t *req, int status, int events)
-{
- int flags = 0;
- struct contextuv *c = (struct contextuv *) req->data;
- (void)status;
- if(events & UV_READABLE)
- flags |= CURL_CSELECT_IN;
- if(events & UV_WRITABLE)
- flags |= CURL_CSELECT_OUT;
-
- curl_multi_socket_action(c->uv->s->multi, c->sockfd, flags,
- &c->uv->s->still_running);
-}
-
-/* callback from libuv when timeout expires */
-static void on_uv_timeout(uv_timer_t *req)
-{
- struct datauv *uv = (struct datauv *) req->data;
-#if DEBUG_UV
- fprintf(tool_stderr, "parallel_event: on_uv_timeout\n");
-#endif
- if(uv && uv->s) {
- curl_multi_socket_action(uv->s->multi, CURL_SOCKET_TIMEOUT, 0,
- &uv->s->still_running);
- check_multi_info(uv);
- }
-}
-
-/* callback from libcurl to update the timeout expiry */
-static int cb_timeout(CURLM *multi, long timeout_ms,
- struct datauv *uv)
-{
- (void)multi;
-#if DEBUG_UV
- fprintf(tool_stderr, "parallel_event: cb_timeout=%ld\n", timeout_ms);
-#endif
- if(timeout_ms < 0)
- uv_timer_stop(&uv->timeout);
- else {
- if(timeout_ms == 0)
- timeout_ms = 1; /* 0 means call curl_multi_socket_action asap but NOT
- within the callback itself */
- uv_timer_start(&uv->timeout, on_uv_timeout, timeout_ms,
- 0); /* do not repeat */
- }
- return 0;
-}
-
-static struct contextuv *create_context(curl_socket_t sockfd,
- struct datauv *uv)
-{
- struct contextuv *c;
-
- c = (struct contextuv *) malloc(sizeof(*c));
-
- c->sockfd = sockfd;
- c->uv = uv;
-
- uv_poll_init_socket(uv->loop, &c->poll_handle, sockfd);
- c->poll_handle.data = c;
-
- return c;
-}
-
-static void close_cb(uv_handle_t *handle)
-{
- struct contextuv *c = (struct contextuv *) handle->data;
- free(c);
-}
-
-static void destroy_context(struct contextuv *c)
-{
- uv_close((uv_handle_t *) &c->poll_handle, close_cb);
-}
-
-/* callback from libcurl to update socket activity to wait for */
-static int cb_socket(CURL *easy, curl_socket_t s, int action,
- struct datauv *uv,
- void *socketp)
-{
- struct contextuv *c;
- int events = 0;
- (void)easy;
-
- switch(action) {
- case CURL_POLL_IN:
- case CURL_POLL_OUT:
- case CURL_POLL_INOUT:
- c = socketp ?
- (struct contextuv *) socketp : create_context(s, uv);
-
- curl_multi_assign(uv->s->multi, s, c);
-
- if(action != CURL_POLL_IN)
- events |= UV_WRITABLE;
- if(action != CURL_POLL_OUT)
- events |= UV_READABLE;
-
- uv_poll_start(&c->poll_handle, events, on_uv_socket);
- break;
- case CURL_POLL_REMOVE:
- if(socketp) {
- c = (struct contextuv *)socketp;
- uv_poll_stop(&c->poll_handle);
- destroy_context(c);
- curl_multi_assign(uv->s->multi, s, NULL);
- /* check if we can do more now */
- check_multi_info(uv);
- }
- break;
- default:
- abort();
- }
-
- return 0;
-}
-
-static CURLcode parallel_event(struct parastate *s)
-{
- CURLcode result = CURLE_OK;
- struct datauv uv = { 0 };
-
- s->result = CURLE_OK;
- uv.s = s;
- uv.loop = uv_default_loop();
- uv_timer_init(uv.loop, &uv.timeout);
- uv.timeout.data = &uv;
-
- /* setup event callbacks */
- curl_multi_setopt(s->multi, CURLMOPT_SOCKETFUNCTION, cb_socket);
- curl_multi_setopt(s->multi, CURLMOPT_SOCKETDATA, &uv);
- curl_multi_setopt(s->multi, CURLMOPT_TIMERFUNCTION, cb_timeout);
- curl_multi_setopt(s->multi, CURLMOPT_TIMERDATA, &uv);
-
- /* kickstart the thing */
- curl_multi_socket_action(s->multi, CURL_SOCKET_TIMEOUT, 0,
- &s->still_running);
-
- while(!s->mcode && (s->still_running || s->more_transfers)) {
-#if DEBUG_UV
- fprintf(tool_stderr, "parallel_event: uv_run(), mcode=%d, %d running, "
- "%d more\n", s->mcode, uv.s->still_running, s->more_transfers);
-#endif
- uv_run(uv.loop, UV_RUN_DEFAULT);
-#if DEBUG_UV
- fprintf(tool_stderr, "parallel_event: uv_run() returned\n");
-#endif
-
- result = check_finished(s);
- if(result && !s->result)
- s->result = result;
+ bool wrapitup_processed = FALSE;
+ time_t tick = time(NULL);
- /* early exit called */
- if(s->wrapitup) {
- if(s->still_running && !s->wrapitup_processed) {
- struct per_transfer *per;
- for(per = transfers; per; per = per->next) {
- if(per->added)
- per->abort = TRUE;
- }
- s->wrapitup_processed = TRUE;
- }
- break;
- }
-
- if(s->more_transfers) {
- result = add_parallel_transfers(s->global, s->multi, s->share,
- &s->more_transfers, &s->added_transfers);
- if(result && !s->result)
- s->result = result;
- }
- }
-
-#if DEBUG_UV
- fprintf(tool_stderr, "DONE parallel_event -> %d, mcode=%d, %d running, "
- "%d more\n",
- s->result, s->mcode, uv.s->still_running, s->more_transfers);
-#endif
- return s->result;
-}
-
-#endif
-
-static CURLcode check_finished(struct parastate *s)
-{
- CURLcode result = CURLE_OK;
- int rc;
- CURLMsg *msg;
- bool checkmore = FALSE;
- struct GlobalConfig *global = s->global;
- progress_meter(global, &s->start, FALSE);
- do {
- msg = curl_multi_info_read(s->multi, &rc);
- if(msg) {
- bool retry;
- long delay;
- struct per_transfer *ended;
- CURL *easy = msg->easy_handle;
- CURLcode tres = msg->data.result;
- curl_easy_getinfo(easy, CURLINFO_PRIVATE, (void *)&ended);
- curl_multi_remove_handle(s->multi, easy);
-
- if(ended->abort && (tres == CURLE_ABORTED_BY_CALLBACK) &&
- ended->errorbuffer) {
- msnprintf(ended->errorbuffer, CURL_ERROR_SIZE,
- "Transfer aborted due to critical error "
- "in another transfer");
- }
- tres = post_per_transfer(global, ended, tres, &retry, &delay);
- progress_finalize(ended); /* before it goes away */
- all_added--; /* one fewer added */
- checkmore = TRUE;
- if(retry) {
- ended->added = FALSE; /* add it again */
- /* we delay retries in full integer seconds only */
- ended->startat = delay ? time(NULL) + delay/1000 : 0;
- }
- else {
- /* result receives this transfer's error unless the transfer was
- marked for abort due to a critical error in another transfer */
- if(tres && (!ended->abort || !result))
- result = tres;
- if(is_fatal_error(result) || (result && global->fail_early))
- s->wrapitup = TRUE;
- (void)del_per_transfer(ended);
- }
- }
- } while(msg);
- if(!s->wrapitup) {
- if(!checkmore) {
- time_t tock = time(NULL);
- if(s->tick != tock) {
- checkmore = TRUE;
- s->tick = tock;
- }
- }
- if(checkmore) {
- /* one or more transfers completed, add more! */
- CURLcode tres = add_parallel_transfers(global, s->multi, s->share,
- &s->more_transfers,
- &s->added_transfers);
- if(tres)
- result = tres;
- if(s->added_transfers)
- /* we added new ones, make sure the loop does not exit yet */
- s->still_running = 1;
- }
- if(is_fatal_error(result) || (result && global->fail_early))
- s->wrapitup = TRUE;
- }
- return result;
-}
-
-static CURLcode parallel_transfers(struct GlobalConfig *global,
- CURLSH *share)
-{
- CURLcode result;
- struct parastate p;
- struct parastate *s = &p;
- s->share = share;
- s->mcode = CURLM_OK;
- s->result = CURLE_OK;
- s->still_running = 1;
- s->start = tvnow();
- s->wrapitup = FALSE;
- s->wrapitup_processed = FALSE;
- s->tick = time(NULL);
- s->global = global;
- s->multi = curl_multi_init();
- if(!s->multi)
+ multi = curl_multi_init();
+ if(!multi)
return CURLE_OUT_OF_MEMORY;
- result = add_parallel_transfers(global, s->multi, s->share,
- &s->more_transfers, &s->added_transfers);
+ result = add_parallel_transfers(global, multi, share,
+ &more_transfers, &added_transfers);
if(result) {
- curl_multi_cleanup(s->multi);
+ curl_multi_cleanup(multi);
return result;
}
-#ifdef DEBUGBUILD
- if(global->test_event_based)
-#ifdef USE_LIBUV
- result = parallel_event(s);
-#else
- errorf(global, "Testing --parallel event-based requires libuv");
-#endif
- else
-#endif
- while(!s->mcode && (s->still_running || s->more_transfers)) {
+ while(!mcode && (still_running || more_transfers)) {
/* If stopping prematurely (eg due to a --fail-early condition) then signal
that any transfers in the multi should abort (via progress callback). */
- if(s->wrapitup) {
- if(!s->still_running)
+ if(wrapitup) {
+ if(!still_running)
break;
- if(!s->wrapitup_processed) {
+ if(!wrapitup_processed) {
struct per_transfer *per;
for(per = transfers; per; per = per->next) {
if(per->added)
per->abort = TRUE;
}
- s->wrapitup_processed = TRUE;
+ wrapitup_processed = TRUE;
}
}
- s->mcode = curl_multi_poll(s->multi, NULL, 0, 1000, NULL);
- if(!s->mcode)
- s->mcode = curl_multi_perform(s->multi, &s->still_running);
-
- if(!s->mcode)
- result = check_finished(s);
+ mcode = curl_multi_poll(multi, NULL, 0, 1000, NULL);
+ if(!mcode)
+ mcode = curl_multi_perform(multi, &still_running);
+
+ progress_meter(global, &start, FALSE);
+
+ if(!mcode) {
+ int rc;
+ CURLMsg *msg;
+ bool checkmore = FALSE;
+ do {
+ msg = curl_multi_info_read(multi, &rc);
+ if(msg) {
+ bool retry;
+ long delay;
+ struct per_transfer *ended;
+ CURL *easy = msg->easy_handle;
+ CURLcode tres = msg->data.result;
+ curl_easy_getinfo(easy, CURLINFO_PRIVATE, (void *)&ended);
+ curl_multi_remove_handle(multi, easy);
+
+ if(ended->abort && (tres == CURLE_ABORTED_BY_CALLBACK) &&
+ ended->errorbuffer) {
+ msnprintf(ended->errorbuffer, CURL_ERROR_SIZE,
+ "Transfer aborted due to critical error "
+ "in another transfer");
+ }
+ tres = post_per_transfer(global, ended, tres, &retry, &delay);
+ progress_finalize(ended); /* before it goes away */
+ all_added--; /* one fewer added */
+ checkmore = TRUE;
+ if(retry) {
+ ended->added = FALSE; /* add it again */
+ /* we delay retries in full integer seconds only */
+ ended->startat = delay ? time(NULL) + delay/1000 : 0;
+ }
+ else {
+ /* result receives this transfer's error unless the transfer was
+ marked for abort due to a critical error in another transfer */
+ if(tres && (!ended->abort || !result))
+ result = tres;
+ if(is_fatal_error(result) || (result && global->fail_early))
+ wrapitup = TRUE;
+ (void)del_per_transfer(ended);
+ }
+ }
+ } while(msg);
+ if(wrapitup) {
+ if(still_running)
+ continue;
+ else
+ break;
+ }
+ if(!checkmore) {
+ time_t tock = time(NULL);
+ if(tick != tock) {
+ checkmore = TRUE;
+ tick = tock;
+ }
+ }
+ if(checkmore) {
+ /* one or more transfers completed, add more! */
+ CURLcode tres = add_parallel_transfers(global, multi, share,
+ &more_transfers,
+ &added_transfers);
+ if(tres)
+ result = tres;
+ if(added_transfers)
+ /* we added new ones, make sure the loop doesn't exit yet */
+ still_running = 1;
+ }
+ if(is_fatal_error(result) || (result && global->fail_early))
+ wrapitup = TRUE;
+ }
}
- (void)progress_meter(global, &s->start, TRUE);
+ (void)progress_meter(global, &start, TRUE);
/* Make sure to return some kind of error if there was a multi problem */
- if(s->mcode) {
- result = (s->mcode == CURLM_OUT_OF_MEMORY) ? CURLE_OUT_OF_MEMORY :
+ if(mcode) {
+ result = (mcode == CURLM_OUT_OF_MEMORY) ? CURLE_OUT_OF_MEMORY :
/* The other multi errors should never happen, so return
something suitably generic */
CURLE_BAD_FUNCTION_ARGUMENT;
}
- curl_multi_cleanup(s->multi);
+ curl_multi_cleanup(multi);
return result;
}
@@ -2917,29 +2482,22 @@ static CURLcode serial_transfers(struct GlobalConfig *global,
long delay_ms;
bool bailout = FALSE;
struct timeval start;
+ result = pre_transfer(global, per);
+ if(result)
+ break;
- start = tvnow();
- if(!per->skip) {
- result = pre_transfer(global, per);
+ if(global->libcurl) {
+ result = easysrc_perform();
if(result)
break;
-
- if(global->libcurl) {
- result = easysrc_perform();
- if(result)
- break;
- }
-
-#ifdef DEBUGBUILD
- if(getenv("CURL_FORBID_REUSE"))
- (void)curl_easy_setopt(per->curl, CURLOPT_FORBID_REUSE, 1L);
-
- if(global->test_event_based)
- result = curl_easy_perform_ev(per->curl);
- else
-#endif
- result = curl_easy_perform(per->curl);
}
+ start = tvnow();
+#ifdef CURLDEBUG
+ if(global->test_event_based)
+ result = curl_easy_perform_ev(per->curl);
+ else
+#endif
+ result = curl_easy_perform(per->curl);
returncode = post_per_transfer(global, per, result, &retry, &delay_ms);
if(retry) {
@@ -3002,10 +2560,10 @@ static CURLcode transfer_per_config(struct GlobalConfig *global,
return CURLE_FAILED_INIT;
}
- /* On Windows we cannot set the path to curl-ca-bundle.crt at compile time.
- * We look for the file in two ways:
+ /* On WIN32 we can't set the path to curl-ca-bundle.crt
+ * at compile time. So we look here for the file in two ways:
* 1: look at the environment variable CURL_CA_BUNDLE for a path
- * 2: if #1 is not found, use the Windows API function SearchPath()
+ * 2: if #1 isn't found, use the windows API function SearchPath()
* to find it along the app's path (includes app's dir and CWD)
*
* We support the environment variable thing for non-Windows platforms
@@ -3039,33 +2597,34 @@ static CURLcode transfer_per_config(struct GlobalConfig *global,
*/
if(tls_backend_info->backend != CURLSSLBACKEND_SCHANNEL) {
char *env;
- env = curl_getenv("CURL_CA_BUNDLE");
+ env = curlx_getenv("CURL_CA_BUNDLE");
if(env) {
config->cacert = strdup(env);
- curl_free(env);
if(!config->cacert) {
+ curl_free(env);
curl_easy_cleanup(curltls);
errorf(global, "out of memory");
return CURLE_OUT_OF_MEMORY;
}
}
else {
- env = curl_getenv("SSL_CERT_DIR");
+ env = curlx_getenv("SSL_CERT_DIR");
if(env) {
config->capath = strdup(env);
- curl_free(env);
if(!config->capath) {
+ curl_free(env);
curl_easy_cleanup(curltls);
errorf(global, "out of memory");
return CURLE_OUT_OF_MEMORY;
}
+ curl_free(env);
capath_from_env = true;
}
- env = curl_getenv("SSL_CERT_FILE");
+ env = curlx_getenv("SSL_CERT_FILE");
if(env) {
config->cacert = strdup(env);
- curl_free(env);
if(!config->cacert) {
+ curl_free(env);
if(capath_from_env)
free(config->capath);
curl_easy_cleanup(curltls);
@@ -3075,10 +2634,13 @@ static CURLcode transfer_per_config(struct GlobalConfig *global,
}
}
+ if(env)
+ curl_free(env);
#ifdef _WIN32
- if(!env)
+ else {
result = FindWin32CACert(config, tls_backend_info->backend,
TEXT("curl-ca-bundle.crt"));
+ }
#endif
}
curl_easy_cleanup(curltls);
@@ -3135,7 +2697,7 @@ static CURLcode run_all_transfers(struct GlobalConfig *global,
long delay;
CURLcode result2 = post_per_transfer(global, per, result, &retry, &delay);
if(!result)
- /* do not overwrite the original error */
+ /* don't overwrite the original error */
result = result2;
/* Free list of given URLs */
@@ -3166,7 +2728,7 @@ CURLcode operate(struct GlobalConfig *global, int argc, argv_item_t argv[])
/* Parse .curlrc if necessary */
if((argc == 1) ||
(first_arg && strncmp(first_arg, "-q", 2) &&
- strcmp(first_arg, "--disable"))) {
+ !curl_strequal(first_arg, "--disable"))) {
parseconfig(NULL, global); /* ignore possible failure */
/* If we had no arguments then make sure a url was specified in .curlrc */
@@ -3196,12 +2758,6 @@ CURLcode operate(struct GlobalConfig *global, int argc, argv_item_t argv[])
/* Check if we were asked to list the SSL engines */
else if(res == PARAM_ENGINES_REQUESTED)
tool_list_engines();
- /* Check if we were asked to dump the embedded CA bundle */
- else if(res == PARAM_CA_EMBED_REQUESTED) {
-#ifdef CURL_CA_EMBED
- printf("%s", curl_ca_embed);
-#endif
- }
else if(res == PARAM_LIBCURL_UNSUPPORTED_PROTOCOL)
result = CURLE_UNSUPPORTED_PROTOCOL;
else if(res == PARAM_READ_ERROR)
diff --git a/contrib/libs/curl/src/tool_operate.h b/contrib/libs/curl/src/tool_operate.h
index a2bd83b10b..4993b1c961 100644
--- a/contrib/libs/curl/src/tool_operate.h
+++ b/contrib/libs/curl/src/tool_operate.h
@@ -35,25 +35,33 @@ struct per_transfer {
struct OperationConfig *config; /* for this transfer */
struct curl_certinfo *certinfo;
CURL *curl;
- long retry_remaining;
+ long retry_numretries;
long retry_sleep_default;
long retry_sleep;
- long num_retries; /* counts the performed retries */
struct timeval start; /* start of this transfer */
struct timeval retrystart;
char *this_url;
unsigned int urlnum; /* the index of the given URL */
char *outfile;
+ bool infdopen; /* TRUE if infd needs closing */
int infd;
+ bool noprogress;
struct ProgressData progressbar;
struct OutStruct outs;
struct OutStruct heads;
struct OutStruct etag_save;
struct HdrCbData hdrcbdata;
long num_headers;
+ bool was_last_header_empty;
+
+ bool added; /* set TRUE when added to the multi handle */
time_t startat; /* when doing parallel transfers, this is a retry transfer
that has been set to sleep until this time before it
should get started (again) */
+ bool abort; /* when doing parallel transfers and this is TRUE then a critical
+ error (eg --fail-early) has occurred in another transfer and
+ this transfer will be aborted in the progress callback */
+
/* for parallel progress bar */
curl_off_t dltotal;
curl_off_t dlnow;
@@ -68,15 +76,6 @@ struct per_transfer {
char *uploadfile;
char *errorbuffer; /* allocated and assigned while this is used for a
transfer */
- bool infdopen; /* TRUE if infd needs closing */
- bool noprogress;
- bool was_last_header_empty;
-
- bool added; /* set TRUE when added to the multi handle */
- bool abort; /* when doing parallel transfers and this is TRUE then a critical
- error (eg --fail-early) has occurred in another transfer and
- this transfer will be aborted in the progress callback */
- bool skip; /* considered already done */
};
CURLcode operate(struct GlobalConfig *config, int argc, argv_item_t argv[]);
diff --git a/contrib/libs/curl/src/tool_operhlp.c b/contrib/libs/curl/src/tool_operhlp.c
index 0ed441c3f6..d1e8352d88 100644
--- a/contrib/libs/curl/src/tool_operhlp.c
+++ b/contrib/libs/curl/src/tool_operhlp.c
@@ -26,12 +26,13 @@
#include "strcase.h"
+#define ENABLE_CURLX_PRINTF
+/* use our own printf() functions */
#include "curlx.h"
#include "tool_cfgable.h"
#include "tool_doswin.h"
#include "tool_operhlp.h"
-#include "tool_msgs.h"
#include "memdebug.h" /* keep this as LAST include */
@@ -85,7 +86,7 @@ CURLcode urlerr_cvt(CURLUcode ucode)
}
/*
- * Adds the filename to the URL if it does not already have one.
+ * Adds the file name to the URL if it doesn't already have one.
* url will be freed before return if the returned pointer is different
*/
CURLcode add_file_name_to_url(CURL *curl, char **inurlp, const char *filename)
@@ -117,7 +118,7 @@ CURLcode add_file_name_to_url(CURL *curl, char **inurlp, const char *filename)
}
ptr = strrchr(path, '/');
if(!ptr || !*++ptr) {
- /* The URL path has no filename part, add the local filename. In order
+ /* The URL path has no file name part, add the local file name. In order
to be able to do so, we have to create a new URL in another buffer.*/
/* We only want the part of the local path that is on the right
@@ -133,7 +134,7 @@ CURLcode add_file_name_to_url(CURL *curl, char **inurlp, const char *filename)
else
filep = filename;
- /* URL encode the filename */
+ /* URL encode the file name */
encfile = curl_easy_escape(curl, filep, 0 /* use strlen */);
if(encfile) {
char *newpath;
@@ -179,9 +180,9 @@ fail:
* Returns a pointer to a heap-allocated string or NULL if
* no name part, at location indicated by first argument.
*/
-CURLcode get_url_file_name(struct GlobalConfig *global,
- char **filename, const char *url)
+CURLcode get_url_file_name(char **filename, const char *url)
{
+ const char *pc, *pc2;
CURLU *uh = curl_url();
char *path = NULL;
CURLUcode uerr;
@@ -194,31 +195,20 @@ CURLcode get_url_file_name(struct GlobalConfig *global,
uerr = curl_url_set(uh, CURLUPART_URL, url, CURLU_GUESS_SCHEME);
if(!uerr) {
uerr = curl_url_get(uh, CURLUPART_PATH, &path, 0);
- curl_url_cleanup(uh);
- uh = NULL;
if(!uerr) {
- int i;
- char *pc = NULL, *pc2 = NULL;
- for(i = 0; i < 2; i++) {
- pc = strrchr(path, '/');
- pc2 = strrchr(pc ? pc + 1 : path, '\\');
- if(pc2)
- pc = pc2;
- if(pc && !pc[1] && !i) {
- /* if the path ends with slash, try removing the trailing one
- and get the last directory part */
- *pc = 0;
- }
- }
+ curl_url_cleanup(uh);
+
+ pc = strrchr(path, '/');
+ pc2 = strrchr(pc ? pc + 1 : path, '\\');
+ if(pc2)
+ pc = pc2;
if(pc)
/* duplicate the string beyond the slash */
pc++;
- else {
- /* no slash => empty string, use default */
- pc = (char *)"curl_response";
- warnf(global, "No remote file name, uses \"%s\"", pc);
- }
+ else
+ /* no slash => empty string */
+ pc = "";
*filename = strdup(pc);
curl_free(path);
@@ -240,12 +230,12 @@ CURLcode get_url_file_name(struct GlobalConfig *global,
#endif /* _WIN32 || MSDOS */
/* in case we built debug enabled, we allow an environment variable
- * named CURL_TESTDIR to prefix the given filename to put it into a
+ * named CURL_TESTDIR to prefix the given file name to put it into a
* specific directory
*/
#ifdef DEBUGBUILD
{
- char *tdir = curl_getenv("CURL_TESTDIR");
+ char *tdir = curlx_getenv("CURL_TESTDIR");
if(tdir) {
char *alt = aprintf("%s/%s", tdir, *filename);
Curl_safefree(*filename);
diff --git a/contrib/libs/curl/src/tool_operhlp.h b/contrib/libs/curl/src/tool_operhlp.h
index 19daa8e430..1d56fa0408 100644
--- a/contrib/libs/curl/src/tool_operhlp.h
+++ b/contrib/libs/curl/src/tool_operhlp.h
@@ -35,8 +35,7 @@ bool stdin_upload(const char *uploadfile);
CURLcode add_file_name_to_url(CURL *curl, char **inurlp, const char *filename);
-CURLcode get_url_file_name(struct GlobalConfig *global,
- char **filename, const char *url);
+CURLcode get_url_file_name(char **filename, const char *url);
CURLcode urlerr_cvt(CURLUcode ucode);
diff --git a/contrib/libs/curl/src/tool_paramhlp.c b/contrib/libs/curl/src/tool_paramhlp.c
index d4024e1340..d70e80db4b 100644
--- a/contrib/libs/curl/src/tool_paramhlp.c
+++ b/contrib/libs/curl/src/tool_paramhlp.c
@@ -25,6 +25,8 @@
#include "strcase.h"
+#define ENABLE_CURLX_PRINTF
+/* use our own printf() functions */
#include "curlx.h"
#include "tool_cfgable.h"
@@ -61,75 +63,40 @@ struct getout *new_getout(struct OperationConfig *config)
return node;
}
-#define ISCRLF(x) (((x) == '\r') || ((x) == '\n') || ((x) == '\0'))
-
-/* memcrlf() has two modes. Both operate on a given memory area with
- a specified size.
-
- countcrlf FALSE - return number of bytes from the start that DO NOT include
- any CR or LF or NULL
-
- countcrlf TRUE - return number of bytes from the start that are ONLY CR or
- LF or NULL.
-
-*/
-static size_t memcrlf(char *orig,
- bool countcrlf, /* TRUE if we count CRLF, FALSE
- if we count non-CRLF */
- size_t max)
-{
- char *ptr;
- size_t total = max;
- for(ptr = orig; max; max--, ptr++) {
- bool crlf = ISCRLF(*ptr);
- if(countcrlf ^ crlf)
- return ptr - orig;
- }
- return total; /* no delimiter found */
-}
-
-#define MAX_FILE2STRING MAX_FILE2MEMORY
+#define MAX_FILE2STRING (256*1024*1024) /* big enough ? */
ParameterError file2string(char **bufp, FILE *file)
{
struct curlx_dynbuf dyn;
+ DEBUGASSERT(MAX_FILE2STRING < INT_MAX); /* needs to fit in an int later */
curlx_dyn_init(&dyn, MAX_FILE2STRING);
if(file) {
- do {
- char buffer[4096];
- char *ptr;
- size_t nread = fread(buffer, 1, sizeof(buffer), file);
- if(ferror(file)) {
- curlx_dyn_free(&dyn);
- *bufp = NULL;
- return PARAM_READ_ERROR;
- }
- ptr = buffer;
- while(nread) {
- size_t nlen = memcrlf(ptr, FALSE, nread);
- if(curlx_dyn_addn(&dyn, ptr, nlen))
- return PARAM_NO_MEM;
- nread -= nlen;
-
- if(nread) {
- ptr += nlen;
- nlen = memcrlf(ptr, TRUE, nread);
- ptr += nlen;
- nread -= nlen;
- }
- }
- } while(!feof(file));
+ char buffer[256];
+
+ while(fgets(buffer, sizeof(buffer), file)) {
+ char *ptr = strchr(buffer, '\r');
+ if(ptr)
+ *ptr = '\0';
+ ptr = strchr(buffer, '\n');
+ if(ptr)
+ *ptr = '\0';
+ if(curlx_dyn_add(&dyn, buffer))
+ return PARAM_NO_MEM;
+ }
}
*bufp = curlx_dyn_ptr(&dyn);
return PARAM_OK;
}
+#define MAX_FILE2MEMORY (1024*1024*1024) /* big enough ? */
+
ParameterError file2memory(char **bufp, size_t *size, FILE *file)
{
if(file) {
size_t nread;
struct curlx_dynbuf dyn;
/* The size needs to fit in an int later */
+ DEBUGASSERT(MAX_FILE2MEMORY < INT_MAX);
curlx_dyn_init(&dyn, MAX_FILE2MEMORY);
do {
char buffer[4096];
@@ -167,8 +134,6 @@ static ParameterError getnum(long *val, const char *str, int base)
if(str) {
char *endptr = NULL;
long num;
- if(!str[0])
- return PARAM_BLANK_STRING;
errno = 0;
num = strtol(str, &endptr, base);
if(errno == ERANGE)
@@ -395,7 +360,7 @@ ParameterError proto2num(struct OperationConfig *config,
protoset_set(protoset, p);
}
- /* Allow strtok() here since this is not used threaded */
+ /* Allow strtok() here since this isn't used threaded */
/* !checksrc! disable BANNEDFUNC 2 */
for(token = strtok(buffer, sep);
token;
@@ -443,7 +408,7 @@ ParameterError proto2num(struct OperationConfig *config,
break;
case set:
protoset[0] = NULL;
- FALLTHROUGH();
+ /* FALLTHROUGH */
case allow:
protoset_set(protoset, p);
break;
@@ -504,7 +469,7 @@ ParameterError str2offset(curl_off_t *val, const char *str)
{
char *endptr;
if(str[0] == '-')
- /* offsets are not negative, this indicates weird input */
+ /* offsets aren't negative, this indicates weird input */
return PARAM_NEGATIVE_NUMERIC;
#if(SIZEOF_CURL_OFF_T > SIZEOF_LONG)
@@ -557,13 +522,13 @@ static CURLcode checkpasswd(const char *kind, /* for what purpose */
/* build a nice-looking prompt */
if(!i && last)
- msnprintf(prompt, sizeof(prompt),
- "Enter %s password for user '%s':",
- kind, *userpwd);
+ curlx_msnprintf(prompt, sizeof(prompt),
+ "Enter %s password for user '%s':",
+ kind, *userpwd);
else
- msnprintf(prompt, sizeof(prompt),
- "Enter %s password for user '%s' on URL #%zu:",
- kind, *userpwd, i + 1);
+ curlx_msnprintf(prompt, sizeof(prompt),
+ "Enter %s password for user '%s' on URL #%zu:",
+ kind, *userpwd, i + 1);
/* get password */
getpass_r(prompt, passwd, sizeof(passwd));
diff --git a/contrib/libs/curl/src/tool_paramhlp.h b/contrib/libs/curl/src/tool_paramhlp.h
index bd703afc8c..edb8781950 100644
--- a/contrib/libs/curl/src/tool_paramhlp.h
+++ b/contrib/libs/curl/src/tool_paramhlp.h
@@ -30,12 +30,6 @@ struct getout *new_getout(struct OperationConfig *config);
ParameterError file2string(char **bufp, FILE *file);
-#if SIZEOF_SIZE_T > 4
-#define MAX_FILE2MEMORY (16LL*1024*1024*1024)
-#else
-#define MAX_FILE2MEMORY (INT_MAX)
-#endif
-
ParameterError file2memory(char **bufp, size_t *size, FILE *file);
ParameterError str2num(long *val, const char *str);
diff --git a/contrib/libs/curl/src/tool_parsecfg.c b/contrib/libs/curl/src/tool_parsecfg.c
index 6da5a92500..da48700663 100644
--- a/contrib/libs/curl/src/tool_parsecfg.c
+++ b/contrib/libs/curl/src/tool_parsecfg.c
@@ -23,6 +23,8 @@
***************************************************************************/
#include "tool_setup.h"
+#define ENABLE_CURLX_PRINTF
+/* use our own printf() functions */
#include "curlx.h"
#include "tool_cfgable.h"
@@ -49,7 +51,7 @@ static FILE *execpath(const char *filename, char **pathp)
{
static char filebuffer[512];
/* Get the filename of our executable. GetModuleFileName is already declared
- * via inclusions done in setup header file. We assume that we are using
+ * via inclusions done in setup header file. We assume that we are using
* the ASCII version here.
*/
unsigned long len = GetModuleFileNameA(0, filebuffer, sizeof(filebuffer));
@@ -123,12 +125,12 @@ int parseconfig(const char *filename, struct GlobalConfig *global)
int lineno = 0;
bool dashed_option;
struct curlx_dynbuf buf;
- bool fileerror = FALSE;
+ bool fileerror;
curlx_dyn_init(&buf, MAX_CONFIG_LINE_LENGTH);
DEBUGASSERT(filename);
- while(!rc && my_get_line(file, &buf, &fileerror)) {
- ParameterError res;
+ while(my_get_line(file, &buf, &fileerror)) {
+ int res;
bool alloced_param = FALSE;
lineno++;
line = curlx_dyn_ptr(&buf);
@@ -194,7 +196,7 @@ int parseconfig(const char *filename, struct GlobalConfig *global)
if(*line) {
*line = '\0'; /* null-terminate */
- /* to detect mistakes better, see if there is data following */
+ /* to detect mistakes better, see if there's data following */
line++;
/* pass all spaces */
while(*line && ISSPACE(*line))
@@ -215,7 +217,7 @@ int parseconfig(const char *filename, struct GlobalConfig *global)
}
if(!*param)
/* do this so getparameter can check for required parameters.
- Otherwise it always thinks there is a parameter. */
+ Otherwise it always thinks there's a parameter. */
param = NULL;
}
@@ -226,7 +228,7 @@ int parseconfig(const char *filename, struct GlobalConfig *global)
operation = global->last;
if(!res && param && *param && !usedarg)
- /* we passed in a parameter that was not used! */
+ /* we passed in a parameter that wasn't used! */
res = PARAM_GOT_EXTRA_PARAMETER;
if(res == PARAM_NEXT_OPERATION) {
@@ -253,19 +255,17 @@ int parseconfig(const char *filename, struct GlobalConfig *global)
}
if(res != PARAM_OK && res != PARAM_NEXT_OPERATION) {
- /* the help request is not really an error */
+ /* the help request isn't really an error */
if(!strcmp(filename, "-")) {
filename = "<stdin>";
}
if(res != PARAM_HELP_REQUESTED &&
res != PARAM_MANUAL_REQUESTED &&
res != PARAM_VERSION_INFO_REQUESTED &&
- res != PARAM_ENGINES_REQUESTED &&
- res != PARAM_CA_EMBED_REQUESTED) {
+ res != PARAM_ENGINES_REQUESTED) {
const char *reason = param2text(res);
- errorf(operation->global, "%s:%d: '%s' %s",
- filename, lineno, option, reason);
- rc = (int)res;
+ warnf(operation->global, "%s:%d: warning: '%s' %s",
+ filename, lineno, option, reason);
}
}
@@ -281,7 +281,7 @@ int parseconfig(const char *filename, struct GlobalConfig *global)
rc = 1;
}
else
- rc = 1; /* could not open the file */
+ rc = 1; /* couldn't open the file */
free(pathalloc);
return rc;
@@ -292,7 +292,7 @@ int parseconfig(const char *filename, struct GlobalConfig *global)
* backslash-quoted characters and NUL-terminating the output string.
* Stops at the first non-backslash-quoted double quote character or the
* end of the input string. param must be at least as long as the input
- * string. Returns the pointer after the last handled input character.
+ * string. Returns the pointer after the last handled input character.
*/
static const char *unslashquote(const char *line, char *param)
{
@@ -340,7 +340,7 @@ static bool my_get_line(FILE *fp, struct curlx_dynbuf *db,
/* fgets() returns s on success, and NULL on error or when end of file
occurs while no characters have been read. */
if(!fgets(buf, sizeof(buf), fp))
- /* only if there is data in the line, return TRUE */
+ /* only if there's data in the line, return TRUE */
return curlx_dyn_len(db) ? TRUE : FALSE;
if(curlx_dyn_add(db, buf)) {
*error = TRUE; /* error */
diff --git a/contrib/libs/curl/src/tool_progress.c b/contrib/libs/curl/src/tool_progress.c
index 3fac70a70e..db8679deb0 100644
--- a/contrib/libs/curl/src/tool_progress.c
+++ b/contrib/libs/curl/src/tool_progress.c
@@ -26,6 +26,8 @@
#include "tool_progress.h"
#include "tool_util.h"
+#define ENABLE_CURLX_PRINTF
+/* use our own printf() functions */
#include "curlx.h"
/* The point of this function would be to return a string of the input data,
@@ -46,13 +48,13 @@ static char *max5data(curl_off_t bytes, char *max5)
msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "k", bytes/ONE_KILOBYTE);
else if(bytes < CURL_OFF_T_C(100) * ONE_MEGABYTE)
- /* 'XX.XM' is good as long as we are less than 100 megs */
+ /* 'XX.XM' is good as long as we're less than 100 megs */
msnprintf(max5, 6, "%2" CURL_FORMAT_CURL_OFF_T ".%0"
CURL_FORMAT_CURL_OFF_T "M", bytes/ONE_MEGABYTE,
(bytes%ONE_MEGABYTE) / (ONE_MEGABYTE/CURL_OFF_T_C(10)) );
else if(bytes < CURL_OFF_T_C(10000) * ONE_MEGABYTE)
- /* 'XXXXM' is good until we are at 10000MB or above */
+ /* 'XXXXM' is good until we're at 10000MB or above */
msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "M", bytes/ONE_MEGABYTE);
else if(bytes < CURL_OFF_T_C(100) * ONE_GIGABYTE)
@@ -73,7 +75,7 @@ static char *max5data(curl_off_t bytes, char *max5)
/* up to 10000PB, display without decimal: XXXXP */
msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "P", bytes/ONE_PETABYTE);
- /* 16384 petabytes (16 exabytes) is the maximum a 64-bit unsigned number can
+ /* 16384 petabytes (16 exabytes) is the maximum a 64 bit unsigned number can
hold, but our data type is signed so 8192PB will be the maximum. */
return max5;
}
diff --git a/contrib/libs/curl/src/tool_sdecls.h b/contrib/libs/curl/src/tool_sdecls.h
index 2dee9d3149..b93c324624 100644
--- a/contrib/libs/curl/src/tool_sdecls.h
+++ b/contrib/libs/curl/src/tool_sdecls.h
@@ -29,7 +29,7 @@
* OutStruct variables keep track of information relative to curl's
* output writing, which may take place to a standard stream or a file.
*
- * 'filename' member is either a pointer to a filename string or NULL
+ * 'filename' member is either a pointer to a file name string or NULL
* when dealing with a standard stream.
*
* 'alloc_filename' member is TRUE when string pointed by 'filename' has been
@@ -40,7 +40,7 @@
*
* 's_isreg' member is TRUE when output goes to a regular file, this also
* implies that output is 'seekable' and 'appendable' and also that member
- * 'filename' points to filename's string. For any standard stream member
+ * 'filename' points to file name's string. For any standard stream member
* 's_isreg' will be FALSE.
*
* 'fopened' member is TRUE when output goes to a regular file and it
@@ -93,7 +93,7 @@ struct getout {
#define GETOUT_OUTFILE (1<<0) /* set when outfile is deemed done */
#define GETOUT_URL (1<<1) /* set when URL is deemed done */
-#define GETOUT_USEREMOTE (1<<2) /* use remote filename locally */
+#define GETOUT_USEREMOTE (1<<2) /* use remote file name locally */
#define GETOUT_UPLOAD (1<<3) /* if set, -T has been used */
#define GETOUT_NOUPLOAD (1<<4) /* if set, -T "" has been used */
@@ -114,12 +114,12 @@ typedef enum {
*/
typedef enum {
- TOOL_HTTPREQ_UNSPEC, /* first in list */
- TOOL_HTTPREQ_GET,
- TOOL_HTTPREQ_HEAD,
- TOOL_HTTPREQ_MIMEPOST,
- TOOL_HTTPREQ_SIMPLEPOST,
- TOOL_HTTPREQ_PUT
+ HTTPREQ_UNSPEC, /* first in list */
+ HTTPREQ_GET,
+ HTTPREQ_HEAD,
+ HTTPREQ_MIMEPOST,
+ HTTPREQ_SIMPLEPOST,
+ HTTPREQ_PUT
} HttpReq;
diff --git a/contrib/libs/curl/src/tool_setopt.c b/contrib/libs/curl/src/tool_setopt.c
index 52ae0f9607..de3b78fab5 100644
--- a/contrib/libs/curl/src/tool_setopt.c
+++ b/contrib/libs/curl/src/tool_setopt.c
@@ -25,6 +25,8 @@
#ifndef CURL_DISABLE_LIBCURL_OPTION
+#define ENABLE_CURLX_PRINTF
+/* use our own printf() functions */
#include "curlx.h"
#include "tool_cfgable.h"
@@ -76,6 +78,7 @@ const struct NameValueUnsigned setopt_nv_CURLAUTH[] = {
NV(CURLAUTH_GSSNEGOTIATE),
NV(CURLAUTH_NTLM),
NV(CURLAUTH_DIGEST_IE),
+ NV(CURLAUTH_NTLM_WB),
NV(CURLAUTH_ONLY),
NV(CURLAUTH_NONE),
NVEND,
@@ -104,16 +107,6 @@ const struct NameValue setopt_nv_CURL_SSLVERSION[] = {
NVEND,
};
-const struct NameValue setopt_nv_CURL_SSLVERSION_MAX[] = {
- NV(CURL_SSLVERSION_MAX_NONE),
- NV(CURL_SSLVERSION_MAX_DEFAULT),
- NV(CURL_SSLVERSION_MAX_TLSv1_0),
- NV(CURL_SSLVERSION_MAX_TLSv1_1),
- NV(CURL_SSLVERSION_MAX_TLSv1_2),
- NV(CURL_SSLVERSION_MAX_TLSv1_3),
- NVEND,
-};
-
const struct NameValue setopt_nv_CURL_TIMECOND[] = {
NV(CURL_TIMECOND_IFMODSINCE),
NV(CURL_TIMECOND_IFUNMODSINCE),
@@ -205,7 +198,7 @@ static const struct NameValue setopt_nv_CURLNONZERODEFAULTS[] = {
#define REM1(f,a) ADDF((&easysrc_toohard, f,a))
#define REM3(f,a,b,c) ADDF((&easysrc_toohard, f,a,b,c))
-/* Escape string to C string syntax. Return NULL if out of memory.
+/* Escape string to C string syntax. Return NULL if out of memory.
* Is this correct for those wacky EBCDIC guys? */
#define MAX_STRING_LENGTH_OUTPUT 2000
@@ -247,10 +240,14 @@ static char *c_escape(const char *str, curl_off_t len)
if(p && *p)
result = curlx_dyn_addn(&escaped, to + 2 * (p - from), 2);
else {
- result = curlx_dyn_addf(&escaped,
- /* Octal escape to avoid >2 digit hex. */
- (len > 1 && ISXDIGIT(s[1])) ?
- "\\%03o" : "\\x%02x",
+ const char *format = "\\x%02x";
+
+ if(len > 1 && ISXDIGIT(s[1])) {
+ /* Octal escape to avoid >2 digit hex. */
+ format = "\\%03o";
+ }
+
+ result = curlx_dyn_addf(&escaped, format,
(unsigned int) *(unsigned char *) s);
}
}
@@ -303,50 +300,6 @@ nomem:
return ret;
}
-/* setopt wrapper for CURLOPT_SSLVERSION */
-CURLcode tool_setopt_SSLVERSION(CURL *curl, struct GlobalConfig *config,
- const char *name, CURLoption tag,
- long lval)
-{
- CURLcode ret = CURLE_OK;
- bool skip = FALSE;
-
- ret = curl_easy_setopt(curl, tag, lval);
- if(!lval)
- skip = TRUE;
-
- if(config->libcurl && !skip && !ret) {
- /* we only use this for real if --libcurl was used */
- const struct NameValue *nv = NULL;
- const struct NameValue *nv2 = NULL;
- for(nv = setopt_nv_CURL_SSLVERSION; nv->name; nv++) {
- if(nv->value == (lval & 0xffff))
- break; /* found it */
- }
- for(nv2 = setopt_nv_CURL_SSLVERSION_MAX; nv2->name; nv2++) {
- if(nv2->value == (lval & ~0xffff))
- break; /* found it */
- }
- if(!nv->name) {
- /* If no definition was found, output an explicit value.
- * This could happen if new values are defined and used
- * but the NameValue list is not updated. */
- CODE2("curl_easy_setopt(hnd, %s, %ldL);", name, lval);
- }
- else {
- CODE3("curl_easy_setopt(hnd, %s, (long)(%s | %s));",
- name, nv->name, nv2->name);
- }
- }
-
-#ifdef DEBUGBUILD
- if(ret)
- warnf(config, "option %s returned error (%d)", name, (int)ret);
-#endif
-nomem:
- return ret;
-}
-
/* setopt wrapper for bitmasks */
CURLcode tool_setopt_bitmask(CURL *curl, struct GlobalConfig *config,
const char *name, CURLoption tag,
@@ -478,7 +431,7 @@ static CURLcode libcurl_generate_mime_part(CURL *curl,
case TOOLMIME_STDIN:
if(!filename)
filename = "-";
- FALLTHROUGH();
+ /* FALLTHROUGH */
case TOOLMIME_STDINDATA:
/* Can only be reading stdin in the current context. */
CODE1("curl_mime_data_cb(part%d, -1, (curl_read_callback) fread, \\",
@@ -700,7 +653,7 @@ CURLcode tool_setopt(CURL *curl, bool str, struct GlobalConfig *global,
if(escape) {
curl_off_t len = ZERO_TERMINATED;
if(tag == CURLOPT_POSTFIELDS)
- len = curlx_dyn_len(&config->postdata);
+ len = config->postfieldsize;
escaped = c_escape(value, len);
NULL_CHECK(escaped);
CODE2("curl_easy_setopt(hnd, %s, \"%s\");", name, escaped);
diff --git a/contrib/libs/curl/src/tool_setopt.h b/contrib/libs/curl/src/tool_setopt.h
index 6588da9ced..cd59a74cd8 100644
--- a/contrib/libs/curl/src/tool_setopt.h
+++ b/contrib/libs/curl/src/tool_setopt.h
@@ -52,7 +52,6 @@ extern const struct NameValue setopt_nv_CURLPROXY[];
extern const struct NameValue setopt_nv_CURL_SOCKS_PROXY[];
extern const struct NameValue setopt_nv_CURL_HTTP_VERSION[];
extern const struct NameValue setopt_nv_CURL_SSLVERSION[];
-extern const struct NameValue setopt_nv_CURL_SSLVERSION_MAX[];
extern const struct NameValue setopt_nv_CURL_TIMECOND[];
extern const struct NameValue setopt_nv_CURLFTPSSL_CCC[];
extern const struct NameValue setopt_nv_CURLUSESSL[];
@@ -82,9 +81,6 @@ extern const struct NameValueUnsigned setopt_nv_CURLHSTS[];
CURLcode tool_setopt_enum(CURL *curl, struct GlobalConfig *config,
const char *name, CURLoption tag,
const struct NameValue *nv, long lval);
-CURLcode tool_setopt_SSLVERSION(CURL *curl, struct GlobalConfig *config,
- const char *name, CURLoption tag,
- long lval);
CURLcode tool_setopt_flags(CURL *curl, struct GlobalConfig *config,
const char *name, CURLoption tag,
const struct NameValue *nv, long lval);
@@ -110,9 +106,6 @@ CURLcode tool_setopt(CURL *curl, bool str, struct GlobalConfig *global,
#define my_setopt_enum(x,y,z) \
SETOPT_CHECK(tool_setopt_enum(x, global, #y, y, setopt_nv_ ## y, z), y)
-#define my_setopt_SSLVERSION(x,y,z) \
- SETOPT_CHECK(tool_setopt_SSLVERSION(x, global, #y, y, z), y)
-
#define my_setopt_bitmask(x,y,z) \
SETOPT_CHECK(tool_setopt_bitmask(x, global, #y, y, setopt_nv_ ## y, z), y)
@@ -139,9 +132,6 @@ CURLcode tool_setopt(CURL *curl, bool str, struct GlobalConfig *global,
#define my_setopt_enum(x,y,z) \
SETOPT_CHECK(curl_easy_setopt(x, y, z), y)
-#define my_setopt_SSLVERSION(x,y,z) \
- SETOPT_CHECK(curl_easy_setopt(x, y, z), y)
-
#define my_setopt_bitmask(x,y,z) \
SETOPT_CHECK(curl_easy_setopt(x, y, z), y)
diff --git a/contrib/libs/curl/src/tool_setup.h b/contrib/libs/curl/src/tool_setup.h
index 07cba7da2e..c69859ea64 100644
--- a/contrib/libs/curl/src/tool_setup.h
+++ b/contrib/libs/curl/src/tool_setup.h
@@ -74,17 +74,4 @@ extern bool tool_isVistaOrGreater;
extern bool tool_term_has_bold;
#endif
-#if defined(_WIN32) && !defined(HAVE_FTRUNCATE)
-
-int tool_ftruncate64(int fd, curl_off_t where);
-
-#undef ftruncate
-#define ftruncate(fd,where) tool_ftruncate64(fd,where)
-
-#define HAVE_FTRUNCATE 1
-#define USE_TOOL_FTRUNCATE 1
-
-#endif /* _WIN32 && ! HAVE_FTRUNCATE */
-
-
#endif /* HEADER_CURL_TOOL_SETUP_H */
diff --git a/contrib/libs/curl/src/tool_sleep.c b/contrib/libs/curl/src/tool_sleep.c
index 31b5f01c92..c24f73729e 100644
--- a/contrib/libs/curl/src/tool_sleep.c
+++ b/contrib/libs/curl/src/tool_sleep.c
@@ -48,7 +48,7 @@ void tool_go_sleep(long ms)
#if defined(MSDOS)
delay(ms);
#elif defined(_WIN32)
- Sleep((DWORD)ms);
+ Sleep(ms);
#elif defined(HAVE_POLL_FINE)
(void)poll((void *)0, 0, (int)ms);
#else
diff --git a/contrib/libs/curl/src/tool_urlglob.c b/contrib/libs/curl/src/tool_urlglob.c
index 35f472d4f2..e45c7d10b2 100644
--- a/contrib/libs/curl/src/tool_urlglob.c
+++ b/contrib/libs/curl/src/tool_urlglob.c
@@ -23,6 +23,8 @@
***************************************************************************/
#include "tool_setup.h"
+#define ENABLE_CURLX_PRINTF
+/* use our own printf() functions */
#include "curlx.h"
#include "tool_cfgable.h"
#include "tool_doswin.h"
@@ -78,7 +80,7 @@ static int multiply(curl_off_t *amount, curl_off_t with)
#else
sum = *amount * with;
if(sum/with != *amount)
- return 1; /* did not fit, bail out */
+ return 1; /* didn't fit, bail out */
#endif
}
*amount = sum;
@@ -121,11 +123,11 @@ static CURLcode glob_set(struct URLGlob *glob, char **patternp,
return GLOBERROR("empty string within braces", *posp,
CURLE_URL_MALFORMAT);
- /* add 1 to size since it will be incremented below */
+ /* add 1 to size since it'll be incremented below */
if(multiply(amount, pat->content.Set.size + 1))
return GLOBERROR("range overflow", 0, CURLE_URL_MALFORMAT);
- FALLTHROUGH();
+ /* FALLTHROUGH */
case ',':
*buf = '\0';
@@ -169,7 +171,7 @@ static CURLcode glob_set(struct URLGlob *glob, char **patternp,
++pattern;
++(*posp);
}
- FALLTHROUGH();
+ /* FALLTHROUGH */
default:
*buf++ = *pattern++; /* copy character to set element */
++(*posp);
diff --git a/contrib/libs/curl/src/tool_util.c b/contrib/libs/curl/src/tool_util.c
index e612bec031..812a689d03 100644
--- a/contrib/libs/curl/src/tool_util.c
+++ b/contrib/libs/curl/src/tool_util.c
@@ -81,7 +81,7 @@ struct timeval tvnow(void)
/*
** Even when the configure process has truly detected monotonic clock
** availability, it might happen that it is not actually available at
- ** runtime. When this occurs simply fallback to other time source.
+ ** run-time. When this occurs simply fallback to other time source.
*/
#ifdef HAVE_GETTIMEOFDAY
else
@@ -126,7 +126,7 @@ struct timeval tvnow(void)
/*
* Make sure that the first argument is the more recent time, as otherwise
- * we will get a weird negative time-diff back...
+ * we'll get a weird negative time-diff back...
*
* Returns: the time difference in number of milliseconds.
*/
@@ -159,32 +159,3 @@ int struplocompare4sort(const void *p1, const void *p2)
{
return struplocompare(* (char * const *) p1, * (char * const *) p2);
}
-
-#ifdef USE_TOOL_FTRUNCATE
-
-#ifdef _WIN32_WCE
-/* 64-bit lseek-like function unavailable */
-# undef _lseeki64
-# define _lseeki64(hnd,ofs,whence) lseek(hnd,ofs,whence)
-# undef _get_osfhandle
-# define _get_osfhandle(fd) (fd)
-#endif
-
-/*
- * Truncate a file handle at a 64-bit position 'where'.
- */
-
-int tool_ftruncate64(int fd, curl_off_t where)
-{
- intptr_t handle = _get_osfhandle(fd);
-
- if(_lseeki64(fd, where, SEEK_SET) < 0)
- return -1;
-
- if(!SetEndOfFile((HANDLE)handle))
- return -1;
-
- return 0;
-}
-
-#endif /* USE_TOOL_FTRUNCATE */
diff --git a/contrib/libs/curl/src/tool_version.h b/contrib/libs/curl/src/tool_version.h
index e4cfa70249..2eca403c4e 100644
--- a/contrib/libs/curl/src/tool_version.h
+++ b/contrib/libs/curl/src/tool_version.h
@@ -27,7 +27,7 @@
#define CURL_NAME "curl"
#define CURL_COPYRIGHT LIBCURL_COPYRIGHT
-#define CURL_VERSION "8.10.1"
+#define CURL_VERSION "8.5.0"
#define CURL_VERSION_MAJOR LIBCURL_VERSION_MAJOR
#define CURL_VERSION_MINOR LIBCURL_VERSION_MINOR
#define CURL_VERSION_PATCH LIBCURL_VERSION_PATCH
diff --git a/contrib/libs/curl/src/tool_vms.c b/contrib/libs/curl/src/tool_vms.c
index 36d05870c9..36d0ebe6ca 100644
--- a/contrib/libs/curl/src/tool_vms.c
+++ b/contrib/libs/curl/src/tool_vms.c
@@ -30,6 +30,7 @@
#include <unixlib.h>
#endif
+#define ENABLE_CURLX_PRINTF
#include "curlx.h"
#error #include "curlmsg_vms.h"
@@ -73,7 +74,7 @@ int is_vms_shell(void)
}
/*
- * VMS has two exit() routines. When running under a Unix style shell, then
+ * VMS has two exit() routines. When running under a Unix style shell, then
* Unix style and the __posix_exit() routine is used.
*
* When running under the DCL shell, then the VMS encoded codes and decc$exit()
@@ -93,7 +94,7 @@ void vms_special_exit(int code, int vms_show)
{
int vms_code;
- /* The POSIX exit mode is only available after VMS 7.0 */
+ /* The Posix exit mode is only available after VMS 7.0 */
#if __CRTL_VER >= 70000000
if(is_vms_shell() == 0) {
decc$__posix_exit(code);
@@ -132,9 +133,9 @@ struct decc_feat_t {
static const struct decc_feat_t decc_feat_array[] = {
/* Preserve command-line case with SET PROCESS/PARSE_STYLE=EXTENDED */
{ "DECC$ARGV_PARSE_STYLE", 1 },
- /* Preserve case for filenames on ODS5 disks. */
+ /* Preserve case for file names on ODS5 disks. */
{ "DECC$EFS_CASE_PRESERVE", 1 },
- /* Enable multiple dots (and most characters) in ODS5 filenames,
+ /* Enable multiple dots (and most characters) in ODS5 file names,
while preserving VMS-ness of ";version". */
{ "DECC$EFS_CHARSET", 1 },
/* List terminator. */
@@ -164,14 +165,14 @@ static void decc_init(void)
feat_index = decc$feature_get_index(decc_feat_array[i].name);
if(feat_index >= 0) {
- /* Valid item. Collect its properties. */
+ /* Valid item. Collect its properties. */
feat_value = decc$feature_get_value(feat_index, 1);
feat_value_min = decc$feature_get_value(feat_index, 2);
feat_value_max = decc$feature_get_value(feat_index, 3);
if((decc_feat_array[i].value >= feat_value_min) &&
(decc_feat_array[i].value <= feat_value_max)) {
- /* Valid value. Set it if necessary. */
+ /* Valid value. Set it if necessary. */
if(feat_value != decc_feat_array[i].value) {
sts = decc$feature_set_value(feat_index, 1,
decc_feat_array[i].value);
@@ -197,7 +198,7 @@ static void decc_init(void)
#pragma nostandard
/* Establish the LIB$INITIALIZE PSECTs, with proper alignment and
- other attributes. Note that "nopic" is significant only on VAX. */
+ other attributes. Note that "nopic" is significant only on VAX. */
#pragma extern_model save
#pragma extern_model strict_refdef "LIB$INITIALIZ" 2, nopic, nowrt
const int spare[8] = {0};
diff --git a/contrib/libs/curl/src/tool_writeout.c b/contrib/libs/curl/src/tool_writeout.c
index 141178c332..981065c9ef 100644
--- a/contrib/libs/curl/src/tool_writeout.c
+++ b/contrib/libs/curl/src/tool_writeout.c
@@ -22,7 +22,8 @@
*
***************************************************************************/
#include "tool_setup.h"
-
+#define ENABLE_CURLX_PRINTF
+/* use our own printf() functions */
#include "curlx.h"
#include "tool_cfgable.h"
#include "tool_writeout.h"
@@ -69,12 +70,12 @@ static const struct httpmap http_version[] = {
Yes: "http_version": "1.1"
No: "http_version": 1.1
- Variable names MUST be in alphabetical order.
+ Variable names should be in alphabetical order.
*/
static const struct writeoutvar variables[] = {
{"certs", VAR_CERT, CURLINFO_NONE, writeString},
- {"conn_id", VAR_CONN_ID, CURLINFO_CONN_ID, writeOffset},
{"content_type", VAR_CONTENT_TYPE, CURLINFO_CONTENT_TYPE, writeString},
+ {"conn_id", VAR_CONN_ID, CURLINFO_CONN_ID, writeOffset},
{"errormsg", VAR_ERRORMSG, CURLINFO_NONE, writeString},
{"exitcode", VAR_EXITCODE, CURLINFO_NONE, writeLong},
{"filename_effective", VAR_EFFECTIVE_FILENAME, CURLINFO_NONE, writeString},
@@ -91,11 +92,9 @@ static const struct writeoutvar variables[] = {
{"num_connects", VAR_NUM_CONNECTS, CURLINFO_NUM_CONNECTS, writeLong},
{"num_headers", VAR_NUM_HEADERS, CURLINFO_NONE, writeLong},
{"num_redirects", VAR_REDIRECT_COUNT, CURLINFO_REDIRECT_COUNT, writeLong},
- {"num_retries", VAR_NUM_RETRY, CURLINFO_NONE, writeLong},
{"onerror", VAR_ONERROR, CURLINFO_NONE, NULL},
{"proxy_ssl_verify_result", VAR_PROXY_SSL_VERIFY_RESULT,
CURLINFO_PROXY_SSL_VERIFYRESULT, writeLong},
- {"proxy_used", VAR_PROXY_USED, CURLINFO_USED_PROXY, writeLong},
{"redirect_url", VAR_REDIRECT_URL, CURLINFO_REDIRECT_URL, writeString},
{"referer", VAR_REFERER, CURLINFO_REFERER, writeString},
{"remote_ip", VAR_PRIMARY_IP, CURLINFO_PRIMARY_IP, writeString},
@@ -118,8 +117,6 @@ static const struct writeoutvar variables[] = {
{"time_connect", VAR_CONNECT_TIME, CURLINFO_CONNECT_TIME_T, writeTime},
{"time_namelookup", VAR_NAMELOOKUP_TIME, CURLINFO_NAMELOOKUP_TIME_T,
writeTime},
- {"time_posttransfer", VAR_POSTTRANSFER_TIME, CURLINFO_POSTTRANSFER_TIME_T,
- writeTime},
{"time_pretransfer", VAR_PRETRANSFER_TIME, CURLINFO_PRETRANSFER_TIME_T,
writeTime},
{"time_redirect", VAR_REDIRECT_TIME, CURLINFO_REDIRECT_TIME_T, writeTime},
@@ -127,29 +124,30 @@ static const struct writeoutvar variables[] = {
writeTime},
{"time_total", VAR_TOTAL_TIME, CURLINFO_TOTAL_TIME_T, writeTime},
{"url", VAR_INPUT_URL, CURLINFO_NONE, writeString},
- {"url.fragment", VAR_INPUT_URLFRAGMENT, CURLINFO_NONE, writeString},
- {"url.host", VAR_INPUT_URLHOST, CURLINFO_NONE, writeString},
- {"url.options", VAR_INPUT_URLOPTIONS, CURLINFO_NONE, writeString},
+ {"url.scheme", VAR_INPUT_URLSCHEME, CURLINFO_NONE, writeString},
+ {"url.user", VAR_INPUT_URLUSER, CURLINFO_NONE, writeString},
{"url.password", VAR_INPUT_URLPASSWORD, CURLINFO_NONE, writeString},
- {"url.path", VAR_INPUT_URLPATH, CURLINFO_NONE, writeString},
+ {"url.options", VAR_INPUT_URLOPTIONS, CURLINFO_NONE, writeString},
+ {"url.host", VAR_INPUT_URLHOST, CURLINFO_NONE, writeString},
{"url.port", VAR_INPUT_URLPORT, CURLINFO_NONE, writeString},
+ {"url.path", VAR_INPUT_URLPATH, CURLINFO_NONE, writeString},
{"url.query", VAR_INPUT_URLQUERY, CURLINFO_NONE, writeString},
- {"url.scheme", VAR_INPUT_URLSCHEME, CURLINFO_NONE, writeString},
- {"url.user", VAR_INPUT_URLUSER, CURLINFO_NONE, writeString},
+ {"url.fragment", VAR_INPUT_URLFRAGMENT, CURLINFO_NONE, writeString},
{"url.zoneid", VAR_INPUT_URLZONEID, CURLINFO_NONE, writeString},
- {"url_effective", VAR_EFFECTIVE_URL, CURLINFO_EFFECTIVE_URL, writeString},
- {"urle.fragment", VAR_INPUT_URLEFRAGMENT, CURLINFO_NONE, writeString},
- {"urle.host", VAR_INPUT_URLEHOST, CURLINFO_NONE, writeString},
- {"urle.options", VAR_INPUT_URLEOPTIONS, CURLINFO_NONE, writeString},
+ {"urle.scheme", VAR_INPUT_URLESCHEME, CURLINFO_NONE, writeString},
+ {"urle.user", VAR_INPUT_URLEUSER, CURLINFO_NONE, writeString},
{"urle.password", VAR_INPUT_URLEPASSWORD, CURLINFO_NONE, writeString},
- {"urle.path", VAR_INPUT_URLEPATH, CURLINFO_NONE, writeString},
+ {"urle.options", VAR_INPUT_URLEOPTIONS, CURLINFO_NONE, writeString},
+ {"urle.host", VAR_INPUT_URLEHOST, CURLINFO_NONE, writeString},
{"urle.port", VAR_INPUT_URLEPORT, CURLINFO_NONE, writeString},
+ {"urle.path", VAR_INPUT_URLEPATH, CURLINFO_NONE, writeString},
{"urle.query", VAR_INPUT_URLEQUERY, CURLINFO_NONE, writeString},
- {"urle.scheme", VAR_INPUT_URLESCHEME, CURLINFO_NONE, writeString},
- {"urle.user", VAR_INPUT_URLEUSER, CURLINFO_NONE, writeString},
+ {"urle.fragment", VAR_INPUT_URLEFRAGMENT, CURLINFO_NONE, writeString},
{"urle.zoneid", VAR_INPUT_URLEZONEID, CURLINFO_NONE, writeString},
+ {"url_effective", VAR_EFFECTIVE_URL, CURLINFO_EFFECTIVE_URL, writeString},
{"urlnum", VAR_URLNUM, CURLINFO_NONE, writeLong},
- {"xfer_id", VAR_EASY_ID, CURLINFO_XFER_ID, writeOffset}
+ {"xfer_id", VAR_EASY_ID, CURLINFO_XFER_ID, writeOffset},
+ {NULL, VAR_NONE, CURLINFO_NONE, NULL}
};
static int writeTime(FILE *stream, const struct writeoutvar *wovar,
@@ -199,7 +197,7 @@ static int urlpart(struct per_transfer *per, writeoutid vid,
char *part = NULL;
const char *url = NULL;
- if(vid >= VAR_INPUT_URLESCHEME) {
+ if(vid >= VAR_INPUT_URLEHOST) {
if(curl_easy_getinfo(per->curl, CURLINFO_EFFECTIVE_URL, &url))
rc = 5;
}
@@ -270,15 +268,6 @@ static int urlpart(struct per_transfer *per, writeoutid vid,
return rc;
}
-static void certinfo(struct per_transfer *per)
-{
- if(!per->certinfo) {
- struct curl_certinfo *certinfo;
- CURLcode res = curl_easy_getinfo(per->curl, CURLINFO_CERTINFO, &certinfo);
- per->certinfo = (!res && certinfo) ? certinfo : NULL;
- }
-}
-
static int writeString(FILE *stream, const struct writeoutvar *wovar,
struct per_transfer *per, CURLcode per_result,
bool use_json)
@@ -314,7 +303,6 @@ static int writeString(FILE *stream, const struct writeoutvar *wovar,
else {
switch(wovar->id) {
case VAR_CERT:
- certinfo(per);
if(per->certinfo) {
int i;
bool error = FALSE;
@@ -445,12 +433,7 @@ static int writeLong(FILE *stream, const struct writeoutvar *wovar,
}
else {
switch(wovar->id) {
- case VAR_NUM_RETRY:
- longinfo = per->num_retries;
- valid = true;
- break;
case VAR_NUM_CERTS:
- certinfo(per);
longinfo = per->certinfo ? per->certinfo->num_of_certs : 0;
valid = true;
break;
@@ -459,7 +442,7 @@ static int writeLong(FILE *stream, const struct writeoutvar *wovar,
valid = true;
break;
case VAR_EXITCODE:
- longinfo = (long)per_result;
+ longinfo = per_result;
valid = true;
break;
case VAR_URLNUM:
@@ -525,17 +508,6 @@ static int writeOffset(FILE *stream, const struct writeoutvar *wovar,
return 1; /* return 1 if anything was written */
}
-static int
-matchvar(const void *m1, const void *m2)
-{
- const struct writeoutvar *v1 = m1;
- const struct writeoutvar *v2 = m2;
-
- return strcmp(v1->name, v2->name);
-}
-
-#define MAX_WRITEOUT_NAME_LENGTH 24
-
void ourWriteOut(struct OperationConfig *config, struct per_transfer *per,
CURLcode per_result)
{
@@ -543,13 +515,16 @@ void ourWriteOut(struct OperationConfig *config, struct per_transfer *per,
const char *writeinfo = config->writeout;
const char *ptr = writeinfo;
bool done = FALSE;
+ struct curl_certinfo *certinfo;
+ CURLcode res = curl_easy_getinfo(per->curl, CURLINFO_CERTINFO, &certinfo);
bool fclose_stream = FALSE;
- struct dynbuf name;
if(!writeinfo)
return;
- curlx_dyn_init(&name, MAX_WRITEOUT_NAME_LENGTH);
+ if(!res && certinfo)
+ per->certinfo = certinfo;
+
while(ptr && *ptr && !done) {
if('%' == *ptr && ptr[1]) {
if('%' == ptr[1]) {
@@ -562,8 +537,8 @@ void ourWriteOut(struct OperationConfig *config, struct per_transfer *per,
char *end;
size_t vlen;
if('{' == ptr[1]) {
- struct writeoutvar *wv = NULL;
- struct writeoutvar find = { 0 };
+ int i;
+ bool match = FALSE;
end = strchr(ptr, '}');
ptr += 2; /* pass the % and the { */
if(!end) {
@@ -571,47 +546,43 @@ void ourWriteOut(struct OperationConfig *config, struct per_transfer *per,
continue;
}
vlen = end - ptr;
-
- curlx_dyn_reset(&name);
- if(!curlx_dyn_addn(&name, ptr, vlen)) {
- find.name = curlx_dyn_ptr(&name);
- wv = bsearch(&find,
- variables, sizeof(variables)/sizeof(variables[0]),
- sizeof(variables[0]), matchvar);
- }
- if(wv) {
- switch(wv->id) {
- case VAR_ONERROR:
- if(per_result == CURLE_OK)
- /* this is not error so skip the rest */
- done = TRUE;
- break;
- case VAR_STDOUT:
- if(fclose_stream)
- fclose(stream);
- fclose_stream = FALSE;
- stream = stdout;
- break;
- case VAR_STDERR:
- if(fclose_stream)
- fclose(stream);
- fclose_stream = FALSE;
- stream = tool_stderr;
- break;
- case VAR_JSON:
- ourWriteOutJSON(stream, variables,
- sizeof(variables)/sizeof(variables[0]),
- per, per_result);
- break;
- case VAR_HEADER_JSON:
- headerJSON(stream, per);
- break;
- default:
- (void)wv->writefunc(stream, wv, per, per_result, false);
+ for(i = 0; variables[i].name; i++) {
+ if((strlen(variables[i].name) == vlen) &&
+ curl_strnequal(ptr, variables[i].name, vlen)) {
+ match = TRUE;
+ switch(variables[i].id) {
+ case VAR_ONERROR:
+ if(per_result == CURLE_OK)
+ /* this isn't error so skip the rest */
+ done = TRUE;
+ break;
+ case VAR_STDOUT:
+ if(fclose_stream)
+ fclose(stream);
+ fclose_stream = FALSE;
+ stream = stdout;
+ break;
+ case VAR_STDERR:
+ if(fclose_stream)
+ fclose(stream);
+ fclose_stream = FALSE;
+ stream = tool_stderr;
+ break;
+ case VAR_JSON:
+ ourWriteOutJSON(stream, variables, per, per_result);
+ break;
+ case VAR_HEADER_JSON:
+ headerJSON(stream, per);
+ break;
+ default:
+ (void)variables[i].writefunc(stream, &variables[i],
+ per, per_result, false);
+ break;
+ }
break;
}
}
- else {
+ if(!match) {
fprintf(tool_stderr,
"curl: unknown --write-out variable: '%.*s'\n",
(int)vlen, ptr);
@@ -646,7 +617,7 @@ void ourWriteOut(struct OperationConfig *config, struct per_transfer *per,
}
end = strchr(ptr, '}');
if(end) {
- char fname[512]; /* holds the longest filename */
+ char fname[512]; /* holds the longest file name */
size_t flen = end - ptr;
if(flen < sizeof(fname)) {
FILE *stream2;
@@ -701,5 +672,4 @@ void ourWriteOut(struct OperationConfig *config, struct per_transfer *per,
}
if(fclose_stream)
fclose(stream);
- curlx_dyn_free(&name);
}
diff --git a/contrib/libs/curl/src/tool_writeout.h b/contrib/libs/curl/src/tool_writeout.h
index 7b3ca7bd02..4e690a65c9 100644
--- a/contrib/libs/curl/src/tool_writeout.h
+++ b/contrib/libs/curl/src/tool_writeout.h
@@ -57,7 +57,7 @@ typedef enum {
VAR_INPUT_URLFRAGMENT,
VAR_INPUT_URLZONEID,
/* the same ones again for url *effective* */
- VAR_INPUT_URLESCHEME, /* keep this the first URLE* variable */
+ VAR_INPUT_URLESCHEME,
VAR_INPUT_URLEUSER,
VAR_INPUT_URLEPASSWORD,
VAR_INPUT_URLEOPTIONS,
@@ -74,14 +74,11 @@ typedef enum {
VAR_NUM_CERTS,
VAR_NUM_CONNECTS,
VAR_NUM_HEADERS,
- VAR_NUM_RETRY,
VAR_ONERROR,
VAR_PRETRANSFER_TIME,
- VAR_POSTTRANSFER_TIME,
VAR_PRIMARY_IP,
VAR_PRIMARY_PORT,
VAR_PROXY_SSL_VERIFY_RESULT,
- VAR_PROXY_USED,
VAR_REDIRECT_COUNT,
VAR_REDIRECT_TIME,
VAR_REDIRECT_URL,
diff --git a/contrib/libs/curl/src/tool_writeout_json.c b/contrib/libs/curl/src/tool_writeout_json.c
index 205b702ae1..4ed6b93fb7 100644
--- a/contrib/libs/curl/src/tool_writeout_json.c
+++ b/contrib/libs/curl/src/tool_writeout_json.c
@@ -23,6 +23,9 @@
***************************************************************************/
#include "tool_setup.h"
+#define ENABLE_CURLX_PRINTF
+
+/* use our own printf() functions */
#include "curlx.h"
#include "tool_cfgable.h"
#include "tool_writeout_json.h"
@@ -69,9 +72,9 @@ int jsonquoted(const char *in, size_t len,
if(*i < 32)
result = curlx_dyn_addf(out, "\\u%04x", *i);
else {
- char o = (char)*i;
+ char o = *i;
if(lowercase && (o >= 'A' && o <= 'Z'))
- /* do not use tolower() since that is locale specific */
+ /* do not use tolower() since that's locale specific */
o |= ('a' - 'A');
result = curlx_dyn_addn(out, &o, 1);
}
@@ -98,14 +101,13 @@ void jsonWriteString(FILE *stream, const char *in, bool lowercase)
}
void ourWriteOutJSON(FILE *stream, const struct writeoutvar mappings[],
- size_t nentries,
struct per_transfer *per, CURLcode per_result)
{
- size_t i;
+ int i;
fputs("{", stream);
- for(i = 0; i < nentries; i++) {
+ for(i = 0; mappings[i].name != NULL; i++) {
if(mappings[i].writefunc &&
mappings[i].writefunc(stream, &mappings[i], per, per_result, true))
fputs(",", stream);
diff --git a/contrib/libs/curl/src/tool_writeout_json.h b/contrib/libs/curl/src/tool_writeout_json.h
index 91f5d93dc8..49a28194ff 100644
--- a/contrib/libs/curl/src/tool_writeout_json.h
+++ b/contrib/libs/curl/src/tool_writeout_json.h
@@ -30,7 +30,6 @@ int jsonquoted(const char *in, size_t len,
struct curlx_dynbuf *out, bool lowercase);
void ourWriteOutJSON(FILE *stream, const struct writeoutvar mappings[],
- size_t nentries,
struct per_transfer *per, CURLcode per_result);
void headerJSON(FILE *stream, struct per_transfer *per);
void jsonWriteString(FILE *stream, const char *in, bool lowercase);
diff --git a/contrib/libs/curl/src/tool_xattr.c b/contrib/libs/curl/src/tool_xattr.c
index f832e24757..9472194faa 100644
--- a/contrib/libs/curl/src/tool_xattr.c
+++ b/contrib/libs/curl/src/tool_xattr.c
@@ -55,7 +55,7 @@ char *stripcredentials(const char *url)
char *nurl;
u = curl_url();
if(u) {
- uc = curl_url_set(u, CURLUPART_URL, url, CURLU_GUESS_SCHEME);
+ uc = curl_url_set(u, CURLUPART_URL, url, 0);
if(uc)
goto error;
@@ -87,11 +87,12 @@ static int xattr(int fd,
int err = 0;
if(value) {
#ifdef DEBUGBUILD
+ (void)fd;
if(getenv("CURL_FAKE_XATTR")) {
printf("%s => %s\n", attr, value);
- return 0;
}
-#endif
+ return 0;
+#else
#ifdef HAVE_FSETXATTR_6
err = fsetxattr(fd, attr, value, strlen(value), 0, 0);
#elif defined(HAVE_FSETXATTR_5)
@@ -105,6 +106,7 @@ static int xattr(int fd,
err = (rc < 0 ? -1 : 0);
}
#endif
+#endif
}
return err;
}
diff --git a/contrib/libs/curl/src/var.c b/contrib/libs/curl/src/var.c
index dbcef3c116..388d45592f 100644
--- a/contrib/libs/curl/src/var.c
+++ b/contrib/libs/curl/src/var.c
@@ -23,6 +23,8 @@
***************************************************************************/
#include "tool_setup.h"
+#define ENABLE_CURLX_PRINTF
+/* use our own printf() functions */
#include "curlx.h"
#include "tool_cfgable.h"
@@ -40,7 +42,6 @@
#include "memdebug.h" /* keep this as LAST include */
#define MAX_EXPAND_CONTENT 10000000
-#define MAX_VAR_LEN 128 /* max length of a name */
static char *Memdup(const char *data, size_t len)
{
@@ -61,6 +62,7 @@ void varcleanup(struct GlobalConfig *global)
struct var *t = list;
list = list->next;
free((char *)t->content);
+ free((char *)t->name);
free(t);
}
}
@@ -108,7 +110,7 @@ static ParameterError varfunc(struct GlobalConfig *global,
if(*f == '}')
/* end of functions */
break;
- /* On entry, this is known to be a colon already. In subsequent laps, it
+ /* On entry, this is known to be a colon already. In subsequent laps, it
is also known to be a colon since that is part of the FUNCMATCH()
checks */
f++;
@@ -231,7 +233,7 @@ ParameterError varexpand(struct GlobalConfig *global,
line = &envp[2];
}
else if(envp) {
- char name[MAX_VAR_LEN];
+ char name[128];
size_t nlen;
size_t i;
char *funcp;
@@ -340,7 +342,7 @@ ParameterError varexpand(struct GlobalConfig *global,
}
/*
- * Created in a way that is not revealing how variables are actually stored so
+ * Created in a way that is not revealing how variables is actually stored so
* that we can improve this if we want better performance when managing many
* at a later point.
*/
@@ -353,24 +355,29 @@ static ParameterError addvariable(struct GlobalConfig *global,
{
struct var *p;
const struct var *check = varcontent(global, name, nlen);
- DEBUGASSERT(nlen);
if(check)
notef(global, "Overwriting variable '%s'", check->name);
- p = calloc(1, sizeof(struct var) + nlen);
- if(p) {
- memcpy(p->name, name, nlen);
+ p = calloc(1, sizeof(struct var));
+ if(!p)
+ return PARAM_NO_MEM;
- p->content = contalloc ? content: Memdup(content, clen);
- if(p->content) {
- p->clen = clen;
+ p->name = Memdup(name, nlen);
+ if(!p->name)
+ goto err;
- p->next = global->variables;
- global->variables = p;
- return PARAM_OK;
- }
- free(p);
- }
+ p->content = contalloc ? content: Memdup(content, clen);
+ if(!p->content)
+ goto err;
+ p->clen = clen;
+
+ p->next = global->variables;
+ global->variables = p;
+ return PARAM_OK;
+err:
+ free((char *)p->content);
+ free((char *)p->name);
+ free(p);
return PARAM_NO_MEM;
}
@@ -386,7 +393,6 @@ ParameterError setvariable(struct GlobalConfig *global,
ParameterError err = PARAM_OK;
bool import = FALSE;
char *ge = NULL;
- char buf[MAX_VAR_LEN];
if(*input == '%') {
import = TRUE;
@@ -396,20 +402,12 @@ ParameterError setvariable(struct GlobalConfig *global,
while(*line && (ISALNUM(*line) || (*line == '_')))
line++;
nlen = line - name;
- if(!nlen || (nlen >= MAX_VAR_LEN)) {
+ if(!nlen || (nlen > 128)) {
warnf(global, "Bad variable name length (%zd), skipping", nlen);
return PARAM_OK;
}
if(import) {
- /* this does not use curl_getenv() because we want "" support for blank
- content */
- if(*line) {
- /* if there is a default action, we need to copy the name */
- memcpy(buf, name, nlen);
- buf[nlen] = 0;
- name = buf;
- }
- ge = getenv(name);
+ ge = curl_getenv(name);
if(!*line && !ge) {
/* no assign, no variable, fail */
errorf(global, "Variable '%s' import fail, not set", name);
@@ -461,5 +459,6 @@ ParameterError setvariable(struct GlobalConfig *global,
if(contalloc)
free(content);
}
+ curl_free(ge);
return err;
}
diff --git a/contrib/libs/curl/src/var.h b/contrib/libs/curl/src/var.h
index 2ea9797275..4a71943a3c 100644
--- a/contrib/libs/curl/src/var.h
+++ b/contrib/libs/curl/src/var.h
@@ -29,9 +29,9 @@
struct var {
struct var *next;
+ const char *name;
const char *content;
size_t clen; /* content length */
- char name[1]; /* allocated as part of the struct */
};
struct GlobalConfig;
diff --git a/contrib/libs/curl/ya.make b/contrib/libs/curl/ya.make
index 1d0275a749..5f55a73471 100644
--- a/contrib/libs/curl/ya.make
+++ b/contrib/libs/curl/ya.make
@@ -11,9 +11,9 @@ LICENSE(
LICENSE_TEXTS(.yandex_meta/licenses.list.txt)
-VERSION(8.10.1)
+VERSION(8.5.0)
-ORIGINAL_SOURCE(https://github.com/curl/curl/releases/download/curl-8_10_1/curl-8.10.1.tar.bz2)
+ORIGINAL_SOURCE(https://github.com/curl/curl/releases/download/curl-8_5_0/curl-8.5.0.tar.bz2)
PEERDIR(
contrib/libs/brotli/dec
@@ -92,17 +92,15 @@ SRCS(
lib/curl_memrchr.c
lib/curl_multibyte.c
lib/curl_ntlm_core.c
+ lib/curl_ntlm_wb.c
lib/curl_path.c
lib/curl_range.c
lib/curl_rtmp.c
lib/curl_sasl.c
- lib/curl_sha512_256.c
lib/curl_sspi.c
lib/curl_threads.c
lib/curl_trc.c
- lib/cw-out.c
lib/dict.c
- lib/dllmain.c
lib/doh.c
lib/dynbuf.c
lib/dynhds.c
@@ -164,7 +162,6 @@ SRCS(
lib/psl.c
lib/rand.c
lib/rename.c
- lib/request.c
lib/rtsp.c
lib/select.c
lib/sendf.c
@@ -210,15 +207,12 @@ SRCS(
lib/version_win32.c
lib/vquic/curl_msh3.c
lib/vquic/curl_ngtcp2.c
- lib/vquic/curl_osslq.c
lib/vquic/curl_quiche.c
- lib/vquic/vquic-tls.c
lib/vquic/vquic.c
lib/vssh/libssh.c
lib/vssh/libssh2.c
lib/vssh/wolfssh.c
lib/vtls/bearssl.c
- lib/vtls/cipher_suite.c
lib/vtls/hostcheck.c
lib/vtls/keylog.c
lib/vtls/mbedtls_threadlock.c
diff --git a/contrib/libs/cxxsupp/builtins/.yandex_meta/build.ym b/contrib/libs/cxxsupp/builtins/.yandex_meta/build.ym
new file mode 100644
index 0000000000..573546c8a5
--- /dev/null
+++ b/contrib/libs/cxxsupp/builtins/.yandex_meta/build.ym
@@ -0,0 +1,96 @@
+{% extends '//builtin/bag.ym' %}
+
+{% block current_version %}16.0.6{% endblock %}
+
+{% block current_url %}
+https://github.com/llvm/llvm-project/releases/download/llvmorg-{{self.version().strip()}}/compiler-rt-{{self.version().strip()}}.src.tar.xz
+{% endblock %}
+
+{% block patch_source %}
+(
+cd lib/builtins
+rm CMakeLists.txt
+rm aarch64/lse.S
+sed -e 's|.*zircon/features.h.*||' -i cpu_model.c
+sed -e 's|.*sys/byteorder.h.*||' -i int_endianness.h
+)
+{% endblock %}
+
+{% block ya_make %}
+SUBSCRIBER(
+ pg
+ somov
+ g:contrib
+ g:cpp-contrib
+)
+
+# Check MUSL before NO_PLATFORM() disables it.
+IF (MUSL)
+ # We use C headers despite NO_PLATFORM, but we do not propagate
+ # them with ADDINCL GLOBAL because we do not have an API, and we
+ # can not propagate them because libcxx has to put its own
+ # includes before musl includes for its include_next to work.
+ IF (ARCH_X86_64)
+ ADDINCL(
+ contrib/libs/musl/arch/x86_64
+ )
+ ENDIF()
+
+ IF (ARCH_AARCH64)
+ ADDINCL(
+ contrib/libs/musl/arch/aarch64
+ )
+ ENDIF()
+
+ ADDINCL(
+ contrib/libs/musl/arch/generic
+ contrib/libs/musl/include
+ contrib/libs/musl/extra
+ )
+ENDIF()
+
+NO_UTIL()
+
+NO_RUNTIME()
+
+NO_PLATFORM()
+
+NO_COMPILER_WARNINGS()
+
+IF (GCC OR CLANG)
+ # Clang (maybe GCC too) LTO code generator leaves the builtin calls unresolved
+ # even if they are available. After the code generation pass is done
+ # a linker is forced to select original object files from this library again
+ # as they contain unresolved symbols. But code generation is already done,
+ # object files actually are not ELFs but an LLVM bytecode and we get
+ # "member at xxxxx is not an ELF object" errors from the linker.
+ # Just generate native code from the beginning.
+ NO_LTO()
+ENDIF()
+{% endblock %}
+
+{% block gen_ya_make %}
+(
+cd lib/builtins
+echo 'SRCS('
+ls *.c | sort
+echo ')'
+echo 'IF (ARCH_AARCH64)'
+echo 'SRCS('
+ls aarch64/*.c | sort
+ls aarch64/*.S | sort
+echo ')'
+echo 'ENDIF()'
+echo 'IF (ARCH_X86_64)'
+echo 'SRCS('
+ls x86_64/*.c | sort
+ls x86_64/*.S | sort
+echo ')'
+echo 'ENDIF()'
+) >> ya.make
+{% endblock %}
+
+{% block move_to_output %}
+{{super()}}
+cp -R lib/builtins/* ${OUTPUT}/
+{% endblock %}
diff --git a/contrib/libs/cxxsupp/builtins/.yandex_meta/devtools.copyrights.report b/contrib/libs/cxxsupp/builtins/.yandex_meta/devtools.copyrights.report
index 3a00c42eca..8707d28570 100644
--- a/contrib/libs/cxxsupp/builtins/.yandex_meta/devtools.copyrights.report
+++ b/contrib/libs/cxxsupp/builtins/.yandex_meta/devtools.copyrights.report
@@ -29,19 +29,9 @@
# FILE_INCLUDE - include all file data into licenses text file
# =======================
-KEEP COPYRIGHT_SERVICE_LABEL 6abb44b35108cb004d9a12213d837344
-BELONGS ya.make
- License text:
- Copyright (c) 2009-2018 by the contributors listed in CREDITS.TXT
- Scancode info:
- Original SPDX id: COPYRIGHT_SERVICE_LABEL
- Score : 100.00
- Match type : COPYRIGHT
- Files with this license:
- LICENSE.os_version_check.c.txt [17:17]
-
KEEP COPYRIGHT_SERVICE_LABEL debfce3edcb19585edc08c5b1d986c0b
BELONGS ya.make
+FILE_INCLUDE CREDITS.TXT found in files: LICENSE.TXT at line 293
License text:
Copyright (c) 2009-2015 by the contributors listed in CREDITS.TXT
Scancode info:
@@ -49,13 +39,11 @@ BELONGS ya.make
Score : 100.00
Match type : COPYRIGHT
Files with this license:
- LICENSE.os_version_check.c.patch.txt [293:293]
- LICENSE.os_version_check.c.txt [58:58]
- LICENSE.txt [17:17]
- LICENSE.txt [58:58]
+ LICENSE.TXT [293:293]
KEEP COPYRIGHT_SERVICE_LABEL ebc015cad7377d32e7b2fc0ae5293aa1
BELONGS ya.make
+FILE_INCLUDE CREDITS.TXT found in files: LICENSE.TXT at line 252
# libcxxabi/CREDITS.TXT included in libcxxabi
License text:
Copyright (c) 2009-2019 by the contributors listed in CREDITS.TXT
@@ -64,4 +52,4 @@ BELONGS ya.make
Score : 100.00
Match type : COPYRIGHT
Files with this license:
- LICENSE.os_version_check.c.patch.txt [252:252]
+ LICENSE.TXT [252:252]
diff --git a/contrib/libs/cxxsupp/builtins/.yandex_meta/devtools.licenses.report b/contrib/libs/cxxsupp/builtins/.yandex_meta/devtools.licenses.report
index c9cfdfa9d4..4cb51acc6e 100644
--- a/contrib/libs/cxxsupp/builtins/.yandex_meta/devtools.licenses.report
+++ b/contrib/libs/cxxsupp/builtins/.yandex_meta/devtools.licenses.report
@@ -29,369 +29,8 @@
# FILE_INCLUDE - include all file data into licenses text file
# =======================
-KEEP NCSA 1975f079a20b2f4a333fa0d9e510d9fa
-BELONGS ya.make
- License text:
- \# This file is distributed under the University of Illinois Open Source
- \# License. See LICENSE.TXT for details.
- Scancode info:
- Original SPDX id: NCSA
- Score : 94.00
- Match type : NOTICE
- Links : http://www.otm.illinois.edu/faculty/forms/opensource.asp, https://spdx.org/licenses/NCSA
- Files with this license:
- arm/Makefile.mk [5:6]
- arm64/Makefile.mk [5:6]
- armv6m/Makefile.mk [5:6]
- i386/Makefile.mk [5:6]
- ppc/Makefile.mk [5:6]
- x86_64/Makefile.mk [5:6]
-
-KEEP NCSA AND MIT 27a91d3feda74cb7f51826c55ccf86e1
-BELONGS ya.make
- License text:
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- Scancode info:
- Original SPDX id: NCSA
- Score : 100.00
- Match type : NOTICE
- Links : http://www.otm.illinois.edu/faculty/forms/opensource.asp, https://spdx.org/licenses/NCSA
- Files with this license:
- absvdi2.c [5:6]
- absvsi2.c [5:6]
- absvti2.c [5:6]
- addvdi3.c [5:6]
- addvsi3.c [5:6]
- addvti3.c [5:6]
- apple_versioning.c [5:6]
- arm/aeabi_div0.c [5:6]
- arm/clzdi2.S [5:6]
- arm/clzsi2.S [5:6]
- arm/divmodsi4.S [5:6]
- arm/divsi3.S [5:6]
- arm/modsi3.S [5:6]
- arm/sync-ops.h [5:6]
- arm/sync_fetch_and_add_4.S [5:6]
- arm/sync_fetch_and_add_8.S [5:6]
- arm/sync_fetch_and_and_4.S [5:6]
- arm/sync_fetch_and_and_8.S [5:6]
- arm/sync_fetch_and_max_4.S [5:6]
- arm/sync_fetch_and_max_8.S [5:6]
- arm/sync_fetch_and_min_4.S [5:6]
- arm/sync_fetch_and_min_8.S [5:6]
- arm/sync_fetch_and_nand_4.S [5:6]
- arm/sync_fetch_and_nand_8.S [5:6]
- arm/sync_fetch_and_or_4.S [5:6]
- arm/sync_fetch_and_or_8.S [5:6]
- arm/sync_fetch_and_sub_4.S [5:6]
- arm/sync_fetch_and_sub_8.S [5:6]
- arm/sync_fetch_and_umax_4.S [5:6]
- arm/sync_fetch_and_umax_8.S [5:6]
- arm/sync_fetch_and_umin_4.S [5:6]
- arm/sync_fetch_and_umin_8.S [5:6]
- arm/sync_fetch_and_xor_4.S [5:6]
- arm/sync_fetch_and_xor_8.S [5:6]
- arm/udivmodsi4.S [5:6]
- arm/udivsi3.S [5:6]
- arm/umodsi3.S [5:6]
- ashldi3.c [5:6]
- ashlti3.c [5:6]
- ashrdi3.c [5:6]
- ashrti3.c [5:6]
- assembly.h [5:6]
- atomic.c [5:6]
- atomic_flag_clear.c [5:6]
- atomic_flag_clear_explicit.c [5:6]
- atomic_flag_test_and_set.c [5:6]
- atomic_flag_test_and_set_explicit.c [5:6]
- atomic_signal_fence.c [5:6]
- atomic_thread_fence.c [5:6]
- clear_cache.c [5:6]
- clzdi2.c [5:6]
- clzsi2.c [5:6]
- clzti2.c [5:6]
- cmpdi2.c [5:6]
- cmpti2.c [5:6]
- ctzdi2.c [5:6]
- ctzsi2.c [5:6]
- ctzti2.c [5:6]
- divdc3.c [5:6]
- divdi3.c [5:6]
- divmoddi4.c [5:6]
- divmodsi4.c [5:6]
- divsc3.c [5:6]
- divsi3.c [5:6]
- divtc3.c [5:6]
- divti3.c [5:6]
- divxc3.c [5:6]
- emutls.c [5:6]
- enable_execute_stack.c [5:6]
- eprintf.c [5:6]
- ffsdi2.c [5:6]
- ffsti2.c [5:6]
- fixdfdi.c [5:6]
- fixdfsi.c [5:6]
- fixdfti.c [5:6]
- fixsfdi.c [5:6]
- fixsfsi.c [5:6]
- fixsfti.c [5:6]
- fixtfdi.c [5:6]
- fixtfsi.c [5:6]
- fixtfti.c [5:6]
- fixunsdfdi.c [5:6]
- fixunsdfsi.c [5:6]
- fixunsdfti.c [5:6]
- fixunssfdi.c [5:6]
- fixunssfsi.c [5:6]
- fixunssfti.c [5:6]
- fixunstfdi.c [5:6]
- fixunstfsi.c [5:6]
- fixunstfti.c [5:6]
- fixunsxfdi.c [5:6]
- fixunsxfsi.c [5:6]
- fixunsxfti.c [5:6]
- fixxfdi.c [5:6]
- fixxfti.c [5:6]
- floatdidf.c [5:6]
- floatdisf.c [5:6]
- floatdixf.c [5:6]
- floattidf.c [5:6]
- floattisf.c [5:6]
- floattixf.c [5:6]
- floatundidf.c [5:6]
- floatundisf.c [5:6]
- floatundixf.c [5:6]
- floatuntidf.c [5:6]
- floatuntisf.c [5:6]
- floatuntixf.c [5:6]
- gcc_personality_v0.c [5:6]
- int_endianness.h [5:6]
- int_lib.h [5:6]
- int_math.h [5:6]
- int_types.h [5:6]
- int_util.c [5:6]
- int_util.h [5:6]
- lshrdi3.c [5:6]
- lshrti3.c [5:6]
- moddi3.c [5:6]
- modsi3.c [5:6]
- modti3.c [5:6]
- muldc3.c [5:6]
- muldi3.c [5:6]
- mulodi4.c [5:6]
- mulosi4.c [5:6]
- muloti4.c [5:6]
- mulsc3.c [5:6]
- multc3.c [5:6]
- multi3.c [5:6]
- mulvdi3.c [5:6]
- mulvsi3.c [5:6]
- mulvti3.c [5:6]
- mulxc3.c [5:6]
- negdi2.c [5:6]
- negti2.c [5:6]
- negvdi2.c [5:6]
- negvsi2.c [5:6]
- negvti2.c [5:6]
- os_version_check.c [5:6]
- paritydi2.c [5:6]
- paritysi2.c [5:6]
- parityti2.c [5:6]
- popcountdi2.c [5:6]
- popcountsi2.c [5:6]
- popcountti2.c [5:6]
- powidf2.c [5:6]
- powisf2.c [5:6]
- powitf2.c [5:6]
- powixf2.c [5:6]
- subvdi3.c [5:6]
- subvsi3.c [5:6]
- subvti3.c [5:6]
- trampoline_setup.c [5:6]
- ucmpdi2.c [5:6]
- ucmpti2.c [5:6]
- udivdi3.c [5:6]
- udivmoddi4.c [5:6]
- udivmodsi4.c [5:6]
- udivmodti4.c [5:6]
- udivsi3.c [5:6]
- udivti3.c [5:6]
- umoddi3.c [5:6]
- umodsi3.c [5:6]
- umodti3.c [5:6]
- Scancode info:
- Original SPDX id: MIT
- Score : 100.00
- Match type : NOTICE
- Links : http://opensource.org/licenses/mit-license.php, https://spdx.org/licenses/MIT
- Files with this license:
- absvdi2.c [5:6]
- absvsi2.c [5:6]
- absvti2.c [5:6]
- addvdi3.c [5:6]
- addvsi3.c [5:6]
- addvti3.c [5:6]
- apple_versioning.c [5:6]
- arm/aeabi_div0.c [5:6]
- arm/clzdi2.S [5:6]
- arm/clzsi2.S [5:6]
- arm/divmodsi4.S [5:6]
- arm/divsi3.S [5:6]
- arm/modsi3.S [5:6]
- arm/sync-ops.h [5:6]
- arm/sync_fetch_and_add_4.S [5:6]
- arm/sync_fetch_and_add_8.S [5:6]
- arm/sync_fetch_and_and_4.S [5:6]
- arm/sync_fetch_and_and_8.S [5:6]
- arm/sync_fetch_and_max_4.S [5:6]
- arm/sync_fetch_and_max_8.S [5:6]
- arm/sync_fetch_and_min_4.S [5:6]
- arm/sync_fetch_and_min_8.S [5:6]
- arm/sync_fetch_and_nand_4.S [5:6]
- arm/sync_fetch_and_nand_8.S [5:6]
- arm/sync_fetch_and_or_4.S [5:6]
- arm/sync_fetch_and_or_8.S [5:6]
- arm/sync_fetch_and_sub_4.S [5:6]
- arm/sync_fetch_and_sub_8.S [5:6]
- arm/sync_fetch_and_umax_4.S [5:6]
- arm/sync_fetch_and_umax_8.S [5:6]
- arm/sync_fetch_and_umin_4.S [5:6]
- arm/sync_fetch_and_umin_8.S [5:6]
- arm/sync_fetch_and_xor_4.S [5:6]
- arm/sync_fetch_and_xor_8.S [5:6]
- arm/udivmodsi4.S [5:6]
- arm/udivsi3.S [5:6]
- arm/umodsi3.S [5:6]
- ashldi3.c [5:6]
- ashlti3.c [5:6]
- ashrdi3.c [5:6]
- ashrti3.c [5:6]
- assembly.h [5:6]
- atomic.c [5:6]
- atomic_flag_clear.c [5:6]
- atomic_flag_clear_explicit.c [5:6]
- atomic_flag_test_and_set.c [5:6]
- atomic_flag_test_and_set_explicit.c [5:6]
- atomic_signal_fence.c [5:6]
- atomic_thread_fence.c [5:6]
- clear_cache.c [5:6]
- clzdi2.c [5:6]
- clzsi2.c [5:6]
- clzti2.c [5:6]
- cmpdi2.c [5:6]
- cmpti2.c [5:6]
- ctzdi2.c [5:6]
- ctzsi2.c [5:6]
- ctzti2.c [5:6]
- divdc3.c [5:6]
- divdi3.c [5:6]
- divmoddi4.c [5:6]
- divmodsi4.c [5:6]
- divsc3.c [5:6]
- divsi3.c [5:6]
- divtc3.c [5:6]
- divti3.c [5:6]
- divxc3.c [5:6]
- emutls.c [5:6]
- enable_execute_stack.c [5:6]
- eprintf.c [5:6]
- ffsdi2.c [5:6]
- ffsti2.c [5:6]
- fixdfdi.c [5:6]
- fixdfsi.c [5:6]
- fixdfti.c [5:6]
- fixsfdi.c [5:6]
- fixsfsi.c [5:6]
- fixsfti.c [5:6]
- fixtfdi.c [5:6]
- fixtfsi.c [5:6]
- fixtfti.c [5:6]
- fixunsdfdi.c [5:6]
- fixunsdfsi.c [5:6]
- fixunsdfti.c [5:6]
- fixunssfdi.c [5:6]
- fixunssfsi.c [5:6]
- fixunssfti.c [5:6]
- fixunstfdi.c [5:6]
- fixunstfsi.c [5:6]
- fixunstfti.c [5:6]
- fixunsxfdi.c [5:6]
- fixunsxfsi.c [5:6]
- fixunsxfti.c [5:6]
- fixxfdi.c [5:6]
- fixxfti.c [5:6]
- floatdidf.c [5:6]
- floatdisf.c [5:6]
- floatdixf.c [5:6]
- floattidf.c [5:6]
- floattisf.c [5:6]
- floattixf.c [5:6]
- floatundidf.c [5:6]
- floatundisf.c [5:6]
- floatundixf.c [5:6]
- floatuntidf.c [5:6]
- floatuntisf.c [5:6]
- floatuntixf.c [5:6]
- gcc_personality_v0.c [5:6]
- int_endianness.h [5:6]
- int_lib.h [5:6]
- int_math.h [5:6]
- int_types.h [5:6]
- int_util.c [5:6]
- int_util.h [5:6]
- lshrdi3.c [5:6]
- lshrti3.c [5:6]
- moddi3.c [5:6]
- modsi3.c [5:6]
- modti3.c [5:6]
- muldc3.c [5:6]
- muldi3.c [5:6]
- mulodi4.c [5:6]
- mulosi4.c [5:6]
- muloti4.c [5:6]
- mulsc3.c [5:6]
- multc3.c [5:6]
- multi3.c [5:6]
- mulvdi3.c [5:6]
- mulvsi3.c [5:6]
- mulvti3.c [5:6]
- mulxc3.c [5:6]
- negdi2.c [5:6]
- negti2.c [5:6]
- negvdi2.c [5:6]
- negvsi2.c [5:6]
- negvti2.c [5:6]
- os_version_check.c [5:6]
- paritydi2.c [5:6]
- paritysi2.c [5:6]
- parityti2.c [5:6]
- popcountdi2.c [5:6]
- popcountsi2.c [5:6]
- popcountti2.c [5:6]
- powidf2.c [5:6]
- powisf2.c [5:6]
- powitf2.c [5:6]
- powixf2.c [5:6]
- subvdi3.c [5:6]
- subvsi3.c [5:6]
- subvti3.c [5:6]
- trampoline_setup.c [5:6]
- ucmpdi2.c [5:6]
- ucmpti2.c [5:6]
- udivdi3.c [5:6]
- udivmoddi4.c [5:6]
- udivmodsi4.c [5:6]
- udivmodti4.c [5:6]
- udivsi3.c [5:6]
- udivti3.c [5:6]
- umoddi3.c [5:6]
- umodsi3.c [5:6]
- umodti3.c [5:6]
-
KEEP NCSA 281d1ec07e86b61c925d7c514deecb25
BELONGS ya.make
-FILE_INCLUDE LICENSE.txt found in files: README.txt at line 8
License text:
Compiler-RT is open source software. You may freely distribute it under the
terms of the license agreement found in LICENSE.txt.
@@ -413,19 +52,7 @@ BELONGS ya.make
Match type : REFERENCE
Links : http://www.otm.illinois.edu/faculty/forms/opensource.asp, https://spdx.org/licenses/NCSA
Files with this license:
- LICENSE.os_version_check.c.patch.txt [237:237]
-
-KEEP NCSA 5b89aaa4f22bc812b081b9e1de7d0a13
-BELONGS ya.make
- Note: matched license text is too long. Read it in the source files.
- Scancode info:
- Original SPDX id: NCSA
- Score : 100.00
- Match type : REFERENCE
- Links : http://www.otm.illinois.edu/faculty/forms/opensource.asp, https://spdx.org/licenses/NCSA
- Files with this license:
- LICENSE.os_version_check.c.txt [81:90]
- LICENSE.txt [81:90]
+ LICENSE.TXT [237:237]
KEEP MIT 5debb370f50e1dfd24ff5144233a2ef6
BELONGS ya.make
@@ -437,12 +64,11 @@ BELONGS ya.make
Match type : TEXT
Links : http://opensource.org/licenses/mit-license.php, https://spdx.org/licenses/MIT
Files with this license:
- LICENSE.os_version_check.c.patch.txt [295:311]
- LICENSE.os_version_check.c.txt [60:76]
- LICENSE.txt [60:76]
+ LICENSE.TXT [295:311]
KEEP NCSA AND MIT 72d4e9e6f06ffb6f0c77cb800c3ac442
BELONGS ya.make
+FILE_INCLUDE LICENSE.TXT found in files: extendhftf2.c at line 6, trunctfhf2.c at line 6
License text:
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
@@ -452,96 +78,275 @@ BELONGS ya.make
Match type : NOTICE
Links : http://www.otm.illinois.edu/faculty/forms/opensource.asp, https://spdx.org/licenses/NCSA
Files with this license:
- adddf3.c [5:6]
- addsf3.c [5:6]
- addtf3.c [5:6]
- arm/adddf3vfp.S [5:6]
- arm/addsf3vfp.S [5:6]
- arm/aeabi_cdcmp.S [5:6]
- arm/aeabi_cdcmpeq_check_nan.c [5:6]
- arm/aeabi_cfcmp.S [5:6]
- arm/aeabi_cfcmpeq_check_nan.c [5:6]
- arm/aeabi_dcmp.S [5:6]
- arm/aeabi_drsub.c [5:6]
- arm/aeabi_fcmp.S [5:6]
- arm/aeabi_frsub.c [5:6]
- arm/aeabi_idivmod.S [5:6]
- arm/aeabi_ldivmod.S [5:6]
- arm/aeabi_memcmp.S [5:6]
- arm/aeabi_memcpy.S [5:6]
- arm/aeabi_memmove.S [5:6]
- arm/aeabi_memset.S [5:6]
- arm/aeabi_uidivmod.S [5:6]
- arm/aeabi_uldivmod.S [5:6]
- arm/bswapdi2.S [5:6]
- arm/bswapsi2.S [5:6]
- arm/comparesf2.S [5:6]
- arm/divdf3vfp.S [5:6]
- arm/divsf3vfp.S [5:6]
- arm/eqdf2vfp.S [5:6]
- arm/eqsf2vfp.S [5:6]
- arm/extendsfdf2vfp.S [5:6]
- arm/fixdfsivfp.S [5:6]
- arm/fixsfsivfp.S [5:6]
- arm/fixunsdfsivfp.S [5:6]
- arm/fixunssfsivfp.S [5:6]
- arm/floatsidfvfp.S [5:6]
- arm/floatsisfvfp.S [5:6]
- arm/floatunssidfvfp.S [5:6]
- arm/floatunssisfvfp.S [5:6]
- arm/gedf2vfp.S [5:6]
- arm/gesf2vfp.S [5:6]
- arm/gtdf2vfp.S [5:6]
- arm/gtsf2vfp.S [5:6]
- arm/ledf2vfp.S [5:6]
- arm/lesf2vfp.S [5:6]
- arm/ltdf2vfp.S [5:6]
- arm/ltsf2vfp.S [5:6]
- arm/muldf3vfp.S [5:6]
- arm/mulsf3vfp.S [5:6]
- arm/nedf2vfp.S [5:6]
- arm/negdf2vfp.S [5:6]
- arm/negsf2vfp.S [5:6]
- arm/nesf2vfp.S [5:6]
- arm/restore_vfp_d8_d15_regs.S [5:6]
- arm/save_vfp_d8_d15_regs.S [5:6]
- arm/subdf3vfp.S [5:6]
- arm/subsf3vfp.S [5:6]
- arm/switch16.S [5:6]
- arm/switch32.S [5:6]
- arm/switch8.S [5:6]
- arm/switchu8.S [5:6]
- arm/sync_synchronize.S [5:6]
- arm/truncdfsf2vfp.S [5:6]
- arm/unorddf2vfp.S [5:6]
- arm/unordsf2vfp.S [5:6]
- comparedf2.c [5:6]
- comparesf2.c [5:6]
- comparetf2.c [5:6]
- divdf3.c [5:6]
- divsf3.c [5:6]
- divtf3.c [5:6]
- extenddftf2.c [5:6]
- extendhfsf2.c [5:6]
- extendsfdf2.c [5:6]
- extendsftf2.c [5:6]
- floatditf.c [5:6]
- floatsidf.c [5:6]
- floatsisf.c [5:6]
- floatsitf.c [5:6]
- floatunditf.c [5:6]
- floatunsidf.c [5:6]
- floatunsisf.c [5:6]
- floatunsitf.c [5:6]
- fp_add_impl.inc [5:6]
- fp_extend.h [5:6]
- fp_extend_impl.inc [5:6]
- fp_fixint_impl.inc [5:6]
- fp_fixuint_impl.inc [5:6]
- fp_lib.h [5:6]
- fp_mul_impl.inc [5:6]
- fp_trunc.h [5:6]
- fp_trunc_impl.inc [5:6]
+ extendhftf2.c [5:6]
+ trunctfhf2.c [5:6]
+ Scancode info:
+ Original SPDX id: MIT
+ Score : 100.00
+ Match type : NOTICE
+ Links : http://opensource.org/licenses/mit-license.php, https://spdx.org/licenses/MIT
+ Files with this license:
+ extendhftf2.c [5:6]
+ trunctfhf2.c [5:6]
+
+KEEP Apache-2.0 AND LLVM-exception 755ab7da3ff8c5d6ae90bdbebd177e49
+BELONGS ya.make
+ License text:
+ // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+ // See https://llvm.org/LICENSE.txt for license information.
+ Scancode info:
+ Original SPDX id: Apache-2.0
+ Score : 100.00
+ Match type : NOTICE
+ Links : http://www.apache.org/licenses/, http://www.apache.org/licenses/LICENSE-2.0, https://spdx.org/licenses/Apache-2.0
+ Files with this license:
+ aarch64/chkstk.S [1:2]
+ aarch64/fp_mode.c [3:4]
+ absvdi2.c [3:4]
+ absvsi2.c [3:4]
+ absvti2.c [3:4]
+ adddf3.c [3:4]
+ addsf3.c [3:4]
+ addtf3.c [3:4]
+ addvdi3.c [3:4]
+ addvsi3.c [3:4]
+ addvti3.c [3:4]
+ apple_versioning.c [3:4]
+ arm/adddf3vfp.S [3:4]
+ arm/addsf3.S [3:4]
+ arm/addsf3vfp.S [3:4]
+ arm/aeabi_cdcmp.S [3:4]
+ arm/aeabi_cdcmpeq_check_nan.c [3:4]
+ arm/aeabi_cfcmp.S [3:4]
+ arm/aeabi_cfcmpeq_check_nan.c [3:4]
+ arm/aeabi_dcmp.S [3:4]
+ arm/aeabi_div0.c [3:4]
+ arm/aeabi_drsub.c [3:4]
+ arm/aeabi_fcmp.S [3:4]
+ arm/aeabi_frsub.c [3:4]
+ arm/aeabi_idivmod.S [3:4]
+ arm/aeabi_ldivmod.S [3:4]
+ arm/aeabi_memcmp.S [3:4]
+ arm/aeabi_memcpy.S [3:4]
+ arm/aeabi_memmove.S [3:4]
+ arm/aeabi_memset.S [3:4]
+ arm/aeabi_uidivmod.S [3:4]
+ arm/aeabi_uldivmod.S [3:4]
+ arm/bswapdi2.S [3:4]
+ arm/bswapsi2.S [3:4]
+ arm/chkstk.S [1:2]
+ arm/clzdi2.S [3:4]
+ arm/clzsi2.S [3:4]
+ arm/comparesf2.S [3:4]
+ arm/divdf3vfp.S [3:4]
+ arm/divmodsi4.S [3:4]
+ arm/divsf3vfp.S [3:4]
+ arm/divsi3.S [3:4]
+ arm/eqdf2vfp.S [3:4]
+ arm/eqsf2vfp.S [3:4]
+ arm/extendsfdf2vfp.S [3:4]
+ arm/fixdfsivfp.S [3:4]
+ arm/fixsfsivfp.S [3:4]
+ arm/fixunsdfsivfp.S [3:4]
+ arm/fixunssfsivfp.S [3:4]
+ arm/floatsidfvfp.S [3:4]
+ arm/floatsisfvfp.S [3:4]
+ arm/floatunssidfvfp.S [3:4]
+ arm/floatunssisfvfp.S [3:4]
+ arm/fp_mode.c [3:4]
+ arm/gedf2vfp.S [3:4]
+ arm/gesf2vfp.S [3:4]
+ arm/gtdf2vfp.S [3:4]
+ arm/gtsf2vfp.S [3:4]
+ arm/ledf2vfp.S [3:4]
+ arm/lesf2vfp.S [3:4]
+ arm/ltdf2vfp.S [3:4]
+ arm/ltsf2vfp.S [3:4]
+ arm/modsi3.S [3:4]
+ arm/muldf3vfp.S [3:4]
+ arm/mulsf3vfp.S [3:4]
+ arm/nedf2vfp.S [3:4]
+ arm/negdf2vfp.S [3:4]
+ arm/negsf2vfp.S [3:4]
+ arm/nesf2vfp.S [3:4]
+ arm/restore_vfp_d8_d15_regs.S [3:4]
+ arm/save_vfp_d8_d15_regs.S [3:4]
+ arm/subdf3vfp.S [3:4]
+ arm/subsf3vfp.S [3:4]
+ arm/switch16.S [3:4]
+ arm/switch32.S [3:4]
+ arm/switch8.S [3:4]
+ arm/switchu8.S [3:4]
+ arm/sync-ops.h [3:4]
+ arm/sync_fetch_and_add_4.S [3:4]
+ arm/sync_fetch_and_add_8.S [3:4]
+ arm/sync_fetch_and_and_4.S [3:4]
+ arm/sync_fetch_and_and_8.S [3:4]
+ arm/sync_fetch_and_max_4.S [3:4]
+ arm/sync_fetch_and_max_8.S [3:4]
+ arm/sync_fetch_and_min_4.S [3:4]
+ arm/sync_fetch_and_min_8.S [3:4]
+ arm/sync_fetch_and_nand_4.S [3:4]
+ arm/sync_fetch_and_nand_8.S [3:4]
+ arm/sync_fetch_and_or_4.S [3:4]
+ arm/sync_fetch_and_or_8.S [3:4]
+ arm/sync_fetch_and_sub_4.S [3:4]
+ arm/sync_fetch_and_sub_8.S [3:4]
+ arm/sync_fetch_and_umax_4.S [3:4]
+ arm/sync_fetch_and_umax_8.S [3:4]
+ arm/sync_fetch_and_umin_4.S [3:4]
+ arm/sync_fetch_and_umin_8.S [3:4]
+ arm/sync_fetch_and_xor_4.S [3:4]
+ arm/sync_fetch_and_xor_8.S [3:4]
+ arm/sync_synchronize.S [3:4]
+ arm/truncdfsf2vfp.S [3:4]
+ arm/udivmodsi4.S [3:4]
+ arm/udivsi3.S [3:4]
+ arm/umodsi3.S [3:4]
+ arm/unorddf2vfp.S [3:4]
+ arm/unordsf2vfp.S [3:4]
+ ashldi3.c [3:4]
+ ashlti3.c [3:4]
+ ashrdi3.c [3:4]
+ ashrti3.c [3:4]
+ assembly.h [3:4]
+ atomic.c [3:4]
+ atomic_flag_clear.c [3:4]
+ atomic_flag_clear_explicit.c [3:4]
+ atomic_flag_test_and_set.c [3:4]
+ atomic_flag_test_and_set_explicit.c [3:4]
+ atomic_signal_fence.c [3:4]
+ atomic_thread_fence.c [3:4]
+ avr/divmodhi4.S [3:4]
+ avr/divmodqi4.S [3:4]
+ avr/exit.S [3:4]
+ avr/mulhi3.S [3:4]
+ avr/mulqi3.S [3:4]
+ avr/udivmodhi4.S [3:4]
+ avr/udivmodqi4.S [3:4]
+ bswapdi2.c [3:4]
+ bswapsi2.c [3:4]
+ clear_cache.c [3:4]
+ clzdi2.c [3:4]
+ clzsi2.c [3:4]
+ clzti2.c [3:4]
+ cmpdi2.c [3:4]
+ cmpti2.c [3:4]
+ comparedf2.c [3:4]
+ comparesf2.c [3:4]
+ comparetf2.c [3:4]
+ cpu_model.c [3:4]
+ ctzdi2.c [3:4]
+ ctzsi2.c [3:4]
+ ctzti2.c [3:4]
+ divdc3.c [3:4]
+ divdf3.c [3:4]
+ divdi3.c [3:4]
+ divmoddi4.c [3:4]
+ divmodsi4.c [4:5]
+ divmodti4.c [3:4]
+ divsc3.c [3:4]
+ divsf3.c [3:4]
+ divsi3.c [3:4]
+ divtc3.c [3:4]
+ divtf3.c [3:4]
+ divti3.c [3:4]
+ divxc3.c [3:4]
+ emutls.c [3:4]
+ enable_execute_stack.c [3:4]
+ eprintf.c [3:4]
+ extenddftf2.c [3:4]
+ extendhfsf2.c [3:4]
+ extendsfdf2.c [3:4]
+ extendsftf2.c [3:4]
+ ffsdi2.c [3:4]
+ ffssi2.c [3:4]
+ ffsti2.c [3:4]
+ fixdfdi.c [3:4]
+ fixdfsi.c [3:4]
+ fixdfti.c [3:4]
+ fixsfdi.c [3:4]
+ fixsfsi.c [3:4]
+ fixsfti.c [3:4]
+ fixtfdi.c [3:4]
+ fixtfsi.c [3:4]
+ fixtfti.c [3:4]
+ fixunsdfdi.c [3:4]
+ fixunsdfsi.c [3:4]
+ fixunsdfti.c [3:4]
+ fixunssfdi.c [3:4]
+ fixunssfsi.c [3:4]
+ fixunssfti.c [3:4]
+ fixunstfdi.c [3:4]
+ fixunstfsi.c [3:4]
+ fixunstfti.c [3:4]
+ fixunsxfdi.c [3:4]
+ fixunsxfsi.c [3:4]
+ fixunsxfti.c [3:4]
+ fixxfdi.c [3:4]
+ fixxfti.c [3:4]
+ floatdidf.c [3:4]
+ floatdisf.c [3:4]
+ floatditf.c [3:4]
+ floatdixf.c [3:4]
+ floatsidf.c [3:4]
+ floatsisf.c [3:4]
+ floatsitf.c [3:4]
+ floattidf.c [3:4]
+ floattisf.c [3:4]
+ floattitf.c [3:4]
+ floattixf.c [3:4]
+ floatundidf.c [3:4]
+ floatundisf.c [3:4]
+ floatunditf.c [3:4]
+ floatundixf.c [3:4]
+ floatunsidf.c [3:4]
+ floatunsisf.c [3:4]
+ floatunsitf.c [3:4]
+ floatuntidf.c [3:4]
+ floatuntisf.c [3:4]
+ floatuntitf.c [3:4]
+ floatuntixf.c [3:4]
+ fp_add_impl.inc [3:4]
+ fp_compare_impl.inc [3:4]
+ fp_div_impl.inc [3:4]
+ fp_extend.h [4:5]
+ fp_extend_impl.inc [3:4]
+ fp_fixint_impl.inc [3:4]
+ fp_fixuint_impl.inc [3:4]
+ fp_lib.h [3:4]
+ fp_mode.c [3:4]
+ fp_mode.h [3:4]
+ fp_mul_impl.inc [3:4]
+ fp_trunc.h [3:4]
+ fp_trunc_impl.inc [3:4]
+ gcc_personality_v0.c [3:4]
+ hexagon/common_entry_exit_abi1.S [3:4]
+ hexagon/common_entry_exit_abi2.S [3:4]
+ hexagon/common_entry_exit_legacy.S [3:4]
+ hexagon/dfaddsub.S [3:4]
+ hexagon/dfdiv.S [3:4]
+ hexagon/dffma.S [3:4]
+ hexagon/dfminmax.S [3:4]
+ hexagon/dfmul.S [3:4]
+ hexagon/dfsqrt.S [3:4]
+ hexagon/divdi3.S [3:4]
+ hexagon/divsi3.S [3:4]
+ hexagon/fastmath2_dlib_asm.S [3:4]
+ hexagon/fastmath2_ldlib_asm.S [3:4]
+ hexagon/fastmath_dlib_asm.S [3:4]
+ hexagon/memcpy_forward_vp4cp4n2.S [3:4]
+ hexagon/memcpy_likely_aligned.S [3:4]
+ hexagon/moddi3.S [3:4]
+ hexagon/modsi3.S [3:4]
+ hexagon/sfdiv_opt.S [3:4]
+ hexagon/sfsqrt_opt.S [3:4]
+ hexagon/udivdi3.S [3:4]
+ hexagon/udivmoddi4.S [3:4]
+ hexagon/udivmodsi4.S [3:4]
+ hexagon/udivsi3.S [3:4]
+ hexagon/umoddi3.S [3:4]
+ hexagon/umodsi3.S [3:4]
i386/ashldi3.S [1:2]
i386/ashrdi3.S [1:2]
i386/chkstk.S [1:2]
@@ -550,130 +355,373 @@ BELONGS ya.make
i386/floatdidf.S [1:2]
i386/floatdisf.S [1:2]
i386/floatdixf.S [1:2]
- i386/floatundidf.S [5:6]
+ i386/floatundidf.S [3:4]
i386/floatundisf.S [1:2]
i386/floatundixf.S [1:2]
+ i386/fp_mode.c [3:4]
i386/lshrdi3.S [1:2]
i386/moddi3.S [1:2]
i386/muldi3.S [1:2]
i386/udivdi3.S [1:2]
i386/umoddi3.S [1:2]
- muldf3.c [5:6]
- mulsf3.c [5:6]
- multf3.c [5:6]
- negdf2.c [5:6]
- negsf2.c [5:6]
- ppc/restFP.S [5:6]
- ppc/saveFP.S [5:6]
- subdf3.c [5:6]
- subsf3.c [5:6]
- subtf3.c [5:6]
- truncdfhf2.c [5:6]
- truncdfsf2.c [5:6]
- truncsfhf2.c [5:6]
- trunctfdf2.c [5:6]
- trunctfsf2.c [5:6]
+ int_div_impl.inc [3:4]
+ int_endianness.h [3:4]
+ int_lib.h [3:4]
+ int_math.h [3:4]
+ int_mulo_impl.inc [3:4]
+ int_mulv_impl.inc [3:4]
+ int_types.h [3:4]
+ int_util.c [3:4]
+ int_util.h [3:4]
+ loongarch/fp_mode.c [3:4]
+ lshrdi3.c [3:4]
+ lshrti3.c [3:4]
+ moddi3.c [3:4]
+ modsi3.c [3:4]
+ modti3.c [3:4]
+ muldc3.c [3:4]
+ muldf3.c [3:4]
+ muldi3.c [3:4]
+ mulodi4.c [3:4]
+ mulosi4.c [3:4]
+ muloti4.c [3:4]
+ mulsc3.c [3:4]
+ mulsf3.c [3:4]
+ multc3.c [3:4]
+ multf3.c [3:4]
+ multi3.c [3:4]
+ mulvdi3.c [3:4]
+ mulvsi3.c [3:4]
+ mulvti3.c [3:4]
+ mulxc3.c [3:4]
+ negdf2.c [3:4]
+ negdi2.c [3:4]
+ negsf2.c [3:4]
+ negti2.c [3:4]
+ negvdi2.c [3:4]
+ negvsi2.c [3:4]
+ negvti2.c [3:4]
+ os_version_check.c [3:4]
+ paritydi2.c [3:4]
+ paritysi2.c [3:4]
+ parityti2.c [3:4]
+ popcountdi2.c [3:4]
+ popcountsi2.c [3:4]
+ popcountti2.c [4:5]
+ powidf2.c [3:4]
+ powisf2.c [3:4]
+ powitf2.c [3:4]
+ powixf2.c [3:4]
+ ppc/divtc3.c [1:2]
+ ppc/fixtfdi.c [1:2]
+ ppc/fixtfti.c [3:4]
+ ppc/fixunstfdi.c [1:2]
+ ppc/fixunstfti.c [3:4]
+ ppc/floatditf.c [1:2]
+ ppc/floattitf.c [3:4]
+ ppc/floatunditf.c [1:2]
+ ppc/gcc_qadd.c [1:2]
+ ppc/gcc_qdiv.c [1:2]
+ ppc/gcc_qmul.c [1:2]
+ ppc/gcc_qsub.c [1:2]
+ ppc/multc3.c [1:2]
+ ppc/restFP.S [3:4]
+ ppc/saveFP.S [3:4]
+ riscv/fp_mode.c [3:4]
+ riscv/int_mul_impl.inc [3:4]
+ riscv/muldi3.S [3:4]
+ riscv/mulsi3.S [3:4]
+ riscv/restore.S [3:4]
+ riscv/save.S [3:4]
+ subdf3.c [3:4]
+ subsf3.c [3:4]
+ subtf3.c [3:4]
+ subvdi3.c [3:4]
+ subvsi3.c [3:4]
+ subvti3.c [3:4]
+ trampoline_setup.c [3:4]
+ truncdfbf2.c [3:4]
+ truncdfhf2.c [3:4]
+ truncdfsf2.c [3:4]
+ truncsfbf2.c [3:4]
+ truncsfhf2.c [3:4]
+ trunctfdf2.c [3:4]
+ trunctfsf2.c [3:4]
+ ucmpdi2.c [3:4]
+ ucmpti2.c [3:4]
+ udivdi3.c [3:4]
+ udivmoddi4.c [3:4]
+ udivmodsi4.c [3:4]
+ udivmodti4.c [3:4]
+ udivsi3.c [3:4]
+ udivti3.c [3:4]
+ umoddi3.c [3:4]
+ umodsi3.c [3:4]
+ umodti3.c [3:4]
+ unwind-ehabi-helpers.h [3:4]
+ ve/grow_stack.S [1:2]
+ ve/grow_stack_align.S [1:2]
x86_64/chkstk.S [1:2]
x86_64/chkstk2.S [1:2]
- x86_64/floatundidf.S [5:6]
+ x86_64/floatdidf.c [1:2]
+ x86_64/floatdisf.c [1:2]
+ x86_64/floatdixf.c [1:2]
+ x86_64/floatundidf.S [3:4]
x86_64/floatundisf.S [1:2]
x86_64/floatundixf.S [1:2]
Scancode info:
- Original SPDX id: MIT
+ Original SPDX id: LLVM-exception
Score : 100.00
Match type : NOTICE
- Links : http://opensource.org/licenses/mit-license.php, https://spdx.org/licenses/MIT
+ Links : http://llvm.org/foundation/relicensing/LICENSE.txt, https://spdx.org/licenses/LLVM-exception
Files with this license:
- adddf3.c [5:6]
- addsf3.c [5:6]
- addtf3.c [5:6]
- arm/adddf3vfp.S [5:6]
- arm/addsf3vfp.S [5:6]
- arm/aeabi_cdcmp.S [5:6]
- arm/aeabi_cdcmpeq_check_nan.c [5:6]
- arm/aeabi_cfcmp.S [5:6]
- arm/aeabi_cfcmpeq_check_nan.c [5:6]
- arm/aeabi_dcmp.S [5:6]
- arm/aeabi_drsub.c [5:6]
- arm/aeabi_fcmp.S [5:6]
- arm/aeabi_frsub.c [5:6]
- arm/aeabi_idivmod.S [5:6]
- arm/aeabi_ldivmod.S [5:6]
- arm/aeabi_memcmp.S [5:6]
- arm/aeabi_memcpy.S [5:6]
- arm/aeabi_memmove.S [5:6]
- arm/aeabi_memset.S [5:6]
- arm/aeabi_uidivmod.S [5:6]
- arm/aeabi_uldivmod.S [5:6]
- arm/bswapdi2.S [5:6]
- arm/bswapsi2.S [5:6]
- arm/comparesf2.S [5:6]
- arm/divdf3vfp.S [5:6]
- arm/divsf3vfp.S [5:6]
- arm/eqdf2vfp.S [5:6]
- arm/eqsf2vfp.S [5:6]
- arm/extendsfdf2vfp.S [5:6]
- arm/fixdfsivfp.S [5:6]
- arm/fixsfsivfp.S [5:6]
- arm/fixunsdfsivfp.S [5:6]
- arm/fixunssfsivfp.S [5:6]
- arm/floatsidfvfp.S [5:6]
- arm/floatsisfvfp.S [5:6]
- arm/floatunssidfvfp.S [5:6]
- arm/floatunssisfvfp.S [5:6]
- arm/gedf2vfp.S [5:6]
- arm/gesf2vfp.S [5:6]
- arm/gtdf2vfp.S [5:6]
- arm/gtsf2vfp.S [5:6]
- arm/ledf2vfp.S [5:6]
- arm/lesf2vfp.S [5:6]
- arm/ltdf2vfp.S [5:6]
- arm/ltsf2vfp.S [5:6]
- arm/muldf3vfp.S [5:6]
- arm/mulsf3vfp.S [5:6]
- arm/nedf2vfp.S [5:6]
- arm/negdf2vfp.S [5:6]
- arm/negsf2vfp.S [5:6]
- arm/nesf2vfp.S [5:6]
- arm/restore_vfp_d8_d15_regs.S [5:6]
- arm/save_vfp_d8_d15_regs.S [5:6]
- arm/subdf3vfp.S [5:6]
- arm/subsf3vfp.S [5:6]
- arm/switch16.S [5:6]
- arm/switch32.S [5:6]
- arm/switch8.S [5:6]
- arm/switchu8.S [5:6]
- arm/sync_synchronize.S [5:6]
- arm/truncdfsf2vfp.S [5:6]
- arm/unorddf2vfp.S [5:6]
- arm/unordsf2vfp.S [5:6]
- comparedf2.c [5:6]
- comparesf2.c [5:6]
- comparetf2.c [5:6]
- divdf3.c [5:6]
- divsf3.c [5:6]
- divtf3.c [5:6]
- extenddftf2.c [5:6]
- extendhfsf2.c [5:6]
- extendsfdf2.c [5:6]
- extendsftf2.c [5:6]
- floatditf.c [5:6]
- floatsidf.c [5:6]
- floatsisf.c [5:6]
- floatsitf.c [5:6]
- floatunditf.c [5:6]
- floatunsidf.c [5:6]
- floatunsisf.c [5:6]
- floatunsitf.c [5:6]
- fp_add_impl.inc [5:6]
- fp_extend.h [5:6]
- fp_extend_impl.inc [5:6]
- fp_fixint_impl.inc [5:6]
- fp_fixuint_impl.inc [5:6]
- fp_lib.h [5:6]
- fp_mul_impl.inc [5:6]
- fp_trunc.h [5:6]
- fp_trunc_impl.inc [5:6]
+ aarch64/chkstk.S [1:2]
+ aarch64/fp_mode.c [3:4]
+ absvdi2.c [3:4]
+ absvsi2.c [3:4]
+ absvti2.c [3:4]
+ adddf3.c [3:4]
+ addsf3.c [3:4]
+ addtf3.c [3:4]
+ addvdi3.c [3:4]
+ addvsi3.c [3:4]
+ addvti3.c [3:4]
+ apple_versioning.c [3:4]
+ arm/adddf3vfp.S [3:4]
+ arm/addsf3.S [3:4]
+ arm/addsf3vfp.S [3:4]
+ arm/aeabi_cdcmp.S [3:4]
+ arm/aeabi_cdcmpeq_check_nan.c [3:4]
+ arm/aeabi_cfcmp.S [3:4]
+ arm/aeabi_cfcmpeq_check_nan.c [3:4]
+ arm/aeabi_dcmp.S [3:4]
+ arm/aeabi_div0.c [3:4]
+ arm/aeabi_drsub.c [3:4]
+ arm/aeabi_fcmp.S [3:4]
+ arm/aeabi_frsub.c [3:4]
+ arm/aeabi_idivmod.S [3:4]
+ arm/aeabi_ldivmod.S [3:4]
+ arm/aeabi_memcmp.S [3:4]
+ arm/aeabi_memcpy.S [3:4]
+ arm/aeabi_memmove.S [3:4]
+ arm/aeabi_memset.S [3:4]
+ arm/aeabi_uidivmod.S [3:4]
+ arm/aeabi_uldivmod.S [3:4]
+ arm/bswapdi2.S [3:4]
+ arm/bswapsi2.S [3:4]
+ arm/chkstk.S [1:2]
+ arm/clzdi2.S [3:4]
+ arm/clzsi2.S [3:4]
+ arm/comparesf2.S [3:4]
+ arm/divdf3vfp.S [3:4]
+ arm/divmodsi4.S [3:4]
+ arm/divsf3vfp.S [3:4]
+ arm/divsi3.S [3:4]
+ arm/eqdf2vfp.S [3:4]
+ arm/eqsf2vfp.S [3:4]
+ arm/extendsfdf2vfp.S [3:4]
+ arm/fixdfsivfp.S [3:4]
+ arm/fixsfsivfp.S [3:4]
+ arm/fixunsdfsivfp.S [3:4]
+ arm/fixunssfsivfp.S [3:4]
+ arm/floatsidfvfp.S [3:4]
+ arm/floatsisfvfp.S [3:4]
+ arm/floatunssidfvfp.S [3:4]
+ arm/floatunssisfvfp.S [3:4]
+ arm/fp_mode.c [3:4]
+ arm/gedf2vfp.S [3:4]
+ arm/gesf2vfp.S [3:4]
+ arm/gtdf2vfp.S [3:4]
+ arm/gtsf2vfp.S [3:4]
+ arm/ledf2vfp.S [3:4]
+ arm/lesf2vfp.S [3:4]
+ arm/ltdf2vfp.S [3:4]
+ arm/ltsf2vfp.S [3:4]
+ arm/modsi3.S [3:4]
+ arm/muldf3vfp.S [3:4]
+ arm/mulsf3vfp.S [3:4]
+ arm/nedf2vfp.S [3:4]
+ arm/negdf2vfp.S [3:4]
+ arm/negsf2vfp.S [3:4]
+ arm/nesf2vfp.S [3:4]
+ arm/restore_vfp_d8_d15_regs.S [3:4]
+ arm/save_vfp_d8_d15_regs.S [3:4]
+ arm/subdf3vfp.S [3:4]
+ arm/subsf3vfp.S [3:4]
+ arm/switch16.S [3:4]
+ arm/switch32.S [3:4]
+ arm/switch8.S [3:4]
+ arm/switchu8.S [3:4]
+ arm/sync-ops.h [3:4]
+ arm/sync_fetch_and_add_4.S [3:4]
+ arm/sync_fetch_and_add_8.S [3:4]
+ arm/sync_fetch_and_and_4.S [3:4]
+ arm/sync_fetch_and_and_8.S [3:4]
+ arm/sync_fetch_and_max_4.S [3:4]
+ arm/sync_fetch_and_max_8.S [3:4]
+ arm/sync_fetch_and_min_4.S [3:4]
+ arm/sync_fetch_and_min_8.S [3:4]
+ arm/sync_fetch_and_nand_4.S [3:4]
+ arm/sync_fetch_and_nand_8.S [3:4]
+ arm/sync_fetch_and_or_4.S [3:4]
+ arm/sync_fetch_and_or_8.S [3:4]
+ arm/sync_fetch_and_sub_4.S [3:4]
+ arm/sync_fetch_and_sub_8.S [3:4]
+ arm/sync_fetch_and_umax_4.S [3:4]
+ arm/sync_fetch_and_umax_8.S [3:4]
+ arm/sync_fetch_and_umin_4.S [3:4]
+ arm/sync_fetch_and_umin_8.S [3:4]
+ arm/sync_fetch_and_xor_4.S [3:4]
+ arm/sync_fetch_and_xor_8.S [3:4]
+ arm/sync_synchronize.S [3:4]
+ arm/truncdfsf2vfp.S [3:4]
+ arm/udivmodsi4.S [3:4]
+ arm/udivsi3.S [3:4]
+ arm/umodsi3.S [3:4]
+ arm/unorddf2vfp.S [3:4]
+ arm/unordsf2vfp.S [3:4]
+ ashldi3.c [3:4]
+ ashlti3.c [3:4]
+ ashrdi3.c [3:4]
+ ashrti3.c [3:4]
+ assembly.h [3:4]
+ atomic.c [3:4]
+ atomic_flag_clear.c [3:4]
+ atomic_flag_clear_explicit.c [3:4]
+ atomic_flag_test_and_set.c [3:4]
+ atomic_flag_test_and_set_explicit.c [3:4]
+ atomic_signal_fence.c [3:4]
+ atomic_thread_fence.c [3:4]
+ avr/divmodhi4.S [3:4]
+ avr/divmodqi4.S [3:4]
+ avr/exit.S [3:4]
+ avr/mulhi3.S [3:4]
+ avr/mulqi3.S [3:4]
+ avr/udivmodhi4.S [3:4]
+ avr/udivmodqi4.S [3:4]
+ bswapdi2.c [3:4]
+ bswapsi2.c [3:4]
+ clear_cache.c [3:4]
+ clzdi2.c [3:4]
+ clzsi2.c [3:4]
+ clzti2.c [3:4]
+ cmpdi2.c [3:4]
+ cmpti2.c [3:4]
+ comparedf2.c [3:4]
+ comparesf2.c [3:4]
+ comparetf2.c [3:4]
+ cpu_model.c [3:4]
+ ctzdi2.c [3:4]
+ ctzsi2.c [3:4]
+ ctzti2.c [3:4]
+ divdc3.c [3:4]
+ divdf3.c [3:4]
+ divdi3.c [3:4]
+ divmoddi4.c [3:4]
+ divmodsi4.c [4:5]
+ divmodti4.c [3:4]
+ divsc3.c [3:4]
+ divsf3.c [3:4]
+ divsi3.c [3:4]
+ divtc3.c [3:4]
+ divtf3.c [3:4]
+ divti3.c [3:4]
+ divxc3.c [3:4]
+ emutls.c [3:4]
+ enable_execute_stack.c [3:4]
+ eprintf.c [3:4]
+ extenddftf2.c [3:4]
+ extendhfsf2.c [3:4]
+ extendsfdf2.c [3:4]
+ extendsftf2.c [3:4]
+ ffsdi2.c [3:4]
+ ffssi2.c [3:4]
+ ffsti2.c [3:4]
+ fixdfdi.c [3:4]
+ fixdfsi.c [3:4]
+ fixdfti.c [3:4]
+ fixsfdi.c [3:4]
+ fixsfsi.c [3:4]
+ fixsfti.c [3:4]
+ fixtfdi.c [3:4]
+ fixtfsi.c [3:4]
+ fixtfti.c [3:4]
+ fixunsdfdi.c [3:4]
+ fixunsdfsi.c [3:4]
+ fixunsdfti.c [3:4]
+ fixunssfdi.c [3:4]
+ fixunssfsi.c [3:4]
+ fixunssfti.c [3:4]
+ fixunstfdi.c [3:4]
+ fixunstfsi.c [3:4]
+ fixunstfti.c [3:4]
+ fixunsxfdi.c [3:4]
+ fixunsxfsi.c [3:4]
+ fixunsxfti.c [3:4]
+ fixxfdi.c [3:4]
+ fixxfti.c [3:4]
+ floatdidf.c [3:4]
+ floatdisf.c [3:4]
+ floatditf.c [3:4]
+ floatdixf.c [3:4]
+ floatsidf.c [3:4]
+ floatsisf.c [3:4]
+ floatsitf.c [3:4]
+ floattidf.c [3:4]
+ floattisf.c [3:4]
+ floattitf.c [3:4]
+ floattixf.c [3:4]
+ floatundidf.c [3:4]
+ floatundisf.c [3:4]
+ floatunditf.c [3:4]
+ floatundixf.c [3:4]
+ floatunsidf.c [3:4]
+ floatunsisf.c [3:4]
+ floatunsitf.c [3:4]
+ floatuntidf.c [3:4]
+ floatuntisf.c [3:4]
+ floatuntitf.c [3:4]
+ floatuntixf.c [3:4]
+ fp_add_impl.inc [3:4]
+ fp_compare_impl.inc [3:4]
+ fp_div_impl.inc [3:4]
+ fp_extend.h [4:5]
+ fp_extend_impl.inc [3:4]
+ fp_fixint_impl.inc [3:4]
+ fp_fixuint_impl.inc [3:4]
+ fp_lib.h [3:4]
+ fp_mode.c [3:4]
+ fp_mode.h [3:4]
+ fp_mul_impl.inc [3:4]
+ fp_trunc.h [3:4]
+ fp_trunc_impl.inc [3:4]
+ gcc_personality_v0.c [3:4]
+ hexagon/common_entry_exit_abi1.S [3:4]
+ hexagon/common_entry_exit_abi2.S [3:4]
+ hexagon/common_entry_exit_legacy.S [3:4]
+ hexagon/dfaddsub.S [3:4]
+ hexagon/dfdiv.S [3:4]
+ hexagon/dffma.S [3:4]
+ hexagon/dfminmax.S [3:4]
+ hexagon/dfmul.S [3:4]
+ hexagon/dfsqrt.S [3:4]
+ hexagon/divdi3.S [3:4]
+ hexagon/divsi3.S [3:4]
+ hexagon/fastmath2_dlib_asm.S [3:4]
+ hexagon/fastmath2_ldlib_asm.S [3:4]
+ hexagon/fastmath_dlib_asm.S [3:4]
+ hexagon/memcpy_forward_vp4cp4n2.S [3:4]
+ hexagon/memcpy_likely_aligned.S [3:4]
+ hexagon/moddi3.S [3:4]
+ hexagon/modsi3.S [3:4]
+ hexagon/sfdiv_opt.S [3:4]
+ hexagon/sfsqrt_opt.S [3:4]
+ hexagon/udivdi3.S [3:4]
+ hexagon/udivmoddi4.S [3:4]
+ hexagon/udivmodsi4.S [3:4]
+ hexagon/udivsi3.S [3:4]
+ hexagon/umoddi3.S [3:4]
+ hexagon/umodsi3.S [3:4]
i386/ashldi3.S [1:2]
i386/ashrdi3.S [1:2]
i386/chkstk.S [1:2]
@@ -682,32 +730,118 @@ BELONGS ya.make
i386/floatdidf.S [1:2]
i386/floatdisf.S [1:2]
i386/floatdixf.S [1:2]
- i386/floatundidf.S [5:6]
+ i386/floatundidf.S [3:4]
i386/floatundisf.S [1:2]
i386/floatundixf.S [1:2]
+ i386/fp_mode.c [3:4]
i386/lshrdi3.S [1:2]
i386/moddi3.S [1:2]
i386/muldi3.S [1:2]
i386/udivdi3.S [1:2]
i386/umoddi3.S [1:2]
- muldf3.c [5:6]
- mulsf3.c [5:6]
- multf3.c [5:6]
- negdf2.c [5:6]
- negsf2.c [5:6]
- ppc/restFP.S [5:6]
- ppc/saveFP.S [5:6]
- subdf3.c [5:6]
- subsf3.c [5:6]
- subtf3.c [5:6]
- truncdfhf2.c [5:6]
- truncdfsf2.c [5:6]
- truncsfhf2.c [5:6]
- trunctfdf2.c [5:6]
- trunctfsf2.c [5:6]
+ int_div_impl.inc [3:4]
+ int_endianness.h [3:4]
+ int_lib.h [3:4]
+ int_math.h [3:4]
+ int_mulo_impl.inc [3:4]
+ int_mulv_impl.inc [3:4]
+ int_types.h [3:4]
+ int_util.c [3:4]
+ int_util.h [3:4]
+ loongarch/fp_mode.c [3:4]
+ lshrdi3.c [3:4]
+ lshrti3.c [3:4]
+ moddi3.c [3:4]
+ modsi3.c [3:4]
+ modti3.c [3:4]
+ muldc3.c [3:4]
+ muldf3.c [3:4]
+ muldi3.c [3:4]
+ mulodi4.c [3:4]
+ mulosi4.c [3:4]
+ muloti4.c [3:4]
+ mulsc3.c [3:4]
+ mulsf3.c [3:4]
+ multc3.c [3:4]
+ multf3.c [3:4]
+ multi3.c [3:4]
+ mulvdi3.c [3:4]
+ mulvsi3.c [3:4]
+ mulvti3.c [3:4]
+ mulxc3.c [3:4]
+ negdf2.c [3:4]
+ negdi2.c [3:4]
+ negsf2.c [3:4]
+ negti2.c [3:4]
+ negvdi2.c [3:4]
+ negvsi2.c [3:4]
+ negvti2.c [3:4]
+ os_version_check.c [3:4]
+ paritydi2.c [3:4]
+ paritysi2.c [3:4]
+ parityti2.c [3:4]
+ popcountdi2.c [3:4]
+ popcountsi2.c [3:4]
+ popcountti2.c [4:5]
+ powidf2.c [3:4]
+ powisf2.c [3:4]
+ powitf2.c [3:4]
+ powixf2.c [3:4]
+ ppc/divtc3.c [1:2]
+ ppc/fixtfdi.c [1:2]
+ ppc/fixtfti.c [3:4]
+ ppc/fixunstfdi.c [1:2]
+ ppc/fixunstfti.c [3:4]
+ ppc/floatditf.c [1:2]
+ ppc/floattitf.c [3:4]
+ ppc/floatunditf.c [1:2]
+ ppc/gcc_qadd.c [1:2]
+ ppc/gcc_qdiv.c [1:2]
+ ppc/gcc_qmul.c [1:2]
+ ppc/gcc_qsub.c [1:2]
+ ppc/multc3.c [1:2]
+ ppc/restFP.S [3:4]
+ ppc/saveFP.S [3:4]
+ riscv/fp_mode.c [3:4]
+ riscv/int_mul_impl.inc [3:4]
+ riscv/muldi3.S [3:4]
+ riscv/mulsi3.S [3:4]
+ riscv/restore.S [3:4]
+ riscv/save.S [3:4]
+ subdf3.c [3:4]
+ subsf3.c [3:4]
+ subtf3.c [3:4]
+ subvdi3.c [3:4]
+ subvsi3.c [3:4]
+ subvti3.c [3:4]
+ trampoline_setup.c [3:4]
+ truncdfbf2.c [3:4]
+ truncdfhf2.c [3:4]
+ truncdfsf2.c [3:4]
+ truncsfbf2.c [3:4]
+ truncsfhf2.c [3:4]
+ trunctfdf2.c [3:4]
+ trunctfsf2.c [3:4]
+ ucmpdi2.c [3:4]
+ ucmpti2.c [3:4]
+ udivdi3.c [3:4]
+ udivmoddi4.c [3:4]
+ udivmodsi4.c [3:4]
+ udivmodti4.c [3:4]
+ udivsi3.c [3:4]
+ udivti3.c [3:4]
+ umoddi3.c [3:4]
+ umodsi3.c [3:4]
+ umodti3.c [3:4]
+ unwind-ehabi-helpers.h [3:4]
+ ve/grow_stack.S [1:2]
+ ve/grow_stack_align.S [1:2]
x86_64/chkstk.S [1:2]
x86_64/chkstk2.S [1:2]
- x86_64/floatundidf.S [5:6]
+ x86_64/floatdidf.c [1:2]
+ x86_64/floatdisf.c [1:2]
+ x86_64/floatdixf.c [1:2]
+ x86_64/floatundidf.S [3:4]
x86_64/floatundisf.S [1:2]
x86_64/floatundixf.S [1:2]
@@ -720,31 +854,7 @@ BELONGS ya.make
Match type : TEXT
Links : http://llvm.org/foundation/relicensing/LICENSE.txt, https://spdx.org/licenses/LLVM-exception
Files with this license:
- LICENSE.os_version_check.c.patch.txt [208:222]
-
-KEEP NCSA 866c17e668b5e51841e1c1979de94aa1
-BELONGS ya.make
- License text:
- /* This file is distributed under the University of Illinois Open Source
- * License. See LICENSE.TXT for details.
- Scancode info:
- Original SPDX id: NCSA
- Score : 94.00
- Match type : NOTICE
- Links : http://www.otm.illinois.edu/faculty/forms/opensource.asp, https://spdx.org/licenses/NCSA
- Files with this license:
- ppc/divtc3.c [1:2]
- ppc/fixtfdi.c [1:2]
- ppc/fixunstfdi.c [1:2]
- ppc/floatditf.c [1:2]
- ppc/floatunditf.c [1:2]
- ppc/gcc_qdiv.c [1:2]
- ppc/gcc_qmul.c [1:2]
- ppc/gcc_qsub.c [1:2]
- ppc/multc3.c [1:2]
- x86_64/floatdidf.c [1:2]
- x86_64/floatdisf.c [1:2]
- x86_64/floatdixf.c [1:2]
+ LICENSE.TXT [208:222]
KEEP Apache-2.0 9ac77f65a898755c7eed97099caded94
BELONGS ya.make
@@ -756,7 +866,7 @@ BELONGS ya.make
Match type : TEXT
Links : http://www.apache.org/licenses/, http://www.apache.org/licenses/LICENSE-2.0, https://spdx.org/licenses/Apache-2.0
Files with this license:
- LICENSE.os_version_check.c.patch.txt [5:205]
+ LICENSE.TXT [5:205]
KEEP NCSA AND MIT acaf5a1ddffd6829f7ebecb9e50c6c5f
BELONGS ya.make
@@ -767,18 +877,14 @@ BELONGS ya.make
Match type : NOTICE
Links : http://www.otm.illinois.edu/faculty/forms/opensource.asp, https://spdx.org/licenses/NCSA
Files with this license:
- LICENSE.os_version_check.c.patch.txt [240:245]
- LICENSE.os_version_check.c.txt [5:10]
- LICENSE.txt [5:10]
+ LICENSE.TXT [240:245]
Scancode info:
Original SPDX id: MIT
Score : 100.00
Match type : NOTICE
Links : http://opensource.org/licenses/mit-license.php, https://spdx.org/licenses/MIT
Files with this license:
- LICENSE.os_version_check.c.patch.txt [240:245]
- LICENSE.os_version_check.c.txt [5:10]
- LICENSE.txt [5:10]
+ LICENSE.TXT [240:245]
KEEP NCSA b160d8bd561da097b0edd40b062e1c84
BELONGS ya.make
@@ -790,9 +896,762 @@ BELONGS ya.make
Match type : TEXT
Links : http://www.otm.illinois.edu/faculty/forms/opensource.asp, https://spdx.org/licenses/NCSA
Files with this license:
- LICENSE.os_version_check.c.patch.txt [264:289]
- LICENSE.os_version_check.c.txt [29:54]
- LICENSE.txt [29:54]
+ LICENSE.TXT [264:289]
+
+KEEP Apache-2.0 AND LLVM-exception b7566a1930e050e1090162bf1d543650
+BELONGS ya.make
+ License text:
+ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+ Scancode info:
+ Original SPDX id: Apache-2.0
+ Score : 100.00
+ Match type : TAG
+ Links : http://www.apache.org/licenses/, http://www.apache.org/licenses/LICENSE-2.0, https://spdx.org/licenses/Apache-2.0
+ Files with this license:
+ aarch64/chkstk.S [3:3]
+ aarch64/fp_mode.c [5:5]
+ absvdi2.c [5:5]
+ absvsi2.c [5:5]
+ absvti2.c [5:5]
+ adddf3.c [5:5]
+ addsf3.c [5:5]
+ addtf3.c [5:5]
+ addvdi3.c [5:5]
+ addvsi3.c [5:5]
+ addvti3.c [5:5]
+ apple_versioning.c [5:5]
+ arm/adddf3vfp.S [5:5]
+ arm/addsf3.S [5:5]
+ arm/addsf3vfp.S [5:5]
+ arm/aeabi_cdcmp.S [5:5]
+ arm/aeabi_cdcmpeq_check_nan.c [5:5]
+ arm/aeabi_cfcmp.S [5:5]
+ arm/aeabi_cfcmpeq_check_nan.c [5:5]
+ arm/aeabi_dcmp.S [5:5]
+ arm/aeabi_div0.c [5:5]
+ arm/aeabi_drsub.c [5:5]
+ arm/aeabi_fcmp.S [5:5]
+ arm/aeabi_frsub.c [5:5]
+ arm/aeabi_idivmod.S [5:5]
+ arm/aeabi_ldivmod.S [5:5]
+ arm/aeabi_memcmp.S [5:5]
+ arm/aeabi_memcpy.S [5:5]
+ arm/aeabi_memmove.S [5:5]
+ arm/aeabi_memset.S [5:5]
+ arm/aeabi_uidivmod.S [5:5]
+ arm/aeabi_uldivmod.S [5:5]
+ arm/bswapdi2.S [5:5]
+ arm/bswapsi2.S [5:5]
+ arm/chkstk.S [3:3]
+ arm/clzdi2.S [5:5]
+ arm/clzsi2.S [5:5]
+ arm/comparesf2.S [5:5]
+ arm/divdf3vfp.S [5:5]
+ arm/divmodsi4.S [5:5]
+ arm/divsf3vfp.S [5:5]
+ arm/divsi3.S [5:5]
+ arm/eqdf2vfp.S [5:5]
+ arm/eqsf2vfp.S [5:5]
+ arm/extendsfdf2vfp.S [5:5]
+ arm/fixdfsivfp.S [5:5]
+ arm/fixsfsivfp.S [5:5]
+ arm/fixunsdfsivfp.S [5:5]
+ arm/fixunssfsivfp.S [5:5]
+ arm/floatsidfvfp.S [5:5]
+ arm/floatsisfvfp.S [5:5]
+ arm/floatunssidfvfp.S [5:5]
+ arm/floatunssisfvfp.S [5:5]
+ arm/fp_mode.c [5:5]
+ arm/gedf2vfp.S [5:5]
+ arm/gesf2vfp.S [5:5]
+ arm/gtdf2vfp.S [5:5]
+ arm/gtsf2vfp.S [5:5]
+ arm/ledf2vfp.S [5:5]
+ arm/lesf2vfp.S [5:5]
+ arm/ltdf2vfp.S [5:5]
+ arm/ltsf2vfp.S [5:5]
+ arm/modsi3.S [5:5]
+ arm/muldf3vfp.S [5:5]
+ arm/mulsf3vfp.S [5:5]
+ arm/nedf2vfp.S [5:5]
+ arm/negdf2vfp.S [5:5]
+ arm/negsf2vfp.S [5:5]
+ arm/nesf2vfp.S [5:5]
+ arm/restore_vfp_d8_d15_regs.S [5:5]
+ arm/save_vfp_d8_d15_regs.S [5:5]
+ arm/subdf3vfp.S [5:5]
+ arm/subsf3vfp.S [5:5]
+ arm/switch16.S [5:5]
+ arm/switch32.S [5:5]
+ arm/switch8.S [5:5]
+ arm/switchu8.S [5:5]
+ arm/sync-ops.h [5:5]
+ arm/sync_fetch_and_add_4.S [5:5]
+ arm/sync_fetch_and_add_8.S [5:5]
+ arm/sync_fetch_and_and_4.S [5:5]
+ arm/sync_fetch_and_and_8.S [5:5]
+ arm/sync_fetch_and_max_4.S [5:5]
+ arm/sync_fetch_and_max_8.S [5:5]
+ arm/sync_fetch_and_min_4.S [5:5]
+ arm/sync_fetch_and_min_8.S [5:5]
+ arm/sync_fetch_and_nand_4.S [5:5]
+ arm/sync_fetch_and_nand_8.S [5:5]
+ arm/sync_fetch_and_or_4.S [5:5]
+ arm/sync_fetch_and_or_8.S [5:5]
+ arm/sync_fetch_and_sub_4.S [5:5]
+ arm/sync_fetch_and_sub_8.S [5:5]
+ arm/sync_fetch_and_umax_4.S [5:5]
+ arm/sync_fetch_and_umax_8.S [5:5]
+ arm/sync_fetch_and_umin_4.S [5:5]
+ arm/sync_fetch_and_umin_8.S [5:5]
+ arm/sync_fetch_and_xor_4.S [5:5]
+ arm/sync_fetch_and_xor_8.S [5:5]
+ arm/sync_synchronize.S [5:5]
+ arm/truncdfsf2vfp.S [5:5]
+ arm/udivmodsi4.S [5:5]
+ arm/udivsi3.S [5:5]
+ arm/umodsi3.S [5:5]
+ arm/unorddf2vfp.S [5:5]
+ arm/unordsf2vfp.S [5:5]
+ ashldi3.c [5:5]
+ ashlti3.c [5:5]
+ ashrdi3.c [5:5]
+ ashrti3.c [5:5]
+ assembly.h [5:5]
+ atomic.c [5:5]
+ atomic_flag_clear.c [5:5]
+ atomic_flag_clear_explicit.c [5:5]
+ atomic_flag_test_and_set.c [5:5]
+ atomic_flag_test_and_set_explicit.c [5:5]
+ atomic_signal_fence.c [5:5]
+ atomic_thread_fence.c [5:5]
+ avr/divmodhi4.S [5:5]
+ avr/divmodqi4.S [5:5]
+ avr/exit.S [5:5]
+ avr/mulhi3.S [5:5]
+ avr/mulqi3.S [5:5]
+ avr/udivmodhi4.S [5:5]
+ avr/udivmodqi4.S [5:5]
+ bswapdi2.c [5:5]
+ bswapsi2.c [5:5]
+ clear_cache.c [5:5]
+ clzdi2.c [5:5]
+ clzsi2.c [5:5]
+ clzti2.c [5:5]
+ cmpdi2.c [5:5]
+ cmpti2.c [5:5]
+ comparedf2.c [5:5]
+ comparesf2.c [5:5]
+ comparetf2.c [5:5]
+ cpu_model.c [5:5]
+ ctzdi2.c [5:5]
+ ctzsi2.c [5:5]
+ ctzti2.c [5:5]
+ divdc3.c [5:5]
+ divdf3.c [5:5]
+ divdi3.c [5:5]
+ divmoddi4.c [5:5]
+ divmodsi4.c [6:6]
+ divmodti4.c [5:5]
+ divsc3.c [5:5]
+ divsf3.c [5:5]
+ divsi3.c [5:5]
+ divtc3.c [5:5]
+ divtf3.c [5:5]
+ divti3.c [5:5]
+ divxc3.c [5:5]
+ emutls.c [5:5]
+ enable_execute_stack.c [5:5]
+ eprintf.c [5:5]
+ extenddftf2.c [5:5]
+ extendhfsf2.c [5:5]
+ extendsfdf2.c [5:5]
+ extendsftf2.c [5:5]
+ ffsdi2.c [5:5]
+ ffssi2.c [5:5]
+ ffsti2.c [5:5]
+ fixdfdi.c [5:5]
+ fixdfsi.c [5:5]
+ fixdfti.c [5:5]
+ fixsfdi.c [5:5]
+ fixsfsi.c [5:5]
+ fixsfti.c [5:5]
+ fixtfdi.c [5:5]
+ fixtfsi.c [5:5]
+ fixtfti.c [5:5]
+ fixunsdfdi.c [5:5]
+ fixunsdfsi.c [5:5]
+ fixunsdfti.c [5:5]
+ fixunssfdi.c [5:5]
+ fixunssfsi.c [5:5]
+ fixunssfti.c [5:5]
+ fixunstfdi.c [5:5]
+ fixunstfsi.c [5:5]
+ fixunstfti.c [5:5]
+ fixunsxfdi.c [5:5]
+ fixunsxfsi.c [5:5]
+ fixunsxfti.c [5:5]
+ fixxfdi.c [5:5]
+ fixxfti.c [5:5]
+ floatdidf.c [5:5]
+ floatdisf.c [5:5]
+ floatditf.c [5:5]
+ floatdixf.c [5:5]
+ floatsidf.c [5:5]
+ floatsisf.c [5:5]
+ floatsitf.c [5:5]
+ floattidf.c [5:5]
+ floattisf.c [5:5]
+ floattitf.c [5:5]
+ floattixf.c [5:5]
+ floatundidf.c [5:5]
+ floatundisf.c [5:5]
+ floatunditf.c [5:5]
+ floatundixf.c [5:5]
+ floatunsidf.c [5:5]
+ floatunsisf.c [5:5]
+ floatunsitf.c [5:5]
+ floatuntidf.c [5:5]
+ floatuntisf.c [5:5]
+ floatuntitf.c [5:5]
+ floatuntixf.c [5:5]
+ fp_add_impl.inc [5:5]
+ fp_compare_impl.inc [5:5]
+ fp_div_impl.inc [5:5]
+ fp_extend.h [6:6]
+ fp_extend_impl.inc [5:5]
+ fp_fixint_impl.inc [5:5]
+ fp_fixuint_impl.inc [5:5]
+ fp_lib.h [5:5]
+ fp_mode.c [5:5]
+ fp_mode.h [5:5]
+ fp_mul_impl.inc [5:5]
+ fp_trunc.h [5:5]
+ fp_trunc_impl.inc [5:5]
+ gcc_personality_v0.c [5:5]
+ hexagon/common_entry_exit_abi1.S [5:5]
+ hexagon/common_entry_exit_abi2.S [5:5]
+ hexagon/common_entry_exit_legacy.S [5:5]
+ hexagon/dfaddsub.S [5:5]
+ hexagon/dfdiv.S [5:5]
+ hexagon/dffma.S [5:5]
+ hexagon/dfminmax.S [5:5]
+ hexagon/dfmul.S [5:5]
+ hexagon/dfsqrt.S [5:5]
+ hexagon/divdi3.S [5:5]
+ hexagon/divsi3.S [5:5]
+ hexagon/fastmath2_dlib_asm.S [5:5]
+ hexagon/fastmath2_ldlib_asm.S [5:5]
+ hexagon/fastmath_dlib_asm.S [5:5]
+ hexagon/memcpy_forward_vp4cp4n2.S [5:5]
+ hexagon/memcpy_likely_aligned.S [5:5]
+ hexagon/moddi3.S [5:5]
+ hexagon/modsi3.S [5:5]
+ hexagon/sfdiv_opt.S [5:5]
+ hexagon/sfsqrt_opt.S [5:5]
+ hexagon/udivdi3.S [5:5]
+ hexagon/udivmoddi4.S [5:5]
+ hexagon/udivmodsi4.S [5:5]
+ hexagon/udivsi3.S [5:5]
+ hexagon/umoddi3.S [5:5]
+ hexagon/umodsi3.S [5:5]
+ i386/ashldi3.S [3:3]
+ i386/ashrdi3.S [3:3]
+ i386/chkstk.S [3:3]
+ i386/chkstk2.S [3:3]
+ i386/divdi3.S [3:3]
+ i386/floatdidf.S [3:3]
+ i386/floatdisf.S [3:3]
+ i386/floatdixf.S [3:3]
+ i386/floatundidf.S [5:5]
+ i386/floatundisf.S [3:3]
+ i386/floatundixf.S [3:3]
+ i386/fp_mode.c [5:5]
+ i386/lshrdi3.S [3:3]
+ i386/moddi3.S [3:3]
+ i386/muldi3.S [3:3]
+ i386/udivdi3.S [3:3]
+ i386/umoddi3.S [3:3]
+ int_div_impl.inc [5:5]
+ int_endianness.h [5:5]
+ int_lib.h [5:5]
+ int_math.h [5:5]
+ int_mulo_impl.inc [5:5]
+ int_mulv_impl.inc [5:5]
+ int_types.h [5:5]
+ int_util.c [5:5]
+ int_util.h [5:5]
+ loongarch/fp_mode.c [5:5]
+ lshrdi3.c [5:5]
+ lshrti3.c [5:5]
+ moddi3.c [5:5]
+ modsi3.c [5:5]
+ modti3.c [5:5]
+ muldc3.c [5:5]
+ muldf3.c [5:5]
+ muldi3.c [5:5]
+ mulodi4.c [5:5]
+ mulosi4.c [5:5]
+ muloti4.c [5:5]
+ mulsc3.c [5:5]
+ mulsf3.c [5:5]
+ multc3.c [5:5]
+ multf3.c [5:5]
+ multi3.c [5:5]
+ mulvdi3.c [5:5]
+ mulvsi3.c [5:5]
+ mulvti3.c [5:5]
+ mulxc3.c [5:5]
+ negdf2.c [5:5]
+ negdi2.c [5:5]
+ negsf2.c [5:5]
+ negti2.c [5:5]
+ negvdi2.c [5:5]
+ negvsi2.c [5:5]
+ negvti2.c [5:5]
+ os_version_check.c [5:5]
+ paritydi2.c [5:5]
+ paritysi2.c [5:5]
+ parityti2.c [5:5]
+ popcountdi2.c [5:5]
+ popcountsi2.c [5:5]
+ popcountti2.c [6:6]
+ powidf2.c [5:5]
+ powisf2.c [5:5]
+ powitf2.c [5:5]
+ powixf2.c [5:5]
+ ppc/divtc3.c [3:3]
+ ppc/fixtfdi.c [3:3]
+ ppc/fixtfti.c [5:5]
+ ppc/fixunstfdi.c [3:3]
+ ppc/fixunstfti.c [5:5]
+ ppc/floatditf.c [3:3]
+ ppc/floattitf.c [5:5]
+ ppc/floatunditf.c [3:3]
+ ppc/gcc_qadd.c [3:3]
+ ppc/gcc_qdiv.c [3:3]
+ ppc/gcc_qmul.c [3:3]
+ ppc/gcc_qsub.c [3:3]
+ ppc/multc3.c [3:3]
+ ppc/restFP.S [5:5]
+ ppc/saveFP.S [5:5]
+ riscv/fp_mode.c [5:5]
+ riscv/int_mul_impl.inc [5:5]
+ riscv/muldi3.S [5:5]
+ riscv/mulsi3.S [5:5]
+ riscv/restore.S [5:5]
+ riscv/save.S [5:5]
+ subdf3.c [5:5]
+ subsf3.c [5:5]
+ subtf3.c [5:5]
+ subvdi3.c [5:5]
+ subvsi3.c [5:5]
+ subvti3.c [5:5]
+ trampoline_setup.c [5:5]
+ truncdfbf2.c [5:5]
+ truncdfhf2.c [5:5]
+ truncdfsf2.c [5:5]
+ truncsfbf2.c [5:5]
+ truncsfhf2.c [5:5]
+ trunctfdf2.c [5:5]
+ trunctfsf2.c [5:5]
+ ucmpdi2.c [5:5]
+ ucmpti2.c [5:5]
+ udivdi3.c [5:5]
+ udivmoddi4.c [5:5]
+ udivmodsi4.c [5:5]
+ udivmodti4.c [5:5]
+ udivsi3.c [5:5]
+ udivti3.c [5:5]
+ umoddi3.c [5:5]
+ umodsi3.c [5:5]
+ umodti3.c [5:5]
+ unwind-ehabi-helpers.h [5:5]
+ ve/grow_stack.S [3:3]
+ ve/grow_stack_align.S [3:3]
+ x86_64/chkstk.S [3:3]
+ x86_64/chkstk2.S [3:3]
+ x86_64/floatdidf.c [3:3]
+ x86_64/floatdisf.c [3:3]
+ x86_64/floatdixf.c [3:3]
+ x86_64/floatundidf.S [5:5]
+ x86_64/floatundisf.S [3:3]
+ x86_64/floatundixf.S [3:3]
+ Scancode info:
+ Original SPDX id: LLVM-exception
+ Score : 100.00
+ Match type : TAG
+ Links : http://llvm.org/foundation/relicensing/LICENSE.txt, https://spdx.org/licenses/LLVM-exception
+ Files with this license:
+ aarch64/chkstk.S [3:3]
+ aarch64/fp_mode.c [5:5]
+ absvdi2.c [5:5]
+ absvsi2.c [5:5]
+ absvti2.c [5:5]
+ adddf3.c [5:5]
+ addsf3.c [5:5]
+ addtf3.c [5:5]
+ addvdi3.c [5:5]
+ addvsi3.c [5:5]
+ addvti3.c [5:5]
+ apple_versioning.c [5:5]
+ arm/adddf3vfp.S [5:5]
+ arm/addsf3.S [5:5]
+ arm/addsf3vfp.S [5:5]
+ arm/aeabi_cdcmp.S [5:5]
+ arm/aeabi_cdcmpeq_check_nan.c [5:5]
+ arm/aeabi_cfcmp.S [5:5]
+ arm/aeabi_cfcmpeq_check_nan.c [5:5]
+ arm/aeabi_dcmp.S [5:5]
+ arm/aeabi_div0.c [5:5]
+ arm/aeabi_drsub.c [5:5]
+ arm/aeabi_fcmp.S [5:5]
+ arm/aeabi_frsub.c [5:5]
+ arm/aeabi_idivmod.S [5:5]
+ arm/aeabi_ldivmod.S [5:5]
+ arm/aeabi_memcmp.S [5:5]
+ arm/aeabi_memcpy.S [5:5]
+ arm/aeabi_memmove.S [5:5]
+ arm/aeabi_memset.S [5:5]
+ arm/aeabi_uidivmod.S [5:5]
+ arm/aeabi_uldivmod.S [5:5]
+ arm/bswapdi2.S [5:5]
+ arm/bswapsi2.S [5:5]
+ arm/chkstk.S [3:3]
+ arm/clzdi2.S [5:5]
+ arm/clzsi2.S [5:5]
+ arm/comparesf2.S [5:5]
+ arm/divdf3vfp.S [5:5]
+ arm/divmodsi4.S [5:5]
+ arm/divsf3vfp.S [5:5]
+ arm/divsi3.S [5:5]
+ arm/eqdf2vfp.S [5:5]
+ arm/eqsf2vfp.S [5:5]
+ arm/extendsfdf2vfp.S [5:5]
+ arm/fixdfsivfp.S [5:5]
+ arm/fixsfsivfp.S [5:5]
+ arm/fixunsdfsivfp.S [5:5]
+ arm/fixunssfsivfp.S [5:5]
+ arm/floatsidfvfp.S [5:5]
+ arm/floatsisfvfp.S [5:5]
+ arm/floatunssidfvfp.S [5:5]
+ arm/floatunssisfvfp.S [5:5]
+ arm/fp_mode.c [5:5]
+ arm/gedf2vfp.S [5:5]
+ arm/gesf2vfp.S [5:5]
+ arm/gtdf2vfp.S [5:5]
+ arm/gtsf2vfp.S [5:5]
+ arm/ledf2vfp.S [5:5]
+ arm/lesf2vfp.S [5:5]
+ arm/ltdf2vfp.S [5:5]
+ arm/ltsf2vfp.S [5:5]
+ arm/modsi3.S [5:5]
+ arm/muldf3vfp.S [5:5]
+ arm/mulsf3vfp.S [5:5]
+ arm/nedf2vfp.S [5:5]
+ arm/negdf2vfp.S [5:5]
+ arm/negsf2vfp.S [5:5]
+ arm/nesf2vfp.S [5:5]
+ arm/restore_vfp_d8_d15_regs.S [5:5]
+ arm/save_vfp_d8_d15_regs.S [5:5]
+ arm/subdf3vfp.S [5:5]
+ arm/subsf3vfp.S [5:5]
+ arm/switch16.S [5:5]
+ arm/switch32.S [5:5]
+ arm/switch8.S [5:5]
+ arm/switchu8.S [5:5]
+ arm/sync-ops.h [5:5]
+ arm/sync_fetch_and_add_4.S [5:5]
+ arm/sync_fetch_and_add_8.S [5:5]
+ arm/sync_fetch_and_and_4.S [5:5]
+ arm/sync_fetch_and_and_8.S [5:5]
+ arm/sync_fetch_and_max_4.S [5:5]
+ arm/sync_fetch_and_max_8.S [5:5]
+ arm/sync_fetch_and_min_4.S [5:5]
+ arm/sync_fetch_and_min_8.S [5:5]
+ arm/sync_fetch_and_nand_4.S [5:5]
+ arm/sync_fetch_and_nand_8.S [5:5]
+ arm/sync_fetch_and_or_4.S [5:5]
+ arm/sync_fetch_and_or_8.S [5:5]
+ arm/sync_fetch_and_sub_4.S [5:5]
+ arm/sync_fetch_and_sub_8.S [5:5]
+ arm/sync_fetch_and_umax_4.S [5:5]
+ arm/sync_fetch_and_umax_8.S [5:5]
+ arm/sync_fetch_and_umin_4.S [5:5]
+ arm/sync_fetch_and_umin_8.S [5:5]
+ arm/sync_fetch_and_xor_4.S [5:5]
+ arm/sync_fetch_and_xor_8.S [5:5]
+ arm/sync_synchronize.S [5:5]
+ arm/truncdfsf2vfp.S [5:5]
+ arm/udivmodsi4.S [5:5]
+ arm/udivsi3.S [5:5]
+ arm/umodsi3.S [5:5]
+ arm/unorddf2vfp.S [5:5]
+ arm/unordsf2vfp.S [5:5]
+ ashldi3.c [5:5]
+ ashlti3.c [5:5]
+ ashrdi3.c [5:5]
+ ashrti3.c [5:5]
+ assembly.h [5:5]
+ atomic.c [5:5]
+ atomic_flag_clear.c [5:5]
+ atomic_flag_clear_explicit.c [5:5]
+ atomic_flag_test_and_set.c [5:5]
+ atomic_flag_test_and_set_explicit.c [5:5]
+ atomic_signal_fence.c [5:5]
+ atomic_thread_fence.c [5:5]
+ avr/divmodhi4.S [5:5]
+ avr/divmodqi4.S [5:5]
+ avr/exit.S [5:5]
+ avr/mulhi3.S [5:5]
+ avr/mulqi3.S [5:5]
+ avr/udivmodhi4.S [5:5]
+ avr/udivmodqi4.S [5:5]
+ bswapdi2.c [5:5]
+ bswapsi2.c [5:5]
+ clear_cache.c [5:5]
+ clzdi2.c [5:5]
+ clzsi2.c [5:5]
+ clzti2.c [5:5]
+ cmpdi2.c [5:5]
+ cmpti2.c [5:5]
+ comparedf2.c [5:5]
+ comparesf2.c [5:5]
+ comparetf2.c [5:5]
+ cpu_model.c [5:5]
+ ctzdi2.c [5:5]
+ ctzsi2.c [5:5]
+ ctzti2.c [5:5]
+ divdc3.c [5:5]
+ divdf3.c [5:5]
+ divdi3.c [5:5]
+ divmoddi4.c [5:5]
+ divmodsi4.c [6:6]
+ divmodti4.c [5:5]
+ divsc3.c [5:5]
+ divsf3.c [5:5]
+ divsi3.c [5:5]
+ divtc3.c [5:5]
+ divtf3.c [5:5]
+ divti3.c [5:5]
+ divxc3.c [5:5]
+ emutls.c [5:5]
+ enable_execute_stack.c [5:5]
+ eprintf.c [5:5]
+ extenddftf2.c [5:5]
+ extendhfsf2.c [5:5]
+ extendsfdf2.c [5:5]
+ extendsftf2.c [5:5]
+ ffsdi2.c [5:5]
+ ffssi2.c [5:5]
+ ffsti2.c [5:5]
+ fixdfdi.c [5:5]
+ fixdfsi.c [5:5]
+ fixdfti.c [5:5]
+ fixsfdi.c [5:5]
+ fixsfsi.c [5:5]
+ fixsfti.c [5:5]
+ fixtfdi.c [5:5]
+ fixtfsi.c [5:5]
+ fixtfti.c [5:5]
+ fixunsdfdi.c [5:5]
+ fixunsdfsi.c [5:5]
+ fixunsdfti.c [5:5]
+ fixunssfdi.c [5:5]
+ fixunssfsi.c [5:5]
+ fixunssfti.c [5:5]
+ fixunstfdi.c [5:5]
+ fixunstfsi.c [5:5]
+ fixunstfti.c [5:5]
+ fixunsxfdi.c [5:5]
+ fixunsxfsi.c [5:5]
+ fixunsxfti.c [5:5]
+ fixxfdi.c [5:5]
+ fixxfti.c [5:5]
+ floatdidf.c [5:5]
+ floatdisf.c [5:5]
+ floatditf.c [5:5]
+ floatdixf.c [5:5]
+ floatsidf.c [5:5]
+ floatsisf.c [5:5]
+ floatsitf.c [5:5]
+ floattidf.c [5:5]
+ floattisf.c [5:5]
+ floattitf.c [5:5]
+ floattixf.c [5:5]
+ floatundidf.c [5:5]
+ floatundisf.c [5:5]
+ floatunditf.c [5:5]
+ floatundixf.c [5:5]
+ floatunsidf.c [5:5]
+ floatunsisf.c [5:5]
+ floatunsitf.c [5:5]
+ floatuntidf.c [5:5]
+ floatuntisf.c [5:5]
+ floatuntitf.c [5:5]
+ floatuntixf.c [5:5]
+ fp_add_impl.inc [5:5]
+ fp_compare_impl.inc [5:5]
+ fp_div_impl.inc [5:5]
+ fp_extend.h [6:6]
+ fp_extend_impl.inc [5:5]
+ fp_fixint_impl.inc [5:5]
+ fp_fixuint_impl.inc [5:5]
+ fp_lib.h [5:5]
+ fp_mode.c [5:5]
+ fp_mode.h [5:5]
+ fp_mul_impl.inc [5:5]
+ fp_trunc.h [5:5]
+ fp_trunc_impl.inc [5:5]
+ gcc_personality_v0.c [5:5]
+ hexagon/common_entry_exit_abi1.S [5:5]
+ hexagon/common_entry_exit_abi2.S [5:5]
+ hexagon/common_entry_exit_legacy.S [5:5]
+ hexagon/dfaddsub.S [5:5]
+ hexagon/dfdiv.S [5:5]
+ hexagon/dffma.S [5:5]
+ hexagon/dfminmax.S [5:5]
+ hexagon/dfmul.S [5:5]
+ hexagon/dfsqrt.S [5:5]
+ hexagon/divdi3.S [5:5]
+ hexagon/divsi3.S [5:5]
+ hexagon/fastmath2_dlib_asm.S [5:5]
+ hexagon/fastmath2_ldlib_asm.S [5:5]
+ hexagon/fastmath_dlib_asm.S [5:5]
+ hexagon/memcpy_forward_vp4cp4n2.S [5:5]
+ hexagon/memcpy_likely_aligned.S [5:5]
+ hexagon/moddi3.S [5:5]
+ hexagon/modsi3.S [5:5]
+ hexagon/sfdiv_opt.S [5:5]
+ hexagon/sfsqrt_opt.S [5:5]
+ hexagon/udivdi3.S [5:5]
+ hexagon/udivmoddi4.S [5:5]
+ hexagon/udivmodsi4.S [5:5]
+ hexagon/udivsi3.S [5:5]
+ hexagon/umoddi3.S [5:5]
+ hexagon/umodsi3.S [5:5]
+ i386/ashldi3.S [3:3]
+ i386/ashrdi3.S [3:3]
+ i386/chkstk.S [3:3]
+ i386/chkstk2.S [3:3]
+ i386/divdi3.S [3:3]
+ i386/floatdidf.S [3:3]
+ i386/floatdisf.S [3:3]
+ i386/floatdixf.S [3:3]
+ i386/floatundidf.S [5:5]
+ i386/floatundisf.S [3:3]
+ i386/floatundixf.S [3:3]
+ i386/fp_mode.c [5:5]
+ i386/lshrdi3.S [3:3]
+ i386/moddi3.S [3:3]
+ i386/muldi3.S [3:3]
+ i386/udivdi3.S [3:3]
+ i386/umoddi3.S [3:3]
+ int_div_impl.inc [5:5]
+ int_endianness.h [5:5]
+ int_lib.h [5:5]
+ int_math.h [5:5]
+ int_mulo_impl.inc [5:5]
+ int_mulv_impl.inc [5:5]
+ int_types.h [5:5]
+ int_util.c [5:5]
+ int_util.h [5:5]
+ loongarch/fp_mode.c [5:5]
+ lshrdi3.c [5:5]
+ lshrti3.c [5:5]
+ moddi3.c [5:5]
+ modsi3.c [5:5]
+ modti3.c [5:5]
+ muldc3.c [5:5]
+ muldf3.c [5:5]
+ muldi3.c [5:5]
+ mulodi4.c [5:5]
+ mulosi4.c [5:5]
+ muloti4.c [5:5]
+ mulsc3.c [5:5]
+ mulsf3.c [5:5]
+ multc3.c [5:5]
+ multf3.c [5:5]
+ multi3.c [5:5]
+ mulvdi3.c [5:5]
+ mulvsi3.c [5:5]
+ mulvti3.c [5:5]
+ mulxc3.c [5:5]
+ negdf2.c [5:5]
+ negdi2.c [5:5]
+ negsf2.c [5:5]
+ negti2.c [5:5]
+ negvdi2.c [5:5]
+ negvsi2.c [5:5]
+ negvti2.c [5:5]
+ os_version_check.c [5:5]
+ paritydi2.c [5:5]
+ paritysi2.c [5:5]
+ parityti2.c [5:5]
+ popcountdi2.c [5:5]
+ popcountsi2.c [5:5]
+ popcountti2.c [6:6]
+ powidf2.c [5:5]
+ powisf2.c [5:5]
+ powitf2.c [5:5]
+ powixf2.c [5:5]
+ ppc/divtc3.c [3:3]
+ ppc/fixtfdi.c [3:3]
+ ppc/fixtfti.c [5:5]
+ ppc/fixunstfdi.c [3:3]
+ ppc/fixunstfti.c [5:5]
+ ppc/floatditf.c [3:3]
+ ppc/floattitf.c [5:5]
+ ppc/floatunditf.c [3:3]
+ ppc/gcc_qadd.c [3:3]
+ ppc/gcc_qdiv.c [3:3]
+ ppc/gcc_qmul.c [3:3]
+ ppc/gcc_qsub.c [3:3]
+ ppc/multc3.c [3:3]
+ ppc/restFP.S [5:5]
+ ppc/saveFP.S [5:5]
+ riscv/fp_mode.c [5:5]
+ riscv/int_mul_impl.inc [5:5]
+ riscv/muldi3.S [5:5]
+ riscv/mulsi3.S [5:5]
+ riscv/restore.S [5:5]
+ riscv/save.S [5:5]
+ subdf3.c [5:5]
+ subsf3.c [5:5]
+ subtf3.c [5:5]
+ subvdi3.c [5:5]
+ subvsi3.c [5:5]
+ subvti3.c [5:5]
+ trampoline_setup.c [5:5]
+ truncdfbf2.c [5:5]
+ truncdfhf2.c [5:5]
+ truncdfsf2.c [5:5]
+ truncsfbf2.c [5:5]
+ truncsfhf2.c [5:5]
+ trunctfdf2.c [5:5]
+ trunctfsf2.c [5:5]
+ ucmpdi2.c [5:5]
+ ucmpti2.c [5:5]
+ udivdi3.c [5:5]
+ udivmoddi4.c [5:5]
+ udivmodsi4.c [5:5]
+ udivmodti4.c [5:5]
+ udivsi3.c [5:5]
+ udivti3.c [5:5]
+ umoddi3.c [5:5]
+ umodsi3.c [5:5]
+ umodti3.c [5:5]
+ unwind-ehabi-helpers.h [5:5]
+ ve/grow_stack.S [3:3]
+ ve/grow_stack_align.S [3:3]
+ x86_64/chkstk.S [3:3]
+ x86_64/chkstk2.S [3:3]
+ x86_64/floatdidf.c [3:3]
+ x86_64/floatdisf.c [3:3]
+ x86_64/floatdixf.c [3:3]
+ x86_64/floatundidf.S [5:5]
+ x86_64/floatundisf.S [3:3]
+ x86_64/floatundixf.S [3:3]
KEEP NCSA c26d0b72f92421989c4471ae0acbc943
BELONGS ya.make
@@ -805,9 +1664,7 @@ BELONGS ya.make
Match type : REFERENCE
Links : http://www.otm.illinois.edu/faculty/forms/opensource.asp, https://spdx.org/licenses/NCSA
Files with this license:
- LICENSE.os_version_check.c.patch.txt [249:250]
- LICENSE.os_version_check.c.txt [14:15]
- LICENSE.txt [14:15]
+ LICENSE.TXT [249:250]
KEEP Apache-2.0 WITH LLVM-exception df18889e552d44a4679aff552267f802
BELONGS ya.make
@@ -819,24 +1676,11 @@ BELONGS ya.make
Match type : NOTICE
Links : http://www.apache.org/licenses/, http://www.apache.org/licenses/LICENSE-2.0, https://spdx.org/licenses/Apache-2.0
Files with this license:
- LICENSE.os_version_check.c.patch.txt [2:2]
+ LICENSE.TXT [2:2]
Scancode info:
Original SPDX id: LLVM-exception
Score : 100.00
Match type : NOTICE
Links : http://llvm.org/foundation/relicensing/LICENSE.txt, https://spdx.org/licenses/LLVM-exception
Files with this license:
- LICENSE.os_version_check.c.patch.txt [2:2]
-
-KEEP NCSA efa7c9a4e646ac38725d00250dd0b1a5
-BELONGS ya.make
- License text:
- /* This file is distributed under the University of Illinois Open Source
- * License. See LICENSE.TXT for details.
- Scancode info:
- Original SPDX id: NCSA
- Score : 94.00
- Match type : NOTICE
- Links : http://www.otm.illinois.edu/faculty/forms/opensource.asp, https://spdx.org/licenses/NCSA
- Files with this license:
- ppc/gcc_qadd.c [1:2]
+ LICENSE.TXT [2:2]
diff --git a/contrib/libs/cxxsupp/builtins/.yandex_meta/licenses.list.txt b/contrib/libs/cxxsupp/builtins/.yandex_meta/licenses.list.txt
index ee63781e18..fc8451d2eb 100644
--- a/contrib/libs/cxxsupp/builtins/.yandex_meta/licenses.list.txt
+++ b/contrib/libs/cxxsupp/builtins/.yandex_meta/licenses.list.txt
@@ -202,6 +202,15 @@
limitations under the License.
+====================Apache-2.0 AND LLVM-exception====================
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+
+
+====================Apache-2.0 AND LLVM-exception====================
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+
====================Apache-2.0 WITH LLVM-exception====================
---- LLVM Exceptions to the Apache 2.0 License ----
@@ -229,16 +238,286 @@ Copyright (c) 2009-2015 by the contributors listed in CREDITS.TXT
====================COPYRIGHT====================
-Copyright (c) 2009-2018 by the contributors listed in CREDITS.TXT
+Copyright (c) 2009-2019 by the contributors listed in CREDITS.TXT
-====================COPYRIGHT====================
-Copyright (c) 2009-2019 by the contributors listed in CREDITS.TXT
+====================File: CREDITS.TXT====================
+This file is a partial list of people who have contributed to the LLVM/CompilerRT
+project. If you have contributed a patch or made some other contribution to
+LLVM/CompilerRT, please submit a patch to this file to add yourself, and it will be
+done!
+
+The list is sorted by surname and formatted to allow easy grepping and
+beautification by scripts. The fields are: name (N), email (E), web-address
+(W), PGP key ID and fingerprint (P), description (D), and snail-mail address
+(S).
+
+N: Craig van Vliet
+E: cvanvliet@auroraux.org
+W: http://www.auroraux.org
+D: Code style and Readability fixes.
+
+N: Edward O'Callaghan
+E: eocallaghan@auroraux.org
+W: http://www.auroraux.org
+D: CMake'ify Compiler-RT build system
+D: Maintain Solaris & AuroraUX ports of Compiler-RT
+
+N: Howard Hinnant
+E: hhinnant@apple.com
+D: Architect and primary author of compiler-rt
+
+N: Guan-Hong Liu
+E: koviankevin@hotmail.com
+D: IEEE Quad-precision functions
+
+N: Joerg Sonnenberger
+E: joerg@NetBSD.org
+D: Maintains NetBSD port.
+
+N: Matt Thomas
+E: matt@NetBSD.org
+D: ARM improvements.
+
+
+====================File: LICENSE.TXT====================
+==============================================================================
+The LLVM Project is under the Apache License v2.0 with LLVM Exceptions:
+==============================================================================
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+
+---- LLVM Exceptions to the Apache 2.0 License ----
+
+As an exception, if, as a result of your compiling your source code, portions
+of this Software are embedded into an Object form of such source code, you
+may redistribute such embedded portions in such Object form without complying
+with the conditions of Sections 4(a), 4(b) and 4(d) of the License.
+
+In addition, if you combine or link compiled forms of this Software with
+software that is licensed under the GPLv2 ("Combined Software") and if a
+court of competent jurisdiction determines that the patent provision (Section
+3), the indemnity provision (Section 9) or other Section of the License
+conflicts with the conditions of the GPLv2, you may retroactively and
+prospectively choose to deem waived or otherwise exclude such Section(s) of
+the License, but only in their entirety and only with respect to the Combined
+Software.
-====================File: LICENSE.txt====================
==============================================================================
-compiler_rt License
+Software from third parties included in the LLVM Project:
+==============================================================================
+The LLVM Project contains third party software which is under different license
+terms. All such code will be identified clearly using at least one of two
+mechanisms:
+1) It will be in a separate directory tree with its own `LICENSE.txt` or
+ `LICENSE` file at the top containing the specific license and restrictions
+ which apply to that software, or
+2) It will contain specific license and restriction terms at the top of every
+ file.
+
+==============================================================================
+Legacy LLVM License (https://llvm.org/docs/DeveloperPolicy.html#legacy):
==============================================================================
The compiler_rt library is dual licensed under both the University of Illinois
@@ -253,7 +532,7 @@ Full text of the relevant licenses is included below.
University of Illinois/NCSA
Open Source License
-Copyright (c) 2009-2015 by the contributors listed in CREDITS.TXT
+Copyright (c) 2009-2019 by the contributors listed in CREDITS.TXT
All rights reserved.
@@ -314,21 +593,6 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-==============================================================================
-Copyrights and Licenses for Third Party Software Distributed with LLVM:
-==============================================================================
-The LLVM software contains code written by third parties. Such software will
-have its own individual LICENSE.TXT file in the directory in which it appears.
-This file will describe the copyrights, license, and restrictions which apply
-to that code.
-
-The disclaimer of warranty in the University of Illinois Open Source License
-applies to all code in the LLVM Distribution, and nothing in any of the
-other licenses gives permission to use the names of the LLVM Team or the
-University of Illinois to endorse or promote products derived from this
-Software.
-
-
====================MIT====================
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -350,21 +614,6 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
====================NCSA====================
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-
-
-====================NCSA====================
-/* This file is distributed under the University of Illinois Open Source
- * License. See LICENSE.TXT for details.
-
-
-====================NCSA====================
-/* This file is distributed under the University of Illinois Open Source
- * License. See LICENSE.TXT for details.
-
-
-====================NCSA====================
Compiler-RT is open source software. You may freely distribute it under the
terms of the license agreement found in LICENSE.txt.
@@ -403,29 +652,11 @@ SOFTWARE.
====================NCSA====================
-The LLVM software contains code written by third parties. Such software will
-have its own individual LICENSE.TXT file in the directory in which it appears.
-This file will describe the copyrights, license, and restrictions which apply
-to that code.
-
-The disclaimer of warranty in the University of Illinois Open Source License
-applies to all code in the LLVM Distribution, and nothing in any of the
-other licenses gives permission to use the names of the LLVM Team or the
-University of Illinois to endorse or promote products derived from this
-Software.
-
-
-====================NCSA====================
University of Illinois/NCSA
Open Source License
====================NCSA AND MIT====================
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
-
-
-====================NCSA AND MIT====================
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
diff --git a/contrib/libs/cxxsupp/builtins/CMakeLists.txt b/contrib/libs/cxxsupp/builtins/CMakeLists.txt
new file mode 100644
index 0000000000..8a13508fcb
--- /dev/null
+++ b/contrib/libs/cxxsupp/builtins/CMakeLists.txt
@@ -0,0 +1,786 @@
+# CMake build for CompilerRT.
+#
+# An important constraint of the build is that it only produces libraries
+# based on the ability of the host toolchain to target various platforms.
+
+cmake_minimum_required(VERSION 3.13.4)
+
+# Check if compiler-rt is built as a standalone project.
+if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR OR COMPILER_RT_STANDALONE_BUILD)
+ project(CompilerRT C CXX ASM)
+ set(COMPILER_RT_STANDALONE_BUILD TRUE)
+ set_property(GLOBAL PROPERTY USE_FOLDERS ON)
+ if ("${CMAKE_VERSION}" VERSION_LESS "3.20.0")
+ message(WARNING
+ "Your CMake version is ${CMAKE_VERSION}. Starting with LLVM 17.0.0, the "
+ "minimum version of CMake required to build LLVM will become 3.20.0, and "
+ "using an older CMake will become an error. Please upgrade your CMake to "
+ "at least 3.20.0 now to avoid issues in the future!")
+ endif()
+endif()
+
+set(LLVM_COMMON_CMAKE_UTILS "${CMAKE_CURRENT_SOURCE_DIR}/../cmake")
+
+# Add path for custom compiler-rt modules.
+list(INSERT CMAKE_MODULE_PATH 0
+ "${CMAKE_CURRENT_SOURCE_DIR}/cmake"
+ "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules"
+ "${LLVM_COMMON_CMAKE_UTILS}"
+ "${LLVM_COMMON_CMAKE_UTILS}/Modules"
+ )
+
+if(CMAKE_CONFIGURATION_TYPES)
+ set(CMAKE_CFG_RESOLVED_INTDIR "${CMAKE_CFG_INTDIR}/")
+else()
+ set(CMAKE_CFG_RESOLVED_INTDIR "")
+endif()
+
+include(SetPlatformToolchainTools)
+include(base-config-ix)
+include(CompilerRTUtils)
+include(CMakeDependentOption)
+
+option(COMPILER_RT_BUILD_BUILTINS "Build builtins" ON)
+mark_as_advanced(COMPILER_RT_BUILD_BUILTINS)
+option(COMPILER_RT_DISABLE_AARCH64_FMV "Disable AArch64 Function Multi Versioning support" OFF)
+mark_as_advanced(COMPILER_RT_DISABLE_AARCH64_FMV)
+option(COMPILER_RT_BUILD_CRT "Build crtbegin.o/crtend.o" ON)
+mark_as_advanced(COMPILER_RT_BUILD_CRT)
+option(COMPILER_RT_CRT_USE_EH_FRAME_REGISTRY "Use eh_frame in crtbegin.o/crtend.o" ON)
+mark_as_advanced(COMPILER_RT_CRT_USE_EH_FRAME_REGISTRY)
+option(COMPILER_RT_BUILD_SANITIZERS "Build sanitizers" ON)
+mark_as_advanced(COMPILER_RT_BUILD_SANITIZERS)
+option(COMPILER_RT_BUILD_XRAY "Build xray" ON)
+mark_as_advanced(COMPILER_RT_BUILD_XRAY)
+option(COMPILER_RT_BUILD_LIBFUZZER "Build libFuzzer" ON)
+mark_as_advanced(COMPILER_RT_BUILD_LIBFUZZER)
+option(COMPILER_RT_BUILD_PROFILE "Build profile runtime" ON)
+mark_as_advanced(COMPILER_RT_BUILD_PROFILE)
+option(COMPILER_RT_BUILD_MEMPROF "Build memory profiling runtime" ON)
+mark_as_advanced(COMPILER_RT_BUILD_MEMPROF)
+option(COMPILER_RT_BUILD_XRAY_NO_PREINIT "Build xray with no preinit patching" OFF)
+mark_as_advanced(COMPILER_RT_BUILD_XRAY_NO_PREINIT)
+option(COMPILER_RT_BUILD_ORC "Build ORC runtime" ON)
+mark_as_advanced(COMPILER_RT_BUILD_ORC)
+option(COMPILER_RT_BUILD_GWP_ASAN "Build GWP-ASan, and link it into SCUDO" ON)
+mark_as_advanced(COMPILER_RT_BUILD_GWP_ASAN)
+option(COMPILER_RT_ENABLE_CET "Build Compiler RT with CET enabled" OFF)
+
+option(COMPILER_RT_SCUDO_STANDALONE_SYSROOT_PATH "Set custom sysroot for building SCUDO standalone" OFF)
+mark_as_advanced(COMPILER_RT_SCUDO_STANDALONE_SYSROOT_PATH)
+option(COMPILER_RT_SCUDO_STANDALONE_BUILD_SHARED "Build SCUDO standalone for shared libraries" ON)
+mark_as_advanced(COMPILER_RT_SCUDO_STANDALONE_BUILD_SHARED)
+option(COMPILER_RT_BUILD_SCUDO_STANDALONE_WITH_LLVM_LIBC "Build SCUDO standalone with LLVM's libc headers" OFF)
+mark_as_advanced(COMPILER_RT_BUILD_SCUDO_STANDALONE_WITH_LLVM_LIBC)
+
+if(FUCHSIA)
+ set(COMPILER_RT_HWASAN_WITH_INTERCEPTORS_DEFAULT OFF)
+else()
+ set(COMPILER_RT_HWASAN_WITH_INTERCEPTORS_DEFAULT ON)
+endif()
+set(COMPILER_RT_HWASAN_WITH_INTERCEPTORS ${COMPILER_RT_HWASAN_WITH_INTERCEPTORS_DEFAULT} CACHE BOOL "Enable libc interceptors in HWASan (testing mode)")
+
+set(COMPILER_RT_BAREMETAL_BUILD OFF CACHE BOOL
+ "Build for a bare-metal target.")
+
+if (COMPILER_RT_STANDALONE_BUILD)
+ set(CMAKE_CXX_STANDARD 17 CACHE STRING "C++ standard to conform to")
+ set(CMAKE_CXX_STANDARD_REQUIRED YES)
+ set(CMAKE_CXX_EXTENSIONS NO)
+
+ if (NOT LLVM_RUNTIMES_BUILD)
+ load_llvm_config()
+ endif()
+ if (TARGET intrinsics_gen)
+ # Loading the llvm config causes this target to be imported so place it
+ # under the appropriate folder in an IDE.
+ set_target_properties(intrinsics_gen PROPERTIES FOLDER "Compiler-RT Misc")
+ endif()
+
+ find_package(Python3 COMPONENTS Interpreter)
+ if(NOT Python3_Interpreter_FOUND)
+ message(WARNING "Python3 not found, using python2 as a fallback")
+ find_package(Python2 COMPONENTS Interpreter REQUIRED)
+ if(Python2_VERSION VERSION_LESS 2.7)
+ message(SEND_ERROR "Python 2.7 or newer is required")
+ endif()
+
+ # Treat python2 as python3
+ add_executable(Python3::Interpreter IMPORTED)
+ set_target_properties(Python3::Interpreter PROPERTIES
+ IMPORTED_LOCATION ${Python2_EXECUTABLE})
+ set(Python3_EXECUTABLE ${Python2_EXECUTABLE})
+ endif()
+
+ # Ensure that fat libraries are built correctly on Darwin
+ if(APPLE)
+ include(UseLibtool)
+ endif()
+
+ # Define default arguments to lit.
+ set(LIT_ARGS_DEFAULT "-sv")
+ if (MSVC OR XCODE)
+ set(LIT_ARGS_DEFAULT "${LIT_ARGS_DEFAULT} --no-progress-bar")
+ endif()
+ set(LLVM_LIT_ARGS "${LIT_ARGS_DEFAULT}" CACHE STRING "Default options for lit")
+ set(LLVM_LIT_OUTPUT_DIR "${COMPILER_RT_EXEC_OUTPUT_DIR}")
+endif()
+
+construct_compiler_rt_default_triple()
+if ("${COMPILER_RT_DEFAULT_TARGET_TRIPLE}" MATCHES ".*hf$")
+ if (${COMPILER_RT_DEFAULT_TARGET_ARCH} MATCHES "^arm")
+ set(COMPILER_RT_DEFAULT_TARGET_ARCH "armhf")
+ CHECK_SYMBOL_EXISTS (__thumb__ "" COMPILER_RT_ARM_THUMB)
+ endif()
+endif()
+if (${COMPILER_RT_DEFAULT_TARGET_ARCH} MATCHES "^mips")
+ CHECK_SYMBOL_EXISTS (_MIPS_ARCH_MIPS32R6 "" COMPILER_RT_MIPS32R6)
+ CHECK_SYMBOL_EXISTS (_MIPS_ARCH_MIPS64R6 "" COMPILER_RT_MIPS64R6)
+ CHECK_SYMBOL_EXISTS (__mips64 "" COMPILER_RT_MIPS_64)
+ CHECK_SYMBOL_EXISTS (__MIPSEL__ "" COMPILER_RT_MIPS_EL)
+ if ("${COMPILER_RT_MIPS_64}")
+ set(COMPILER_RT_DEFAULT_TARGET_ARCH "mips64")
+ else()
+ set(COMPILER_RT_DEFAULT_TARGET_ARCH "mips")
+ endif()
+ if ("${COMPILER_RT_MIPS_EL}")
+ set(COMPILER_RT_DEFAULT_TARGET_ARCH "${COMPILER_RT_DEFAULT_TARGET_ARCH}el")
+ endif()
+endif()
+if ("${COMPILER_RT_DEFAULT_TARGET_TRIPLE}" MATCHES ".*android.*")
+ set(ANDROID 1)
+ string(REGEX MATCH "-target(=| +)[^ ]+android[a-z]*([0-9]+)" ANDROID_API_LEVEL "${CMAKE_C_FLAGS}")
+ set(ANDROID_API_LEVEL ${CMAKE_MATCH_2})
+endif()
+pythonize_bool(ANDROID)
+
+set(COMPILER_RT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
+set(COMPILER_RT_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR})
+
+pythonize_bool(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR)
+
+# We support running instrumented tests when we're not cross-compiling
+# and target a UNIX-like system or Windows.
+# We can run tests on Android even when we are cross-compiling.
+if(("${CMAKE_HOST_SYSTEM_NAME}" STREQUAL "${CMAKE_SYSTEM_NAME}" AND (UNIX OR WIN32))
+ OR ANDROID OR COMPILER_RT_EMULATOR)
+ option(COMPILER_RT_CAN_EXECUTE_TESTS "Can we execute instrumented tests" ON)
+else()
+ option(COMPILER_RT_CAN_EXECUTE_TESTS "Can we execute instrumented tests" OFF)
+endif()
+
+option(COMPILER_RT_DEBUG "Build runtimes with full debug info" OFF)
+option(COMPILER_RT_EXTERNALIZE_DEBUGINFO
+ "Generate dSYM files and strip executables and libraries (Darwin Only)" OFF)
+# COMPILER_RT_DEBUG_PYBOOL is used by lit.common.configured.in.
+pythonize_bool(COMPILER_RT_DEBUG)
+
+option(COMPILER_RT_INTERCEPT_LIBDISPATCH
+ "Support interception of libdispatch (GCD). Requires '-fblocks'" OFF)
+option(COMPILER_RT_LIBDISPATCH_INSTALL_PATH
+ "Specify if libdispatch is installed in a custom location" "")
+if (COMPILER_RT_INTERCEPT_LIBDISPATCH AND NOT APPLE)
+ set(COMPILER_RT_LIBDISPATCH_CFLAGS -fblocks)
+ set(COMPILER_RT_TEST_LIBDISPATCH_CFLAGS)
+ if (COMPILER_RT_LIBDISPATCH_INSTALL_PATH)
+ list(APPEND COMPILER_RT_TEST_LIBDISPATCH_CFLAGS
+ -I${COMPILER_RT_LIBDISPATCH_INSTALL_PATH}/include
+ -L${COMPILER_RT_LIBDISPATCH_INSTALL_PATH}/lib
+ -Wl,-rpath=${COMPILER_RT_LIBDISPATCH_INSTALL_PATH}/lib)
+ endif()
+ list(APPEND COMPILER_RT_TEST_LIBDISPATCH_CFLAGS -lBlocksRuntime -ldispatch)
+endif()
+if (APPLE) # Always enable on Apple platforms.
+ set(COMPILER_RT_INTERCEPT_LIBDISPATCH ON)
+endif()
+pythonize_bool(COMPILER_RT_INTERCEPT_LIBDISPATCH)
+
+if(APPLE AND SANITIZER_MIN_OSX_VERSION AND SANITIZER_MIN_OSX_VERSION VERSION_LESS "10.9")
+ # Mac OS X prior to 10.9 had problems with exporting symbols from
+ # libc++/libc++abi.
+ set(cxxabi_supported OFF)
+else()
+ set(cxxabi_supported ON)
+endif()
+
+option(SANITIZER_ALLOW_CXXABI "Allow use of C++ ABI details in ubsan" ON)
+
+set(SANITIZER_CAN_USE_CXXABI OFF)
+if (cxxabi_supported AND SANITIZER_ALLOW_CXXABI)
+ set(SANITIZER_CAN_USE_CXXABI ON)
+endif()
+pythonize_bool(SANITIZER_CAN_USE_CXXABI)
+
+macro(handle_default_cxx_lib var)
+ # Specifying -stdlib= in CMAKE_CXX_FLAGS overrides the defaults.
+ if (CMAKE_CXX_FLAGS MATCHES "-stdlib=([a-zA-Z+]*)")
+ set(${var}_LIBNAME "${CMAKE_MATCH_1}")
+ set(${var}_SYSTEM 1)
+ elseif (${var} STREQUAL "default")
+ if (APPLE OR CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
+ set(${var}_LIBNAME "libc++")
+ set(${var}_SYSTEM 1)
+ elseif (FUCHSIA)
+ set(${var}_LIBNAME "libc++")
+ set(${var}_INTREE 1)
+ else()
+ set(${var}_LIBNAME "libstdc++")
+ set(${var}_SYSTEM 1)
+ endif()
+ else()
+ set(${var}_LIBNAME "${${var}}")
+ set(${var}_SYSTEM 1)
+ endif()
+endmacro()
+
+# This is either directly the C++ ABI library or the full C++ library
+# which pulls in the ABI transitively.
+# TODO: Mark this as internal flag, most users should use COMPILER_RT_CXX_LIBRARY.
+set(SANITIZER_CXX_ABI "default" CACHE STRING
+ "Specify C++ ABI library to use.")
+set(CXXABIS none default libstdc++ libc++ libcxxabi)
+set_property(CACHE SANITIZER_CXX_ABI PROPERTY STRINGS ;${CXXABIS})
+handle_default_cxx_lib(SANITIZER_CXX_ABI)
+
+# This needs to be a full C++ library for linking gtest and unit tests.
+# TODO: Mark this as internal flag, most users should use COMPILER_RT_CXX_LIBRARY.
+set(SANITIZER_TEST_CXX "default" CACHE STRING
+ "Specify C++ library to use for tests.")
+set(CXXLIBS none default libstdc++ libc++)
+set_property(CACHE SANITIZER_TEST_CXX PROPERTY STRINGS ;${CXXLIBS})
+handle_default_cxx_lib(SANITIZER_TEST_CXX)
+
+option(COMPILER_RT_USE_LLVM_UNWINDER "Use the LLVM unwinder." OFF)
+cmake_dependent_option(COMPILER_RT_ENABLE_STATIC_UNWINDER
+ "Statically link the LLVM unwinder." OFF
+ "COMPILER_RT_USE_LLVM_UNWINDER" OFF)
+
+set(DEFAULT_SANITIZER_USE_STATIC_LLVM_UNWINDER OFF)
+if (FUCHSIA)
+ set(DEFAULT_SANITIZER_USE_STATIC_LLVM_UNWINDER ON)
+elseif (DEFINED LIBUNWIND_ENABLE_SHARED AND NOT LIBUNWIND_ENABLE_SHARED)
+ set(DEFAULT_SANITIZER_USE_STATIC_LLVM_UNWINDER ON)
+endif()
+
+option(SANITIZER_USE_STATIC_LLVM_UNWINDER
+ "Use static LLVM unwinder." ${DEFAULT_SANITIZER_USE_STATIC_LLVM_UNWINDER})
+pythonize_bool(SANITIZER_USE_STATIC_LLVM_UNWINDER)
+
+set(DEFAULT_SANITIZER_USE_STATIC_CXX_ABI OFF)
+if (DEFINED LIBCXXABI_ENABLE_SHARED AND NOT LIBCXXABI_ENABLE_SHARED)
+ set(DEFAULT_SANITIZER_USE_STATIC_CXX_ABI ON)
+endif()
+
+option(SANITIZER_USE_STATIC_CXX_ABI
+ "Use static libc++abi." ${DEFAULT_SANITIZER_USE_STATIC_CXX_ABI})
+pythonize_bool(SANITIZER_USE_STATIC_CXX_ABI)
+
+set(DEFAULT_SANITIZER_USE_STATIC_TEST_CXX OFF)
+if (DEFINED LIBCXX_ENABLE_SHARED AND NOT LIBCXX_ENABLE_SHARED)
+ set(DEFAULT_SANITIZER_USE_STATIC_TEST_CXX ON)
+endif()
+
+option(SANITIZER_USE_STATIC_TEST_CXX
+ "Use static libc++ for tests." ${DEFAULT_SANITIZER_USE_STATIC_TEST_CXX})
+pythonize_bool(SANITIZER_USE_STATIC_TEST_CXX)
+
+set(COMPILER_RT_SUPPORTED_CXX_LIBRARIES none default libcxx)
+set(COMPILER_RT_CXX_LIBRARY "default" CACHE STRING "Specify C++ library to use. Supported values are ${COMPILER_RT_SUPPORTED_CXX_LIBRARIES}.")
+if (NOT "${COMPILER_RT_CXX_LIBRARY}" IN_LIST COMPILER_RT_SUPPORTED_CXX_LIBRARIES)
+ message(FATAL_ERROR "Unsupported C++ library: '${COMPILER_RT_CXX_LIBRARY}'. Supported values are ${COMPILER_RT_SUPPORTED_CXX_LIBRARIES}.")
+endif()
+cmake_dependent_option(COMPILER_RT_STATIC_CXX_LIBRARY
+ "Statically link the C++ library." OFF
+ "COMPILER_RT_CXX_LIBRARY" OFF)
+
+set(DEFAULT_COMPILER_RT_USE_BUILTINS_LIBRARY OFF)
+if (FUCHSIA)
+ set(DEFAULT_COMPILER_RT_USE_BUILTINS_LIBRARY ON)
+endif()
+
+option(COMPILER_RT_USE_BUILTINS_LIBRARY
+ "Use compiler-rt builtins instead of libgcc" ${DEFAULT_COMPILER_RT_USE_BUILTINS_LIBRARY})
+
+include(config-ix)
+
+#================================
+# Setup Compiler Flags
+#================================
+
+# fcf-protection is a gcc/clang option for CET support on Linux platforms.
+# We need to handle MSVC CET option on Windows platforms.
+if (NOT MSVC)
+ if (COMPILER_RT_ENABLE_CET AND NOT COMPILER_RT_HAS_FCF_PROTECTION_FLAG)
+ message(FATAL_ERROR "Compiler used to build compiler-rt doesn't support CET!")
+ endif()
+endif()
+
+if(MSVC)
+ # Override any existing /W flags with /W4. This is what LLVM does. Failing to
+ # remove other /W[0-4] flags will result in a warning about overriding a
+ # previous flag.
+ if (COMPILER_RT_HAS_W4_FLAG)
+ string(REGEX REPLACE " /W[0-4]" "" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}")
+ string(REGEX REPLACE " /W[0-4]" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
+ append_string_if(COMPILER_RT_HAS_W4_FLAG /W4 CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
+ endif()
+else()
+ append_string_if(COMPILER_RT_HAS_WALL_FLAG -Wall CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
+endif()
+if(COMPILER_RT_ENABLE_WERROR)
+ append_string_if(COMPILER_RT_HAS_WERROR_FLAG -Werror CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
+ append_string_if(COMPILER_RT_HAS_WX_FLAG /WX CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
+endif()
+
+# Emulate C99 and C++11's __func__ for MSVC prior to 2013 CTP.
+if(NOT COMPILER_RT_HAS_FUNC_SYMBOL)
+ add_definitions(-D__func__=__FUNCTION__)
+endif()
+
+# Provide some common commandline flags for Sanitizer runtimes.
+if("${ANDROID_API_LEVEL}" GREATER_EQUAL 29)
+ list(APPEND SANITIZER_COMMON_CFLAGS -fno-emulated-tls)
+ string(APPEND COMPILER_RT_TEST_COMPILER_CFLAGS " -fno-emulated-tls")
+endif()
+if(NOT WIN32)
+ append_list_if(COMPILER_RT_HAS_FPIC_FLAG -fPIC SANITIZER_COMMON_CFLAGS)
+endif()
+append_list_if(COMPILER_RT_HAS_FNO_BUILTIN_FLAG -fno-builtin SANITIZER_COMMON_CFLAGS)
+append_list_if(COMPILER_RT_HAS_FNO_EXCEPTIONS_FLAG -fno-exceptions SANITIZER_COMMON_CFLAGS)
+if(NOT COMPILER_RT_DEBUG AND NOT APPLE)
+ append_list_if(COMPILER_RT_HAS_FOMIT_FRAME_POINTER_FLAG -fomit-frame-pointer SANITIZER_COMMON_CFLAGS)
+endif()
+append_list_if(COMPILER_RT_HAS_FUNWIND_TABLES_FLAG -funwind-tables SANITIZER_COMMON_CFLAGS)
+append_list_if(COMPILER_RT_HAS_FNO_STACK_PROTECTOR_FLAG -fno-stack-protector SANITIZER_COMMON_CFLAGS)
+append_list_if(COMPILER_RT_HAS_FNO_SANITIZE_SAFE_STACK_FLAG -fno-sanitize=safe-stack SANITIZER_COMMON_CFLAGS)
+append_list_if(COMPILER_RT_HAS_FVISIBILITY_HIDDEN_FLAG -fvisibility=hidden SANITIZER_COMMON_CFLAGS)
+if(NOT COMPILER_RT_HAS_FVISIBILITY_HIDDEN_FLAG)
+ append_list_if(COMPILER_RT_HAS_FVISIBILITY_INLINES_HIDDEN_FLAG -fvisibility-inlines-hidden SANITIZER_COMMON_CFLAGS)
+endif()
+append_list_if(COMPILER_RT_HAS_FNO_LTO_FLAG -fno-lto SANITIZER_COMMON_CFLAGS)
+
+# By default do not instrument or use profdata for compiler-rt.
+if(NOT COMPILER_RT_ENABLE_PGO)
+ if(LLVM_PROFDATA_FILE AND COMPILER_RT_HAS_FNO_PROFILE_INSTR_USE_FLAG)
+ list(APPEND SANITIZER_COMMON_CFLAGS "-fno-profile-instr-use")
+ endif()
+ if(LLVM_BUILD_INSTRUMENTED MATCHES IR AND COMPILER_RT_HAS_FNO_PROFILE_GENERATE_FLAG)
+ list(APPEND SANITIZER_COMMON_CFLAGS "-fno-profile-generate")
+ elseif((LLVM_BUILD_INSTRUMENTED OR LLVM_BUILD_INSTRUMENTED_COVERAGE) AND COMPILER_RT_HAS_FNO_PROFILE_INSTR_GENERATE_FLAG)
+ list(APPEND SANITIZER_COMMON_CFLAGS "-fno-profile-instr-generate")
+ if(LLVM_BUILD_INSTRUMENTED_COVERAGE AND COMPILER_RT_HAS_FNO_COVERAGE_MAPPING_FLAG)
+ list(APPEND SANITIZER_COMMON_CFLAGS "-fno-coverage-mapping")
+ endif()
+ endif()
+endif()
+
+# The following is a workaround for powerpc64le. This is the only architecture
+# that requires -fno-function-sections to work properly. If lacking, the ASan
+# Linux test function-sections-are-bad.cpp fails with the following error:
+# 'undefined symbol: __sanitizer_unaligned_load32'.
+if(DEFINED TARGET_powerpc64le_CFLAGS)
+ if(CMAKE_CXX_COMPILER_ID MATCHES "XL")
+ append("-qnofuncsect" TARGET_powerpc64le_CFLAGS)
+ else()
+ append_list_if(COMPILER_RT_HAS_FNO_FUNCTION_SECTIONS_FLAG -fno-function-sections TARGET_powerpc64le_CFLAGS)
+ endif()
+endif()
+
+# The following is a workaround for s390x. This avoids creation of "partial
+# inline" function fragments when building the asan libraries with certain
+# GCC versions. The presence of those fragments, in particular for the
+# interceptors, changes backtraces seen in asan error cases, which causes
+# testsuite failures.
+if("${COMPILER_RT_DEFAULT_TARGET_ARCH}" MATCHES "s390x")
+ append_list_if(COMPILER_RT_HAS_FNO_PARTIAL_INLINING_FLAG -fno-partial-inlining SANITIZER_COMMON_CFLAGS)
+endif()
+
+if(MSVC)
+ # Replace the /M[DT][d] flags with /MT, and strip any definitions of _DEBUG,
+ # which cause definition mismatches at link time.
+ # FIXME: In fact, sanitizers should support both /MT and /MD, see PR20214.
+ if(COMPILER_RT_HAS_MT_FLAG)
+ foreach(flag_var
+ CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE
+ CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO
+ CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
+ CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
+ string(REGEX REPLACE "/M[DT]d" "/MT" ${flag_var} "${${flag_var}}")
+ string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}")
+ string(REGEX REPLACE "/D_DEBUG" "" ${flag_var} "${${flag_var}}")
+ endforeach()
+ endif()
+ append_list_if(COMPILER_RT_HAS_Oy_FLAG /Oy- SANITIZER_COMMON_CFLAGS)
+ append_list_if(COMPILER_RT_HAS_GS_FLAG /GS- SANITIZER_COMMON_CFLAGS)
+
+ # Disable thread safe initialization for static locals. ASan shouldn't need
+ # it. Thread safe initialization assumes that the CRT has already been
+ # initialized, but ASan initializes before the CRT.
+ list(APPEND SANITIZER_COMMON_CFLAGS /Zc:threadSafeInit-)
+endif()
+
+append_list_if(COMPILER_RT_DEBUG -DSANITIZER_DEBUG=1 SANITIZER_COMMON_CFLAGS)
+
+append_list_if(COMPILER_RT_HAS_WTHREAD_SAFETY_FLAG -Wthread-safety THREAD_SAFETY_FLAGS)
+append_list_if(COMPILER_RT_HAS_WTHREAD_SAFETY_REFERENCE_FLAG -Wthread-safety-reference THREAD_SAFETY_FLAGS)
+append_list_if(COMPILER_RT_HAS_WTHREAD_SAFETY_BETA_FLAG -Wthread-safety-beta THREAD_SAFETY_FLAGS)
+list(APPEND SANITIZER_COMMON_CFLAGS ${THREAD_SAFETY_FLAGS})
+string(REPLACE ";" " " thread_safety_flags_space_sep "${THREAD_SAFETY_FLAGS}")
+string(APPEND COMPILER_RT_TEST_COMPILER_CFLAGS " ${thread_safety_flags_space_sep}")
+
+# If we're using MSVC,
+# always respect the optimization flags set by CMAKE_BUILD_TYPE instead.
+if (NOT MSVC)
+
+ # Build with optimization, unless we're in debug mode.
+ if(COMPILER_RT_DEBUG)
+ list(APPEND SANITIZER_COMMON_CFLAGS -O1)
+ else()
+ list(APPEND SANITIZER_COMMON_CFLAGS -O3)
+ endif()
+endif()
+
+# Determine if we should restrict stack frame sizes.
+# Stack frames on PowerPC, Mips, SystemZ and in debug build can be much larger than
+# anticipated.
+# FIXME: Fix all sanitizers and add -Wframe-larger-than to
+# SANITIZER_COMMON_FLAGS
+if(COMPILER_RT_HAS_WFRAME_LARGER_THAN_FLAG AND NOT COMPILER_RT_DEBUG
+ AND NOT ${COMPILER_RT_DEFAULT_TARGET_ARCH} MATCHES "powerpc|mips|s390x")
+ set(SANITIZER_LIMIT_FRAME_SIZE TRUE)
+else()
+ set(SANITIZER_LIMIT_FRAME_SIZE FALSE)
+endif()
+
+if(FUCHSIA OR UNIX)
+ set(SANITIZER_USE_SYMBOLS TRUE)
+else()
+ set(SANITIZER_USE_SYMBOLS FALSE)
+endif()
+
+# Build sanitizer runtimes with debug info.
+if(MSVC)
+ # Use /Z7 instead of /Zi for the asan runtime. This avoids the LNK4099
+ # warning from the MS linker complaining that it can't find the 'vc140.pdb'
+ # file used by our object library compilations.
+ list(APPEND SANITIZER_COMMON_CFLAGS /Z7)
+ foreach(var_to_update
+ CMAKE_CXX_FLAGS
+ CMAKE_CXX_FLAGS_DEBUG
+ CMAKE_CXX_FLAGS_RELWITHDEBINFO)
+ string(REGEX REPLACE "(^| )/Z[i7I]($| )" " /Z7 "
+ "${var_to_update}" "${${var_to_update}}")
+ endforeach()
+elseif(APPLE)
+ # On Apple platforms use full debug info (i.e. not `-gline-tables-only`)
+ # for all build types so that the runtime can be debugged.
+ if(NOT COMPILER_RT_HAS_G_FLAG)
+ message(FATAL_ERROR "-g is not supported by host compiler")
+ endif()
+ list(APPEND SANITIZER_COMMON_CFLAGS -g)
+elseif(COMPILER_RT_HAS_GLINE_TABLES_ONLY_FLAG AND NOT COMPILER_RT_DEBUG)
+ list(APPEND SANITIZER_COMMON_CFLAGS -gline-tables-only)
+elseif(COMPILER_RT_HAS_G_FLAG)
+ list(APPEND SANITIZER_COMMON_CFLAGS -g)
+endif()
+
+if(LLVM_ENABLE_MODULES)
+ # Sanitizers cannot be built with -fmodules. The interceptors intentionally
+ # don't include system headers, which is incompatible with modules.
+ list(APPEND SANITIZER_COMMON_CFLAGS -fno-modules)
+endif()
+
+# Turn off several warnings.
+append_list_if(COMPILER_RT_HAS_WGNU_FLAG -Wno-gnu SANITIZER_COMMON_CFLAGS)
+append_list_if(COMPILER_RT_HAS_WVARIADIC_MACROS_FLAG -Wno-variadic-macros SANITIZER_COMMON_CFLAGS)
+append_list_if(COMPILER_RT_HAS_WC99_EXTENSIONS_FLAG -Wno-c99-extensions SANITIZER_COMMON_CFLAGS)
+# format-pedantic warns about passing T* for %p, which is not useful.
+append_list_if(COMPILER_RT_HAS_WD4146_FLAG /wd4146 SANITIZER_COMMON_CFLAGS)
+append_list_if(COMPILER_RT_HAS_WD4291_FLAG /wd4291 SANITIZER_COMMON_CFLAGS)
+append_list_if(COMPILER_RT_HAS_WD4391_FLAG /wd4391 SANITIZER_COMMON_CFLAGS)
+append_list_if(COMPILER_RT_HAS_WD4722_FLAG /wd4722 SANITIZER_COMMON_CFLAGS)
+append_list_if(COMPILER_RT_HAS_WD4800_FLAG /wd4800 SANITIZER_COMMON_CFLAGS)
+
+append_list_if(MINGW -fms-extensions SANITIZER_COMMON_CFLAGS)
+
+# When lsan scans the stack for detecting reachable pointers, it's possible for
+# a leaked pointer, which was pushed to the stack on an earlier function call,
+# to still exist on the stack when doing a leak check if that part of the stack
+# was not overwritten. In particular, if there's any uninitialized data in the
+# lsan runtime, and the SP we start from is sufficiently deep into the runtime,
+# then a leaked pointer could be marked as reachable. Such instances could be
+# mitigated by clobbering any uninitialized data. Note that this won't cover
+# all possible uninitialized stack contents, such as those used for register
+# spill slots, unused portions for alignment, or even local variables not
+# yet in scope at a certain point in the function.
+#
+# Note that this type of issue was discovered with lsan, but can apply to other
+# sanitizers.
+append_list_if(COMPILER_RT_HAS_TRIVIAL_AUTO_INIT -ftrivial-auto-var-init=pattern SANITIZER_COMMON_CFLAGS)
+
+# Set common link flags.
+# TODO: We should consider using the same model as libc++, that is use either
+# -nostdlib++ and --unwindlib=none if supported, or -nodefaultlibs otherwise.
+append_list_if(C_SUPPORTS_NODEFAULTLIBS_FLAG -nodefaultlibs SANITIZER_COMMON_LINK_FLAGS)
+append_list_if(COMPILER_RT_HAS_Z_TEXT -Wl,-z,text SANITIZER_COMMON_LINK_FLAGS)
+
+# Only necessary for 32-bit SPARC. Solaris 11.2+ ld uses -z ignore/-z record
+# natively, but supports --as-needed/--no-as-needed for GNU ld compatibility.
+if("${COMPILER_RT_DEFAULT_TARGET_ARCH}" MATCHES "sparc")
+ list(APPEND SANITIZER_COMMON_LINK_LIBS -Wl,--as-needed atomic -Wl,--no-as-needed)
+endif()
+
+if (COMPILER_RT_USE_BUILTINS_LIBRARY)
+ string(REPLACE "-Wl,-z,defs" "" CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS}")
+else()
+ if (ANDROID)
+ append_list_if(COMPILER_RT_HAS_GCC_LIB gcc SANITIZER_COMMON_LINK_LIBS)
+ else()
+ append_list_if(COMPILER_RT_HAS_GCC_S_LIB gcc_s SANITIZER_COMMON_LINK_LIBS)
+ endif()
+endif()
+
+append_list_if(COMPILER_RT_HAS_LIBC c SANITIZER_COMMON_LINK_LIBS)
+if("${CMAKE_SYSTEM_NAME}" STREQUAL "Fuchsia")
+ list(APPEND SANITIZER_COMMON_LINK_LIBS zircon)
+endif()
+
+if("${CMAKE_SYSTEM_NAME}" STREQUAL "Fuchsia")
+ set(SANITIZER_NO_UNDEFINED_SYMBOLS_DEFAULT ON)
+else()
+ set(SANITIZER_NO_UNDEFINED_SYMBOLS_DEFAULT OFF)
+endif()
+option(SANITIZER_NO_UNDEFINED_SYMBOLS "Report error on unresolved symbol references" ${SANITIZER_NO_UNDEFINED_SYMBOLS_DEFAULT})
+if (SANITIZER_NO_UNDEFINED_SYMBOLS)
+ list(APPEND SANITIZER_COMMON_LINK_FLAGS -Wl,-z,defs)
+endif()
+
+# TODO: COMPILER_RT_COMMON_CFLAGS and COMPILER_RT_COMMON_LINK_FLAGS are
+# intended for use in non-sanitizer runtimes such as libFuzzer, profile or XRay,
+# move these higher to include common flags, then derive SANITIZER_COMMON_CFLAGS
+# and SANITIZER_COMMON_LINK_FLAGS from those and append sanitizer-specific flags.
+set(COMPILER_RT_COMMON_CFLAGS ${SANITIZER_COMMON_CFLAGS})
+set(COMPILER_RT_COMMON_LINK_FLAGS ${SANITIZER_COMMON_LINK_FLAGS})
+
+# We don't use the C++ standard library, so avoid including it by mistake.
+append_list_if(COMPILER_RT_HAS_NOSTDINCXX_FLAG -nostdinc++ SANITIZER_COMMON_CFLAGS)
+append_list_if(COMPILER_RT_HAS_NOSTDLIBXX_FLAG -nostdlib++ SANITIZER_COMMON_LINK_FLAGS)
+
+# Remove -stdlib= which is unused when passing -nostdinc++...
+string(REGEX MATCHALL "-stdlib=[a-zA-Z+]*" stdlib_flag "${CMAKE_CXX_FLAGS}")
+string(REGEX REPLACE "-stdlib=[a-zA-Z+]*" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
+
+# ...we need it to build some runtimes and tests so readd it where appropriate.
+list(APPEND COMPILER_RT_COMMON_CFLAGS ${stdlib_flag})
+list(APPEND COMPILER_RT_COMMON_LINK_FLAGS ${stdlib_flag})
+
+# TODO: There's a lot of duplication across lib/*/tests/CMakeLists.txt files,
+# move some of the common flags to COMPILER_RT_UNITTEST_CFLAGS.
+
+# Unittests need access to C++ standard library.
+string(APPEND COMPILER_RT_TEST_COMPILER_CFLAGS " ${stdlib_flag}")
+
+# When cross-compiling, COMPILER_RT_TEST_COMPILER_CFLAGS help in compilation
+# and linking of unittests.
+string(REPLACE " " ";" COMPILER_RT_UNITTEST_CFLAGS "${COMPILER_RT_TEST_COMPILER_CFLAGS}")
+set(COMPILER_RT_UNITTEST_LINK_FLAGS ${COMPILER_RT_UNITTEST_CFLAGS})
+
+if(COMPILER_RT_USE_LLVM_UNWINDER)
+ # We're linking directly against the libunwind that we're building so don't
+ # try to link in the toolchain's default libunwind which may be missing.
+ append_list_if(CXX_SUPPORTS_UNWINDLIB_NONE_FLAG --unwindlib=none COMPILER_RT_COMMON_LINK_FLAGS)
+ append_list_if(CXX_SUPPORTS_UNWINDLIB_NONE_FLAG --unwindlib=none COMPILER_RT_UNITTEST_LINK_FLAGS)
+ if (COMPILER_RT_ENABLE_STATIC_UNWINDER)
+ list(APPEND COMPILER_RT_UNWINDER_LINK_LIBS "$<TARGET_LINKER_FILE:unwind_static>")
+ else()
+ list(APPEND COMPILER_RT_UNWINDER_LINK_LIBS "$<TARGET_LINKER_FILE:$<IF:$<TARGET_EXISTS:unwind_shared>,unwind_shared,unwind_static>>")
+ endif()
+endif()
+
+if (COMPILER_RT_CXX_LIBRARY STREQUAL "libcxx")
+ # We are using the in-tree libc++ so avoid including the default one.
+ append_list_if(COMPILER_RT_HAS_NOSTDINCXX_FLAG -nostdinc++ COMPILER_RT_COMMON_CFLAGS)
+ append_list_if(COMPILER_RT_HAS_NOSTDLIBXX_FLAG -nostdlib++ COMPILER_RT_COMMON_LINK_FLAGS)
+ # Use the in-tree libc++ through explicit include and library paths.
+ set(COMPILER_RT_CXX_CFLAGS "$<$<TARGET_EXISTS:cxx-headers>:$<IF:$<BOOL:${MSVC}>,/imsvc,-isystem>$<JOIN:$<TARGET_PROPERTY:cxx-headers,INTERFACE_INCLUDE_DIRECTORIES>,$<SEMICOLON>$<IF:$<BOOL:${MSVC}>,/imsvc,-isystem>>>")
+ if (COMPILER_RT_STATIC_CXX_LIBRARY)
+ set(COMPILER_RT_CXX_LINK_LIBS "$<TARGET_LINKER_FILE:cxx_static>")
+ else()
+ set(COMPILER_RT_CXX_LINK_LIBS "$<TARGET_LINKER_FILE:$<IF:$<TARGET_EXISTS:cxx_shared>,cxx_shared,cxx_static>>")
+ endif()
+elseif (COMPILER_RT_CXX_LIBRARY STREQUAL "none")
+ # We aren't using any C++ standard library so avoid including the default one.
+ append_list_if(COMPILER_RT_HAS_NOSTDINCXX_FLAG -nostdinc++ COMPILER_RT_COMMON_CFLAGS)
+ append_list_if(COMPILER_RT_HAS_NOSTDLIBXX_FLAG -nostdlib++ COMPILER_RT_COMMON_LINK_FLAGS)
+else()
+ # Nothing to be done for `default`.
+endif()
+
+if (SANITIZER_CXX_ABI_LIBNAME STREQUAL "libc++")
+ if (SANITIZER_CXX_ABI_INTREE)
+ # TODO: We don't need to add --unwindlib=none to SANITIZER_COMMON_LINK_FLAGS
+ # because we added -nodefaultlibs there earlier, and adding would result in
+ # a warning, but if we switch to -nostdlib++, we would need to add it here.
+ # append_list_if(CXX_SUPPORTS_UNWINDLIB_NONE_FLAG --unwindlib=none SANITIZER_COMMON_LINK_FLAGS)
+ if(SANITIZER_USE_STATIC_CXX_ABI)
+ if(TARGET libcxx-abi-static)
+ set(SANITIZER_CXX_ABI_LIBRARIES libcxx-abi-static)
+ endif()
+ else()
+ if(TARGET libcxx-abi-shared)
+ set(SANITIZER_CXX_ABI_LIBRARIES libcxx-abi-shared)
+ elseif(TARGET libcxx-abi-static)
+ set(SANITIZER_CXX_ABI_LIBRARIES libcxx-abi-static)
+ endif()
+ endif()
+ else()
+ append_list_if(COMPILER_RT_HAS_LIBCXX c++ SANITIZER_CXX_ABI_LIBRARIES)
+ endif()
+elseif (SANITIZER_CXX_ABI_LIBNAME STREQUAL "libcxxabi")
+ list(APPEND SANITIZER_CXX_ABI_LIBRARIES "c++abi")
+elseif (SANITIZER_CXX_ABI_LIBNAME STREQUAL "libstdc++")
+ append_list_if(COMPILER_RT_HAS_LIBSTDCXX stdc++ SANITIZER_CXX_ABI_LIBRARIES)
+endif()
+
+if (SANITIZER_TEST_CXX_LIBNAME STREQUAL "libc++")
+ if (SANITIZER_TEST_CXX_INTREE)
+ list(APPEND SANITIZER_TEST_CXX_CFLAGS "$<$<TARGET_EXISTS:cxx-headers>:$<IF:$<BOOL:${MSVC}>,/imsvc,-isystem>$<JOIN:$<TARGET_PROPERTY:cxx-headers,INTERFACE_INCLUDE_DIRECTORIES>,$<SEMICOLON>$<IF:$<BOOL:${MSVC}>,/imsvc,-isystem>>>")
+ if (SANITIZER_USE_STATIC_TEST_CXX)
+ list(APPEND SANITIZER_TEST_CXX_LIBRARIES "$<TARGET_LINKER_FILE:cxx_static>")
+ else()
+ list(APPEND SANITIZER_TEST_CXX_LIBRARIES "$<TARGET_LINKER_FILE:$<IF:$<TARGET_EXISTS:cxx_shared>,cxx_shared,cxx_static>>")
+ endif()
+ # We are using the in tree libc++ so avoid including the default one.
+ append_list_if(COMPILER_RT_HAS_NOSTDINCXX_FLAG -nostdinc++ COMPILER_RT_UNITTEST_CFLAGS)
+ append_list_if(COMPILER_RT_HAS_NOSTDLIBXX_FLAG -nostdlib++ COMPILER_RT_UNITTEST_LINK_FLAGS)
+ else()
+ append_list_if(COMPILER_RT_HAS_LIBCXX -lc++ SANITIZER_TEST_CXX_LIBRARIES)
+ endif()
+elseif (SANITIZER_TEST_CXX_LIBNAME STREQUAL "libstdc++")
+ append_list_if(COMPILER_RT_HAS_LIBSTDCXX -lstdc++ SANITIZER_TEST_CXX_LIBRARIES)
+endif()
+
+# Unittests support.
+# FIXME: When compiler-rt is build using -DLLVM_BUILD_EXTERNAL_COMPILER_RT=ON, then
+# The LLVM_THIRD_PARTY_DIR variable is not set.
+if (NOT LLVM_THIRD_PARTY_DIR)
+ set(LLVM_THIRD_PARTY_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../third-party")
+endif()
+
+set(COMPILER_RT_GTEST_PATH ${LLVM_THIRD_PARTY_DIR}/unittest/googletest)
+set(COMPILER_RT_GTEST_SOURCE ${COMPILER_RT_GTEST_PATH}/src/gtest-all.cc)
+set(COMPILER_RT_GTEST_CFLAGS
+ -DGTEST_NO_LLVM_SUPPORT=1
+ -DGTEST_HAS_RTTI=0
+ -I${COMPILER_RT_GTEST_PATH}/include
+ -I${COMPILER_RT_GTEST_PATH}
+)
+
+# Mocking support.
+set(COMPILER_RT_GMOCK_PATH ${LLVM_THIRD_PARTY_DIR}/unittest/googlemock)
+set(COMPILER_RT_GMOCK_SOURCE ${COMPILER_RT_GMOCK_PATH}/src/gmock-all.cc)
+set(COMPILER_RT_GMOCK_CFLAGS
+ -DGTEST_NO_LLVM_SUPPORT=1
+ -DGTEST_HAS_RTTI=0
+ -I${COMPILER_RT_GMOCK_PATH}/include
+ -I${COMPILER_RT_GMOCK_PATH}
+)
+
+if(COMPILER_RT_HAS_G_FLAG)
+ list(APPEND COMPILER_RT_UNITTEST_CFLAGS -g)
+endif()
+append_list_if(COMPILER_RT_DEBUG -DSANITIZER_DEBUG=1 COMPILER_RT_UNITTEST_CFLAGS)
+append_list_if(COMPILER_RT_HAS_WCOVERED_SWITCH_DEFAULT_FLAG -Wno-covered-switch-default COMPILER_RT_UNITTEST_CFLAGS)
+append_list_if(COMPILER_RT_HAS_WSUGGEST_OVERRIDE_FLAG -Wno-suggest-override COMPILER_RT_UNITTEST_CFLAGS)
+
+if(MSVC)
+ # gtest use a lot of stuff marked as deprecated on Windows.
+ list(APPEND COMPILER_RT_GTEST_CFLAGS -Wno-deprecated-declarations)
+endif()
+
+# Warnings to turn off for all libraries, not just sanitizers.
+append_string_if(COMPILER_RT_HAS_WUNUSED_PARAMETER_FLAG -Wno-unused-parameter CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
+
+if (CMAKE_LINKER MATCHES "link.exe$")
+ # Silence MSVC linker warnings caused by empty object files. The
+ # sanitizer libraries intentionally use ifdefs that result in empty
+ # files, rather than skipping these files in the build system.
+ # Ideally, we would pass this flag only for the libraries that need
+ # it, but CMake doesn't seem to have a way to set linker flags for
+ # individual static libraries, so we enable the suppression flag for
+ # the whole compiler-rt project.
+ set(CMAKE_STATIC_LINKER_FLAGS "${CMAKE_STATIC_LINKER_FLAGS} /IGNORE:4221")
+endif()
+
+add_subdirectory(include)
+
+option(COMPILER_RT_USE_LIBCXX
+ "Enable compiler-rt to use libc++ from the source tree" ON)
+if(COMPILER_RT_USE_LIBCXX)
+ if(LLVM_ENABLE_PROJECTS_USED)
+ # Don't use libcxx if LLVM_ENABLE_PROJECTS does not enable it.
+ set(COMPILER_RT_LIBCXX_PATH ${LLVM_EXTERNAL_LIBCXX_SOURCE_DIR})
+ set(COMPILER_RT_LIBCXXABI_PATH ${LLVM_EXTERNAL_LIBCXXABI_SOURCE_DIR})
+ else()
+ foreach(path IN ITEMS ${LLVM_MAIN_SRC_DIR}/projects/libcxx
+ ${LLVM_MAIN_SRC_DIR}/runtimes/libcxx
+ ${LLVM_MAIN_SRC_DIR}/../libcxx
+ ${LLVM_EXTERNAL_LIBCXX_SOURCE_DIR})
+ if(IS_DIRECTORY ${path})
+ set(COMPILER_RT_LIBCXX_PATH ${path})
+ break()
+ endif()
+ endforeach()
+ foreach(path IN ITEMS ${LLVM_MAIN_SRC_DIR}/projects/libcxxabi
+ ${LLVM_MAIN_SRC_DIR}/runtimes/libcxxabi
+ ${LLVM_MAIN_SRC_DIR}/../libcxxabi
+ ${LLVM_EXTERNAL_LIBCXXABI_SOURCE_DIR})
+ if(IS_DIRECTORY ${path})
+ set(COMPILER_RT_LIBCXXABI_PATH ${path})
+ break()
+ endif()
+ endforeach()
+ endif()
+endif()
+
+set(COMPILER_RT_LLD_PATH ${LLVM_MAIN_SRC_DIR}/tools/lld)
+if(EXISTS ${COMPILER_RT_LLD_PATH}/ AND LLVM_TOOL_LLD_BUILD)
+ set(COMPILER_RT_HAS_LLD TRUE)
+else()
+ set(COMPILER_RT_LLD_PATH ${LLVM_MAIN_SRC_DIR}/../lld)
+ if(EXISTS ${COMPILER_RT_LLD_PATH}/ AND LLVM_TOOL_LLD_BUILD)
+ set(COMPILER_RT_HAS_LLD TRUE)
+ endif()
+endif()
+
+if(ANDROID)
+ set(COMPILER_RT_HAS_LLD TRUE)
+ set(COMPILER_RT_TEST_USE_LLD TRUE)
+ append_list_if(COMPILER_RT_HAS_FUSE_LD_LLD_FLAG -fuse-ld=lld SANITIZER_COMMON_LINK_FLAGS)
+ append_list_if(COMPILER_RT_HAS_LLD -fuse-ld=lld COMPILER_RT_UNITTEST_LINK_FLAGS)
+endif()
+pythonize_bool(COMPILER_RT_HAS_LLD)
+pythonize_bool(COMPILER_RT_TEST_USE_LLD)
+
+add_subdirectory(lib)
+
+if(COMPILER_RT_INCLUDE_TESTS)
+ add_subdirectory(unittests)
+ add_subdirectory(test)
+ # Don't build llvm-lit for runtimes-build, it will clean up map_config.
+ if (COMPILER_RT_STANDALONE_BUILD AND NOT LLVM_RUNTIMES_BUILD)
+ # If we have a valid source tree, generate llvm-lit into the bin directory.
+ # The user can still choose to have the check targets *use* a different lit
+ # by specifying -DLLVM_EXTERNAL_LIT, but we generate it regardless.
+ if (EXISTS ${LLVM_MAIN_SRC_DIR}/utils/llvm-lit)
+ # Needed for lit support in standalone builds.
+ include(AddLLVM)
+ add_subdirectory(${LLVM_MAIN_SRC_DIR}/utils/llvm-lit ${CMAKE_CURRENT_BINARY_DIR}/llvm-lit)
+ elseif(NOT EXISTS ${LLVM_EXTERNAL_LIT})
+ message(WARNING "Could not find LLVM source directory and LLVM_EXTERNAL_LIT does not"
+ "point to a valid file. You will not be able to run tests.")
+ endif()
+ endif()
+endif()
+
+add_subdirectory(tools)
diff --git a/contrib/libs/cxxsupp/builtins/CODE_OWNERS.TXT b/contrib/libs/cxxsupp/builtins/CODE_OWNERS.TXT
new file mode 100644
index 0000000000..80f7a93efc
--- /dev/null
+++ b/contrib/libs/cxxsupp/builtins/CODE_OWNERS.TXT
@@ -0,0 +1,61 @@
+This file is a list of the people responsible for ensuring that patches for a
+particular part of compiler-rt are reviewed, either by themself or by
+someone else. They are also the gatekeepers for their part of compiler-rt, with
+the final word on what goes in or not.
+
+The list is sorted by surname and formatted to allow easy grepping and
+beautification by scripts. The fields are: name (N), email (E), web-address
+(W), PGP key ID and fingerprint (P), description (D), and snail-mail address
+(S).
+
+N: Saleem Abdulrasool
+E: compnerd@compnerd.org
+D: builtins library
+
+N: Vitaly Buka
+E: vitalybuka@google.com
+D: Sanitizers
+
+N: Peter Collingbourne
+E: peter@pcc.me.uk
+D: CFI, SafeStack
+
+N: Lang Hames
+E: lhames@gmail.com
+D: ORC
+
+N: Petr Hosek
+E: phosek@google.com
+D: CRT, CMake build
+
+N: Teresa Johnson
+E: tejohnson@google.com
+D: MemProf
+
+N: Mitch Phillips
+E: mitchp@google.com
+D: GWP ASAN
+
+N: Alexander Potapenko
+E: glider@google.com
+D: Sanitizers
+
+N: Kostya Serebryany
+E: kcc@google.com
+D: AddressSanitizer, sanitizer_common, LeakSanitizer, LibFuzzer
+
+N: Richard Smith
+E: richard-llvm@metafoo.co.uk
+D: UndefinedBehaviorSanitizer
+
+N: Evgeniy Stepanov
+E: eugenis@google.com
+D: MemorySanitizer, Android port of sanitizers
+
+N: Dmitry Vyukov
+E: dvyukov@google.com
+D: ThreadSanitizer
+
+N: Bill Wendling
+E: isanbard@gmail.com
+D: Profile runtime library
diff --git a/contrib/libs/cxxsupp/builtins/CREDITS.TXT b/contrib/libs/cxxsupp/builtins/CREDITS.TXT
new file mode 100644
index 0000000000..6964eba020
--- /dev/null
+++ b/contrib/libs/cxxsupp/builtins/CREDITS.TXT
@@ -0,0 +1,36 @@
+This file is a partial list of people who have contributed to the LLVM/CompilerRT
+project. If you have contributed a patch or made some other contribution to
+LLVM/CompilerRT, please submit a patch to this file to add yourself, and it will be
+done!
+
+The list is sorted by surname and formatted to allow easy grepping and
+beautification by scripts. The fields are: name (N), email (E), web-address
+(W), PGP key ID and fingerprint (P), description (D), and snail-mail address
+(S).
+
+N: Craig van Vliet
+E: cvanvliet@auroraux.org
+W: http://www.auroraux.org
+D: Code style and Readability fixes.
+
+N: Edward O'Callaghan
+E: eocallaghan@auroraux.org
+W: http://www.auroraux.org
+D: CMake'ify Compiler-RT build system
+D: Maintain Solaris & AuroraUX ports of Compiler-RT
+
+N: Howard Hinnant
+E: hhinnant@apple.com
+D: Architect and primary author of compiler-rt
+
+N: Guan-Hong Liu
+E: koviankevin@hotmail.com
+D: IEEE Quad-precision functions
+
+N: Joerg Sonnenberger
+E: joerg@NetBSD.org
+D: Maintains NetBSD port.
+
+N: Matt Thomas
+E: matt@NetBSD.org
+D: ARM improvements.
diff --git a/contrib/libs/cxxsupp/builtins/Darwin-excludes/10.4-x86_64.txt b/contrib/libs/cxxsupp/builtins/Darwin-excludes/10.4-x86_64.txt
deleted file mode 100644
index f2ee7fef0c..0000000000
--- a/contrib/libs/cxxsupp/builtins/Darwin-excludes/10.4-x86_64.txt
+++ /dev/null
@@ -1,35 +0,0 @@
-absvti2
-addvti3
-ashlti3
-ashrti3
-clzti2
-cmpti2
-ctzti2
-divti3
-ffsti2
-fixdfti
-fixsfti
-fixunsdfti
-fixunssfti
-fixunsxfti
-fixxfti
-floattidf
-floattisf
-floattixf
-floatuntidf
-floatuntisf
-floatuntixf
-lshrti3
-modti3
-muloti4
-multi3
-mulvti3
-negti2
-negvti2
-parityti2
-popcountti2
-subvti3
-ucmpti2
-udivmodti4
-udivti3
-umodti3
diff --git a/contrib/libs/cxxsupp/builtins/Darwin-excludes/10.4.txt b/contrib/libs/cxxsupp/builtins/Darwin-excludes/10.4.txt
deleted file mode 100644
index 70d3644f27..0000000000
--- a/contrib/libs/cxxsupp/builtins/Darwin-excludes/10.4.txt
+++ /dev/null
@@ -1,96 +0,0 @@
-apple_versioning
-absvdi2
-absvsi2
-adddf3
-addsf3
-addvdi3
-addvsi3
-ashldi3
-ashrdi3
-clear_cache
-clzdi2
-clzsi2
-cmpdi2
-ctzdi2
-ctzsi2
-divdc3
-divdf3
-divdi3
-divmoddi4
-divmodsi4
-divsc3
-divsf3
-divsi3
-divxc3
-enable_execute_stack
-comparedf2
-comparesf2
-extendhfsf2
-extendsfdf2
-ffsdi2
-fixdfdi
-fixdfsi
-fixsfdi
-fixsfsi
-fixunsdfdi
-fixunsdfsi
-fixunssfdi
-fixunssfsi
-fixunsxfdi
-fixunsxfsi
-fixxfdi
-floatdidf
-floatdisf
-floatdixf
-floatsidf
-floatsisf
-floatunsidf
-floatunsisf
-gcc_personality_v0
-gnu_f2h_ieee
-gnu_h2f_ieee
-lshrdi3
-moddi3
-modsi3
-muldc3
-muldf3
-muldi3
-mulodi4
-mulosi4
-mulsc3
-mulsf3
-mulvdi3
-mulvsi3
-mulxc3
-negdf2
-negdi2
-negsf2
-negvdi2
-negvsi2
-paritydi2
-paritysi2
-popcountdi2
-popcountsi2
-powidf2
-powisf2
-powixf2
-subdf3
-subsf3
-subvdi3
-subvsi3
-truncdfhf2
-truncdfsf2
-truncsfhf2
-ucmpdi2
-udivdi3
-udivmoddi4
-udivmodsi4
-udivsi3
-umoddi3
-umodsi3
-atomic_flag_clear
-atomic_flag_clear_explicit
-atomic_flag_test_and_set
-atomic_flag_test_and_set_explicit
-atomic_signal_fence
-atomic_thread_fence \ No newline at end of file
diff --git a/contrib/libs/cxxsupp/builtins/Darwin-excludes/osx-i386.txt b/contrib/libs/cxxsupp/builtins/Darwin-excludes/osx-i386.txt
index 60c0e2d650..f2ee7fef0c 100644
--- a/contrib/libs/cxxsupp/builtins/Darwin-excludes/osx-i386.txt
+++ b/contrib/libs/cxxsupp/builtins/Darwin-excludes/osx-i386.txt
@@ -1,5 +1,4 @@
absvti2
-addtf3
addvti3
ashlti3
ashrti3
@@ -7,7 +6,6 @@ clzti2
cmpti2
ctzti2
divti3
-divtf3
ffsti2
fixdfti
fixsfti
@@ -25,57 +23,12 @@ lshrti3
modti3
muloti4
multi3
-multf3
mulvti3
negti2
negvti2
parityti2
popcountti2
-powitf2
subvti3
-subtf3
-trampoline_setup
-ucmpti2
-udivmodti4
-udivti3
-umodti3
-absvti2
-addtf3
-addvti3
-ashlti3
-ashrti3
-clzti2
-cmpti2
-ctzti2
-divti3
-divtf3
-ffsti2
-fixdfti
-fixsfti
-fixunsdfti
-fixunssfti
-fixunsxfti
-fixxfti
-floattidf
-floattisf
-floattixf
-floatuntidf
-floatuntisf
-floatuntixf
-lshrti3
-modti3
-muloti4
-multi3
-multf3
-mulvti3
-negti2
-negvti2
-parityti2
-popcountti2
-powitf2
-subvti3
-subtf3
-trampoline_setup
ucmpti2
udivmodti4
udivti3
diff --git a/contrib/libs/cxxsupp/builtins/Darwin-excludes/osx-x86_64.txt b/contrib/libs/cxxsupp/builtins/Darwin-excludes/osx-x86_64.txt
deleted file mode 100644
index de1574e6ce..0000000000
--- a/contrib/libs/cxxsupp/builtins/Darwin-excludes/osx-x86_64.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-addtf3
-divtf3
-multf3
-powitf2
-subtf3
-trampoline_setup
-addtf3
-divtf3
-multf3
-powitf2
-subtf3
-trampoline_setup
diff --git a/contrib/libs/cxxsupp/builtins/Darwin-excludes/osx.txt b/contrib/libs/cxxsupp/builtins/Darwin-excludes/osx.txt
index 5db24000a1..6f9d0a7b24 100644
--- a/contrib/libs/cxxsupp/builtins/Darwin-excludes/osx.txt
+++ b/contrib/libs/cxxsupp/builtins/Darwin-excludes/osx.txt
@@ -1 +1,7 @@
apple_versioning
+addtf3
+divtf3
+multf3
+powitf2
+subtf3
+trampoline_setup
diff --git a/contrib/libs/cxxsupp/builtins/LICENSE.os_version_check.c.patch.txt b/contrib/libs/cxxsupp/builtins/LICENSE.TXT
index 5a79a1b9d5..5a79a1b9d5 100644
--- a/contrib/libs/cxxsupp/builtins/LICENSE.os_version_check.c.patch.txt
+++ b/contrib/libs/cxxsupp/builtins/LICENSE.TXT
diff --git a/contrib/libs/cxxsupp/builtins/LICENSE.os_version_check.c.txt b/contrib/libs/cxxsupp/builtins/LICENSE.os_version_check.c.txt
deleted file mode 100644
index 0134694e4e..0000000000
--- a/contrib/libs/cxxsupp/builtins/LICENSE.os_version_check.c.txt
+++ /dev/null
@@ -1,91 +0,0 @@
-==============================================================================
-compiler_rt License
-==============================================================================
-
-The compiler_rt library is dual licensed under both the University of Illinois
-"BSD-Like" license and the MIT license. As a user of this code you may choose
-to use it under either license. As a contributor, you agree to allow your code
-to be used under both.
-
-Full text of the relevant licenses is included below.
-
-==============================================================================
-
-University of Illinois/NCSA
-Open Source License
-
-Copyright (c) 2009-2018 by the contributors listed in CREDITS.TXT
-
-All rights reserved.
-
-Developed by:
-
- LLVM Team
-
- University of Illinois at Urbana-Champaign
-
- http://llvm.org
-
-Permission is hereby granted, free of charge, to any person obtaining a copy of
-this software and associated documentation files (the "Software"), to deal with
-the Software without restriction, including without limitation the rights to
-use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
-of the Software, and to permit persons to whom the Software is furnished to do
-so, subject to the following conditions:
-
- * Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimers.
-
- * Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimers in the
- documentation and/or other materials provided with the distribution.
-
- * Neither the names of the LLVM Team, University of Illinois at
- Urbana-Champaign, nor the names of its contributors may be used to
- endorse or promote products derived from this Software without specific
- prior written permission.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
-FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
-SOFTWARE.
-
-==============================================================================
-
-Copyright (c) 2009-2015 by the contributors listed in CREDITS.TXT
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
-
-==============================================================================
-Copyrights and Licenses for Third Party Software Distributed with LLVM:
-==============================================================================
-The LLVM software contains code written by third parties. Such software will
-have its own individual LICENSE.TXT file in the directory in which it appears.
-This file will describe the copyrights, license, and restrictions which apply
-to that code.
-
-The disclaimer of warranty in the University of Illinois Open Source License
-applies to all code in the LLVM Distribution, and nothing in any of the
-other licenses gives permission to use the names of the LLVM Team or the
-University of Illinois to endorse or promote products derived from this
-Software.
-
diff --git a/contrib/libs/cxxsupp/builtins/LICENSE.txt b/contrib/libs/cxxsupp/builtins/LICENSE.txt
deleted file mode 100644
index aa4115e2a7..0000000000
--- a/contrib/libs/cxxsupp/builtins/LICENSE.txt
+++ /dev/null
@@ -1,91 +0,0 @@
-==============================================================================
-compiler_rt License
-==============================================================================
-
-The compiler_rt library is dual licensed under both the University of Illinois
-"BSD-Like" license and the MIT license. As a user of this code you may choose
-to use it under either license. As a contributor, you agree to allow your code
-to be used under both.
-
-Full text of the relevant licenses is included below.
-
-==============================================================================
-
-University of Illinois/NCSA
-Open Source License
-
-Copyright (c) 2009-2015 by the contributors listed in CREDITS.TXT
-
-All rights reserved.
-
-Developed by:
-
- LLVM Team
-
- University of Illinois at Urbana-Champaign
-
- http://llvm.org
-
-Permission is hereby granted, free of charge, to any person obtaining a copy of
-this software and associated documentation files (the "Software"), to deal with
-the Software without restriction, including without limitation the rights to
-use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
-of the Software, and to permit persons to whom the Software is furnished to do
-so, subject to the following conditions:
-
- * Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimers.
-
- * Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimers in the
- documentation and/or other materials provided with the distribution.
-
- * Neither the names of the LLVM Team, University of Illinois at
- Urbana-Champaign, nor the names of its contributors may be used to
- endorse or promote products derived from this Software without specific
- prior written permission.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
-FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
-SOFTWARE.
-
-==============================================================================
-
-Copyright (c) 2009-2015 by the contributors listed in CREDITS.TXT
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
-
-==============================================================================
-Copyrights and Licenses for Third Party Software Distributed with LLVM:
-==============================================================================
-The LLVM software contains code written by third parties. Such software will
-have its own individual LICENSE.TXT file in the directory in which it appears.
-This file will describe the copyrights, license, and restrictions which apply
-to that code.
-
-The disclaimer of warranty in the University of Illinois Open Source License
-applies to all code in the LLVM Distribution, and nothing in any of the
-other licenses gives permission to use the names of the LLVM Team or the
-University of Illinois to endorse or promote products derived from this
-Software.
-
diff --git a/contrib/libs/cxxsupp/builtins/README.txt b/contrib/libs/cxxsupp/builtins/README.txt
index ad36e4e527..53d656d508 100644
--- a/contrib/libs/cxxsupp/builtins/README.txt
+++ b/contrib/libs/cxxsupp/builtins/README.txt
@@ -20,13 +20,18 @@ Here is the specification for this library:
http://gcc.gnu.org/onlinedocs/gccint/Libgcc.html#Libgcc
+Please note that the libgcc specification explicitly mentions actual types of
+arguments and returned values being expressed with machine modes.
+In some cases particular types such as "int", "unsigned", "long long", etc.
+may be specified just as examples there.
+
Here is a synopsis of the contents of this library:
-typedef int si_int;
-typedef unsigned su_int;
+typedef int32_t si_int;
+typedef uint32_t su_int;
-typedef long long di_int;
-typedef unsigned long long du_int;
+typedef int64_t di_int;
+typedef uint64_t du_int;
// Integral bit manipulation
@@ -38,26 +43,27 @@ ti_int __ashrti3(ti_int a, si_int b); // a >> b arithmetic (sign fill)
di_int __lshrdi3(di_int a, si_int b); // a >> b logical (zero fill)
ti_int __lshrti3(ti_int a, si_int b); // a >> b logical (zero fill)
-si_int __clzsi2(si_int a); // count leading zeros
-si_int __clzdi2(di_int a); // count leading zeros
-si_int __clzti2(ti_int a); // count leading zeros
-si_int __ctzsi2(si_int a); // count trailing zeros
-si_int __ctzdi2(di_int a); // count trailing zeros
-si_int __ctzti2(ti_int a); // count trailing zeros
+int __clzsi2(si_int a); // count leading zeros
+int __clzdi2(di_int a); // count leading zeros
+int __clzti2(ti_int a); // count leading zeros
+int __ctzsi2(si_int a); // count trailing zeros
+int __ctzdi2(di_int a); // count trailing zeros
+int __ctzti2(ti_int a); // count trailing zeros
-si_int __ffsdi2(di_int a); // find least significant 1 bit
-si_int __ffsti2(ti_int a); // find least significant 1 bit
+int __ffssi2(si_int a); // find least significant 1 bit
+int __ffsdi2(di_int a); // find least significant 1 bit
+int __ffsti2(ti_int a); // find least significant 1 bit
-si_int __paritysi2(si_int a); // bit parity
-si_int __paritydi2(di_int a); // bit parity
-si_int __parityti2(ti_int a); // bit parity
+int __paritysi2(si_int a); // bit parity
+int __paritydi2(di_int a); // bit parity
+int __parityti2(ti_int a); // bit parity
-si_int __popcountsi2(si_int a); // bit population
-si_int __popcountdi2(di_int a); // bit population
-si_int __popcountti2(ti_int a); // bit population
+int __popcountsi2(si_int a); // bit population
+int __popcountdi2(di_int a); // bit population
+int __popcountti2(ti_int a); // bit population
-uint32_t __bswapsi2(uint32_t a); // a byteswapped, arm only
-uint64_t __bswapdi2(uint64_t a); // a byteswapped, arm only
+uint32_t __bswapsi2(uint32_t a); // a byteswapped
+uint64_t __bswapdi2(uint64_t a); // a byteswapped
// Integral arithmetic
@@ -81,6 +87,8 @@ du_int __udivmoddi4(du_int a, du_int b, du_int* rem); // a / b, *rem = a % b u
tu_int __udivmodti4(tu_int a, tu_int b, tu_int* rem); // a / b, *rem = a % b unsigned
su_int __udivmodsi4(su_int a, su_int b, su_int* rem); // a / b, *rem = a % b unsigned
si_int __divmodsi4(si_int a, si_int b, si_int* rem); // a / b, *rem = a % b signed
+di_int __divmoddi4(di_int a, di_int b, di_int* rem); // a / b, *rem = a % b signed
+ti_int __divmodti4(ti_int a, ti_int b, ti_int* rem); // a / b, *rem = a % b signed
@@ -168,10 +176,10 @@ long double __floatuntixf(tu_int a);
// Floating point raised to integer power
-float __powisf2( float a, si_int b); // a ^ b
-double __powidf2( double a, si_int b); // a ^ b
-long double __powixf2(long double a, si_int b); // a ^ b
-long double __powitf2(long double a, si_int b); // ppc only, a ^ b
+float __powisf2( float a, int b); // a ^ b
+double __powidf2( double a, int b); // a ^ b
+long double __powixf2(long double a, int b); // a ^ b
+long double __powitf2(long double a, int b); // ppc only, a ^ b
// Complex arithmetic
@@ -263,8 +271,8 @@ switchu8
// There is no C interface to the *_vfp_d8_d15_regs functions. There are
// called in the prolog and epilog of Thumb1 functions. When the C++ ABI use
-// SJLJ for exceptions, each function with a catch clause or destuctors needs
-// to save and restore all registers in it prolog and epliog. But there is
+// SJLJ for exceptions, each function with a catch clause or destructors needs
+// to save and restore all registers in it prolog and epilog. But there is
// no way to access vector and high float registers from thumb1 code, so the
// compiler must add call outs to these helper functions in the prolog and
// epilog.
@@ -303,9 +311,9 @@ double __floatsidfvfp(int a); // Appears to convert from
float __floatsisfvfp(int a); // Appears to convert from
// int to float.
double __floatunssidfvfp(unsigned int a); // Appears to convert from
- // unisgned int to double.
+ // unsigned int to double.
float __floatunssisfvfp(unsigned int a); // Appears to convert from
- // unisgned int to float.
+ // unsigned int to float.
int __gedf2vfp(double a, double b); // Appears to return __gedf2
// (a >= b)
int __gesf2vfp(float a, float b); // Appears to return __gesf2
diff --git a/contrib/libs/cxxsupp/builtins/aarch64/chkstk.S b/contrib/libs/cxxsupp/builtins/aarch64/chkstk.S
new file mode 100644
index 0000000000..01f90366f0
--- /dev/null
+++ b/contrib/libs/cxxsupp/builtins/aarch64/chkstk.S
@@ -0,0 +1,35 @@
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+#include "../assembly.h"
+
+// __chkstk routine
+// This routine is windows specific.
+// http://msdn.microsoft.com/en-us/library/ms648426.aspx
+
+// This clobbers registers x16 and x17.
+// Does not modify any memory or the stack pointer.
+
+// mov x15, #256 // Number of bytes of stack, in units of 16 byte
+// bl __chkstk
+// sub sp, sp, x15, lsl #4
+
+#ifdef __aarch64__
+
+#define PAGE_SIZE 4096
+
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__chkstk)
+ lsl x16, x15, #4
+ mov x17, sp
+1:
+ sub x17, x17, #PAGE_SIZE
+ subs x16, x16, #PAGE_SIZE
+ ldr xzr, [x17]
+ b.gt 1b
+
+ ret
+END_COMPILERRT_FUNCTION(__chkstk)
+
+#endif // __aarch64__
diff --git a/contrib/libs/cxxsupp/builtins/aarch64/fp_mode.c b/contrib/libs/cxxsupp/builtins/aarch64/fp_mode.c
new file mode 100644
index 0000000000..03d75cd8be
--- /dev/null
+++ b/contrib/libs/cxxsupp/builtins/aarch64/fp_mode.c
@@ -0,0 +1,60 @@
+//===----- lib/aarch64/fp_mode.c - Floaing-point mode utilities ---*- C -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include <stdint.h>
+
+#include "../fp_mode.h"
+
+#define AARCH64_TONEAREST 0x0
+#define AARCH64_UPWARD 0x1
+#define AARCH64_DOWNWARD 0x2
+#define AARCH64_TOWARDZERO 0x3
+#define AARCH64_RMODE_MASK (AARCH64_TONEAREST | AARCH64_UPWARD | \
+ AARCH64_DOWNWARD | AARCH64_TOWARDZERO)
+#define AARCH64_RMODE_SHIFT 22
+
+#define AARCH64_INEXACT 0x10
+
+#ifndef __ARM_FP
+// For soft float targets, allow changing rounding mode by overriding the weak
+// __aarch64_fe_default_rmode symbol.
+CRT_FE_ROUND_MODE __attribute__((weak)) __aarch64_fe_default_rmode =
+ CRT_FE_TONEAREST;
+#endif
+
+CRT_FE_ROUND_MODE __fe_getround(void) {
+#ifdef __ARM_FP
+ uint64_t fpcr;
+ __asm__ __volatile__("mrs %0, fpcr" : "=r" (fpcr));
+ fpcr = fpcr >> AARCH64_RMODE_SHIFT & AARCH64_RMODE_MASK;
+ switch (fpcr) {
+ case AARCH64_UPWARD:
+ return CRT_FE_UPWARD;
+ case AARCH64_DOWNWARD:
+ return CRT_FE_DOWNWARD;
+ case AARCH64_TOWARDZERO:
+ return CRT_FE_TOWARDZERO;
+ case AARCH64_TONEAREST:
+ default:
+ return CRT_FE_TONEAREST;
+ }
+#else
+ return __aarch64_fe_default_rmode;
+#endif
+}
+
+int __fe_raise_inexact(void) {
+#ifdef __ARM_FP
+ uint64_t fpsr;
+ __asm__ __volatile__("mrs %0, fpsr" : "=r" (fpsr));
+ __asm__ __volatile__("msr fpsr, %0" : : "ri" (fpsr | AARCH64_INEXACT));
+ return 0;
+#else
+ return 0;
+#endif
+}
diff --git a/contrib/libs/cxxsupp/builtins/absvdi2.c b/contrib/libs/cxxsupp/builtins/absvdi2.c
index 682c2355d2..b9566cd874 100644
--- a/contrib/libs/cxxsupp/builtins/absvdi2.c
+++ b/contrib/libs/cxxsupp/builtins/absvdi2.c
@@ -1,29 +1,25 @@
-/*===-- absvdi2.c - Implement __absvdi2 -----------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- *===----------------------------------------------------------------------===
- *
- * This file implements __absvdi2 for the compiler_rt library.
- *
- *===----------------------------------------------------------------------===
- */
+//===-- absvdi2.c - Implement __absvdi2 -----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __absvdi2 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
-/* Returns: absolute value */
+// Returns: absolute value
-/* Effects: aborts if abs(x) < 0 */
+// Effects: aborts if abs(x) < 0
-COMPILER_RT_ABI di_int
-__absvdi2(di_int a)
-{
- const int N = (int)(sizeof(di_int) * CHAR_BIT);
- if (a == ((di_int)1 << (N-1)))
- compilerrt_abort();
- const di_int t = a >> (N - 1);
- return (a ^ t) - t;
+COMPILER_RT_ABI di_int __absvdi2(di_int a) {
+ const int N = (int)(sizeof(di_int) * CHAR_BIT);
+ if (a == ((di_int)1 << (N - 1)))
+ compilerrt_abort();
+ const di_int t = a >> (N - 1);
+ return (a ^ t) - t;
}
diff --git a/contrib/libs/cxxsupp/builtins/absvsi2.c b/contrib/libs/cxxsupp/builtins/absvsi2.c
index 4812af8159..9d5de7e8a3 100644
--- a/contrib/libs/cxxsupp/builtins/absvsi2.c
+++ b/contrib/libs/cxxsupp/builtins/absvsi2.c
@@ -1,29 +1,25 @@
-/* ===-- absvsi2.c - Implement __absvsi2 -----------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __absvsi2 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- absvsi2.c - Implement __absvsi2 -----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __absvsi2 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
-/* Returns: absolute value */
+// Returns: absolute value
-/* Effects: aborts if abs(x) < 0 */
+// Effects: aborts if abs(x) < 0
-COMPILER_RT_ABI si_int
-__absvsi2(si_int a)
-{
- const int N = (int)(sizeof(si_int) * CHAR_BIT);
- if (a == (1 << (N-1)))
- compilerrt_abort();
- const si_int t = a >> (N - 1);
- return (a ^ t) - t;
+COMPILER_RT_ABI si_int __absvsi2(si_int a) {
+ const int N = (int)(sizeof(si_int) * CHAR_BIT);
+ if (a == ((si_int)1 << (N - 1)))
+ compilerrt_abort();
+ const si_int t = a >> (N - 1);
+ return (a ^ t) - t;
}
diff --git a/contrib/libs/cxxsupp/builtins/absvti2.c b/contrib/libs/cxxsupp/builtins/absvti2.c
index 7927770c9a..491d99d7ce 100644
--- a/contrib/libs/cxxsupp/builtins/absvti2.c
+++ b/contrib/libs/cxxsupp/builtins/absvti2.c
@@ -1,34 +1,29 @@
-/* ===-- absvti2.c - Implement __absvdi2 -----------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __absvti2 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- absvti2.c - Implement __absvdi2 -----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __absvti2 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
#ifdef CRT_HAS_128BIT
-/* Returns: absolute value */
+// Returns: absolute value
-/* Effects: aborts if abs(x) < 0 */
+// Effects: aborts if abs(x) < 0
-COMPILER_RT_ABI ti_int
-__absvti2(ti_int a)
-{
- const int N = (int)(sizeof(ti_int) * CHAR_BIT);
- if (a == ((ti_int)1 << (N-1)))
- compilerrt_abort();
- const ti_int s = a >> (N - 1);
- return (a ^ s) - s;
+COMPILER_RT_ABI ti_int __absvti2(ti_int a) {
+ const int N = (int)(sizeof(ti_int) * CHAR_BIT);
+ if (a == ((ti_int)1 << (N - 1)))
+ compilerrt_abort();
+ const ti_int s = a >> (N - 1);
+ return (a ^ s) - s;
}
-#endif /* CRT_HAS_128BIT */
-
+#endif // CRT_HAS_128BIT
diff --git a/contrib/libs/cxxsupp/builtins/adddf3.c b/contrib/libs/cxxsupp/builtins/adddf3.c
index 8b7aae0a6f..26f11bfa22 100644
--- a/contrib/libs/cxxsupp/builtins/adddf3.c
+++ b/contrib/libs/cxxsupp/builtins/adddf3.c
@@ -1,22 +1,24 @@
//===-- lib/adddf3.c - Double-precision addition ------------------*- C -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
-// This file implements double-precision soft-float addition with the IEEE-754
-// default rounding (to nearest, ties to even).
+// This file implements double-precision soft-float addition.
//
//===----------------------------------------------------------------------===//
#define DOUBLE_PRECISION
#include "fp_add_impl.inc"
-ARM_EABI_FNALIAS(dadd, adddf3)
+COMPILER_RT_ABI double __adddf3(double a, double b) { return __addXf3__(a, b); }
-COMPILER_RT_ABI double __adddf3(double a, double b){
- return __addXf3__(a, b);
-}
+#if defined(__ARM_EABI__)
+#if defined(COMPILER_RT_ARMHF_TARGET)
+AEABI_RTABI double __aeabi_dadd(double a, double b) { return __adddf3(a, b); }
+#else
+COMPILER_RT_ALIAS(__adddf3, __aeabi_dadd)
+#endif
+#endif
diff --git a/contrib/libs/cxxsupp/builtins/addsf3.c b/contrib/libs/cxxsupp/builtins/addsf3.c
index 0f5d6ea409..9f1d517c1f 100644
--- a/contrib/libs/cxxsupp/builtins/addsf3.c
+++ b/contrib/libs/cxxsupp/builtins/addsf3.c
@@ -1,22 +1,24 @@
//===-- lib/addsf3.c - Single-precision addition ------------------*- C -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
-// This file implements single-precision soft-float addition with the IEEE-754
-// default rounding (to nearest, ties to even).
+// This file implements single-precision soft-float addition.
//
//===----------------------------------------------------------------------===//
#define SINGLE_PRECISION
#include "fp_add_impl.inc"
-ARM_EABI_FNALIAS(fadd, addsf3)
+COMPILER_RT_ABI float __addsf3(float a, float b) { return __addXf3__(a, b); }
-COMPILER_RT_ABI float __addsf3(float a, float b) {
- return __addXf3__(a, b);
-}
+#if defined(__ARM_EABI__)
+#if defined(COMPILER_RT_ARMHF_TARGET)
+AEABI_RTABI float __aeabi_fadd(float a, float b) { return __addsf3(a, b); }
+#else
+COMPILER_RT_ALIAS(__addsf3, __aeabi_fadd)
+#endif
+#endif
diff --git a/contrib/libs/cxxsupp/builtins/addtf3.c b/contrib/libs/cxxsupp/builtins/addtf3.c
index e4bbe0227a..86e4f4cfc3 100644
--- a/contrib/libs/cxxsupp/builtins/addtf3.c
+++ b/contrib/libs/cxxsupp/builtins/addtf3.c
@@ -1,14 +1,12 @@
//===-- lib/addtf3.c - Quad-precision addition --------------------*- C -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
-// This file implements quad-precision soft-float addition with the IEEE-754
-// default rounding (to nearest, ties to even).
+// This file implements quad-precision soft-float addition.
//
//===----------------------------------------------------------------------===//
@@ -18,8 +16,8 @@
#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT)
#include "fp_add_impl.inc"
-COMPILER_RT_ABI long double __addtf3(long double a, long double b){
- return __addXf3__(a, b);
+COMPILER_RT_ABI fp_t __addtf3(fp_t a, fp_t b) {
+ return __addXf3__(a, b);
}
#endif
diff --git a/contrib/libs/cxxsupp/builtins/addvdi3.c b/contrib/libs/cxxsupp/builtins/addvdi3.c
index 0da3894567..28661fda84 100644
--- a/contrib/libs/cxxsupp/builtins/addvdi3.c
+++ b/contrib/libs/cxxsupp/builtins/addvdi3.c
@@ -1,36 +1,29 @@
-/* ===-- addvdi3.c - Implement __addvdi3 -----------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __addvdi3 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- addvdi3.c - Implement __addvdi3 -----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __addvdi3 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
-/* Returns: a + b */
+// Returns: a + b
-/* Effects: aborts if a + b overflows */
+// Effects: aborts if a + b overflows
-COMPILER_RT_ABI di_int
-__addvdi3(di_int a, di_int b)
-{
- di_int s = (du_int) a + (du_int) b;
- if (b >= 0)
- {
- if (s < a)
- compilerrt_abort();
- }
- else
- {
- if (s >= a)
- compilerrt_abort();
- }
- return s;
+COMPILER_RT_ABI di_int __addvdi3(di_int a, di_int b) {
+ di_int s = (du_int)a + (du_int)b;
+ if (b >= 0) {
+ if (s < a)
+ compilerrt_abort();
+ } else {
+ if (s >= a)
+ compilerrt_abort();
+ }
+ return s;
}
diff --git a/contrib/libs/cxxsupp/builtins/addvsi3.c b/contrib/libs/cxxsupp/builtins/addvsi3.c
index 94ca726f42..4040023752 100644
--- a/contrib/libs/cxxsupp/builtins/addvsi3.c
+++ b/contrib/libs/cxxsupp/builtins/addvsi3.c
@@ -1,36 +1,29 @@
-/* ===-- addvsi3.c - Implement __addvsi3 -----------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __addvsi3 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- addvsi3.c - Implement __addvsi3 -----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __addvsi3 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
-/* Returns: a + b */
+// Returns: a + b
-/* Effects: aborts if a + b overflows */
+// Effects: aborts if a + b overflows
-COMPILER_RT_ABI si_int
-__addvsi3(si_int a, si_int b)
-{
- si_int s = (su_int) a + (su_int) b;
- if (b >= 0)
- {
- if (s < a)
- compilerrt_abort();
- }
- else
- {
- if (s >= a)
- compilerrt_abort();
- }
- return s;
+COMPILER_RT_ABI si_int __addvsi3(si_int a, si_int b) {
+ si_int s = (su_int)a + (su_int)b;
+ if (b >= 0) {
+ if (s < a)
+ compilerrt_abort();
+ } else {
+ if (s >= a)
+ compilerrt_abort();
+ }
+ return s;
}
diff --git a/contrib/libs/cxxsupp/builtins/addvti3.c b/contrib/libs/cxxsupp/builtins/addvti3.c
index c224de60aa..aa709875d2 100644
--- a/contrib/libs/cxxsupp/builtins/addvti3.c
+++ b/contrib/libs/cxxsupp/builtins/addvti3.c
@@ -1,40 +1,33 @@
-/* ===-- addvti3.c - Implement __addvti3 -----------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __addvti3 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- addvti3.c - Implement __addvti3 -----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __addvti3 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
#ifdef CRT_HAS_128BIT
-/* Returns: a + b */
+// Returns: a + b
-/* Effects: aborts if a + b overflows */
+// Effects: aborts if a + b overflows
-COMPILER_RT_ABI ti_int
-__addvti3(ti_int a, ti_int b)
-{
- ti_int s = (tu_int) a + (tu_int) b;
- if (b >= 0)
- {
- if (s < a)
- compilerrt_abort();
- }
- else
- {
- if (s >= a)
- compilerrt_abort();
- }
- return s;
+COMPILER_RT_ABI ti_int __addvti3(ti_int a, ti_int b) {
+ ti_int s = (tu_int)a + (tu_int)b;
+ if (b >= 0) {
+ if (s < a)
+ compilerrt_abort();
+ } else {
+ if (s >= a)
+ compilerrt_abort();
+ }
+ return s;
}
-#endif /* CRT_HAS_128BIT */
+#endif // CRT_HAS_128BIT
diff --git a/contrib/libs/cxxsupp/builtins/apple_versioning.c b/contrib/libs/cxxsupp/builtins/apple_versioning.c
index 3797a1ab02..83d419418f 100644
--- a/contrib/libs/cxxsupp/builtins/apple_versioning.c
+++ b/contrib/libs/cxxsupp/builtins/apple_versioning.c
@@ -1,47 +1,42 @@
-/* ===-- apple_versioning.c - Adds versioning symbols for ld ---------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- */
-
+//===-- apple_versioning.c - Adds versioning symbols for ld ---------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
#if __APPLE__
- #include <Availability.h>
-
- #if __IPHONE_OS_VERSION_MIN_REQUIRED
- #define NOT_HERE_BEFORE_10_6(sym)
- #define NOT_HERE_IN_10_8_AND_EARLIER(sym) \
- extern const char sym##_tmp61 __asm("$ld$hide$os6.1$_" #sym ); \
- __attribute__((visibility("default"))) const char sym##_tmp61 = 0; \
- extern const char sym##_tmp60 __asm("$ld$hide$os6.0$_" #sym ); \
- __attribute__((visibility("default"))) const char sym##_tmp60 = 0; \
- extern const char sym##_tmp51 __asm("$ld$hide$os5.1$_" #sym ); \
- __attribute__((visibility("default"))) const char sym##_tmp51 = 0; \
- extern const char sym##_tmp50 __asm("$ld$hide$os5.0$_" #sym ); \
- __attribute__((visibility("default"))) const char sym##_tmp50 = 0;
- #else
- #define NOT_HERE_BEFORE_10_6(sym) \
- extern const char sym##_tmp4 __asm("$ld$hide$os10.4$_" #sym ); \
- __attribute__((visibility("default"))) const char sym##_tmp4 = 0; \
- extern const char sym##_tmp5 __asm("$ld$hide$os10.5$_" #sym ); \
- __attribute__((visibility("default"))) const char sym##_tmp5 = 0;
- #define NOT_HERE_IN_10_8_AND_EARLIER(sym) \
- extern const char sym##_tmp8 __asm("$ld$hide$os10.8$_" #sym ); \
- __attribute__((visibility("default"))) const char sym##_tmp8 = 0; \
- extern const char sym##_tmp7 __asm("$ld$hide$os10.7$_" #sym ); \
- __attribute__((visibility("default"))) const char sym##_tmp7 = 0; \
- extern const char sym##_tmp6 __asm("$ld$hide$os10.6$_" #sym ); \
- __attribute__((visibility("default"))) const char sym##_tmp6 = 0;
- #endif
+#include <Availability.h>
+#if __IPHONE_OS_VERSION_MIN_REQUIRED
+#define NOT_HERE_BEFORE_10_6(sym)
+#define NOT_HERE_IN_10_8_AND_EARLIER(sym) \
+ extern const char sym##_tmp61 __asm("$ld$hide$os6.1$_" #sym); \
+ __attribute__((visibility("default"))) const char sym##_tmp61 = 0; \
+ extern const char sym##_tmp60 __asm("$ld$hide$os6.0$_" #sym); \
+ __attribute__((visibility("default"))) const char sym##_tmp60 = 0; \
+ extern const char sym##_tmp51 __asm("$ld$hide$os5.1$_" #sym); \
+ __attribute__((visibility("default"))) const char sym##_tmp51 = 0; \
+ extern const char sym##_tmp50 __asm("$ld$hide$os5.0$_" #sym); \
+ __attribute__((visibility("default"))) const char sym##_tmp50 = 0;
+#else
+#define NOT_HERE_BEFORE_10_6(sym) \
+ extern const char sym##_tmp4 __asm("$ld$hide$os10.4$_" #sym); \
+ __attribute__((visibility("default"))) const char sym##_tmp4 = 0; \
+ extern const char sym##_tmp5 __asm("$ld$hide$os10.5$_" #sym); \
+ __attribute__((visibility("default"))) const char sym##_tmp5 = 0;
+#define NOT_HERE_IN_10_8_AND_EARLIER(sym) \
+ extern const char sym##_tmp8 __asm("$ld$hide$os10.8$_" #sym); \
+ __attribute__((visibility("default"))) const char sym##_tmp8 = 0; \
+ extern const char sym##_tmp7 __asm("$ld$hide$os10.7$_" #sym); \
+ __attribute__((visibility("default"))) const char sym##_tmp7 = 0; \
+ extern const char sym##_tmp6 __asm("$ld$hide$os10.6$_" #sym); \
+ __attribute__((visibility("default"))) const char sym##_tmp6 = 0;
+#endif
-/* Symbols in libSystem.dylib in 10.6 and later,
- * but are in libgcc_s.dylib in earlier versions
- */
+// Symbols in libSystem.dylib in 10.6 and later,
+// but are in libgcc_s.dylib in earlier versions
NOT_HERE_BEFORE_10_6(__absvdi2)
NOT_HERE_BEFORE_10_6(__absvsi2)
@@ -143,14 +138,13 @@ NOT_HERE_BEFORE_10_6(__udivti3)
NOT_HERE_BEFORE_10_6(__umoddi3)
NOT_HERE_BEFORE_10_6(__umodti3)
-
-#if __ppc__
+#if __powerpc__
NOT_HERE_BEFORE_10_6(__gcc_qadd)
NOT_HERE_BEFORE_10_6(__gcc_qdiv)
NOT_HERE_BEFORE_10_6(__gcc_qmul)
NOT_HERE_BEFORE_10_6(__gcc_qsub)
NOT_HERE_BEFORE_10_6(__trampoline_setup)
-#endif /* __ppc__ */
+#endif // __powerpc__
NOT_HERE_IN_10_8_AND_EARLIER(__atomic_compare_exchange)
NOT_HERE_IN_10_8_AND_EARLIER(__atomic_compare_exchange_1)
@@ -201,24 +195,23 @@ NOT_HERE_IN_10_8_AND_EARLIER(__atomic_store_2)
NOT_HERE_IN_10_8_AND_EARLIER(__atomic_store_4)
NOT_HERE_IN_10_8_AND_EARLIER(__atomic_store_8)
-
#if __arm__ && __DYNAMIC__
- #define NOT_HERE_UNTIL_AFTER_4_3(sym) \
- extern const char sym##_tmp1 __asm("$ld$hide$os3.0$_" #sym ); \
- __attribute__((visibility("default"))) const char sym##_tmp1 = 0; \
- extern const char sym##_tmp2 __asm("$ld$hide$os3.1$_" #sym ); \
- __attribute__((visibility("default"))) const char sym##_tmp2 = 0; \
- extern const char sym##_tmp3 __asm("$ld$hide$os3.2$_" #sym ); \
- __attribute__((visibility("default"))) const char sym##_tmp3 = 0; \
- extern const char sym##_tmp4 __asm("$ld$hide$os4.0$_" #sym ); \
- __attribute__((visibility("default"))) const char sym##_tmp4 = 0; \
- extern const char sym##_tmp5 __asm("$ld$hide$os4.1$_" #sym ); \
- __attribute__((visibility("default"))) const char sym##_tmp5 = 0; \
- extern const char sym##_tmp6 __asm("$ld$hide$os4.2$_" #sym ); \
- __attribute__((visibility("default"))) const char sym##_tmp6 = 0; \
- extern const char sym##_tmp7 __asm("$ld$hide$os4.3$_" #sym ); \
- __attribute__((visibility("default"))) const char sym##_tmp7 = 0;
-
+#define NOT_HERE_UNTIL_AFTER_4_3(sym) \
+ extern const char sym##_tmp1 __asm("$ld$hide$os3.0$_" #sym); \
+ __attribute__((visibility("default"))) const char sym##_tmp1 = 0; \
+ extern const char sym##_tmp2 __asm("$ld$hide$os3.1$_" #sym); \
+ __attribute__((visibility("default"))) const char sym##_tmp2 = 0; \
+ extern const char sym##_tmp3 __asm("$ld$hide$os3.2$_" #sym); \
+ __attribute__((visibility("default"))) const char sym##_tmp3 = 0; \
+ extern const char sym##_tmp4 __asm("$ld$hide$os4.0$_" #sym); \
+ __attribute__((visibility("default"))) const char sym##_tmp4 = 0; \
+ extern const char sym##_tmp5 __asm("$ld$hide$os4.1$_" #sym); \
+ __attribute__((visibility("default"))) const char sym##_tmp5 = 0; \
+ extern const char sym##_tmp6 __asm("$ld$hide$os4.2$_" #sym); \
+ __attribute__((visibility("default"))) const char sym##_tmp6 = 0; \
+ extern const char sym##_tmp7 __asm("$ld$hide$os4.3$_" #sym); \
+ __attribute__((visibility("default"))) const char sym##_tmp7 = 0;
+
NOT_HERE_UNTIL_AFTER_4_3(__absvdi2)
NOT_HERE_UNTIL_AFTER_4_3(__absvsi2)
NOT_HERE_UNTIL_AFTER_4_3(__adddf3)
@@ -339,12 +332,8 @@ NOT_HERE_UNTIL_AFTER_4_3(__divmodsi4)
NOT_HERE_UNTIL_AFTER_4_3(__udivmodsi4)
#endif // __arm__ && __DYNAMIC__
-
-
-
-
-#else /* !__APPLE__ */
+#else // !__APPLE__
extern int avoid_empty_file;
-#endif /* !__APPLE__*/
+#endif // !__APPLE__
diff --git a/contrib/libs/cxxsupp/builtins/arm/Makefile.mk b/contrib/libs/cxxsupp/builtins/arm/Makefile.mk
deleted file mode 100644
index ed2e8323e3..0000000000
--- a/contrib/libs/cxxsupp/builtins/arm/Makefile.mk
+++ /dev/null
@@ -1,20 +0,0 @@
-#===- lib/builtins/arm/Makefile.mk -------------------------*- Makefile -*--===#
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-#===------------------------------------------------------------------------===#
-
-ModuleName := builtins
-SubDirs :=
-OnlyArchs := armv5 armv6 armv7 armv7k armv7m armv7em armv7s
-
-AsmSources := $(foreach file,$(wildcard $(Dir)/*.S),$(notdir $(file)))
-Sources := $(foreach file,$(wildcard $(Dir)/*.c),$(notdir $(file)))
-ObjNames := $(Sources:%.c=%.o) $(AsmSources:%.S=%.o)
-Implementation := Optimized
-
-# FIXME: use automatic dependencies?
-Dependencies := $(wildcard lib/*.h $(Dir)/*.h)
diff --git a/contrib/libs/cxxsupp/builtins/arm/adddf3vfp.S b/contrib/libs/cxxsupp/builtins/arm/adddf3vfp.S
index 2825ae92cd..1a271db084 100644
--- a/contrib/libs/cxxsupp/builtins/arm/adddf3vfp.S
+++ b/contrib/libs/cxxsupp/builtins/arm/adddf3vfp.S
@@ -1,26 +1,31 @@
//===-- adddf3vfp.S - Implement adddf3vfp ---------------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "../assembly.h"
-//
// double __adddf3vfp(double a, double b) { return a + b; }
//
// Adds two double precision floating point numbers using the Darwin
// calling convention where double arguments are passsed in GPR pairs
-//
+
.syntax unified
.p2align 2
DEFINE_COMPILERRT_FUNCTION(__adddf3vfp)
+#if defined(COMPILER_RT_ARMHF_TARGET)
+ vadd.f64 d0, d0, d1
+#else
vmov d6, r0, r1 // move first param from r0/r1 pair into d6
vmov d7, r2, r3 // move second param from r2/r3 pair into d7
- vadd.f64 d6, d6, d7
+ vadd.f64 d6, d6, d7
vmov r0, r1, d6 // move result back to r0/r1 pair
+#endif
bx lr
END_COMPILERRT_FUNCTION(__adddf3vfp)
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/addsf3.S b/contrib/libs/cxxsupp/builtins/arm/addsf3.S
new file mode 100644
index 0000000000..aa4d40473e
--- /dev/null
+++ b/contrib/libs/cxxsupp/builtins/arm/addsf3.S
@@ -0,0 +1,276 @@
+//===-- addsf3.S - Adds two single precision floating pointer numbers-----===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the __addsf3 (single precision floating pointer number
+// addition with the IEEE-754 default rounding (to nearest, ties to even)
+// function for the ARM Thumb1 ISA.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../assembly.h"
+#define significandBits 23
+#define typeWidth 32
+
+ .syntax unified
+ .text
+ .thumb
+ .p2align 2
+
+DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_fadd, __addsf3)
+
+DEFINE_COMPILERRT_THUMB_FUNCTION(__addsf3)
+ push {r4, r5, r6, r7, lr}
+ // Get the absolute value of a and b.
+ lsls r2, r0, #1
+ lsls r3, r1, #1
+ lsrs r2, r2, #1 // aAbs
+ beq LOCAL_LABEL(a_zero_nan_inf)
+ lsrs r3, r3, #1 // bAbs
+ beq LOCAL_LABEL(zero_nan_inf)
+
+ // Detect if a or b is infinity or Nan.
+ lsrs r6, r2, #(significandBits)
+ lsrs r7, r3, #(significandBits)
+ cmp r6, #0xFF
+ beq LOCAL_LABEL(zero_nan_inf)
+ cmp r7, #0xFF
+ beq LOCAL_LABEL(zero_nan_inf)
+
+ // Swap Rep and Abs so that a and aAbs has the larger absolute value.
+ cmp r2, r3
+ bhs LOCAL_LABEL(no_swap)
+ movs r4, r0
+ movs r5, r2
+ movs r0, r1
+ movs r2, r3
+ movs r1, r4
+ movs r3, r5
+LOCAL_LABEL(no_swap):
+
+ // Get the significands and shift them to give us round, guard and sticky.
+ lsls r4, r0, #(typeWidth - significandBits)
+ lsrs r4, r4, #(typeWidth - significandBits - 3) // aSignificand << 3
+ lsls r5, r1, #(typeWidth - significandBits)
+ lsrs r5, r5, #(typeWidth - significandBits - 3) // bSignificand << 3
+
+ // Get the implicitBit.
+ movs r6, #1
+ lsls r6, r6, #(significandBits + 3)
+
+ // Get aExponent and set implicit bit if necessary.
+ lsrs r2, r2, #(significandBits)
+ beq LOCAL_LABEL(a_done_implicit_bit)
+ orrs r4, r6
+LOCAL_LABEL(a_done_implicit_bit):
+
+ // Get bExponent and set implicit bit if necessary.
+ lsrs r3, r3, #(significandBits)
+ beq LOCAL_LABEL(b_done_implicit_bit)
+ orrs r5, r6
+LOCAL_LABEL(b_done_implicit_bit):
+
+ // Get the difference in exponents.
+ subs r6, r2, r3
+ beq LOCAL_LABEL(done_align)
+
+ // If b is denormal, then a must be normal as align > 0, and we only need to
+ // right shift bSignificand by (align - 1) bits.
+ cmp r3, #0
+ bne 1f
+ subs r6, r6, #1
+1:
+
+ // No longer needs bExponent. r3 is dead here.
+ // Set sticky bits of b: sticky = bSignificand << (typeWidth - align).
+ movs r3, #(typeWidth)
+ subs r3, r3, r6
+ movs r7, r5
+ lsls r7, r3
+ beq 1f
+ movs r7, #1
+1:
+
+ // bSignificand = bSignificand >> align | sticky;
+ lsrs r5, r6
+ orrs r5, r7
+ bne LOCAL_LABEL(done_align)
+ movs r5, #1 // sticky; b is known to be non-zero.
+
+LOCAL_LABEL(done_align):
+ // isSubtraction = (aRep ^ bRep) >> 31;
+ movs r7, r0
+ eors r7, r1
+ lsrs r7, #31
+ bne LOCAL_LABEL(do_substraction)
+
+ // Same sign, do Addition.
+
+ // aSignificand += bSignificand;
+ adds r4, r4, r5
+
+ // Check carry bit.
+ movs r6, #1
+ lsls r6, r6, #(significandBits + 3 + 1)
+ movs r7, r4
+ ands r7, r6
+ beq LOCAL_LABEL(form_result)
+ // If the addition carried up, we need to right-shift the result and
+ // adjust the exponent.
+ movs r7, r4
+ movs r6, #1
+ ands r7, r6 // sticky = aSignificand & 1;
+ lsrs r4, #1
+ orrs r4, r7 // result Significand
+ adds r2, #1 // result Exponent
+ // If we have overflowed the type, return +/- infinity.
+ cmp r2, 0xFF
+ beq LOCAL_LABEL(ret_inf)
+
+LOCAL_LABEL(form_result):
+ // Shift the sign, exponent and significand into place.
+ lsrs r0, #(typeWidth - 1)
+ lsls r0, #(typeWidth - 1) // Get Sign.
+ lsls r2, #(significandBits)
+ orrs r0, r2
+ movs r1, r4
+ lsls r4, #(typeWidth - significandBits - 3)
+ lsrs r4, #(typeWidth - significandBits)
+ orrs r0, r4
+
+ // Final rounding. The result may overflow to infinity, but that is the
+ // correct result in that case.
+ // roundGuardSticky = aSignificand & 0x7;
+ movs r2, #0x7
+ ands r1, r2
+ // if (roundGuardSticky > 0x4) result++;
+
+ cmp r1, #0x4
+ blt LOCAL_LABEL(done_round)
+ beq 1f
+ adds r0, #1
+ pop {r4, r5, r6, r7, pc}
+1:
+
+ // if (roundGuardSticky == 0x4) result += result & 1;
+ movs r1, r0
+ lsrs r1, #1
+ bcc LOCAL_LABEL(done_round)
+ adds r0, r0, #1
+LOCAL_LABEL(done_round):
+ pop {r4, r5, r6, r7, pc}
+
+LOCAL_LABEL(do_substraction):
+ subs r4, r4, r5 // aSignificand -= bSignificand;
+ beq LOCAL_LABEL(ret_zero)
+ movs r6, r4
+ cmp r2, 0
+ beq LOCAL_LABEL(form_result) // if a's exp is 0, no need to normalize.
+ // If partial cancellation occured, we need to left-shift the result
+ // and adjust the exponent:
+ lsrs r6, r6, #(significandBits + 3)
+ bne LOCAL_LABEL(form_result)
+
+ push {r0, r1, r2, r3}
+ movs r0, r4
+ bl SYMBOL_NAME(__clzsi2)
+ movs r5, r0
+ pop {r0, r1, r2, r3}
+ // shift = rep_clz(aSignificand) - rep_clz(implicitBit << 3);
+ subs r5, r5, #(typeWidth - significandBits - 3 - 1)
+ // aSignificand <<= shift; aExponent -= shift;
+ lsls r4, r5
+ subs r2, r2, r5
+ bgt LOCAL_LABEL(form_result)
+
+ // Do normalization if aExponent <= 0.
+ movs r6, #1
+ subs r6, r6, r2 // 1 - aExponent;
+ movs r2, #0 // aExponent = 0;
+ movs r3, #(typeWidth) // bExponent is dead.
+ subs r3, r3, r6
+ movs r7, r4
+ lsls r7, r3 // stickyBit = (bool)(aSignificant << (typeWidth - align))
+ beq 1f
+ movs r7, #1
+1:
+ lsrs r4, r6 // aSignificand >> shift
+ orrs r4, r7
+ b LOCAL_LABEL(form_result)
+
+LOCAL_LABEL(ret_zero):
+ movs r0, #0
+ pop {r4, r5, r6, r7, pc}
+
+
+LOCAL_LABEL(a_zero_nan_inf):
+ lsrs r3, r3, #1
+
+LOCAL_LABEL(zero_nan_inf):
+ // Here r2 has aAbs, r3 has bAbs
+ movs r4, #0xFF
+ lsls r4, r4, #(significandBits) // Make +inf.
+
+ cmp r2, r4
+ bhi LOCAL_LABEL(a_is_nan)
+ cmp r3, r4
+ bhi LOCAL_LABEL(b_is_nan)
+
+ cmp r2, r4
+ bne LOCAL_LABEL(a_is_rational)
+ // aAbs is INF.
+ eors r1, r0 // aRep ^ bRep.
+ movs r6, #1
+ lsls r6, r6, #(typeWidth - 1) // get sign mask.
+ cmp r1, r6 // if they only differ on sign bit, it's -INF + INF
+ beq LOCAL_LABEL(a_is_nan)
+ pop {r4, r5, r6, r7, pc}
+
+LOCAL_LABEL(a_is_rational):
+ cmp r3, r4
+ bne LOCAL_LABEL(b_is_rational)
+ movs r0, r1
+ pop {r4, r5, r6, r7, pc}
+
+LOCAL_LABEL(b_is_rational):
+ // either a or b or both are zero.
+ adds r4, r2, r3
+ beq LOCAL_LABEL(both_zero)
+ cmp r2, #0 // is absA 0 ?
+ beq LOCAL_LABEL(ret_b)
+ pop {r4, r5, r6, r7, pc}
+
+LOCAL_LABEL(both_zero):
+ ands r0, r1 // +0 + -0 = +0
+ pop {r4, r5, r6, r7, pc}
+
+LOCAL_LABEL(ret_b):
+ movs r0, r1
+
+LOCAL_LABEL(ret):
+ pop {r4, r5, r6, r7, pc}
+
+LOCAL_LABEL(b_is_nan):
+ movs r0, r1
+LOCAL_LABEL(a_is_nan):
+ movs r1, #1
+ lsls r1, r1, #(significandBits -1) // r1 is quiet bit.
+ orrs r0, r1
+ pop {r4, r5, r6, r7, pc}
+
+LOCAL_LABEL(ret_inf):
+ movs r4, #0xFF
+ lsls r4, r4, #(significandBits)
+ orrs r0, r4
+ lsrs r0, r0, #(significandBits)
+ lsls r0, r0, #(significandBits)
+ pop {r4, r5, r6, r7, pc}
+
+
+END_COMPILERRT_FUNCTION(__addsf3)
+
+NO_EXEC_STACK_DIRECTIVE
diff --git a/contrib/libs/cxxsupp/builtins/arm/addsf3vfp.S b/contrib/libs/cxxsupp/builtins/arm/addsf3vfp.S
index bff5a7e0fb..c9d1fd1509 100644
--- a/contrib/libs/cxxsupp/builtins/arm/addsf3vfp.S
+++ b/contrib/libs/cxxsupp/builtins/arm/addsf3vfp.S
@@ -1,9 +1,8 @@
//===-- addsf3vfp.S - Implement addsf3vfp ---------------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -18,9 +17,16 @@
.syntax unified
.p2align 2
DEFINE_COMPILERRT_FUNCTION(__addsf3vfp)
+#if defined(COMPILER_RT_ARMHF_TARGET)
+ vadd.f32 s0, s0, s1
+#else
vmov s14, r0 // move first param from r0 into float register
vmov s15, r1 // move second param from r1 into float register
vadd.f32 s14, s14, s15
vmov r0, s14 // move result back to r0
+#endif
bx lr
END_COMPILERRT_FUNCTION(__addsf3vfp)
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/aeabi_cdcmp.S b/contrib/libs/cxxsupp/builtins/arm/aeabi_cdcmp.S
index 036a6f542f..bd039a0329 100644
--- a/contrib/libs/cxxsupp/builtins/arm/aeabi_cdcmp.S
+++ b/contrib/libs/cxxsupp/builtins/arm/aeabi_cdcmp.S
@@ -1,9 +1,8 @@
//===-- aeabi_cdcmp.S - EABI cdcmp* implementation ------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -30,13 +29,35 @@ DEFINE_COMPILERRT_FUNCTION(__aeabi_cdcmpeq)
push {r0-r3, lr}
bl __aeabi_cdcmpeq_check_nan
cmp r0, #1
+#if defined(USE_THUMB_1)
+ beq 1f
+ // NaN has been ruled out, so __aeabi_cdcmple can't trap
+ mov r0, sp
+ ldm r0, {r0-r3}
+ bl __aeabi_cdcmple
+ pop {r0-r3, pc}
+1:
+ // Z = 0, C = 1
+ movs r0, #0xF
+ lsls r0, r0, #31
+ pop {r0-r3, pc}
+#else
pop {r0-r3, lr}
// NaN has been ruled out, so __aeabi_cdcmple can't trap
+ // Use "it ne" + unconditional branch to guarantee a supported relocation if
+ // __aeabi_cdcmple is in a different section for some builds.
+ IT(ne)
bne __aeabi_cdcmple
- msr CPSR_f, #APSR_C
+#if defined(USE_THUMB_2)
+ mov ip, #APSR_C
+ msr APSR_nzcvq, ip
+#else
+ msr APSR_nzcvq, #APSR_C
+#endif
JMP(lr)
+#endif
END_COMPILERRT_FUNCTION(__aeabi_cdcmpeq)
@@ -59,19 +80,44 @@ DEFINE_COMPILERRT_FUNCTION(__aeabi_cdcmple)
bl __aeabi_dcmplt
cmp r0, #1
+#if defined(USE_THUMB_1)
+ bne 1f
+ // Z = 0, C = 0
+ movs r0, #1
+ lsls r0, r0, #1
+ pop {r0-r3, pc}
+1:
+ mov r0, sp
+ ldm r0, {r0-r3}
+ bl __aeabi_dcmpeq
+ cmp r0, #1
+ bne 2f
+ // Z = 1, C = 1
+ movs r0, #2
+ lsls r0, r0, #31
+ pop {r0-r3, pc}
+2:
+ // Z = 0, C = 1
+ movs r0, #0xF
+ lsls r0, r0, #31
+ pop {r0-r3, pc}
+#else
+ ITT(eq)
moveq ip, #0
beq 1f
ldm sp, {r0-r3}
bl __aeabi_dcmpeq
cmp r0, #1
+ ITE(eq)
moveq ip, #(APSR_C | APSR_Z)
movne ip, #(APSR_C)
1:
- msr CPSR_f, ip
+ msr APSR_nzcvq, ip
pop {r0-r3}
POP_PC()
+#endif
END_COMPILERRT_FUNCTION(__aeabi_cdcmple)
// int __aeabi_cdrcmple(double a, double b) {
@@ -94,3 +140,5 @@ DEFINE_COMPILERRT_FUNCTION(__aeabi_cdrcmple)
b __aeabi_cdcmple
END_COMPILERRT_FUNCTION(__aeabi_cdrcmple)
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/aeabi_cdcmpeq_check_nan.c b/contrib/libs/cxxsupp/builtins/arm/aeabi_cdcmpeq_check_nan.c
index 577f6b2c55..7bae8743fc 100644
--- a/contrib/libs/cxxsupp/builtins/arm/aeabi_cdcmpeq_check_nan.c
+++ b/contrib/libs/cxxsupp/builtins/arm/aeabi_cdcmpeq_check_nan.c
@@ -1,16 +1,15 @@
//===-- lib/arm/aeabi_cdcmpeq_helper.c - Helper for cdcmpeq ---------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
+#include "../int_lib.h"
#include <stdint.h>
-__attribute__((pcs("aapcs")))
-__attribute__((visibility("hidden")))
-int __aeabi_cdcmpeq_check_nan(double a, double b) {
- return __builtin_isnan(a) || __builtin_isnan(b);
+AEABI_RTABI __attribute__((visibility("hidden"))) int
+__aeabi_cdcmpeq_check_nan(double a, double b) {
+ return __builtin_isnan(a) || __builtin_isnan(b);
}
diff --git a/contrib/libs/cxxsupp/builtins/arm/aeabi_cfcmp.S b/contrib/libs/cxxsupp/builtins/arm/aeabi_cfcmp.S
index 43594e5c39..a26cb2a3ce 100644
--- a/contrib/libs/cxxsupp/builtins/arm/aeabi_cfcmp.S
+++ b/contrib/libs/cxxsupp/builtins/arm/aeabi_cfcmp.S
@@ -1,9 +1,8 @@
//===-- aeabi_cfcmp.S - EABI cfcmp* implementation ------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -30,13 +29,35 @@ DEFINE_COMPILERRT_FUNCTION(__aeabi_cfcmpeq)
push {r0-r3, lr}
bl __aeabi_cfcmpeq_check_nan
cmp r0, #1
+#if defined(USE_THUMB_1)
+ beq 1f
+ // NaN has been ruled out, so __aeabi_cfcmple can't trap
+ mov r0, sp
+ ldm r0, {r0-r3}
+ bl __aeabi_cfcmple
+ pop {r0-r3, pc}
+1:
+ // Z = 0, C = 1
+ movs r0, #0xF
+ lsls r0, r0, #31
+ pop {r0-r3, pc}
+#else
pop {r0-r3, lr}
// NaN has been ruled out, so __aeabi_cfcmple can't trap
+ // Use "it ne" + unconditional branch to guarantee a supported relocation if
+ // __aeabi_cfcmple is in a different section for some builds.
+ IT(ne)
bne __aeabi_cfcmple
- msr CPSR_f, #APSR_C
+#if defined(USE_THUMB_2)
+ mov ip, #APSR_C
+ msr APSR_nzcvq, ip
+#else
+ msr APSR_nzcvq, #APSR_C
+#endif
JMP(lr)
+#endif
END_COMPILERRT_FUNCTION(__aeabi_cfcmpeq)
@@ -59,19 +80,44 @@ DEFINE_COMPILERRT_FUNCTION(__aeabi_cfcmple)
bl __aeabi_fcmplt
cmp r0, #1
+#if defined(USE_THUMB_1)
+ bne 1f
+ // Z = 0, C = 0
+ movs r0, #1
+ lsls r0, r0, #1
+ pop {r0-r3, pc}
+1:
+ mov r0, sp
+ ldm r0, {r0-r3}
+ bl __aeabi_fcmpeq
+ cmp r0, #1
+ bne 2f
+ // Z = 1, C = 1
+ movs r0, #2
+ lsls r0, r0, #31
+ pop {r0-r3, pc}
+2:
+ // Z = 0, C = 1
+ movs r0, #0xF
+ lsls r0, r0, #31
+ pop {r0-r3, pc}
+#else
+ ITT(eq)
moveq ip, #0
beq 1f
ldm sp, {r0-r3}
bl __aeabi_fcmpeq
cmp r0, #1
+ ITE(eq)
moveq ip, #(APSR_C | APSR_Z)
movne ip, #(APSR_C)
1:
- msr CPSR_f, ip
+ msr APSR_nzcvq, ip
pop {r0-r3}
POP_PC()
+#endif
END_COMPILERRT_FUNCTION(__aeabi_cfcmple)
// int __aeabi_cfrcmple(float a, float b) {
@@ -89,3 +135,5 @@ DEFINE_COMPILERRT_FUNCTION(__aeabi_cfrcmple)
b __aeabi_cfcmple
END_COMPILERRT_FUNCTION(__aeabi_cfrcmple)
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/aeabi_cfcmpeq_check_nan.c b/contrib/libs/cxxsupp/builtins/arm/aeabi_cfcmpeq_check_nan.c
index 992e31fbd8..25407337d0 100644
--- a/contrib/libs/cxxsupp/builtins/arm/aeabi_cfcmpeq_check_nan.c
+++ b/contrib/libs/cxxsupp/builtins/arm/aeabi_cfcmpeq_check_nan.c
@@ -1,16 +1,15 @@
//===-- lib/arm/aeabi_cfcmpeq_helper.c - Helper for cdcmpeq ---------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
+#include "../int_lib.h"
#include <stdint.h>
-__attribute__((pcs("aapcs")))
-__attribute__((visibility("hidden")))
-int __aeabi_cfcmpeq_check_nan(float a, float b) {
- return __builtin_isnan(a) || __builtin_isnan(b);
+AEABI_RTABI __attribute__((visibility("hidden"))) int
+__aeabi_cfcmpeq_check_nan(float a, float b) {
+ return __builtin_isnan(a) || __builtin_isnan(b);
}
diff --git a/contrib/libs/cxxsupp/builtins/arm/aeabi_dcmp.S b/contrib/libs/cxxsupp/builtins/arm/aeabi_dcmp.S
index 310c35b749..5f720670dd 100644
--- a/contrib/libs/cxxsupp/builtins/arm/aeabi_dcmp.S
+++ b/contrib/libs/cxxsupp/builtins/arm/aeabi_dcmp.S
@@ -1,9 +1,8 @@
//===-- aeabi_dcmp.S - EABI dcmp* implementation ---------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -18,18 +17,27 @@
// }
// }
+#if defined(COMPILER_RT_ARMHF_TARGET)
+# define CONVERT_DCMP_ARGS_TO_DF2_ARGS \
+ vmov d0, r0, r1 SEPARATOR \
+ vmov d1, r2, r3
+#else
+# define CONVERT_DCMP_ARGS_TO_DF2_ARGS
+#endif
+
#define DEFINE_AEABI_DCMP(cond) \
.syntax unified SEPARATOR \
.p2align 2 SEPARATOR \
DEFINE_COMPILERRT_FUNCTION(__aeabi_dcmp ## cond) \
push { r4, lr } SEPARATOR \
+ CONVERT_DCMP_ARGS_TO_DF2_ARGS SEPARATOR \
bl SYMBOL_NAME(__ ## cond ## df2) SEPARATOR \
cmp r0, #0 SEPARATOR \
b ## cond 1f SEPARATOR \
- mov r0, #0 SEPARATOR \
+ movs r0, #0 SEPARATOR \
pop { r4, pc } SEPARATOR \
1: SEPARATOR \
- mov r0, #1 SEPARATOR \
+ movs r0, #1 SEPARATOR \
pop { r4, pc } SEPARATOR \
END_COMPILERRT_FUNCTION(__aeabi_dcmp ## cond)
@@ -38,3 +46,6 @@ DEFINE_AEABI_DCMP(lt)
DEFINE_AEABI_DCMP(le)
DEFINE_AEABI_DCMP(ge)
DEFINE_AEABI_DCMP(gt)
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/aeabi_div0.c b/contrib/libs/cxxsupp/builtins/arm/aeabi_div0.c
index ccc95fa5c1..7e8862321d 100644
--- a/contrib/libs/cxxsupp/builtins/arm/aeabi_div0.c
+++ b/contrib/libs/cxxsupp/builtins/arm/aeabi_div0.c
@@ -1,43 +1,40 @@
-/* ===-- aeabi_div0.c - ARM Runtime ABI support routines for compiler-rt ---===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements the division by zero helper routines as specified by the
- * Run-time ABI for the ARM Architecture.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- aeabi_div0.c - ARM Runtime ABI support routines for compiler-rt ---===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the division by zero helper routines as specified by the
+// Run-time ABI for the ARM Architecture.
+//
+//===----------------------------------------------------------------------===//
-/*
- * RTABI 4.3.2 - Division by zero
- *
- * The *div0 functions:
- * - Return the value passed to them as a parameter
- * - Or, return a fixed value defined by the execution environment (such as 0)
- * - Or, raise a signal (often SIGFPE) or throw an exception, and do not return
- *
- * An application may provide its own implementations of the *div0 functions to
- * for a particular behaviour from the *div and *divmod functions called out of
- * line.
- */
+// RTABI 4.3.2 - Division by zero
+//
+// The *div0 functions:
+// - Return the value passed to them as a parameter
+// - Or, return a fixed value defined by the execution environment (such as 0)
+// - Or, raise a signal (often SIGFPE) or throw an exception, and do not return
+//
+// An application may provide its own implementations of the *div0 functions to
+// for a particular behaviour from the *div and *divmod functions called out of
+// line.
-/* provide an unused declaration to pacify pendantic compilation */
+#include "../int_lib.h"
+
+// provide an unused declaration to pacify pendantic compilation
extern unsigned char declaration;
#if defined(__ARM_EABI__)
-int __attribute__((weak)) __attribute__((visibility("hidden")))
+AEABI_RTABI int __attribute__((weak)) __attribute__((visibility("hidden")))
__aeabi_idiv0(int return_value) {
return return_value;
}
-long long __attribute__((weak)) __attribute__((visibility("hidden")))
-__aeabi_ldiv0(long long return_value) {
+AEABI_RTABI long long __attribute__((weak))
+__attribute__((visibility("hidden"))) __aeabi_ldiv0(long long return_value) {
return return_value;
}
#endif
-
diff --git a/contrib/libs/cxxsupp/builtins/arm/aeabi_drsub.c b/contrib/libs/cxxsupp/builtins/arm/aeabi_drsub.c
index fc17d5a4cc..e4e8dc0514 100644
--- a/contrib/libs/cxxsupp/builtins/arm/aeabi_drsub.c
+++ b/contrib/libs/cxxsupp/builtins/arm/aeabi_drsub.c
@@ -1,19 +1,14 @@
//===-- lib/arm/aeabi_drsub.c - Double-precision subtraction --------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#define DOUBLE_PRECISION
#include "../fp_lib.h"
-COMPILER_RT_ABI fp_t
-__aeabi_dsub(fp_t, fp_t);
+AEABI_RTABI fp_t __aeabi_dsub(fp_t, fp_t);
-COMPILER_RT_ABI fp_t
-__aeabi_drsub(fp_t a, fp_t b) {
- return __aeabi_dsub(b, a);
-}
+AEABI_RTABI fp_t __aeabi_drsub(fp_t a, fp_t b) { return __aeabi_dsub(b, a); }
diff --git a/contrib/libs/cxxsupp/builtins/arm/aeabi_fcmp.S b/contrib/libs/cxxsupp/builtins/arm/aeabi_fcmp.S
index 55f49a2b5a..cd311b4170 100644
--- a/contrib/libs/cxxsupp/builtins/arm/aeabi_fcmp.S
+++ b/contrib/libs/cxxsupp/builtins/arm/aeabi_fcmp.S
@@ -1,9 +1,8 @@
//===-- aeabi_fcmp.S - EABI fcmp* implementation ---------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -18,18 +17,27 @@
// }
// }
+#if defined(COMPILER_RT_ARMHF_TARGET)
+# define CONVERT_FCMP_ARGS_TO_SF2_ARGS \
+ vmov s0, r0 SEPARATOR \
+ vmov s1, r1
+#else
+# define CONVERT_FCMP_ARGS_TO_SF2_ARGS
+#endif
+
#define DEFINE_AEABI_FCMP(cond) \
.syntax unified SEPARATOR \
.p2align 2 SEPARATOR \
DEFINE_COMPILERRT_FUNCTION(__aeabi_fcmp ## cond) \
push { r4, lr } SEPARATOR \
+ CONVERT_FCMP_ARGS_TO_SF2_ARGS SEPARATOR \
bl SYMBOL_NAME(__ ## cond ## sf2) SEPARATOR \
cmp r0, #0 SEPARATOR \
b ## cond 1f SEPARATOR \
- mov r0, #0 SEPARATOR \
+ movs r0, #0 SEPARATOR \
pop { r4, pc } SEPARATOR \
1: SEPARATOR \
- mov r0, #1 SEPARATOR \
+ movs r0, #1 SEPARATOR \
pop { r4, pc } SEPARATOR \
END_COMPILERRT_FUNCTION(__aeabi_fcmp ## cond)
@@ -38,3 +46,6 @@ DEFINE_AEABI_FCMP(lt)
DEFINE_AEABI_FCMP(le)
DEFINE_AEABI_FCMP(ge)
DEFINE_AEABI_FCMP(gt)
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/aeabi_frsub.c b/contrib/libs/cxxsupp/builtins/arm/aeabi_frsub.c
index 64258dc7e0..9a363248f1 100644
--- a/contrib/libs/cxxsupp/builtins/arm/aeabi_frsub.c
+++ b/contrib/libs/cxxsupp/builtins/arm/aeabi_frsub.c
@@ -1,19 +1,14 @@
//===-- lib/arm/aeabi_frsub.c - Single-precision subtraction --------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#define SINGLE_PRECISION
#include "../fp_lib.h"
-COMPILER_RT_ABI fp_t
-__aeabi_fsub(fp_t, fp_t);
+AEABI_RTABI fp_t __aeabi_fsub(fp_t, fp_t);
-COMPILER_RT_ABI fp_t
-__aeabi_frsub(fp_t a, fp_t b) {
- return __aeabi_fsub(b, a);
-}
+AEABI_RTABI fp_t __aeabi_frsub(fp_t a, fp_t b) { return __aeabi_fsub(b, a); }
diff --git a/contrib/libs/cxxsupp/builtins/arm/aeabi_idivmod.S b/contrib/libs/cxxsupp/builtins/arm/aeabi_idivmod.S
index 384add3827..bb80e4b96f 100644
--- a/contrib/libs/cxxsupp/builtins/arm/aeabi_idivmod.S
+++ b/contrib/libs/cxxsupp/builtins/arm/aeabi_idivmod.S
@@ -1,9 +1,8 @@
//===-- aeabi_idivmod.S - EABI idivmod implementation ---------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -15,14 +14,37 @@
// return {quot, rem};
// }
+#if defined(__MINGW32__)
+#define __aeabi_idivmod __rt_sdiv
+#endif
+
.syntax unified
+ .text
+ DEFINE_CODE_STATE
.p2align 2
DEFINE_COMPILERRT_FUNCTION(__aeabi_idivmod)
+#if defined(USE_THUMB_1)
+ push {r0, r1, lr}
+ bl SYMBOL_NAME(__divsi3)
+ pop {r1, r2, r3} // now r0 = quot, r1 = num, r2 = denom
+ muls r2, r0, r2 // r2 = quot * denom
+ subs r1, r1, r2
+ JMP (r3)
+#else // defined(USE_THUMB_1)
push { lr }
sub sp, sp, #4
mov r2, sp
+#if defined(__MINGW32__)
+ mov r3, r0
+ mov r0, r1
+ mov r1, r3
+#endif
bl SYMBOL_NAME(__divmodsi4)
ldr r1, [sp]
add sp, sp, #4
pop { pc }
+#endif // defined(USE_THUMB_1)
END_COMPILERRT_FUNCTION(__aeabi_idivmod)
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/aeabi_ldivmod.S b/contrib/libs/cxxsupp/builtins/arm/aeabi_ldivmod.S
index ad06f1de2a..d0d06be6f3 100644
--- a/contrib/libs/cxxsupp/builtins/arm/aeabi_ldivmod.S
+++ b/contrib/libs/cxxsupp/builtins/arm/aeabi_ldivmod.S
@@ -1,9 +1,8 @@
//===-- aeabi_ldivmod.S - EABI ldivmod implementation ---------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -16,16 +15,31 @@
// return {quot, rem};
// }
+#if defined(__MINGW32__)
+#define __aeabi_ldivmod __rt_sdiv64
+#endif
+
.syntax unified
.p2align 2
DEFINE_COMPILERRT_FUNCTION(__aeabi_ldivmod)
- push {r11, lr}
+ push {r6, lr}
sub sp, sp, #16
- add r12, sp, #8
- str r12, [sp]
+ add r6, sp, #8
+ str r6, [sp]
+#if defined(__MINGW32__)
+ movs r6, r0
+ movs r0, r2
+ movs r2, r6
+ movs r6, r1
+ movs r1, r3
+ movs r3, r6
+#endif
bl SYMBOL_NAME(__divmoddi4)
ldr r2, [sp, #8]
ldr r3, [sp, #12]
add sp, sp, #16
- pop {r11, pc}
+ pop {r6, pc}
END_COMPILERRT_FUNCTION(__aeabi_ldivmod)
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/aeabi_memcmp.S b/contrib/libs/cxxsupp/builtins/arm/aeabi_memcmp.S
index 051ce435ba..41637289c1 100644
--- a/contrib/libs/cxxsupp/builtins/arm/aeabi_memcmp.S
+++ b/contrib/libs/cxxsupp/builtins/arm/aeabi_memcmp.S
@@ -1,9 +1,8 @@
//===-- aeabi_memcmp.S - EABI memcmp implementation -----------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -11,10 +10,20 @@
// void __aeabi_memcmp(void *dest, void *src, size_t n) { memcmp(dest, src, n); }
+ .syntax unified
.p2align 2
DEFINE_COMPILERRT_FUNCTION(__aeabi_memcmp)
+#ifdef USE_THUMB_1
+ push {r7, lr}
+ bl memcmp
+ pop {r7, pc}
+#else
b memcmp
+#endif
END_COMPILERRT_FUNCTION(__aeabi_memcmp)
DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memcmp4, __aeabi_memcmp)
DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memcmp8, __aeabi_memcmp)
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/aeabi_memcpy.S b/contrib/libs/cxxsupp/builtins/arm/aeabi_memcpy.S
index cf02332490..93e1b05d54 100644
--- a/contrib/libs/cxxsupp/builtins/arm/aeabi_memcpy.S
+++ b/contrib/libs/cxxsupp/builtins/arm/aeabi_memcpy.S
@@ -1,9 +1,8 @@
//===-- aeabi_memcpy.S - EABI memcpy implementation -----------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -11,10 +10,20 @@
// void __aeabi_memcpy(void *dest, void *src, size_t n) { memcpy(dest, src, n); }
+ .syntax unified
.p2align 2
DEFINE_COMPILERRT_FUNCTION(__aeabi_memcpy)
+#ifdef USE_THUMB_1
+ push {r7, lr}
+ bl memcpy
+ pop {r7, pc}
+#else
b memcpy
+#endif
END_COMPILERRT_FUNCTION(__aeabi_memcpy)
DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memcpy4, __aeabi_memcpy)
DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memcpy8, __aeabi_memcpy)
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/aeabi_memmove.S b/contrib/libs/cxxsupp/builtins/arm/aeabi_memmove.S
index 4dda06f75d..c2f0fa4cd8 100644
--- a/contrib/libs/cxxsupp/builtins/arm/aeabi_memmove.S
+++ b/contrib/libs/cxxsupp/builtins/arm/aeabi_memmove.S
@@ -1,9 +1,8 @@
//===-- aeabi_memmove.S - EABI memmove implementation --------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===---------------------------------------------------------------------===//
@@ -13,8 +12,17 @@
.p2align 2
DEFINE_COMPILERRT_FUNCTION(__aeabi_memmove)
+#ifdef USE_THUMB_1
+ push {r7, lr}
+ bl memmove
+ pop {r7, pc}
+#else
b memmove
+#endif
END_COMPILERRT_FUNCTION(__aeabi_memmove)
DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memmove4, __aeabi_memmove)
DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memmove8, __aeabi_memmove)
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/aeabi_memset.S b/contrib/libs/cxxsupp/builtins/arm/aeabi_memset.S
index c8b49c7809..2aa8ec0c46 100644
--- a/contrib/libs/cxxsupp/builtins/arm/aeabi_memset.S
+++ b/contrib/libs/cxxsupp/builtins/arm/aeabi_memset.S
@@ -1,9 +1,8 @@
//===-- aeabi_memset.S - EABI memset implementation -----------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -12,23 +11,39 @@
// void __aeabi_memset(void *dest, size_t n, int c) { memset(dest, c, n); }
// void __aeabi_memclr(void *dest, size_t n) { __aeabi_memset(dest, n, 0); }
+ .syntax unified
.p2align 2
DEFINE_COMPILERRT_FUNCTION(__aeabi_memset)
mov r3, r1
mov r1, r2
mov r2, r3
+#ifdef USE_THUMB_1
+ push {r7, lr}
+ bl memset
+ pop {r7, pc}
+#else
b memset
+#endif
END_COMPILERRT_FUNCTION(__aeabi_memset)
DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memset4, __aeabi_memset)
DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memset8, __aeabi_memset)
+ .p2align 2
DEFINE_COMPILERRT_FUNCTION(__aeabi_memclr)
mov r2, r1
- mov r1, #0
+ movs r1, #0
+#ifdef USE_THUMB_1
+ push {r7, lr}
+ bl memset
+ pop {r7, pc}
+#else
b memset
+#endif
END_COMPILERRT_FUNCTION(__aeabi_memclr)
DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memclr4, __aeabi_memclr)
DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_memclr8, __aeabi_memclr)
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/aeabi_uidivmod.S b/contrib/libs/cxxsupp/builtins/arm/aeabi_uidivmod.S
index 8ea474d91c..df030769fd 100644
--- a/contrib/libs/cxxsupp/builtins/arm/aeabi_uidivmod.S
+++ b/contrib/libs/cxxsupp/builtins/arm/aeabi_uidivmod.S
@@ -1,9 +1,8 @@
//===-- aeabi_uidivmod.S - EABI uidivmod implementation -------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -16,14 +15,43 @@
// return {quot, rem};
// }
+#if defined(__MINGW32__)
+#define __aeabi_uidivmod __rt_udiv
+#endif
+
.syntax unified
+ .text
+ DEFINE_CODE_STATE
.p2align 2
DEFINE_COMPILERRT_FUNCTION(__aeabi_uidivmod)
+#if defined(USE_THUMB_1)
+ cmp r0, r1
+ bcc LOCAL_LABEL(case_denom_larger)
+ push {r0, r1, lr}
+ bl SYMBOL_NAME(__aeabi_uidiv)
+ pop {r1, r2, r3}
+ muls r2, r0, r2 // r2 = quot * denom
+ subs r1, r1, r2
+ JMP (r3)
+LOCAL_LABEL(case_denom_larger):
+ movs r1, r0
+ movs r0, #0
+ JMP (lr)
+#else // defined(USE_THUMB_1)
push { lr }
sub sp, sp, #4
mov r2, sp
+#if defined(__MINGW32__)
+ mov r3, r0
+ mov r0, r1
+ mov r1, r3
+#endif
bl SYMBOL_NAME(__udivmodsi4)
ldr r1, [sp]
add sp, sp, #4
pop { pc }
+#endif
END_COMPILERRT_FUNCTION(__aeabi_uidivmod)
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/aeabi_uldivmod.S b/contrib/libs/cxxsupp/builtins/arm/aeabi_uldivmod.S
index 4e1f8e2a67..4fc97704d3 100644
--- a/contrib/libs/cxxsupp/builtins/arm/aeabi_uldivmod.S
+++ b/contrib/libs/cxxsupp/builtins/arm/aeabi_uldivmod.S
@@ -1,9 +1,8 @@
//===-- aeabi_uldivmod.S - EABI uldivmod implementation -------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -16,16 +15,31 @@
// return {quot, rem};
// }
+#if defined(__MINGW32__)
+#define __aeabi_uldivmod __rt_udiv64
+#endif
+
.syntax unified
.p2align 2
DEFINE_COMPILERRT_FUNCTION(__aeabi_uldivmod)
- push {r11, lr}
+ push {r6, lr}
sub sp, sp, #16
- add r12, sp, #8
- str r12, [sp]
+ add r6, sp, #8
+ str r6, [sp]
+#if defined(__MINGW32__)
+ movs r6, r0
+ movs r0, r2
+ movs r2, r6
+ movs r6, r1
+ movs r1, r3
+ movs r3, r6
+#endif
bl SYMBOL_NAME(__udivmoddi4)
ldr r2, [sp, #8]
ldr r3, [sp, #12]
add sp, sp, #16
- pop {r11, pc}
+ pop {r6, pc}
END_COMPILERRT_FUNCTION(__aeabi_uldivmod)
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/bswapdi2.S b/contrib/libs/cxxsupp/builtins/arm/bswapdi2.S
index 86f3bba8c2..271df8bd6a 100644
--- a/contrib/libs/cxxsupp/builtins/arm/bswapdi2.S
+++ b/contrib/libs/cxxsupp/builtins/arm/bswapdi2.S
@@ -1,9 +1,8 @@
//===------- bswapdi2 - Implement bswapdi2 --------------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -11,9 +10,7 @@
.syntax unified
.text
-#if __ARM_ARCH_ISA_THUMB == 2
- .thumb
-#endif
+ DEFINE_CODE_STATE
//
// extern uint64_t __bswapdi2(uint64_t);
@@ -21,11 +18,7 @@
// Reverse all the bytes in a 64-bit integer.
//
.p2align 2
-#if __ARM_ARCH_ISA_THUMB == 2
-DEFINE_COMPILERRT_THUMB_FUNCTION(__bswapdi2)
-#else
DEFINE_COMPILERRT_FUNCTION(__bswapdi2)
-#endif
#if __ARM_ARCH < 6
// before armv6 does not have "rev" instruction
// r2 = rev(r0)
@@ -45,3 +38,6 @@ DEFINE_COMPILERRT_FUNCTION(__bswapdi2)
mov r1, r2 // r1 = r2 = rev(r0)
JMP(lr)
END_COMPILERRT_FUNCTION(__bswapdi2)
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/bswapsi2.S b/contrib/libs/cxxsupp/builtins/arm/bswapsi2.S
index 59ba8158fd..07cc3d8919 100644
--- a/contrib/libs/cxxsupp/builtins/arm/bswapsi2.S
+++ b/contrib/libs/cxxsupp/builtins/arm/bswapsi2.S
@@ -1,9 +1,8 @@
//===------- bswapsi2 - Implement bswapsi2 --------------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -11,9 +10,7 @@
.syntax unified
.text
-#if __ARM_ARCH_ISA_THUMB == 2
- .thumb
-#endif
+ DEFINE_CODE_STATE
//
// extern uint32_t __bswapsi2(uint32_t);
@@ -21,11 +18,7 @@
// Reverse all the bytes in a 32-bit integer.
//
.p2align 2
-#if __ARM_ARCH_ISA_THUMB == 2
-DEFINE_COMPILERRT_THUMB_FUNCTION(__bswapsi2)
-#else
DEFINE_COMPILERRT_FUNCTION(__bswapsi2)
-#endif
#if __ARM_ARCH < 6
// before armv6 does not have "rev" instruction
eor r1, r0, r0, ror #16
@@ -37,3 +30,6 @@ DEFINE_COMPILERRT_FUNCTION(__bswapsi2)
#endif
JMP(lr)
END_COMPILERRT_FUNCTION(__bswapsi2)
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/chkstk.S b/contrib/libs/cxxsupp/builtins/arm/chkstk.S
new file mode 100644
index 0000000000..c5c9ebe0a5
--- /dev/null
+++ b/contrib/libs/cxxsupp/builtins/arm/chkstk.S
@@ -0,0 +1,35 @@
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+#include "../assembly.h"
+
+// __chkstk routine
+// This routine is windows specific.
+// http://msdn.microsoft.com/en-us/library/ms648426.aspx
+
+// This clobbers the register r12, and the condition codes, and uses r5 and r6
+// as temporaries by backing them up and restoring them afterwards.
+// Does not modify any memory or the stack pointer.
+
+// movw r4, #256 // Number of bytes of stack, in units of 4 byte
+// bl __chkstk
+// sub.w sp, sp, r4
+
+#define PAGE_SIZE 4096
+
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__chkstk)
+ lsl r4, r4, #2
+ mov r12, sp
+ push {r5, r6}
+ mov r5, r4
+1:
+ sub r12, r12, #PAGE_SIZE
+ subs r5, r5, #PAGE_SIZE
+ ldr r6, [r12]
+ bgt 1b
+
+ pop {r5, r6}
+ bx lr
+END_COMPILERRT_FUNCTION(__chkstk)
diff --git a/contrib/libs/cxxsupp/builtins/arm/clzdi2.S b/contrib/libs/cxxsupp/builtins/arm/clzdi2.S
index a55abac046..685668b11b 100644
--- a/contrib/libs/cxxsupp/builtins/arm/clzdi2.S
+++ b/contrib/libs/cxxsupp/builtins/arm/clzdi2.S
@@ -1,31 +1,23 @@
-/* ===-- clzdi2.c - Implement __clzdi2 -------------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements count leading zeros for 64bit arguments.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- clzdi2.c - Implement __clzdi2 -------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements count leading zeros for 64bit arguments.
+//
+//===----------------------------------------------------------------------===//
+
#include "../assembly.h"
.syntax unified
.text
-#if __ARM_ARCH_ISA_THUMB == 2
- .thumb
-#endif
-
+ DEFINE_CODE_STATE
.p2align 2
-#if __ARM_ARCH_ISA_THUMB == 2
-DEFINE_COMPILERRT_THUMB_FUNCTION(__clzdi2)
-#else
DEFINE_COMPILERRT_FUNCTION(__clzdi2)
-#endif
#ifdef __ARM_FEATURE_CLZ
#ifdef __ARMEB__
cmp r0, 0
@@ -42,14 +34,12 @@ DEFINE_COMPILERRT_FUNCTION(__clzdi2)
#endif
JMP(lr)
#else
- /* Assumption: n != 0 */
+ // Assumption: n != 0
- /*
- * r0: n
- * r1: upper half of n, overwritten after check
- * r1: count of leading zeros in n + 1
- * r2: scratch register for shifted r0
- */
+ // r0: n
+ // r1: upper half of n, overwritten after check
+ // r1: count of leading zeros in n + 1
+ // r2: scratch register for shifted r0
#ifdef __ARMEB__
cmp r0, 0
moveq r0, r1
@@ -60,14 +50,12 @@ DEFINE_COMPILERRT_FUNCTION(__clzdi2)
movne r1, 1
moveq r1, 33
- /*
- * Basic block:
- * if ((r0 >> SHIFT) == 0)
- * r1 += SHIFT;
- * else
- * r0 >>= SHIFT;
- * for descending powers of two as SHIFT.
- */
+ // Basic block:
+ // if ((r0 >> SHIFT) == 0)
+ // r1 += SHIFT;
+ // else
+ // r0 >>= SHIFT;
+ // for descending powers of two as SHIFT.
#define BLOCK(shift) \
lsrs r2, r0, shift; \
movne r0, r2; \
@@ -78,20 +66,21 @@ DEFINE_COMPILERRT_FUNCTION(__clzdi2)
BLOCK(4)
BLOCK(2)
- /*
- * The basic block invariants at this point are (r0 >> 2) == 0 and
- * r0 != 0. This means 1 <= r0 <= 3 and 0 <= (r0 >> 1) <= 1.
- *
- * r0 | (r0 >> 1) == 0 | (r0 >> 1) == 1 | -(r0 >> 1) | 1 - (r0 >> 1)
- * ---+----------------+----------------+------------+--------------
- * 1 | 1 | 0 | 0 | 1
- * 2 | 0 | 1 | -1 | 0
- * 3 | 0 | 1 | -1 | 0
- *
- * The r1's initial value of 1 compensates for the 1 here.
- */
+ // The basic block invariants at this point are (r0 >> 2) == 0 and
+ // r0 != 0. This means 1 <= r0 <= 3 and 0 <= (r0 >> 1) <= 1.
+ //
+ // r0 | (r0 >> 1) == 0 | (r0 >> 1) == 1 | -(r0 >> 1) | 1 - (r0 >> 1)
+ // ---+----------------+----------------+------------+--------------
+ // 1 | 1 | 0 | 0 | 1
+ // 2 | 0 | 1 | -1 | 0
+ // 3 | 0 | 1 | -1 | 0
+ //
+ // The r1's initial value of 1 compensates for the 1 here.
sub r0, r1, r0, lsr #1
JMP(lr)
#endif // __ARM_FEATURE_CLZ
END_COMPILERRT_FUNCTION(__clzdi2)
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/clzsi2.S b/contrib/libs/cxxsupp/builtins/arm/clzsi2.S
index 1cd379bfb0..5d86fe486e 100644
--- a/contrib/libs/cxxsupp/builtins/arm/clzsi2.S
+++ b/contrib/libs/cxxsupp/builtins/arm/clzsi2.S
@@ -1,51 +1,40 @@
-/* ===-- clzsi2.c - Implement __clzsi2 -------------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements count leading zeros for 32bit arguments.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- clzsi2.c - Implement __clzsi2 -------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements count leading zeros for 32bit arguments.
+//
+//===----------------------------------------------------------------------===//
+
#include "../assembly.h"
.syntax unified
.text
-#if __ARM_ARCH_ISA_THUMB == 2
- .thumb
-#endif
+ DEFINE_CODE_STATE
.p2align 2
-#if __ARM_ARCH_ISA_THUMB == 2
-DEFINE_COMPILERRT_THUMB_FUNCTION(__clzsi2)
-#else
DEFINE_COMPILERRT_FUNCTION(__clzsi2)
-#endif
#ifdef __ARM_FEATURE_CLZ
clz r0, r0
JMP(lr)
#else
- /* Assumption: n != 0 */
+ // Assumption: n != 0
- /*
- * r0: n
- * r1: count of leading zeros in n + 1
- * r2: scratch register for shifted r0
- */
+ // r0: n
+ // r1: count of leading zeros in n + 1
+ // r2: scratch register for shifted r0
mov r1, 1
- /*
- * Basic block:
- * if ((r0 >> SHIFT) == 0)
- * r1 += SHIFT;
- * else
- * r0 >>= SHIFT;
- * for descending powers of two as SHIFT.
- */
+ // Basic block:
+ // if ((r0 >> SHIFT) == 0)
+ // r1 += SHIFT;
+ // else
+ // r0 >>= SHIFT;
+ // for descending powers of two as SHIFT.
#define BLOCK(shift) \
lsrs r2, r0, shift; \
@@ -57,20 +46,21 @@ DEFINE_COMPILERRT_FUNCTION(__clzsi2)
BLOCK(4)
BLOCK(2)
- /*
- * The basic block invariants at this point are (r0 >> 2) == 0 and
- * r0 != 0. This means 1 <= r0 <= 3 and 0 <= (r0 >> 1) <= 1.
- *
- * r0 | (r0 >> 1) == 0 | (r0 >> 1) == 1 | -(r0 >> 1) | 1 - (r0 >> 1)
- * ---+----------------+----------------+------------+--------------
- * 1 | 1 | 0 | 0 | 1
- * 2 | 0 | 1 | -1 | 0
- * 3 | 0 | 1 | -1 | 0
- *
- * The r1's initial value of 1 compensates for the 1 here.
- */
+ // The basic block invariants at this point are (r0 >> 2) == 0 and
+ // r0 != 0. This means 1 <= r0 <= 3 and 0 <= (r0 >> 1) <= 1.
+ //
+ // r0 | (r0 >> 1) == 0 | (r0 >> 1) == 1 | -(r0 >> 1) | 1 - (r0 >> 1)
+ // ---+----------------+----------------+------------+--------------
+ // 1 | 1 | 0 | 0 | 1
+ // 2 | 0 | 1 | -1 | 0
+ // 3 | 0 | 1 | -1 | 0
+ //
+ // The r1's initial value of 1 compensates for the 1 here.
sub r0, r1, r0, lsr #1
JMP(lr)
#endif // __ARM_FEATURE_CLZ
END_COMPILERRT_FUNCTION(__clzsi2)
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/comparesf2.S b/contrib/libs/cxxsupp/builtins/arm/comparesf2.S
index cf71d36e05..24b85d2fee 100644
--- a/contrib/libs/cxxsupp/builtins/arm/comparesf2.S
+++ b/contrib/libs/cxxsupp/builtins/arm/comparesf2.S
@@ -1,9 +1,8 @@
//===-- comparesf2.S - Implement single-precision soft-float comparisons --===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -38,33 +37,62 @@
//===----------------------------------------------------------------------===//
#include "../assembly.h"
-.syntax unified
-.p2align 2
-DEFINE_COMPILERRT_FUNCTION(__eqsf2)
+ .syntax unified
+ .text
+ DEFINE_CODE_STATE
+
+ .macro COMPARESF2_FUNCTION_BODY handle_nan:req
+#if defined(COMPILER_RT_ARMHF_TARGET)
+ vmov r0, s0
+ vmov r1, s1
+#endif
// Make copies of a and b with the sign bit shifted off the top. These will
// be used to detect zeros and NaNs.
+#if defined(USE_THUMB_1)
+ push {r6, lr}
+ lsls r2, r0, #1
+ lsls r3, r1, #1
+#else
mov r2, r0, lsl #1
mov r3, r1, lsl #1
+#endif
// We do the comparison in three stages (ignoring NaN values for the time
// being). First, we orr the absolute values of a and b; this sets the Z
// flag if both a and b are zero (of either sign). The shift of r3 doesn't
// effect this at all, but it *does* make sure that the C flag is clear for
// the subsequent operations.
+#if defined(USE_THUMB_1)
+ lsrs r6, r3, #1
+ orrs r6, r2
+#else
orrs r12, r2, r3, lsr #1
-
+#endif
// Next, we check if a and b have the same or different signs. If they have
// opposite signs, this eor will set the N flag.
+#if defined(USE_THUMB_1)
+ beq 1f
+ movs r6, r0
+ eors r6, r1
+1:
+#else
it ne
eorsne r12, r0, r1
+#endif
// If a and b are equal (either both zeros or bit identical; again, we're
// ignoring NaNs for now), this subtract will zero out r0. If they have the
// same sign, the flags are updated as they would be for a comparison of the
// absolute values of a and b.
+#if defined(USE_THUMB_1)
+ bmi 1f
+ subs r0, r2, r3
+1:
+#else
it pl
subspl r0, r2, r3
+#endif
// If a is smaller in magnitude than b and both have the same sign, place
// the negation of the sign of b in r0. Thus, if both are negative and
@@ -76,73 +104,158 @@ DEFINE_COMPILERRT_FUNCTION(__eqsf2)
// still clear from the shift argument in orrs; if a is positive and b
// negative, this places 0 in r0; if a is negative and b positive, -1 is
// placed in r0.
+#if defined(USE_THUMB_1)
+ bhs 1f
+ // Here if a and b have the same sign and absA < absB, the result is thus
+ // b < 0 ? 1 : -1. Same if a and b have the opposite sign (ignoring Nan).
+ movs r0, #1
+ lsrs r1, #31
+ bne LOCAL_LABEL(CHECK_NAN\@)
+ negs r0, r0
+ b LOCAL_LABEL(CHECK_NAN\@)
+1:
+#else
it lo
mvnlo r0, r1, asr #31
+#endif
// If a is greater in magnitude than b and both have the same sign, place
// the sign of b in r0. Thus, if both are negative and a < b, -1 is placed
// in r0, which is the desired result. Conversely, if both are positive
// and a > b, zero is placed in r0.
+#if defined(USE_THUMB_1)
+ bls 1f
+ // Here both have the same sign and absA > absB.
+ movs r0, #1
+ lsrs r1, #31
+ beq LOCAL_LABEL(CHECK_NAN\@)
+ negs r0, r0
+1:
+#else
it hi
movhi r0, r1, asr #31
+#endif
// If you've been keeping track, at this point r0 contains -1 if a < b and
// 0 if a >= b. All that remains to be done is to set it to 1 if a > b.
// If a == b, then the Z flag is set, so we can get the correct final value
// into r0 by simply or'ing with 1 if Z is clear.
+ // For Thumb-1, r0 contains -1 if a < b, 0 if a > b and 0 if a == b.
+#if !defined(USE_THUMB_1)
it ne
orrne r0, r0, #1
+#endif
// Finally, we need to deal with NaNs. If either argument is NaN, replace
// the value in r0 with 1.
+#if defined(USE_THUMB_1)
+LOCAL_LABEL(CHECK_NAN\@):
+ movs r6, #0xff
+ lsls r6, #24
+ cmp r2, r6
+ bhi 1f
+ cmp r3, r6
+1:
+ bls 2f
+ \handle_nan
+2:
+ pop {r6, pc}
+#else
cmp r2, #0xff000000
ite ls
cmpls r3, #0xff000000
- movhi r0, #1
+ \handle_nan
JMP(lr)
+#endif
+ .endm
+
+@ int __eqsf2(float a, float b)
+
+ .p2align 2
+DEFINE_COMPILERRT_FUNCTION(__eqsf2)
+
+ .macro __eqsf2_handle_nan
+#if defined(USE_THUMB_1)
+ movs r0, #1
+#else
+ movhi r0, #1
+#endif
+ .endm
+
+COMPARESF2_FUNCTION_BODY __eqsf2_handle_nan
+
END_COMPILERRT_FUNCTION(__eqsf2)
+
DEFINE_COMPILERRT_FUNCTION_ALIAS(__lesf2, __eqsf2)
DEFINE_COMPILERRT_FUNCTION_ALIAS(__ltsf2, __eqsf2)
DEFINE_COMPILERRT_FUNCTION_ALIAS(__nesf2, __eqsf2)
-.p2align 2
+#if defined(__ELF__)
+// Alias for libgcc compatibility
+DEFINE_COMPILERRT_FUNCTION_ALIAS(__cmpsf2, __lesf2)
+#endif
+
+@ int __gtsf2(float a, float b)
+
+ .p2align 2
DEFINE_COMPILERRT_FUNCTION(__gtsf2)
- // Identical to the preceding except in that we return -1 for NaN values.
- // Given that the two paths share so much code, one might be tempted to
- // unify them; however, the extra code needed to do so makes the code size
- // to performance tradeoff very hard to justify for such small functions.
- mov r2, r0, lsl #1
- mov r3, r1, lsl #1
- orrs r12, r2, r3, lsr #1
- it ne
- eorsne r12, r0, r1
- it pl
- subspl r0, r2, r3
- it lo
- mvnlo r0, r1, asr #31
- it hi
- movhi r0, r1, asr #31
- it ne
- orrne r0, r0, #1
- cmp r2, #0xff000000
- ite ls
- cmpls r3, #0xff000000
+
+ .macro __gtsf2_handle_nan
+#if defined(USE_THUMB_1)
+ movs r0, #1
+ negs r0, r0
+#else
movhi r0, #-1
- JMP(lr)
+#endif
+ .endm
+
+COMPARESF2_FUNCTION_BODY __gtsf2_handle_nan
+
END_COMPILERRT_FUNCTION(__gtsf2)
+
DEFINE_COMPILERRT_FUNCTION_ALIAS(__gesf2, __gtsf2)
-.p2align 2
+@ int __unordsf2(float a, float b)
+
+ .p2align 2
DEFINE_COMPILERRT_FUNCTION(__unordsf2)
+
+#if defined(COMPILER_RT_ARMHF_TARGET)
+ vmov r0, s0
+ vmov r1, s1
+#endif
// Return 1 for NaN values, 0 otherwise.
- mov r2, r0, lsl #1
- mov r3, r1, lsl #1
- mov r0, #0
+ lsls r2, r0, #1
+ lsls r3, r1, #1
+ movs r0, #0
+#if defined(USE_THUMB_1)
+ movs r1, #0xff
+ lsls r1, #24
+ cmp r2, r1
+ bhi 1f
+ cmp r3, r1
+1:
+ bls 2f
+ movs r0, #1
+2:
+#else
cmp r2, #0xff000000
ite ls
cmpls r3, #0xff000000
movhi r0, #1
+#endif
JMP(lr)
END_COMPILERRT_FUNCTION(__unordsf2)
+#if defined(COMPILER_RT_ARMHF_TARGET)
+DEFINE_COMPILERRT_FUNCTION(__aeabi_fcmpun)
+ vmov s0, r0
+ vmov s1, r1
+ b SYMBOL_NAME(__unordsf2)
+END_COMPILERRT_FUNCTION(__aeabi_fcmpun)
+#else
DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_fcmpun, __unordsf2)
+#endif
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/divdf3vfp.S b/contrib/libs/cxxsupp/builtins/arm/divdf3vfp.S
index 6eebef167a..ad50b57a65 100644
--- a/contrib/libs/cxxsupp/builtins/arm/divdf3vfp.S
+++ b/contrib/libs/cxxsupp/builtins/arm/divdf3vfp.S
@@ -1,9 +1,8 @@
//===-- divdf3vfp.S - Implement divdf3vfp ---------------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -18,9 +17,16 @@
.syntax unified
.p2align 2
DEFINE_COMPILERRT_FUNCTION(__divdf3vfp)
+#if defined(COMPILER_RT_ARMHF_TARGET)
+ vdiv.f64 d0, d0, d1
+#else
vmov d6, r0, r1 // move first param from r0/r1 pair into d6
vmov d7, r2, r3 // move second param from r2/r3 pair into d7
- vdiv.f64 d5, d6, d7
+ vdiv.f64 d5, d6, d7
vmov r0, r1, d5 // move result back to r0/r1 pair
+#endif
bx lr
END_COMPILERRT_FUNCTION(__divdf3vfp)
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/divmodsi4.S b/contrib/libs/cxxsupp/builtins/arm/divmodsi4.S
index 646b9ab78f..f94438dfd5 100644
--- a/contrib/libs/cxxsupp/builtins/arm/divmodsi4.S
+++ b/contrib/libs/cxxsupp/builtins/arm/divmodsi4.S
@@ -1,17 +1,16 @@
-/*===-- divmodsi4.S - 32-bit signed integer divide and modulus ------------===//
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- *===----------------------------------------------------------------------===//
- *
- * This file implements the __divmodsi4 (32-bit signed integer divide and
- * modulus) function for the ARM architecture. A naive digit-by-digit
- * computation is employed for simplicity.
- *
- *===----------------------------------------------------------------------===*/
+//===-- divmodsi4.S - 32-bit signed integer divide and modulus ------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the __divmodsi4 (32-bit signed integer divide and
+// modulus) function for the ARM architecture. A naive digit-by-digit
+// computation is employed for simplicity.
+//
+//===----------------------------------------------------------------------===//
#include "../assembly.h"
@@ -23,20 +22,14 @@
.syntax unified
.text
-#if __ARM_ARCH_ISA_THUMB == 2
- .thumb
-#endif
+ DEFINE_CODE_STATE
@ int __divmodsi4(int divident, int divisor, int *remainder)
@ Calculate the quotient and remainder of the (signed) division. The return
@ value is the quotient, the remainder is placed in the variable.
.p2align 3
-#if __ARM_ARCH_ISA_THUMB == 2
-DEFINE_COMPILERRT_THUMB_FUNCTION(__divmodsi4)
-#else
DEFINE_COMPILERRT_FUNCTION(__divmodsi4)
-#endif
#if __ARM_ARCH_EXT_IDIV__
tst r1, r1
beq LOCAL_LABEL(divzero)
@@ -72,3 +65,6 @@ LOCAL_LABEL(divzero):
CLEAR_FRAME_AND_RETURN
#endif
END_COMPILERRT_FUNCTION(__divmodsi4)
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/divsf3vfp.S b/contrib/libs/cxxsupp/builtins/arm/divsf3vfp.S
index fdbaebc883..958a6724bb 100644
--- a/contrib/libs/cxxsupp/builtins/arm/divsf3vfp.S
+++ b/contrib/libs/cxxsupp/builtins/arm/divsf3vfp.S
@@ -1,9 +1,8 @@
//===-- divsf3vfp.S - Implement divsf3vfp ---------------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -18,9 +17,16 @@
.syntax unified
.p2align 2
DEFINE_COMPILERRT_FUNCTION(__divsf3vfp)
+#if defined(COMPILER_RT_ARMHF_TARGET)
+ vdiv.f32 s0, s0, s1
+#else
vmov s14, r0 // move first param from r0 into float register
vmov s15, r1 // move second param from r1 into float register
vdiv.f32 s13, s14, s15
vmov r0, s13 // move result back to r0
+#endif
bx lr
END_COMPILERRT_FUNCTION(__divsf3vfp)
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/divsi3.S b/contrib/libs/cxxsupp/builtins/arm/divsi3.S
index adf8f94fc7..761bf49d3e 100644
--- a/contrib/libs/cxxsupp/builtins/arm/divsi3.S
+++ b/contrib/libs/cxxsupp/builtins/arm/divsi3.S
@@ -1,16 +1,15 @@
-/*===-- divsi3.S - 32-bit signed integer divide ---------------------------===//
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- *===----------------------------------------------------------------------===//
- *
- * This file implements the __divsi3 (32-bit signed integer divide) function
- * for the ARM architecture as a wrapper around the unsigned routine.
- *
- *===----------------------------------------------------------------------===*/
+//===-- divsi3.S - 32-bit signed integer divide ---------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the __divsi3 (32-bit signed integer divide) function
+// for the ARM architecture as a wrapper around the unsigned routine.
+//
+//===----------------------------------------------------------------------===//
#include "../assembly.h"
@@ -20,11 +19,9 @@
#define CLEAR_FRAME_AND_RETURN \
pop {r4, r7, pc}
- .syntax unified
- .text
-#if __ARM_ARCH_ISA_THUMB == 2
- .thumb
-#endif
+ .syntax unified
+ .text
+ DEFINE_CODE_STATE
.p2align 3
// Ok, APCS and AAPCS agree on 32 bit args, so it's safe to use the same routine.
@@ -33,11 +30,7 @@ DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_idiv, __divsi3)
@ int __divsi3(int divident, int divisor)
@ Calculate and return the quotient of the (signed) division.
-#if __ARM_ARCH_ISA_THUMB == 2
-DEFINE_COMPILERRT_THUMB_FUNCTION(__divsi3)
-#else
DEFINE_COMPILERRT_FUNCTION(__divsi3)
-#endif
#if __ARM_ARCH_EXT_IDIV__
tst r1,r1
beq LOCAL_LABEL(divzero)
@@ -49,17 +42,40 @@ LOCAL_LABEL(divzero):
#else
ESTABLISH_FRAME
// Set aside the sign of the quotient.
+# if defined(USE_THUMB_1)
+ movs r4, r0
+ eors r4, r1
+# else
eor r4, r0, r1
+# endif
// Take absolute value of a and b via abs(x) = (x^(x >> 31)) - (x >> 31).
+# if defined(USE_THUMB_1)
+ asrs r2, r0, #31
+ asrs r3, r1, #31
+ eors r0, r2
+ eors r1, r3
+ subs r0, r0, r2
+ subs r1, r1, r3
+# else
eor r2, r0, r0, asr #31
eor r3, r1, r1, asr #31
sub r0, r2, r0, asr #31
sub r1, r3, r1, asr #31
+# endif
// abs(a) / abs(b)
bl SYMBOL_NAME(__udivsi3)
// Apply sign of quotient to result and return.
+# if defined(USE_THUMB_1)
+ asrs r4, #31
+ eors r0, r4
+ subs r0, r0, r4
+# else
eor r0, r0, r4, asr #31
sub r0, r0, r4, asr #31
+# endif
CLEAR_FRAME_AND_RETURN
#endif
END_COMPILERRT_FUNCTION(__divsi3)
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/eqdf2vfp.S b/contrib/libs/cxxsupp/builtins/arm/eqdf2vfp.S
index 7f2fbc3072..2a0a64b97e 100644
--- a/contrib/libs/cxxsupp/builtins/arm/eqdf2vfp.S
+++ b/contrib/libs/cxxsupp/builtins/arm/eqdf2vfp.S
@@ -1,29 +1,35 @@
//===-- eqdf2vfp.S - Implement eqdf2vfp -----------------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "../assembly.h"
-//
// extern int __eqdf2vfp(double a, double b);
//
// Returns one iff a == b and neither is NaN.
-// Uses Darwin calling convention where double precision arguments are passsed
+// Uses Darwin calling convention where double precision arguments are passsed
// like in GPR pairs.
-//
+
.syntax unified
.p2align 2
DEFINE_COMPILERRT_FUNCTION(__eqdf2vfp)
+#if defined(COMPILER_RT_ARMHF_TARGET)
+ vcmp.f64 d0, d1
+#else
vmov d6, r0, r1 // load r0/r1 pair in double register
vmov d7, r2, r3 // load r2/r3 pair in double register
- vcmp.f64 d6, d7
+ vcmp.f64 d6, d7
+#endif
vmrs apsr_nzcv, fpscr
+ ITE(eq)
moveq r0, #1 // set result register to 1 if equal
movne r0, #0
bx lr
END_COMPILERRT_FUNCTION(__eqdf2vfp)
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/eqsf2vfp.S b/contrib/libs/cxxsupp/builtins/arm/eqsf2vfp.S
index a318b336ae..5fefe7b717 100644
--- a/contrib/libs/cxxsupp/builtins/arm/eqsf2vfp.S
+++ b/contrib/libs/cxxsupp/builtins/arm/eqsf2vfp.S
@@ -1,9 +1,8 @@
//===-- eqsf2vfp.S - Implement eqsf2vfp -----------------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -13,17 +12,25 @@
// extern int __eqsf2vfp(float a, float b);
//
// Returns one iff a == b and neither is NaN.
-// Uses Darwin calling convention where single precision arguments are passsed
+// Uses Darwin calling convention where single precision arguments are passsed
// like 32-bit ints
//
.syntax unified
.p2align 2
DEFINE_COMPILERRT_FUNCTION(__eqsf2vfp)
+#if defined(COMPILER_RT_ARMHF_TARGET)
+ vcmp.f32 s0, s1
+#else
vmov s14, r0 // move from GPR 0 to float register
vmov s15, r1 // move from GPR 1 to float register
vcmp.f32 s14, s15
+#endif
vmrs apsr_nzcv, fpscr
+ ITE(eq)
moveq r0, #1 // set result register to 1 if equal
movne r0, #0
bx lr
END_COMPILERRT_FUNCTION(__eqsf2vfp)
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/extendsfdf2vfp.S b/contrib/libs/cxxsupp/builtins/arm/extendsfdf2vfp.S
index b998e58945..37c8be8dcd 100644
--- a/contrib/libs/cxxsupp/builtins/arm/extendsfdf2vfp.S
+++ b/contrib/libs/cxxsupp/builtins/arm/extendsfdf2vfp.S
@@ -1,9 +1,8 @@
//===-- extendsfdf2vfp.S - Implement extendsfdf2vfp -----------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -13,14 +12,21 @@
// extern double __extendsfdf2vfp(float a);
//
// Converts single precision float to double precision result.
-// Uses Darwin calling convention where a single precision parameter is
+// Uses Darwin calling convention where a single precision parameter is
// passed in a GPR and a double precision result is returned in R0/R1 pair.
//
.syntax unified
.p2align 2
DEFINE_COMPILERRT_FUNCTION(__extendsfdf2vfp)
+#if defined(COMPILER_RT_ARMHF_TARGET)
+ vcvt.f64.f32 d0, s0
+#else
vmov s15, r0 // load float register from R0
vcvt.f64.f32 d7, s15 // convert single to double
vmov r0, r1, d7 // return result in r0/r1 pair
+#endif
bx lr
END_COMPILERRT_FUNCTION(__extendsfdf2vfp)
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/fixdfsivfp.S b/contrib/libs/cxxsupp/builtins/arm/fixdfsivfp.S
index e3bd8e05e0..af1d4f4fa5 100644
--- a/contrib/libs/cxxsupp/builtins/arm/fixdfsivfp.S
+++ b/contrib/libs/cxxsupp/builtins/arm/fixdfsivfp.S
@@ -1,9 +1,8 @@
//===-- fixdfsivfp.S - Implement fixdfsivfp -----------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -13,14 +12,22 @@
// extern int __fixdfsivfp(double a);
//
// Converts double precision float to a 32-bit int rounding towards zero.
-// Uses Darwin calling convention where a double precision parameter is
+// Uses Darwin calling convention where a double precision parameter is
// passed in GPR register pair.
//
.syntax unified
.p2align 2
DEFINE_COMPILERRT_FUNCTION(__fixdfsivfp)
+#if defined(COMPILER_RT_ARMHF_TARGET)
+ vcvt.s32.f64 s0, d0
+ vmov r0, s0
+#else
vmov d7, r0, r1 // load double register from R0/R1
vcvt.s32.f64 s15, d7 // convert double to 32-bit int into s15
vmov r0, s15 // move s15 to result register
+#endif
bx lr
END_COMPILERRT_FUNCTION(__fixdfsivfp)
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/fixsfsivfp.S b/contrib/libs/cxxsupp/builtins/arm/fixsfsivfp.S
index 3d0d0f56d2..30b2f3cf93 100644
--- a/contrib/libs/cxxsupp/builtins/arm/fixsfsivfp.S
+++ b/contrib/libs/cxxsupp/builtins/arm/fixsfsivfp.S
@@ -1,9 +1,8 @@
//===-- fixsfsivfp.S - Implement fixsfsivfp -----------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -13,14 +12,22 @@
// extern int __fixsfsivfp(float a);
//
// Converts single precision float to a 32-bit int rounding towards zero.
-// Uses Darwin calling convention where a single precision parameter is
+// Uses Darwin calling convention where a single precision parameter is
// passed in a GPR..
//
.syntax unified
.p2align 2
DEFINE_COMPILERRT_FUNCTION(__fixsfsivfp)
+#if defined(COMPILER_RT_ARMHF_TARGET)
+ vcvt.s32.f32 s0, s0
+ vmov r0, s0
+#else
vmov s15, r0 // load float register from R0
vcvt.s32.f32 s15, s15 // convert single to 32-bit int into s15
vmov r0, s15 // move s15 to result register
+#endif
bx lr
END_COMPILERRT_FUNCTION(__fixsfsivfp)
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/fixunsdfsivfp.S b/contrib/libs/cxxsupp/builtins/arm/fixunsdfsivfp.S
index 35dda5b9b0..44e6dbd498 100644
--- a/contrib/libs/cxxsupp/builtins/arm/fixunsdfsivfp.S
+++ b/contrib/libs/cxxsupp/builtins/arm/fixunsdfsivfp.S
@@ -1,9 +1,8 @@
//===-- fixunsdfsivfp.S - Implement fixunsdfsivfp -------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -12,16 +11,24 @@
//
// extern unsigned int __fixunsdfsivfp(double a);
//
-// Converts double precision float to a 32-bit unsigned int rounding towards
+// Converts double precision float to a 32-bit unsigned int rounding towards
// zero. All negative values become zero.
-// Uses Darwin calling convention where a double precision parameter is
+// Uses Darwin calling convention where a double precision parameter is
// passed in GPR register pair.
//
.syntax unified
.p2align 2
DEFINE_COMPILERRT_FUNCTION(__fixunsdfsivfp)
+#if defined(COMPILER_RT_ARMHF_TARGET)
+ vcvt.u32.f64 s0, d0
+ vmov r0, s0
+#else
vmov d7, r0, r1 // load double register from R0/R1
vcvt.u32.f64 s15, d7 // convert double to 32-bit int into s15
vmov r0, s15 // move s15 to result register
+#endif
bx lr
END_COMPILERRT_FUNCTION(__fixunsdfsivfp)
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/fixunssfsivfp.S b/contrib/libs/cxxsupp/builtins/arm/fixunssfsivfp.S
index 5c3a7d926f..5d6ee7cce2 100644
--- a/contrib/libs/cxxsupp/builtins/arm/fixunssfsivfp.S
+++ b/contrib/libs/cxxsupp/builtins/arm/fixunssfsivfp.S
@@ -1,9 +1,8 @@
//===-- fixunssfsivfp.S - Implement fixunssfsivfp -------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -12,16 +11,24 @@
//
// extern unsigned int __fixunssfsivfp(float a);
//
-// Converts single precision float to a 32-bit unsigned int rounding towards
+// Converts single precision float to a 32-bit unsigned int rounding towards
// zero. All negative values become zero.
-// Uses Darwin calling convention where a single precision parameter is
+// Uses Darwin calling convention where a single precision parameter is
// passed in a GPR..
//
.syntax unified
.p2align 2
DEFINE_COMPILERRT_FUNCTION(__fixunssfsivfp)
+#if defined(COMPILER_RT_ARMHF_TARGET)
+ vcvt.u32.f32 s0, s0
+ vmov r0, s0
+#else
vmov s15, r0 // load float register from R0
vcvt.u32.f32 s15, s15 // convert single to 32-bit unsigned into s15
vmov r0, s15 // move s15 to result register
+#endif
bx lr
END_COMPILERRT_FUNCTION(__fixunssfsivfp)
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/floatsidfvfp.S b/contrib/libs/cxxsupp/builtins/arm/floatsidfvfp.S
index d69184914c..ae8d246588 100644
--- a/contrib/libs/cxxsupp/builtins/arm/floatsidfvfp.S
+++ b/contrib/libs/cxxsupp/builtins/arm/floatsidfvfp.S
@@ -1,9 +1,8 @@
//===-- floatsidfvfp.S - Implement floatsidfvfp ---------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -13,14 +12,22 @@
// extern double __floatsidfvfp(int a);
//
// Converts a 32-bit int to a double precision float.
-// Uses Darwin calling convention where a double precision result is
+// Uses Darwin calling convention where a double precision result is
// return in GPR register pair.
//
.syntax unified
.p2align 2
DEFINE_COMPILERRT_FUNCTION(__floatsidfvfp)
+#if defined(COMPILER_RT_ARMHF_TARGET)
+ vmov s0, r0
+ vcvt.f64.s32 d0, s0
+#else
vmov s15, r0 // move int to float register s15
vcvt.f64.s32 d7, s15 // convert 32-bit int in s15 to double in d7
vmov r0, r1, d7 // move d7 to result register pair r0/r1
+#endif
bx lr
END_COMPILERRT_FUNCTION(__floatsidfvfp)
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/floatsisfvfp.S b/contrib/libs/cxxsupp/builtins/arm/floatsisfvfp.S
index 4a0cb39d0e..a36bc5ee5e 100644
--- a/contrib/libs/cxxsupp/builtins/arm/floatsisfvfp.S
+++ b/contrib/libs/cxxsupp/builtins/arm/floatsisfvfp.S
@@ -1,9 +1,8 @@
//===-- floatsisfvfp.S - Implement floatsisfvfp ---------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -13,14 +12,22 @@
// extern float __floatsisfvfp(int a);
//
// Converts single precision float to a 32-bit int rounding towards zero.
-// Uses Darwin calling convention where a single precision result is
+// Uses Darwin calling convention where a single precision result is
// return in a GPR..
//
.syntax unified
.p2align 2
DEFINE_COMPILERRT_FUNCTION(__floatsisfvfp)
+#if defined(COMPILER_RT_ARMHF_TARGET)
+ vmov s0, r0
+ vcvt.f32.s32 s0, s0
+#else
vmov s15, r0 // move int to float register s15
vcvt.f32.s32 s15, s15 // convert 32-bit int in s15 to float in s15
vmov r0, s15 // move s15 to result register
+#endif
bx lr
END_COMPILERRT_FUNCTION(__floatsisfvfp)
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/floatunssidfvfp.S b/contrib/libs/cxxsupp/builtins/arm/floatunssidfvfp.S
index d92969ea34..0932dab2bd 100644
--- a/contrib/libs/cxxsupp/builtins/arm/floatunssidfvfp.S
+++ b/contrib/libs/cxxsupp/builtins/arm/floatunssidfvfp.S
@@ -1,9 +1,8 @@
//===-- floatunssidfvfp.S - Implement floatunssidfvfp ---------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -13,14 +12,22 @@
// extern double __floatunssidfvfp(unsigned int a);
//
// Converts a 32-bit int to a double precision float.
-// Uses Darwin calling convention where a double precision result is
+// Uses Darwin calling convention where a double precision result is
// return in GPR register pair.
//
.syntax unified
.p2align 2
DEFINE_COMPILERRT_FUNCTION(__floatunssidfvfp)
+#if defined(COMPILER_RT_ARMHF_TARGET)
+ vmov s0, r0
+ vcvt.f64.u32 d0, s0
+#else
vmov s15, r0 // move int to float register s15
vcvt.f64.u32 d7, s15 // convert 32-bit int in s15 to double in d7
vmov r0, r1, d7 // move d7 to result register pair r0/r1
+#endif
bx lr
END_COMPILERRT_FUNCTION(__floatunssidfvfp)
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/floatunssisfvfp.S b/contrib/libs/cxxsupp/builtins/arm/floatunssisfvfp.S
index f6aeba56ae..9578546f40 100644
--- a/contrib/libs/cxxsupp/builtins/arm/floatunssisfvfp.S
+++ b/contrib/libs/cxxsupp/builtins/arm/floatunssisfvfp.S
@@ -1,9 +1,8 @@
//===-- floatunssisfvfp.S - Implement floatunssisfvfp ---------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -13,14 +12,22 @@
// extern float __floatunssisfvfp(unsigned int a);
//
// Converts single precision float to a 32-bit int rounding towards zero.
-// Uses Darwin calling convention where a single precision result is
+// Uses Darwin calling convention where a single precision result is
// return in a GPR..
//
.syntax unified
.p2align 2
DEFINE_COMPILERRT_FUNCTION(__floatunssisfvfp)
+#if defined(COMPILER_RT_ARMHF_TARGET)
+ vmov s0, r0
+ vcvt.f32.u32 s0, s0
+#else
vmov s15, r0 // move int to float register s15
vcvt.f32.u32 s15, s15 // convert 32-bit int in s15 to float in s15
vmov r0, s15 // move s15 to result register
+#endif
bx lr
END_COMPILERRT_FUNCTION(__floatunssisfvfp)
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/fp_mode.c b/contrib/libs/cxxsupp/builtins/arm/fp_mode.c
new file mode 100644
index 0000000000..064f4e94fb
--- /dev/null
+++ b/contrib/libs/cxxsupp/builtins/arm/fp_mode.c
@@ -0,0 +1,60 @@
+//===----- lib/arm/fp_mode.c - Floaing-point mode utilities -------*- C -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include <stdint.h>
+
+#include "../fp_mode.h"
+
+#define ARM_TONEAREST 0x0
+#define ARM_UPWARD 0x1
+#define ARM_DOWNWARD 0x2
+#define ARM_TOWARDZERO 0x3
+#define ARM_RMODE_MASK (ARM_TONEAREST | ARM_UPWARD | \
+ ARM_DOWNWARD | ARM_TOWARDZERO)
+#define ARM_RMODE_SHIFT 22
+
+#define ARM_INEXACT 0x10
+
+#ifndef __ARM_FP
+// For soft float targets, allow changing rounding mode by overriding the weak
+// __arm_fe_default_rmode symbol.
+CRT_FE_ROUND_MODE __attribute__((weak)) __arm_fe_default_rmode =
+ CRT_FE_TONEAREST;
+#endif
+
+CRT_FE_ROUND_MODE __fe_getround(void) {
+#ifdef __ARM_FP
+ uint32_t fpscr;
+ __asm__ __volatile__("vmrs %0, fpscr" : "=r" (fpscr));
+ fpscr = fpscr >> ARM_RMODE_SHIFT & ARM_RMODE_MASK;
+ switch (fpscr) {
+ case ARM_UPWARD:
+ return CRT_FE_UPWARD;
+ case ARM_DOWNWARD:
+ return CRT_FE_DOWNWARD;
+ case ARM_TOWARDZERO:
+ return CRT_FE_TOWARDZERO;
+ case ARM_TONEAREST:
+ default:
+ return CRT_FE_TONEAREST;
+ }
+#else
+ return __arm_fe_default_rmode;
+#endif
+}
+
+int __fe_raise_inexact(void) {
+#ifdef __ARM_FP
+ uint32_t fpscr;
+ __asm__ __volatile__("vmrs %0, fpscr" : "=r" (fpscr));
+ __asm__ __volatile__("vmsr fpscr, %0" : : "ri" (fpscr | ARM_INEXACT));
+ return 0;
+#else
+ return 0;
+#endif
+}
diff --git a/contrib/libs/cxxsupp/builtins/arm/gedf2vfp.S b/contrib/libs/cxxsupp/builtins/arm/gedf2vfp.S
index 9e23527017..2af9d90996 100644
--- a/contrib/libs/cxxsupp/builtins/arm/gedf2vfp.S
+++ b/contrib/libs/cxxsupp/builtins/arm/gedf2vfp.S
@@ -1,9 +1,8 @@
//===-- gedf2vfp.S - Implement gedf2vfp -----------------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -13,17 +12,25 @@
// extern int __gedf2vfp(double a, double b);
//
// Returns one iff a >= b and neither is NaN.
-// Uses Darwin calling convention where double precision arguments are passsed
+// Uses Darwin calling convention where double precision arguments are passsed
// like in GPR pairs.
//
.syntax unified
.p2align 2
DEFINE_COMPILERRT_FUNCTION(__gedf2vfp)
+#if defined(COMPILER_RT_ARMHF_TARGET)
+ vcmp.f64 d0, d1
+#else
vmov d6, r0, r1 // load r0/r1 pair in double register
vmov d7, r2, r3 // load r2/r3 pair in double register
vcmp.f64 d6, d7
+#endif
vmrs apsr_nzcv, fpscr
+ ITE(ge)
movge r0, #1 // set result register to 1 if greater than or equal
movlt r0, #0
bx lr
END_COMPILERRT_FUNCTION(__gedf2vfp)
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/gesf2vfp.S b/contrib/libs/cxxsupp/builtins/arm/gesf2vfp.S
index 0ff6084778..cedd1e13eb 100644
--- a/contrib/libs/cxxsupp/builtins/arm/gesf2vfp.S
+++ b/contrib/libs/cxxsupp/builtins/arm/gesf2vfp.S
@@ -1,9 +1,8 @@
//===-- gesf2vfp.S - Implement gesf2vfp -----------------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -13,17 +12,25 @@
// extern int __gesf2vfp(float a, float b);
//
// Returns one iff a >= b and neither is NaN.
-// Uses Darwin calling convention where single precision arguments are passsed
+// Uses Darwin calling convention where single precision arguments are passsed
// like 32-bit ints
//
.syntax unified
.p2align 2
DEFINE_COMPILERRT_FUNCTION(__gesf2vfp)
+#if defined(COMPILER_RT_ARMHF_TARGET)
+ vcmp.f32 s0, s1
+#else
vmov s14, r0 // move from GPR 0 to float register
vmov s15, r1 // move from GPR 1 to float register
vcmp.f32 s14, s15
+#endif
vmrs apsr_nzcv, fpscr
+ ITE(ge)
movge r0, #1 // set result register to 1 if greater than or equal
movlt r0, #0
bx lr
END_COMPILERRT_FUNCTION(__gesf2vfp)
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/gtdf2vfp.S b/contrib/libs/cxxsupp/builtins/arm/gtdf2vfp.S
index 3dc5d5b592..782ad8cac0 100644
--- a/contrib/libs/cxxsupp/builtins/arm/gtdf2vfp.S
+++ b/contrib/libs/cxxsupp/builtins/arm/gtdf2vfp.S
@@ -1,9 +1,8 @@
//===-- gtdf2vfp.S - Implement gtdf2vfp -----------------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -13,17 +12,25 @@
// extern double __gtdf2vfp(double a, double b);
//
// Returns one iff a > b and neither is NaN.
-// Uses Darwin calling convention where double precision arguments are passsed
+// Uses Darwin calling convention where double precision arguments are passsed
// like in GPR pairs.
//
.syntax unified
.p2align 2
DEFINE_COMPILERRT_FUNCTION(__gtdf2vfp)
+#if defined(COMPILER_RT_ARMHF_TARGET)
+ vcmp.f64 d0, d1
+#else
vmov d6, r0, r1 // load r0/r1 pair in double register
vmov d7, r2, r3 // load r2/r3 pair in double register
vcmp.f64 d6, d7
+#endif
vmrs apsr_nzcv, fpscr
+ ITE(gt)
movgt r0, #1 // set result register to 1 if equal
movle r0, #0
bx lr
END_COMPILERRT_FUNCTION(__gtdf2vfp)
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/gtsf2vfp.S b/contrib/libs/cxxsupp/builtins/arm/gtsf2vfp.S
index ddd843acf5..1cc2bd14f8 100644
--- a/contrib/libs/cxxsupp/builtins/arm/gtsf2vfp.S
+++ b/contrib/libs/cxxsupp/builtins/arm/gtsf2vfp.S
@@ -1,9 +1,8 @@
//===-- gtsf2vfp.S - Implement gtsf2vfp -----------------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -13,17 +12,25 @@
// extern int __gtsf2vfp(float a, float b);
//
// Returns one iff a > b and neither is NaN.
-// Uses Darwin calling convention where single precision arguments are passsed
+// Uses Darwin calling convention where single precision arguments are passsed
// like 32-bit ints
//
.syntax unified
.p2align 2
DEFINE_COMPILERRT_FUNCTION(__gtsf2vfp)
+#if defined(COMPILER_RT_ARMHF_TARGET)
+ vcmp.f32 s0, s1
+#else
vmov s14, r0 // move from GPR 0 to float register
vmov s15, r1 // move from GPR 1 to float register
vcmp.f32 s14, s15
+#endif
vmrs apsr_nzcv, fpscr
+ ITE(gt)
movgt r0, #1 // set result register to 1 if equal
movle r0, #0
bx lr
END_COMPILERRT_FUNCTION(__gtsf2vfp)
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/ledf2vfp.S b/contrib/libs/cxxsupp/builtins/arm/ledf2vfp.S
index b06ff6db5a..0097e4b6c1 100644
--- a/contrib/libs/cxxsupp/builtins/arm/ledf2vfp.S
+++ b/contrib/libs/cxxsupp/builtins/arm/ledf2vfp.S
@@ -1,9 +1,8 @@
//===-- ledf2vfp.S - Implement ledf2vfp -----------------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -13,17 +12,25 @@
// extern double __ledf2vfp(double a, double b);
//
// Returns one iff a <= b and neither is NaN.
-// Uses Darwin calling convention where double precision arguments are passsed
+// Uses Darwin calling convention where double precision arguments are passsed
// like in GPR pairs.
//
.syntax unified
.p2align 2
DEFINE_COMPILERRT_FUNCTION(__ledf2vfp)
+#if defined(COMPILER_RT_ARMHF_TARGET)
+ vcmp.f64 d0, d1
+#else
vmov d6, r0, r1 // load r0/r1 pair in double register
vmov d7, r2, r3 // load r2/r3 pair in double register
vcmp.f64 d6, d7
+#endif
vmrs apsr_nzcv, fpscr
+ ITE(ls)
movls r0, #1 // set result register to 1 if equal
movhi r0, #0
bx lr
END_COMPILERRT_FUNCTION(__ledf2vfp)
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/lesf2vfp.S b/contrib/libs/cxxsupp/builtins/arm/lesf2vfp.S
index 9b33c0c536..2052d38691 100644
--- a/contrib/libs/cxxsupp/builtins/arm/lesf2vfp.S
+++ b/contrib/libs/cxxsupp/builtins/arm/lesf2vfp.S
@@ -1,9 +1,8 @@
//===-- lesf2vfp.S - Implement lesf2vfp -----------------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -13,17 +12,25 @@
// extern int __lesf2vfp(float a, float b);
//
// Returns one iff a <= b and neither is NaN.
-// Uses Darwin calling convention where single precision arguments are passsed
+// Uses Darwin calling convention where single precision arguments are passsed
// like 32-bit ints
//
.syntax unified
.p2align 2
DEFINE_COMPILERRT_FUNCTION(__lesf2vfp)
+#if defined(COMPILER_RT_ARMHF_TARGET)
+ vcmp.f32 s0, s1
+#else
vmov s14, r0 // move from GPR 0 to float register
vmov s15, r1 // move from GPR 1 to float register
vcmp.f32 s14, s15
+#endif
vmrs apsr_nzcv, fpscr
+ ITE(ls)
movls r0, #1 // set result register to 1 if equal
movhi r0, #0
bx lr
END_COMPILERRT_FUNCTION(__lesf2vfp)
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/ltdf2vfp.S b/contrib/libs/cxxsupp/builtins/arm/ltdf2vfp.S
index 9f794b026a..a126aa9e05 100644
--- a/contrib/libs/cxxsupp/builtins/arm/ltdf2vfp.S
+++ b/contrib/libs/cxxsupp/builtins/arm/ltdf2vfp.S
@@ -1,9 +1,8 @@
//===-- ltdf2vfp.S - Implement ltdf2vfp -----------------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -13,17 +12,25 @@
// extern double __ltdf2vfp(double a, double b);
//
// Returns one iff a < b and neither is NaN.
-// Uses Darwin calling convention where double precision arguments are passsed
+// Uses Darwin calling convention where double precision arguments are passsed
// like in GPR pairs.
//
.syntax unified
.p2align 2
DEFINE_COMPILERRT_FUNCTION(__ltdf2vfp)
+#if defined(COMPILER_RT_ARMHF_TARGET)
+ vcmp.f64 d0, d1
+#else
vmov d6, r0, r1 // load r0/r1 pair in double register
vmov d7, r2, r3 // load r2/r3 pair in double register
vcmp.f64 d6, d7
+#endif
vmrs apsr_nzcv, fpscr
+ ITE(mi)
movmi r0, #1 // set result register to 1 if equal
movpl r0, #0
bx lr
END_COMPILERRT_FUNCTION(__ltdf2vfp)
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/ltsf2vfp.S b/contrib/libs/cxxsupp/builtins/arm/ltsf2vfp.S
index ba190d9d8d..ba10d71d20 100644
--- a/contrib/libs/cxxsupp/builtins/arm/ltsf2vfp.S
+++ b/contrib/libs/cxxsupp/builtins/arm/ltsf2vfp.S
@@ -1,9 +1,8 @@
//===-- ltsf2vfp.S - Implement ltsf2vfp -----------------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -13,17 +12,25 @@
// extern int __ltsf2vfp(float a, float b);
//
// Returns one iff a < b and neither is NaN.
-// Uses Darwin calling convention where single precision arguments are passsed
+// Uses Darwin calling convention where single precision arguments are passsed
// like 32-bit ints
//
.syntax unified
.p2align 2
DEFINE_COMPILERRT_FUNCTION(__ltsf2vfp)
+#if defined(COMPILER_RT_ARMHF_TARGET)
+ vcmp.f32 s0, s1
+#else
vmov s14, r0 // move from GPR 0 to float register
vmov s15, r1 // move from GPR 1 to float register
vcmp.f32 s14, s15
+#endif
vmrs apsr_nzcv, fpscr
+ ITE(mi)
movmi r0, #1 // set result register to 1 if equal
movpl r0, #0
bx lr
END_COMPILERRT_FUNCTION(__ltsf2vfp)
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/modsi3.S b/contrib/libs/cxxsupp/builtins/arm/modsi3.S
index 295a227d86..5312f5b41c 100644
--- a/contrib/libs/cxxsupp/builtins/arm/modsi3.S
+++ b/contrib/libs/cxxsupp/builtins/arm/modsi3.S
@@ -1,16 +1,15 @@
-/*===-- modsi3.S - 32-bit signed integer modulus --------------------------===//
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- *===----------------------------------------------------------------------===//
- *
- * This file implements the __modsi3 (32-bit signed integer modulus) function
- * for the ARM architecture as a wrapper around the unsigned routine.
- *
- *===----------------------------------------------------------------------===*/
+//===-- modsi3.S - 32-bit signed integer modulus --------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the __modsi3 (32-bit signed integer modulus) function
+// for the ARM architecture as a wrapper around the unsigned routine.
+//
+//===----------------------------------------------------------------------===//
#include "../assembly.h"
@@ -22,19 +21,13 @@
.syntax unified
.text
-#if __ARM_ARCH_ISA_THUMB == 2
- .thumb
-#endif
+ DEFINE_CODE_STATE
@ int __modsi3(int divident, int divisor)
@ Calculate and return the remainder of the (signed) division.
.p2align 3
-#if __ARM_ARCH_ISA_THUMB == 2
-DEFINE_COMPILERRT_THUMB_FUNCTION(__modsi3)
-#else
DEFINE_COMPILERRT_FUNCTION(__modsi3)
-#endif
#if __ARM_ARCH_EXT_IDIV__
tst r1, r1
beq LOCAL_LABEL(divzero)
@@ -61,3 +54,6 @@ LOCAL_LABEL(divzero):
CLEAR_FRAME_AND_RETURN
#endif
END_COMPILERRT_FUNCTION(__modsi3)
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/muldf3vfp.S b/contrib/libs/cxxsupp/builtins/arm/muldf3vfp.S
index 636cc711ac..9adc937bcb 100644
--- a/contrib/libs/cxxsupp/builtins/arm/muldf3vfp.S
+++ b/contrib/libs/cxxsupp/builtins/arm/muldf3vfp.S
@@ -1,9 +1,8 @@
//===-- muldf3vfp.S - Implement muldf3vfp ---------------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -18,9 +17,16 @@
.syntax unified
.p2align 2
DEFINE_COMPILERRT_FUNCTION(__muldf3vfp)
+#if defined(COMPILER_RT_ARMHF_TARGET)
+ vmul.f64 d0, d0, d1
+#else
vmov d6, r0, r1 // move first param from r0/r1 pair into d6
vmov d7, r2, r3 // move second param from r2/r3 pair into d7
- vmul.f64 d6, d6, d7
+ vmul.f64 d6, d6, d7
vmov r0, r1, d6 // move result back to r0/r1 pair
+#endif
bx lr
END_COMPILERRT_FUNCTION(__muldf3vfp)
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/mulsf3vfp.S b/contrib/libs/cxxsupp/builtins/arm/mulsf3vfp.S
index 7f4008266b..a94131bebb 100644
--- a/contrib/libs/cxxsupp/builtins/arm/mulsf3vfp.S
+++ b/contrib/libs/cxxsupp/builtins/arm/mulsf3vfp.S
@@ -1,9 +1,8 @@
//===-- mulsf3vfp.S - Implement mulsf3vfp ---------------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -18,9 +17,16 @@
.syntax unified
.p2align 2
DEFINE_COMPILERRT_FUNCTION(__mulsf3vfp)
+#if defined(COMPILER_RT_ARMHF_TARGET)
+ vmul.f32 s0, s0, s1
+#else
vmov s14, r0 // move first param from r0 into float register
vmov s15, r1 // move second param from r1 into float register
vmul.f32 s13, s14, s15
+#endif
vmov r0, s13 // move result back to r0
bx lr
END_COMPILERRT_FUNCTION(__mulsf3vfp)
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/nedf2vfp.S b/contrib/libs/cxxsupp/builtins/arm/nedf2vfp.S
index 7ab2f5501c..32d35c41d4 100644
--- a/contrib/libs/cxxsupp/builtins/arm/nedf2vfp.S
+++ b/contrib/libs/cxxsupp/builtins/arm/nedf2vfp.S
@@ -1,29 +1,35 @@
//===-- nedf2vfp.S - Implement nedf2vfp -----------------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "../assembly.h"
-//
// extern double __nedf2vfp(double a, double b);
//
// Returns zero if a and b are unequal and neither is NaN.
-// Uses Darwin calling convention where double precision arguments are passsed
+// Uses Darwin calling convention where double precision arguments are passsed
// like in GPR pairs.
-//
+
.syntax unified
.p2align 2
DEFINE_COMPILERRT_FUNCTION(__nedf2vfp)
+#if defined(COMPILER_RT_ARMHF_TARGET)
+ vcmp.f64 d0, d1
+#else
vmov d6, r0, r1 // load r0/r1 pair in double register
vmov d7, r2, r3 // load r2/r3 pair in double register
- vcmp.f64 d6, d7
+ vcmp.f64 d6, d7
+#endif
vmrs apsr_nzcv, fpscr
+ ITE(ne)
movne r0, #1 // set result register to 0 if unequal
moveq r0, #0
bx lr
END_COMPILERRT_FUNCTION(__nedf2vfp)
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/negdf2vfp.S b/contrib/libs/cxxsupp/builtins/arm/negdf2vfp.S
index 56d73c6761..b7cf91877e 100644
--- a/contrib/libs/cxxsupp/builtins/arm/negdf2vfp.S
+++ b/contrib/libs/cxxsupp/builtins/arm/negdf2vfp.S
@@ -1,9 +1,8 @@
//===-- negdf2vfp.S - Implement negdf2vfp ---------------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -12,12 +11,19 @@
//
// extern double __negdf2vfp(double a, double b);
//
-// Returns the negation a double precision floating point numbers using the
+// Returns the negation a double precision floating point numbers using the
// Darwin calling convention where double arguments are passsed in GPR pairs.
//
.syntax unified
.p2align 2
DEFINE_COMPILERRT_FUNCTION(__negdf2vfp)
+#if defined(COMPILER_RT_ARMHF_TARGET)
+ vneg.f64 d0, d0
+#else
eor r1, r1, #-2147483648 // flip sign bit on double in r0/r1 pair
+#endif
bx lr
END_COMPILERRT_FUNCTION(__negdf2vfp)
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/negsf2vfp.S b/contrib/libs/cxxsupp/builtins/arm/negsf2vfp.S
index a6e32e1ff8..b6d3c61892 100644
--- a/contrib/libs/cxxsupp/builtins/arm/negsf2vfp.S
+++ b/contrib/libs/cxxsupp/builtins/arm/negsf2vfp.S
@@ -1,9 +1,8 @@
//===-- negsf2vfp.S - Implement negsf2vfp ---------------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -12,12 +11,19 @@
//
// extern float __negsf2vfp(float a);
//
-// Returns the negation of a single precision floating point numbers using the
+// Returns the negation of a single precision floating point numbers using the
// Darwin calling convention where single arguments are passsed like 32-bit ints
//
.syntax unified
.p2align 2
DEFINE_COMPILERRT_FUNCTION(__negsf2vfp)
+#if defined(COMPILER_RT_ARMHF_TARGET)
+ vneg.f32 s0, s0
+#else
eor r0, r0, #-2147483648 // flip sign bit on float in r0
+#endif
bx lr
END_COMPILERRT_FUNCTION(__negsf2vfp)
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/nesf2vfp.S b/contrib/libs/cxxsupp/builtins/arm/nesf2vfp.S
index 9fe8ecdefb..34c8bb4896 100644
--- a/contrib/libs/cxxsupp/builtins/arm/nesf2vfp.S
+++ b/contrib/libs/cxxsupp/builtins/arm/nesf2vfp.S
@@ -1,9 +1,8 @@
//===-- nesf2vfp.S - Implement nesf2vfp -----------------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -13,17 +12,25 @@
// extern int __nesf2vfp(float a, float b);
//
// Returns one iff a != b and neither is NaN.
-// Uses Darwin calling convention where single precision arguments are passsed
+// Uses Darwin calling convention where single precision arguments are passsed
// like 32-bit ints
//
.syntax unified
.p2align 2
DEFINE_COMPILERRT_FUNCTION(__nesf2vfp)
+#if defined(COMPILER_RT_ARMHF_TARGET)
+ vcmp.f32 s0, s1
+#else
vmov s14, r0 // move from GPR 0 to float register
vmov s15, r1 // move from GPR 1 to float register
vcmp.f32 s14, s15
+#endif
vmrs apsr_nzcv, fpscr
+ ITE(ne)
movne r0, #1 // set result register to 1 if unequal
moveq r0, #0
bx lr
END_COMPILERRT_FUNCTION(__nesf2vfp)
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/restore_vfp_d8_d15_regs.S b/contrib/libs/cxxsupp/builtins/arm/restore_vfp_d8_d15_regs.S
index 0f6ea51361..fd6d59bb3c 100644
--- a/contrib/libs/cxxsupp/builtins/arm/restore_vfp_d8_d15_regs.S
+++ b/contrib/libs/cxxsupp/builtins/arm/restore_vfp_d8_d15_regs.S
@@ -1,9 +1,8 @@
//===-- save_restore_regs.S - Implement save/restore* ---------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -31,3 +30,5 @@ DEFINE_COMPILERRT_PRIVATE_FUNCTION(__restore_vfp_d8_d15_regs)
bx lr // return to prolog
END_COMPILERRT_FUNCTION(__restore_vfp_d8_d15_regs)
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/save_vfp_d8_d15_regs.S b/contrib/libs/cxxsupp/builtins/arm/save_vfp_d8_d15_regs.S
index f1d90e7580..5eb3a2fbaa 100644
--- a/contrib/libs/cxxsupp/builtins/arm/save_vfp_d8_d15_regs.S
+++ b/contrib/libs/cxxsupp/builtins/arm/save_vfp_d8_d15_regs.S
@@ -1,9 +1,8 @@
//===-- save_restore_regs.S - Implement save/restore* ---------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -31,3 +30,5 @@ DEFINE_COMPILERRT_PRIVATE_FUNCTION(__save_vfp_d8_d15_regs)
bx lr // return to prolog
END_COMPILERRT_FUNCTION(__save_vfp_d8_d15_regs)
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/softfloat-alias.list b/contrib/libs/cxxsupp/builtins/arm/softfloat-alias.list
index cc6a4b3cdd..ab6ed21e54 100644
--- a/contrib/libs/cxxsupp/builtins/arm/softfloat-alias.list
+++ b/contrib/libs/cxxsupp/builtins/arm/softfloat-alias.list
@@ -1,5 +1,5 @@
#
-# These are soft float functions which can be
+# These are soft float functions which can be
# aliased to the *vfp functions on arm processors
# that support floating point instructions.
#
diff --git a/contrib/libs/cxxsupp/builtins/arm/subdf3vfp.S b/contrib/libs/cxxsupp/builtins/arm/subdf3vfp.S
index 5f3c0f70db..f4eaf9af1a 100644
--- a/contrib/libs/cxxsupp/builtins/arm/subdf3vfp.S
+++ b/contrib/libs/cxxsupp/builtins/arm/subdf3vfp.S
@@ -1,9 +1,8 @@
//===-- subdf3vfp.S - Implement subdf3vfp ---------------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -12,15 +11,22 @@
//
// extern double __subdf3vfp(double a, double b);
//
-// Returns difference between two double precision floating point numbers using
+// Returns difference between two double precision floating point numbers using
// the Darwin calling convention where double arguments are passsed in GPR pairs
//
.syntax unified
.p2align 2
DEFINE_COMPILERRT_FUNCTION(__subdf3vfp)
+#if defined(COMPILER_RT_ARMHF_TARGET)
+ vsub.f64 d0, d0, d1
+#else
vmov d6, r0, r1 // move first param from r0/r1 pair into d6
vmov d7, r2, r3 // move second param from r2/r3 pair into d7
- vsub.f64 d6, d6, d7
+ vsub.f64 d6, d6, d7
vmov r0, r1, d6 // move result back to r0/r1 pair
+#endif
bx lr
END_COMPILERRT_FUNCTION(__subdf3vfp)
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/subsf3vfp.S b/contrib/libs/cxxsupp/builtins/arm/subsf3vfp.S
index d6e06df519..80e69f2e8e 100644
--- a/contrib/libs/cxxsupp/builtins/arm/subsf3vfp.S
+++ b/contrib/libs/cxxsupp/builtins/arm/subsf3vfp.S
@@ -1,9 +1,8 @@
//===-- subsf3vfp.S - Implement subsf3vfp ---------------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -12,16 +11,23 @@
//
// extern float __subsf3vfp(float a, float b);
//
-// Returns the difference between two single precision floating point numbers
+// Returns the difference between two single precision floating point numbers
// using the Darwin calling convention where single arguments are passsed
// like 32-bit ints.
//
.syntax unified
.p2align 2
DEFINE_COMPILERRT_FUNCTION(__subsf3vfp)
+#if defined(COMPILER_RT_ARMHF_TARGET)
+ vsub.f32 s0, s0, s1
+#else
vmov s14, r0 // move first param from r0 into float register
vmov s15, r1 // move second param from r1 into float register
vsub.f32 s14, s14, s15
vmov r0, s14 // move result back to r0
+#endif
bx lr
END_COMPILERRT_FUNCTION(__subsf3vfp)
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/switch16.S b/contrib/libs/cxxsupp/builtins/arm/switch16.S
index 3c3a6b1061..a4b568da59 100644
--- a/contrib/libs/cxxsupp/builtins/arm/switch16.S
+++ b/contrib/libs/cxxsupp/builtins/arm/switch16.S
@@ -1,9 +1,8 @@
//===-- switch.S - Implement switch* --------------------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -42,3 +41,5 @@ DEFINE_COMPILERRT_PRIVATE_FUNCTION(__switch16)
bx ip // jump to computed label
END_COMPILERRT_FUNCTION(__switch16)
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/switch32.S b/contrib/libs/cxxsupp/builtins/arm/switch32.S
index b38cd2b764..f2a5af5275 100644
--- a/contrib/libs/cxxsupp/builtins/arm/switch32.S
+++ b/contrib/libs/cxxsupp/builtins/arm/switch32.S
@@ -1,9 +1,8 @@
//===-- switch.S - Implement switch* --------------------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -42,3 +41,5 @@ DEFINE_COMPILERRT_PRIVATE_FUNCTION(__switch32)
bx ip // jump to computed label
END_COMPILERRT_FUNCTION(__switch32)
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/switch8.S b/contrib/libs/cxxsupp/builtins/arm/switch8.S
index d7c20423de..0db875c329 100644
--- a/contrib/libs/cxxsupp/builtins/arm/switch8.S
+++ b/contrib/libs/cxxsupp/builtins/arm/switch8.S
@@ -1,9 +1,8 @@
//===-- switch.S - Implement switch* --------------------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -40,3 +39,5 @@ DEFINE_COMPILERRT_PRIVATE_FUNCTION(__switch8)
bx ip // jump to computed label
END_COMPILERRT_FUNCTION(__switch8)
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/switchu8.S b/contrib/libs/cxxsupp/builtins/arm/switchu8.S
index 1844f11c60..551abebc60 100644
--- a/contrib/libs/cxxsupp/builtins/arm/switchu8.S
+++ b/contrib/libs/cxxsupp/builtins/arm/switchu8.S
@@ -1,9 +1,8 @@
//===-- switch.S - Implement switch* --------------------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -40,3 +39,5 @@ DEFINE_COMPILERRT_PRIVATE_FUNCTION(__switchu8)
bx ip // jump to computed label
END_COMPILERRT_FUNCTION(__switchu8)
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/sync-ops.h b/contrib/libs/cxxsupp/builtins/arm/sync-ops.h
index ee02c30c6e..dca201d8ae 100644
--- a/contrib/libs/cxxsupp/builtins/arm/sync-ops.h
+++ b/contrib/libs/cxxsupp/builtins/arm/sync-ops.h
@@ -1,64 +1,67 @@
-/*===-- sync-ops.h - --===//
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- *===----------------------------------------------------------------------===//
- *
- * This file implements outline macros for the __sync_fetch_and_*
- * operations. Different instantiations will generate appropriate assembly for
- * ARM and Thumb-2 versions of the functions.
- *
- *===----------------------------------------------------------------------===*/
+//===-- sync-ops.h - --===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements outline macros for the __sync_fetch_and_*
+// operations. Different instantiations will generate appropriate assembly for
+// ARM and Thumb-2 versions of the functions.
+//
+//===----------------------------------------------------------------------===//
#include "../assembly.h"
-#define SYNC_OP_4(op) \
- .p2align 2 ; \
- .thumb ; \
- .syntax unified ; \
- DEFINE_COMPILERRT_THUMB_FUNCTION(__sync_fetch_and_ ## op) \
- dmb ; \
- mov r12, r0 ; \
- LOCAL_LABEL(tryatomic_ ## op): \
- ldrex r0, [r12] ; \
- op(r2, r0, r1) ; \
- strex r3, r2, [r12] ; \
- cmp r3, #0 ; \
- bne LOCAL_LABEL(tryatomic_ ## op) ; \
- dmb ; \
- bx lr
+#if __ARM_ARCH >= 7
+#define DMB dmb
+#elif __ARM_ARCH >= 6
+#define DMB mcr p15, #0, r0, c7, c10, #5
+#else
+#error DMB is only supported on ARMv6+
+#endif
-#define SYNC_OP_8(op) \
- .p2align 2 ; \
- .thumb ; \
- .syntax unified ; \
- DEFINE_COMPILERRT_THUMB_FUNCTION(__sync_fetch_and_ ## op) \
- push {r4, r5, r6, lr} ; \
- dmb ; \
- mov r12, r0 ; \
- LOCAL_LABEL(tryatomic_ ## op): \
- ldrexd r0, r1, [r12] ; \
- op(r4, r5, r0, r1, r2, r3) ; \
- strexd r6, r4, r5, [r12] ; \
- cmp r6, #0 ; \
- bne LOCAL_LABEL(tryatomic_ ## op) ; \
- dmb ; \
- pop {r4, r5, r6, pc}
+#define SYNC_OP_4(op) \
+ .p2align 2; \
+ .syntax unified; \
+ DEFINE_COMPILERRT_FUNCTION(__sync_fetch_and_##op) \
+ DMB; \
+ mov r12, r0; \
+ LOCAL_LABEL(tryatomic_##op) : ldrex r0, [r12]; \
+ op(r2, r0, r1); \
+ strex r3, r2, [r12]; \
+ cmp r3, #0; \
+ bne LOCAL_LABEL(tryatomic_##op); \
+ DMB; \
+ bx lr
-#define MINMAX_4(rD, rN, rM, cmp_kind) \
- cmp rN, rM ; \
- mov rD, rM ; \
- it cmp_kind ; \
- mov##cmp_kind rD, rN
+#define SYNC_OP_8(op) \
+ .p2align 2; \
+ .syntax unified; \
+ DEFINE_COMPILERRT_FUNCTION(__sync_fetch_and_##op) \
+ push {r4, r5, r6, lr}; \
+ DMB; \
+ mov r12, r0; \
+ LOCAL_LABEL(tryatomic_##op) : ldrexd r0, r1, [r12]; \
+ op(r4, r5, r0, r1, r2, r3); \
+ strexd r6, r4, r5, [r12]; \
+ cmp r6, #0; \
+ bne LOCAL_LABEL(tryatomic_##op); \
+ DMB; \
+ pop { r4, r5, r6, pc }
-#define MINMAX_8(rD_LO, rD_HI, rN_LO, rN_HI, rM_LO, rM_HI, cmp_kind) \
- cmp rN_LO, rM_LO ; \
- sbcs rN_HI, rM_HI ; \
- mov rD_LO, rM_LO ; \
- mov rD_HI, rM_HI ; \
- itt cmp_kind ; \
- mov##cmp_kind rD_LO, rN_LO ; \
- mov##cmp_kind rD_HI, rN_HI
+#define MINMAX_4(rD, rN, rM, cmp_kind) \
+ cmp rN, rM; \
+ mov rD, rM; \
+ it cmp_kind; \
+ mov##cmp_kind rD, rN
+
+#define MINMAX_8(rD_LO, rD_HI, rN_LO, rN_HI, rM_LO, rM_HI, cmp_kind) \
+ cmp rN_LO, rM_LO; \
+ sbcs rN_HI, rM_HI; \
+ mov rD_LO, rM_LO; \
+ mov rD_HI, rM_HI; \
+ itt cmp_kind; \
+ mov##cmp_kind rD_LO, rN_LO; \
+ mov##cmp_kind rD_HI, rN_HI
diff --git a/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_add_4.S b/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_add_4.S
index 54c33e2d26..0d55975b7a 100644
--- a/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_add_4.S
+++ b/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_add_4.S
@@ -1,21 +1,22 @@
-/*===-- sync_fetch_and_add_4.S - ------------------------------------------===//
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- *===----------------------------------------------------------------------===//
- *
- * This file implements the __sync_fetch_and_add_4 function for the ARM
- * architecture.
- *
- *===----------------------------------------------------------------------===*/
+//===-- sync_fetch_and_add_4.S - ------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the __sync_fetch_and_add_4 function for the ARM
+// architecture.
+//
+//===----------------------------------------------------------------------===//
#include "sync-ops.h"
-/* "adds" is 2 bytes shorter than "add". */
+// "adds" is 2 bytes shorter than "add".
#define add_4(rD, rN, rM) add rD, rN, rM
SYNC_OP_4(add_4)
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_add_8.S b/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_add_8.S
index 5724bb148b..18bdd875b8 100644
--- a/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_add_8.S
+++ b/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_add_8.S
@@ -1,16 +1,15 @@
-/*===-- sync_fetch_and_add_8.S - ------------------------------------------===//
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- *===----------------------------------------------------------------------===//
- *
- * This file implements the __sync_fetch_and_add_8 function for the ARM
- * architecture.
- *
- *===----------------------------------------------------------------------===*/
+//===-- sync_fetch_and_add_8.S - ------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the __sync_fetch_and_add_8 function for the ARM
+// architecture.
+//
+//===----------------------------------------------------------------------===//
#include "sync-ops.h"
@@ -22,3 +21,5 @@
SYNC_OP_8(add_8)
#endif
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_and_4.S b/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_and_4.S
index e2b77a1a87..3a76acca67 100644
--- a/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_and_4.S
+++ b/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_and_4.S
@@ -1,19 +1,21 @@
-/*===-- sync_fetch_and_and_4.S - ------------------------------------------===//
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- *===----------------------------------------------------------------------===//
- *
- * This file implements the __sync_fetch_and_and_4 function for the ARM
- * architecture.
- *
- *===----------------------------------------------------------------------===*/
+//===-- sync_fetch_and_and_4.S - ------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the __sync_fetch_and_and_4 function for the ARM
+// architecture.
+//
+//===----------------------------------------------------------------------===//
#include "sync-ops.h"
#define and_4(rD, rN, rM) and rD, rN, rM
SYNC_OP_4(and_4)
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_and_8.S b/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_and_8.S
index a74163a860..3716eff809 100644
--- a/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_and_8.S
+++ b/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_and_8.S
@@ -1,16 +1,15 @@
-/*===-- sync_fetch_and_and_8.S - ------------------------------------------===//
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- *===----------------------------------------------------------------------===//
- *
- * This file implements the __sync_fetch_and_and_8 function for the ARM
- * architecture.
- *
- *===----------------------------------------------------------------------===*/
+//===-- sync_fetch_and_and_8.S - ------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the __sync_fetch_and_and_8 function for the ARM
+// architecture.
+//
+//===----------------------------------------------------------------------===//
#include "sync-ops.h"
@@ -21,3 +20,6 @@
SYNC_OP_8(and_8)
#endif
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_max_4.S b/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_max_4.S
index 01e4f444c2..b9cee45219 100644
--- a/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_max_4.S
+++ b/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_max_4.S
@@ -1,16 +1,15 @@
-/*===-- sync_fetch_and_max_4.S - ------------------------------------------===//
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- *===----------------------------------------------------------------------===//
- *
- * This file implements the __sync_fetch_and_max_4 function for the ARM
- * architecture.
- *
- *===----------------------------------------------------------------------===*/
+//===-- sync_fetch_and_max_4.S - ------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the __sync_fetch_and_max_4 function for the ARM
+// architecture.
+//
+//===----------------------------------------------------------------------===//
#include "sync-ops.h"
@@ -18,3 +17,5 @@
SYNC_OP_4(max_4)
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_max_8.S b/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_max_8.S
index 1eef2b2236..06115ab552 100644
--- a/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_max_8.S
+++ b/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_max_8.S
@@ -1,16 +1,15 @@
-/*===-- sync_fetch_and_max_8.S - ------------------------------------------===//
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- *===----------------------------------------------------------------------===//
- *
- * This file implements the __sync_fetch_and_max_8 function for the ARM
- * architecture.
- *
- *===----------------------------------------------------------------------===*/
+//===-- sync_fetch_and_max_8.S - ------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the __sync_fetch_and_max_8 function for the ARM
+// architecture.
+//
+//===----------------------------------------------------------------------===//
#include "sync-ops.h"
@@ -19,3 +18,6 @@
SYNC_OP_8(max_8)
#endif
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_min_4.S b/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_min_4.S
index 015626b63d..60d435a0bd 100644
--- a/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_min_4.S
+++ b/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_min_4.S
@@ -1,16 +1,15 @@
-/*===-- sync_fetch_and_min_4.S - ------------------------------------------===//
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- *===----------------------------------------------------------------------===//
- *
- * This file implements the __sync_fetch_and_min_4 function for the ARM
- * architecture.
- *
- *===----------------------------------------------------------------------===*/
+//===-- sync_fetch_and_min_4.S - ------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the __sync_fetch_and_min_4 function for the ARM
+// architecture.
+//
+//===----------------------------------------------------------------------===//
#include "sync-ops.h"
@@ -18,3 +17,5 @@
SYNC_OP_4(min_4)
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_min_8.S b/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_min_8.S
index ad5cce0754..4f3e299d95 100644
--- a/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_min_8.S
+++ b/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_min_8.S
@@ -1,16 +1,15 @@
-/*===-- sync_fetch_and_min_8.S - ------------------------------------------===//
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- *===----------------------------------------------------------------------===//
- *
- * This file implements the __sync_fetch_and_min_8 function for the ARM
- * architecture.
- *
- *===----------------------------------------------------------------------===*/
+//===-- sync_fetch_and_min_8.S - ------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the __sync_fetch_and_min_8 function for the ARM
+// architecture.
+//
+//===----------------------------------------------------------------------===//
#include "sync-ops.h"
@@ -19,3 +18,6 @@
SYNC_OP_8(min_8)
#endif
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_nand_4.S b/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_nand_4.S
index b32a314b39..5a04be0f64 100644
--- a/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_nand_4.S
+++ b/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_nand_4.S
@@ -1,16 +1,15 @@
-/*===-- sync_fetch_and_nand_4.S - -----------------------------------------===//
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- *===----------------------------------------------------------------------===//
- *
- * This file implements the __sync_fetch_and_nand_4 function for the ARM
- * architecture.
- *
- *===----------------------------------------------------------------------===*/
+//===-- sync_fetch_and_nand_4.S - -----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the __sync_fetch_and_nand_4 function for the ARM
+// architecture.
+//
+//===----------------------------------------------------------------------===//
#include "sync-ops.h"
@@ -18,3 +17,5 @@
SYNC_OP_4(nand_4)
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_nand_8.S b/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_nand_8.S
index a2c17c09c0..425c94474a 100644
--- a/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_nand_8.S
+++ b/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_nand_8.S
@@ -1,16 +1,15 @@
-/*===-- sync_fetch_and_nand_8.S - ------------------------------------------===//
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- *===----------------------------------------------------------------------===//
- *
- * This file implements the __sync_fetch_and_nand_8 function for the ARM
- * architecture.
- *
- *===----------------------------------------------------------------------===*/
+//===-- sync_fetch_and_nand_8.S - ------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the __sync_fetch_and_nand_8 function for the ARM
+// architecture.
+//
+//===----------------------------------------------------------------------===//
#include "sync-ops.h"
@@ -22,3 +21,5 @@
SYNC_OP_8(nand_8)
#endif
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_or_4.S b/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_or_4.S
index f2e08576aa..f44751b9a9 100644
--- a/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_or_4.S
+++ b/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_or_4.S
@@ -1,16 +1,15 @@
-/*===-- sync_fetch_and_or_4.S - -------------------------------------------===//
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- *===----------------------------------------------------------------------===//
- *
- * This file implements the __sync_fetch_and_or_4 function for the ARM
- * architecture.
- *
- *===----------------------------------------------------------------------===*/
+//===-- sync_fetch_and_or_4.S - -------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the __sync_fetch_and_or_4 function for the ARM
+// architecture.
+//
+//===----------------------------------------------------------------------===//
#include "sync-ops.h"
@@ -18,3 +17,5 @@
SYNC_OP_4(or_4)
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_or_8.S b/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_or_8.S
index 87b940bf62..4f18dcf84d 100644
--- a/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_or_8.S
+++ b/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_or_8.S
@@ -1,16 +1,15 @@
-/*===-- sync_fetch_and_or_8.S - -------------------------------------------===//
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- *===----------------------------------------------------------------------===//
- *
- * This file implements the __sync_fetch_and_or_8 function for the ARM
- * architecture.
- *
- *===----------------------------------------------------------------------===*/
+//===-- sync_fetch_and_or_8.S - -------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the __sync_fetch_and_or_8 function for the ARM
+// architecture.
+//
+//===----------------------------------------------------------------------===//
#include "sync-ops.h"
@@ -22,3 +21,5 @@
SYNC_OP_8(or_8)
#endif
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_sub_4.S b/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_sub_4.S
index 460b2bc1ed..999d48c28a 100644
--- a/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_sub_4.S
+++ b/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_sub_4.S
@@ -1,21 +1,22 @@
-/*===-- sync_fetch_and_sub_4.S - ------------------------------------------===//
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- *===----------------------------------------------------------------------===//
- *
- * This file implements the __sync_fetch_and_sub_4 function for the ARM
- * architecture.
- *
- *===----------------------------------------------------------------------===*/
+//===-- sync_fetch_and_sub_4.S - ------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the __sync_fetch_and_sub_4 function for the ARM
+// architecture.
+//
+//===----------------------------------------------------------------------===//
#include "sync-ops.h"
-/* "subs" is 2 bytes shorter than "sub". */
+// "subs" is 2 bytes shorter than "sub".
#define sub_4(rD, rN, rM) sub rD, rN, rM
SYNC_OP_4(sub_4)
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_sub_8.S b/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_sub_8.S
index a8035a2768..25a4a10765 100644
--- a/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_sub_8.S
+++ b/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_sub_8.S
@@ -1,16 +1,15 @@
-/*===-- sync_fetch_and_sub_8.S - ------------------------------------------===//
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- *===----------------------------------------------------------------------===//
- *
- * This file implements the __sync_fetch_and_sub_8 function for the ARM
- * architecture.
- *
- *===----------------------------------------------------------------------===*/
+//===-- sync_fetch_and_sub_8.S - ------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the __sync_fetch_and_sub_8 function for the ARM
+// architecture.
+//
+//===----------------------------------------------------------------------===//
#include "sync-ops.h"
@@ -22,3 +21,5 @@
SYNC_OP_8(sub_8)
#endif
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_umax_4.S b/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_umax_4.S
index c591530319..a7b233b153 100644
--- a/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_umax_4.S
+++ b/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_umax_4.S
@@ -1,16 +1,15 @@
-/*===-- sync_fetch_and_umax_4.S - ------------------------------------------===//
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- *===----------------------------------------------------------------------===//
- *
- * This file implements the __sync_fetch_and_umax_4 function for the ARM
- * architecture.
- *
- *===----------------------------------------------------------------------===*/
+//===-- sync_fetch_and_umax_4.S - ------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the __sync_fetch_and_umax_4 function for the ARM
+// architecture.
+//
+//===----------------------------------------------------------------------===//
#include "sync-ops.h"
@@ -18,3 +17,5 @@
SYNC_OP_4(umax_4)
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_umax_8.S b/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_umax_8.S
index d9b7965e52..aa5213ff1d 100644
--- a/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_umax_8.S
+++ b/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_umax_8.S
@@ -1,16 +1,15 @@
-/*===-- sync_fetch_and_umax_8.S - ------------------------------------------===//
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- *===----------------------------------------------------------------------===//
- *
- * This file implements the __sync_fetch_and_umax_8 function for the ARM
- * architecture.
- *
- *===----------------------------------------------------------------------===*/
+//===-- sync_fetch_and_umax_8.S - ------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the __sync_fetch_and_umax_8 function for the ARM
+// architecture.
+//
+//===----------------------------------------------------------------------===//
#include "sync-ops.h"
@@ -19,3 +18,6 @@
SYNC_OP_8(umax_8)
#endif
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_umin_4.S b/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_umin_4.S
index 9f3896fca8..c7a9c89df6 100644
--- a/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_umin_4.S
+++ b/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_umin_4.S
@@ -1,16 +1,15 @@
-/*===-- sync_fetch_and_umin_4.S - ------------------------------------------===//
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- *===----------------------------------------------------------------------===//
- *
- * This file implements the __sync_fetch_and_umin_4 function for the ARM
- * architecture.
- *
- *===----------------------------------------------------------------------===*/
+//===-- sync_fetch_and_umin_4.S - ------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the __sync_fetch_and_umin_4 function for the ARM
+// architecture.
+//
+//===----------------------------------------------------------------------===//
#include "sync-ops.h"
@@ -18,3 +17,5 @@
SYNC_OP_4(umin_4)
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_umin_8.S b/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_umin_8.S
index 7bf5e23565..8b40541ab4 100644
--- a/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_umin_8.S
+++ b/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_umin_8.S
@@ -1,16 +1,15 @@
-/*===-- sync_fetch_and_umin_8.S - ------------------------------------------===//
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- *===----------------------------------------------------------------------===//
- *
- * This file implements the __sync_fetch_and_umin_8 function for the ARM
- * architecture.
- *
- *===----------------------------------------------------------------------===*/
+//===-- sync_fetch_and_umin_8.S - ------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the __sync_fetch_and_umin_8 function for the ARM
+// architecture.
+//
+//===----------------------------------------------------------------------===//
#include "sync-ops.h"
@@ -19,3 +18,6 @@
SYNC_OP_8(umin_8)
#endif
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_xor_4.S b/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_xor_4.S
index 7e7c90c962..f509191d01 100644
--- a/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_xor_4.S
+++ b/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_xor_4.S
@@ -1,16 +1,15 @@
-/*===-- sync_fetch_and_xor_4.S - ------------------------------------------===//
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- *===----------------------------------------------------------------------===//
- *
- * This file implements the __sync_fetch_and_xor_4 function for the ARM
- * architecture.
- *
- *===----------------------------------------------------------------------===*/
+//===-- sync_fetch_and_xor_4.S - ------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the __sync_fetch_and_xor_4 function for the ARM
+// architecture.
+//
+//===----------------------------------------------------------------------===//
#include "sync-ops.h"
@@ -18,3 +17,5 @@
SYNC_OP_4(xor_4)
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_xor_8.S b/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_xor_8.S
index ea9aa6d4b0..7436eb1d4c 100644
--- a/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_xor_8.S
+++ b/contrib/libs/cxxsupp/builtins/arm/sync_fetch_and_xor_8.S
@@ -1,16 +1,15 @@
-/*===-- sync_fetch_and_xor_8.S - ------------------------------------------===//
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- *===----------------------------------------------------------------------===//
- *
- * This file implements the __sync_fetch_and_xor_8 function for the ARM
- * architecture.
- *
- *===----------------------------------------------------------------------===*/
+//===-- sync_fetch_and_xor_8.S - ------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the __sync_fetch_and_xor_8 function for the ARM
+// architecture.
+//
+//===----------------------------------------------------------------------===//
#include "sync-ops.h"
@@ -22,3 +21,5 @@
SYNC_OP_8(xor_8)
#endif
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/sync_synchronize.S b/contrib/libs/cxxsupp/builtins/arm/sync_synchronize.S
index 178f24534c..dd06e7191f 100644
--- a/contrib/libs/cxxsupp/builtins/arm/sync_synchronize.S
+++ b/contrib/libs/cxxsupp/builtins/arm/sync_synchronize.S
@@ -1,20 +1,17 @@
//===-- sync_synchronize - Implement memory barrier * ----------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "../assembly.h"
-//
// When compiling a use of the gcc built-in __sync_synchronize() in thumb1 mode
-// the compiler may emit a call to __sync_synchronize.
-// On Darwin the implementation jumps to an OS supplied function named
+// the compiler may emit a call to __sync_synchronize.
+// On Darwin the implementation jumps to an OS supplied function named
// OSMemoryBarrier
-//
.text
.syntax unified
@@ -31,5 +28,8 @@ END_COMPILERRT_FUNCTION(__sync_synchronize)
// tell linker it can break up file at label boundaries
.subsections_via_symbols
-
+
#endif
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/truncdfsf2vfp.S b/contrib/libs/cxxsupp/builtins/arm/truncdfsf2vfp.S
index fa4362c45e..e1c171262a 100644
--- a/contrib/libs/cxxsupp/builtins/arm/truncdfsf2vfp.S
+++ b/contrib/libs/cxxsupp/builtins/arm/truncdfsf2vfp.S
@@ -1,9 +1,8 @@
//===-- truncdfsf2vfp.S - Implement truncdfsf2vfp -------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -12,15 +11,22 @@
//
// extern float __truncdfsf2vfp(double a);
//
-// Converts double precision float to signle precision result.
-// Uses Darwin calling convention where a double precision parameter is
-// passed in a R0/R1 pair and a signle precision result is returned in R0.
+// Converts double precision float to single precision result.
+// Uses Darwin calling convention where a double precision parameter is
+// passed in a R0/R1 pair and a single precision result is returned in R0.
//
.syntax unified
.p2align 2
DEFINE_COMPILERRT_FUNCTION(__truncdfsf2vfp)
+#if defined(COMPILER_RT_ARMHF_TARGET)
+ vcvt.f32.f64 s0, d0
+#else
vmov d7, r0, r1 // load double from r0/r1 pair
vcvt.f32.f64 s15, d7 // convert double to single (trucate precision)
vmov r0, s15 // return result in r0
+#endif
bx lr
END_COMPILERRT_FUNCTION(__truncdfsf2vfp)
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/udivmodsi4.S b/contrib/libs/cxxsupp/builtins/arm/udivmodsi4.S
index 85b84936c4..0f40575fe9 100644
--- a/contrib/libs/cxxsupp/builtins/arm/udivmodsi4.S
+++ b/contrib/libs/cxxsupp/builtins/arm/udivmodsi4.S
@@ -1,25 +1,21 @@
-/*===-- udivmodsi4.S - 32-bit unsigned integer divide and modulus ---------===//
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- *===----------------------------------------------------------------------===//
- *
- * This file implements the __udivmodsi4 (32-bit unsigned integer divide and
- * modulus) function for the ARM 32-bit architecture.
- *
- *===----------------------------------------------------------------------===*/
+//===-- udivmodsi4.S - 32-bit unsigned integer divide and modulus ---------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the __udivmodsi4 (32-bit unsigned integer divide and
+// modulus) function for the ARM 32-bit architecture.
+//
+//===----------------------------------------------------------------------===//
#include "../assembly.h"
.syntax unified
.text
-
-#if __ARM_ARCH_ISA_THUMB == 2
- .thumb
-#endif
+ DEFINE_CODE_STATE
@ unsigned int __udivmodsi4(unsigned int divident, unsigned int divisor,
@ unsigned int *remainder)
@@ -27,11 +23,7 @@
@ value is the quotient, the remainder is placed in the variable.
.p2align 2
-#if __ARM_ARCH_ISA_THUMB == 2
-DEFINE_COMPILERRT_THUMB_FUNCTION(__udivmodsi4)
-#else
DEFINE_COMPILERRT_FUNCTION(__udivmodsi4)
-#endif
#if __ARM_ARCH_EXT_IDIV__
tst r1, r1
beq LOCAL_LABEL(divby0)
@@ -46,28 +38,27 @@ DEFINE_COMPILERRT_FUNCTION(__udivmodsi4)
beq LOCAL_LABEL(divby1)
cmp r0, r1
bcc LOCAL_LABEL(quotient0)
- /*
- * Implement division using binary long division algorithm.
- *
- * r0 is the numerator, r1 the denominator.
- *
- * The code before JMP computes the correct shift I, so that
- * r0 and (r1 << I) have the highest bit set in the same position.
- * At the time of JMP, ip := .Ldiv0block - 12 * I.
- * This depends on the fixed instruction size of block.
- * For ARM mode, this is 12 Bytes, for THUMB mode 14 Bytes.
- *
- * block(shift) implements the test-and-update-quotient core.
- * It assumes (r0 << shift) can be computed without overflow and
- * that (r0 << shift) < 2 * r1. The quotient is stored in r3.
- */
+
+ // Implement division using binary long division algorithm.
+ //
+ // r0 is the numerator, r1 the denominator.
+ //
+ // The code before JMP computes the correct shift I, so that
+ // r0 and (r1 << I) have the highest bit set in the same position.
+ // At the time of JMP, ip := .Ldiv0block - 12 * I.
+ // This depends on the fixed instruction size of block.
+ // For ARM mode, this is 12 Bytes, for THUMB mode 14 Bytes.
+ //
+ // block(shift) implements the test-and-update-quotient core.
+ // It assumes (r0 << shift) can be computed without overflow and
+ // that (r0 << shift) < 2 * r1. The quotient is stored in r3.
# ifdef __ARM_FEATURE_CLZ
clz ip, r0
clz r3, r1
- /* r0 >= r1 implies clz(r0) <= clz(r1), so ip <= r3. */
+ // r0 >= r1 implies clz(r0) <= clz(r1), so ip <= r3.
sub r3, r3, ip
-# if __ARM_ARCH_ISA_THUMB == 2
+# if defined(USE_THUMB_2)
adr ip, LOCAL_LABEL(div0block) + 1
sub ip, ip, r3, lsl #1
# else
@@ -78,7 +69,7 @@ DEFINE_COMPILERRT_FUNCTION(__udivmodsi4)
mov r3, #0
bx ip
# else
-# if __ARM_ARCH_ISA_THUMB == 2
+# if defined(USE_THUMB_2)
# error THUMB mode requires CLZ or UDIV
# endif
str r4, [sp, #-8]!
@@ -106,11 +97,11 @@ DEFINE_COMPILERRT_FUNCTION(__udivmodsi4)
movhs r4, r3
subhs ip, ip, #(2 * 12)
- /* Last block, no need to update r3 or r4. */
+ // Last block, no need to update r3 or r4.
cmp r1, r4, lsr #1
subls ip, ip, #(1 * 12)
- ldr r4, [sp], #8 /* restore r4, we are done with it. */
+ ldr r4, [sp], #8 // restore r4, we are done with it.
mov r3, #0
JMP(ip)
@@ -171,7 +162,7 @@ LOCAL_LABEL(divby1):
mov r3, #0
str r3, [r2]
JMP(lr)
-#endif /* __ARM_ARCH_EXT_IDIV__ */
+#endif // __ARM_ARCH_EXT_IDIV__
LOCAL_LABEL(divby0):
mov r0, #0
@@ -182,3 +173,6 @@ LOCAL_LABEL(divby0):
#endif
END_COMPILERRT_FUNCTION(__udivmodsi4)
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/udivsi3.S b/contrib/libs/cxxsupp/builtins/arm/udivsi3.S
index 165b2b58ac..9b1b035b33 100644
--- a/contrib/libs/cxxsupp/builtins/arm/udivsi3.S
+++ b/contrib/libs/cxxsupp/builtins/arm/udivsi3.S
@@ -1,25 +1,22 @@
-/*===-- udivsi3.S - 32-bit unsigned integer divide ------------------------===//
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- *===----------------------------------------------------------------------===//
- *
- * This file implements the __udivsi3 (32-bit unsigned integer divide)
- * function for the ARM 32-bit architecture.
- *
- *===----------------------------------------------------------------------===*/
+//===-- udivsi3.S - 32-bit unsigned integer divide ------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the __udivsi3 (32-bit unsigned integer divide)
+// function for the ARM 32-bit architecture.
+//
+//===----------------------------------------------------------------------===//
#include "../assembly.h"
.syntax unified
.text
-#if __ARM_ARCH_ISA_THUMB == 2
- .thumb
-#endif
+DEFINE_CODE_STATE
.p2align 2
DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_uidiv, __udivsi3)
@@ -27,47 +24,64 @@ DEFINE_AEABI_FUNCTION_ALIAS(__aeabi_uidiv, __udivsi3)
@ unsigned int __udivsi3(unsigned int divident, unsigned int divisor)
@ Calculate and return the quotient of the (unsigned) division.
-#if __ARM_ARCH_ISA_THUMB == 2
-DEFINE_COMPILERRT_THUMB_FUNCTION(__udivsi3)
-#else
DEFINE_COMPILERRT_FUNCTION(__udivsi3)
-#endif
#if __ARM_ARCH_EXT_IDIV__
tst r1, r1
beq LOCAL_LABEL(divby0)
udiv r0, r0, r1
bx lr
-#else
+
+LOCAL_LABEL(divby0):
+ mov r0, #0
+# ifdef __ARM_EABI__
+ b __aeabi_idiv0
+# else
+ JMP(lr)
+# endif
+
+#else // ! __ARM_ARCH_EXT_IDIV__
cmp r1, #1
bcc LOCAL_LABEL(divby0)
+#if defined(USE_THUMB_1)
+ bne LOCAL_LABEL(num_neq_denom)
+ JMP(lr)
+LOCAL_LABEL(num_neq_denom):
+#else
IT(eq)
JMPc(lr, eq)
+#endif
cmp r0, r1
+#if defined(USE_THUMB_1)
+ bhs LOCAL_LABEL(num_ge_denom)
+ movs r0, #0
+ JMP(lr)
+LOCAL_LABEL(num_ge_denom):
+#else
ITT(cc)
movcc r0, #0
JMPc(lr, cc)
- /*
- * Implement division using binary long division algorithm.
- *
- * r0 is the numerator, r1 the denominator.
- *
- * The code before JMP computes the correct shift I, so that
- * r0 and (r1 << I) have the highest bit set in the same position.
- * At the time of JMP, ip := .Ldiv0block - 12 * I.
- * This depends on the fixed instruction size of block.
- * For ARM mode, this is 12 Bytes, for THUMB mode 14 Bytes.
- *
- * block(shift) implements the test-and-update-quotient core.
- * It assumes (r0 << shift) can be computed without overflow and
- * that (r0 << shift) < 2 * r1. The quotient is stored in r3.
- */
-
-# ifdef __ARM_FEATURE_CLZ
+#endif
+
+ // Implement division using binary long division algorithm.
+ //
+ // r0 is the numerator, r1 the denominator.
+ //
+ // The code before JMP computes the correct shift I, so that
+ // r0 and (r1 << I) have the highest bit set in the same position.
+ // At the time of JMP, ip := .Ldiv0block - 12 * I.
+ // This depends on the fixed instruction size of block.
+ // For ARM mode, this is 12 Bytes, for THUMB mode 14 Bytes.
+ //
+ // block(shift) implements the test-and-update-quotient core.
+ // It assumes (r0 << shift) can be computed without overflow and
+ // that (r0 << shift) < 2 * r1. The quotient is stored in r3.
+
+# if defined(__ARM_FEATURE_CLZ)
clz ip, r0
clz r3, r1
- /* r0 >= r1 implies clz(r0) <= clz(r1), so ip <= r3. */
+ // r0 >= r1 implies clz(r0) <= clz(r1), so ip <= r3.
sub r3, r3, ip
-# if __ARM_ARCH_ISA_THUMB == 2
+# if defined(USE_THUMB_2)
adr ip, LOCAL_LABEL(div0block) + 1
sub ip, ip, r3, lsl #1
# else
@@ -77,49 +91,131 @@ DEFINE_COMPILERRT_FUNCTION(__udivsi3)
sub ip, ip, r3, lsl #3
mov r3, #0
bx ip
-# else
-# if __ARM_ARCH_ISA_THUMB == 2
+# else // No CLZ Feature
+# if defined(USE_THUMB_2)
# error THUMB mode requires CLZ or UDIV
# endif
+# if defined(USE_THUMB_1)
+# define BLOCK_SIZE 10
+# else
+# define BLOCK_SIZE 12
+# endif
+
mov r2, r0
+# if defined(USE_THUMB_1)
+ mov ip, r0
+ adr r0, LOCAL_LABEL(div0block)
+ adds r0, #1
+# else
adr ip, LOCAL_LABEL(div0block)
-
- lsr r3, r2, #16
+# endif
+ lsrs r3, r2, #16
cmp r3, r1
+# if defined(USE_THUMB_1)
+ blo LOCAL_LABEL(skip_16)
+ movs r2, r3
+ subs r0, r0, #(16 * BLOCK_SIZE)
+LOCAL_LABEL(skip_16):
+# else
movhs r2, r3
- subhs ip, ip, #(16 * 12)
+ subhs ip, ip, #(16 * BLOCK_SIZE)
+# endif
- lsr r3, r2, #8
+ lsrs r3, r2, #8
cmp r3, r1
+# if defined(USE_THUMB_1)
+ blo LOCAL_LABEL(skip_8)
+ movs r2, r3
+ subs r0, r0, #(8 * BLOCK_SIZE)
+LOCAL_LABEL(skip_8):
+# else
movhs r2, r3
- subhs ip, ip, #(8 * 12)
+ subhs ip, ip, #(8 * BLOCK_SIZE)
+# endif
- lsr r3, r2, #4
+ lsrs r3, r2, #4
cmp r3, r1
+# if defined(USE_THUMB_1)
+ blo LOCAL_LABEL(skip_4)
+ movs r2, r3
+ subs r0, r0, #(4 * BLOCK_SIZE)
+LOCAL_LABEL(skip_4):
+# else
movhs r2, r3
- subhs ip, #(4 * 12)
+ subhs ip, #(4 * BLOCK_SIZE)
+# endif
- lsr r3, r2, #2
+ lsrs r3, r2, #2
cmp r3, r1
+# if defined(USE_THUMB_1)
+ blo LOCAL_LABEL(skip_2)
+ movs r2, r3
+ subs r0, r0, #(2 * BLOCK_SIZE)
+LOCAL_LABEL(skip_2):
+# else
movhs r2, r3
- subhs ip, ip, #(2 * 12)
+ subhs ip, ip, #(2 * BLOCK_SIZE)
+# endif
+
+ // Last block, no need to update r2 or r3.
+# if defined(USE_THUMB_1)
+ lsrs r3, r2, #1
+ cmp r3, r1
+ blo LOCAL_LABEL(skip_1)
+ subs r0, r0, #(1 * BLOCK_SIZE)
+LOCAL_LABEL(skip_1):
+ movs r2, r0
+ mov r0, ip
+ movs r3, #0
+ JMP (r2)
- /* Last block, no need to update r2 or r3. */
+# else
cmp r1, r2, lsr #1
- subls ip, ip, #(1 * 12)
+ subls ip, ip, #(1 * BLOCK_SIZE)
- mov r3, #0
+ movs r3, #0
JMP(ip)
-# endif
+# endif
+# endif // __ARM_FEATURE_CLZ
+
#define IMM #
+ // due to the range limit of branch in Thumb1, we have to place the
+ // block closer
+LOCAL_LABEL(divby0):
+ movs r0, #0
+# if defined(__ARM_EABI__)
+ push {r7, lr}
+ bl __aeabi_idiv0 // due to relocation limit, can't use b.
+ pop {r7, pc}
+# else
+ JMP(lr)
+# endif
+
+#if defined(USE_THUMB_1)
+#define block(shift) \
+ lsls r2, r1, IMM shift; \
+ cmp r0, r2; \
+ blo LOCAL_LABEL(block_skip_##shift); \
+ subs r0, r0, r2; \
+ LOCAL_LABEL(block_skip_##shift) :; \
+ adcs r3, r3 // same as ((r3 << 1) | Carry). Carry is set if r0 >= r2.
+
+ // TODO: if current location counter is not not word aligned, we don't
+ // need the .p2align and nop
+ // Label div0block must be word-aligned. First align block 31
+ .p2align 2
+ nop // Padding to align div0block as 31 blocks = 310 bytes
+
+#else
#define block(shift) \
cmp r0, r1, lsl IMM shift; \
ITT(hs); \
WIDE(addhs) r3, r3, IMM (1 << shift); \
WIDE(subhs) r0, r0, r1, lsl IMM shift
+#endif
block(31)
block(30)
@@ -157,14 +253,9 @@ LOCAL_LABEL(div0block):
mov r0, r3
JMP(lr)
-#endif /* __ARM_ARCH_EXT_IDIV__ */
-
-LOCAL_LABEL(divby0):
- mov r0, #0
-#ifdef __ARM_EABI__
- b __aeabi_idiv0
-#else
- JMP(lr)
-#endif
+#endif // __ARM_ARCH_EXT_IDIV__
END_COMPILERRT_FUNCTION(__udivsi3)
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/umodsi3.S b/contrib/libs/cxxsupp/builtins/arm/umodsi3.S
index 9e7a148ce4..5ab78de178 100644
--- a/contrib/libs/cxxsupp/builtins/arm/umodsi3.S
+++ b/contrib/libs/cxxsupp/builtins/arm/umodsi3.S
@@ -1,34 +1,27 @@
-/*===-- umodsi3.S - 32-bit unsigned integer modulus -----------------------===//
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- *===----------------------------------------------------------------------===//
- *
- * This file implements the __umodsi3 (32-bit unsigned integer modulus)
- * function for the ARM 32-bit architecture.
- *
- *===----------------------------------------------------------------------===*/
+//===-- umodsi3.S - 32-bit unsigned integer modulus -----------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the __umodsi3 (32-bit unsigned integer modulus)
+// function for the ARM 32-bit architecture.
+//
+//===----------------------------------------------------------------------===//
#include "../assembly.h"
.syntax unified
.text
-#if __ARM_ARCH_ISA_THUMB == 2
- .thumb
-#endif
+ DEFINE_CODE_STATE
@ unsigned int __umodsi3(unsigned int divident, unsigned int divisor)
@ Calculate and return the remainder of the (unsigned) division.
.p2align 2
-#if __ARM_ARCH_ISA_THUMB == 2
-DEFINE_COMPILERRT_THUMB_FUNCTION(__umodsi3)
-#else
DEFINE_COMPILERRT_FUNCTION(__umodsi3)
-#endif
#if __ARM_ARCH_EXT_IDIV__
tst r1, r1
beq LOCAL_LABEL(divby0)
@@ -44,28 +37,27 @@ DEFINE_COMPILERRT_FUNCTION(__umodsi3)
cmp r0, r1
IT(cc)
JMPc(lr, cc)
- /*
- * Implement division using binary long division algorithm.
- *
- * r0 is the numerator, r1 the denominator.
- *
- * The code before JMP computes the correct shift I, so that
- * r0 and (r1 << I) have the highest bit set in the same position.
- * At the time of JMP, ip := .Ldiv0block - 8 * I.
- * This depends on the fixed instruction size of block.
- * For ARM mode, this is 8 Bytes, for THUMB mode 10 Bytes.
- *
- * block(shift) implements the test-and-update-quotient core.
- * It assumes (r0 << shift) can be computed without overflow and
- * that (r0 << shift) < 2 * r1. The quotient is stored in r3.
- */
+
+ // Implement division using binary long division algorithm.
+ //
+ // r0 is the numerator, r1 the denominator.
+ //
+ // The code before JMP computes the correct shift I, so that
+ // r0 and (r1 << I) have the highest bit set in the same position.
+ // At the time of JMP, ip := .Ldiv0block - 8 * I.
+ // This depends on the fixed instruction size of block.
+ // For ARM mode, this is 8 Bytes, for THUMB mode 10 Bytes.
+ //
+ // block(shift) implements the test-and-update-quotient core.
+ // It assumes (r0 << shift) can be computed without overflow and
+ // that (r0 << shift) < 2 * r1. The quotient is stored in r3.
# ifdef __ARM_FEATURE_CLZ
clz ip, r0
clz r3, r1
- /* r0 >= r1 implies clz(r0) <= clz(r1), so ip <= r3. */
+ // r0 >= r1 implies clz(r0) <= clz(r1), so ip <= r3.
sub r3, r3, ip
-# if __ARM_ARCH_ISA_THUMB == 2
+# if defined(USE_THUMB_2)
adr ip, LOCAL_LABEL(div0block) + 1
sub ip, ip, r3, lsl #1
# else
@@ -74,7 +66,7 @@ DEFINE_COMPILERRT_FUNCTION(__umodsi3)
sub ip, ip, r3, lsl #3
bx ip
# else
-# if __ARM_ARCH_ISA_THUMB == 2
+# if defined(USE_THUMB_2)
# error THUMB mode requires CLZ or UDIV
# endif
mov r2, r0
@@ -100,7 +92,7 @@ DEFINE_COMPILERRT_FUNCTION(__umodsi3)
movhs r2, r3
subhs ip, ip, #(2 * 8)
- /* Last block, no need to update r2 or r3. */
+ // Last block, no need to update r2 or r3.
cmp r1, r2, lsr #1
subls ip, ip, #(1 * 8)
@@ -148,7 +140,7 @@ DEFINE_COMPILERRT_FUNCTION(__umodsi3)
LOCAL_LABEL(div0block):
block(0)
JMP(lr)
-#endif /* __ARM_ARCH_EXT_IDIV__ */
+#endif // __ARM_ARCH_EXT_IDIV__
LOCAL_LABEL(divby0):
mov r0, #0
@@ -159,3 +151,6 @@ LOCAL_LABEL(divby0):
#endif
END_COMPILERRT_FUNCTION(__umodsi3)
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/unorddf2vfp.S b/contrib/libs/cxxsupp/builtins/arm/unorddf2vfp.S
index c4bea2d5ee..ea36a1cb55 100644
--- a/contrib/libs/cxxsupp/builtins/arm/unorddf2vfp.S
+++ b/contrib/libs/cxxsupp/builtins/arm/unorddf2vfp.S
@@ -1,9 +1,8 @@
//===-- unorddf2vfp.S - Implement unorddf2vfp ------------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -13,17 +12,25 @@
// extern int __unorddf2vfp(double a, double b);
//
// Returns one iff a or b is NaN
-// Uses Darwin calling convention where double precision arguments are passsed
+// Uses Darwin calling convention where double precision arguments are passsed
// like in GPR pairs.
//
.syntax unified
.p2align 2
DEFINE_COMPILERRT_FUNCTION(__unorddf2vfp)
+#if defined(COMPILER_RT_ARMHF_TARGET)
+ vcmp.f64 d0, d1
+#else
vmov d6, r0, r1 // load r0/r1 pair in double register
vmov d7, r2, r3 // load r2/r3 pair in double register
- vcmp.f64 d6, d7
+ vcmp.f64 d6, d7
+#endif
vmrs apsr_nzcv, fpscr
+ ITE(vs)
movvs r0, #1 // set result register to 1 if "overflow" (any NaNs)
movvc r0, #0
bx lr
END_COMPILERRT_FUNCTION(__unorddf2vfp)
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm/unordsf2vfp.S b/contrib/libs/cxxsupp/builtins/arm/unordsf2vfp.S
index 886e965681..7311297329 100644
--- a/contrib/libs/cxxsupp/builtins/arm/unordsf2vfp.S
+++ b/contrib/libs/cxxsupp/builtins/arm/unordsf2vfp.S
@@ -1,9 +1,8 @@
//===-- unordsf2vfp.S - Implement unordsf2vfp -----------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -13,17 +12,25 @@
// extern int __unordsf2vfp(float a, float b);
//
// Returns one iff a or b is NaN
-// Uses Darwin calling convention where single precision arguments are passsed
+// Uses Darwin calling convention where single precision arguments are passsed
// like 32-bit ints
//
.syntax unified
.p2align 2
DEFINE_COMPILERRT_FUNCTION(__unordsf2vfp)
+#if defined(COMPILER_RT_ARMHF_TARGET)
+ vcmp.f32 s0, s1
+#else
vmov s14, r0 // move from GPR 0 to float register
vmov s15, r1 // move from GPR 1 to float register
vcmp.f32 s14, s15
+#endif
vmrs apsr_nzcv, fpscr
+ ITE(vs)
movvs r0, #1 // set result register to 1 if "overflow" (any NaNs)
movvc r0, #0
bx lr
END_COMPILERRT_FUNCTION(__unordsf2vfp)
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/arm64/Makefile.mk b/contrib/libs/cxxsupp/builtins/arm64/Makefile.mk
deleted file mode 100644
index 7f7e386613..0000000000
--- a/contrib/libs/cxxsupp/builtins/arm64/Makefile.mk
+++ /dev/null
@@ -1,20 +0,0 @@
-#===- lib/builtins/arm64/Makefile.mk -----------------------*- Makefile -*--===#
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-#===------------------------------------------------------------------------===#
-
-ModuleName := builtins
-SubDirs :=
-OnlyArchs := arm64
-
-AsmSources := $(foreach file,$(wildcard $(Dir)/*.S),$(notdir $(file)))
-Sources := $(foreach file,$(wildcard $(Dir)/*.c),$(notdir $(file)))
-ObjNames := $(Sources:%.c=%.o) $(AsmSources:%.S=%.o)
-Implementation := Optimized
-
-# FIXME: use automatic dependencies?
-Dependencies := $(wildcard lib/*.h $(Dir)/*.h)
diff --git a/contrib/libs/cxxsupp/builtins/armv6m/Makefile.mk b/contrib/libs/cxxsupp/builtins/armv6m/Makefile.mk
deleted file mode 100644
index f3c1807f01..0000000000
--- a/contrib/libs/cxxsupp/builtins/armv6m/Makefile.mk
+++ /dev/null
@@ -1,20 +0,0 @@
-#===- lib/builtins/arm/Makefile.mk -------------------------*- Makefile -*--===#
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-#===------------------------------------------------------------------------===#
-
-ModuleName := builtins
-SubDirs :=
-OnlyArchs := armv6m
-
-AsmSources := $(foreach file,$(wildcard $(Dir)/*.S),$(notdir $(file)))
-Sources := $(foreach file,$(wildcard $(Dir)/*.c),$(notdir $(file)))
-ObjNames := $(Sources:%.c=%.o) $(AsmSources:%.S=%.o)
-Implementation := Optimized
-
-# FIXME: use automatic dependencies?
-Dependencies := $(wildcard lib/*.h $(Dir)/*.h)
diff --git a/contrib/libs/cxxsupp/builtins/ashldi3.c b/contrib/libs/cxxsupp/builtins/ashldi3.c
index eb4698ac51..04f22228f1 100644
--- a/contrib/libs/cxxsupp/builtins/ashldi3.c
+++ b/contrib/libs/cxxsupp/builtins/ashldi3.c
@@ -1,43 +1,38 @@
-/* ====-- ashldi3.c - Implement __ashldi3 -----------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __ashldi3 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+// ====-- ashldi3.c - Implement __ashldi3 ---------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __ashldi3 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
-/* Returns: a << b */
+// Returns: a << b
-/* Precondition: 0 <= b < bits_in_dword */
+// Precondition: 0 <= b < bits_in_dword
-ARM_EABI_FNALIAS(llsl, ashldi3)
-
-COMPILER_RT_ABI di_int
-__ashldi3(di_int a, si_int b)
-{
- const int bits_in_word = (int)(sizeof(si_int) * CHAR_BIT);
- dwords input;
- dwords result;
- input.all = a;
- if (b & bits_in_word) /* bits_in_word <= b < bits_in_dword */
- {
- result.s.low = 0;
- result.s.high = input.s.low << (b - bits_in_word);
- }
- else /* 0 <= b < bits_in_word */
- {
- if (b == 0)
- return a;
- result.s.low = input.s.low << b;
- result.s.high = (input.s.high << b) | (input.s.low >> (bits_in_word - b));
- }
- return result.all;
+COMPILER_RT_ABI di_int __ashldi3(di_int a, int b) {
+ const int bits_in_word = (int)(sizeof(si_int) * CHAR_BIT);
+ dwords input;
+ dwords result;
+ input.all = a;
+ if (b & bits_in_word) /* bits_in_word <= b < bits_in_dword */ {
+ result.s.low = 0;
+ result.s.high = input.s.low << (b - bits_in_word);
+ } else /* 0 <= b < bits_in_word */ {
+ if (b == 0)
+ return a;
+ result.s.low = input.s.low << b;
+ result.s.high = (input.s.high << b) | (input.s.low >> (bits_in_word - b));
+ }
+ return result.all;
}
+
+#if defined(__ARM_EABI__)
+COMPILER_RT_ALIAS(__ashldi3, __aeabi_llsl)
+#endif
diff --git a/contrib/libs/cxxsupp/builtins/ashlti3.c b/contrib/libs/cxxsupp/builtins/ashlti3.c
index 638ae845ff..2d7bd4a893 100644
--- a/contrib/libs/cxxsupp/builtins/ashlti3.c
+++ b/contrib/libs/cxxsupp/builtins/ashlti3.c
@@ -1,45 +1,38 @@
-/* ===-- ashlti3.c - Implement __ashlti3 -----------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __ashlti3 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- ashlti3.c - Implement __ashlti3 -----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __ashlti3 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
#ifdef CRT_HAS_128BIT
-/* Returns: a << b */
+// Returns: a << b
-/* Precondition: 0 <= b < bits_in_tword */
+// Precondition: 0 <= b < bits_in_tword
-COMPILER_RT_ABI ti_int
-__ashlti3(ti_int a, si_int b)
-{
- const int bits_in_dword = (int)(sizeof(di_int) * CHAR_BIT);
- twords input;
- twords result;
- input.all = a;
- if (b & bits_in_dword) /* bits_in_dword <= b < bits_in_tword */
- {
- result.s.low = 0;
- result.s.high = input.s.low << (b - bits_in_dword);
- }
- else /* 0 <= b < bits_in_dword */
- {
- if (b == 0)
- return a;
- result.s.low = input.s.low << b;
- result.s.high = (input.s.high << b) | (input.s.low >> (bits_in_dword - b));
- }
- return result.all;
+COMPILER_RT_ABI ti_int __ashlti3(ti_int a, si_int b) {
+ const int bits_in_dword = (int)(sizeof(di_int) * CHAR_BIT);
+ twords input;
+ twords result;
+ input.all = a;
+ if (b & bits_in_dword) /* bits_in_dword <= b < bits_in_tword */ {
+ result.s.low = 0;
+ result.s.high = input.s.low << (b - bits_in_dword);
+ } else /* 0 <= b < bits_in_dword */ {
+ if (b == 0)
+ return a;
+ result.s.low = input.s.low << b;
+ result.s.high = (input.s.high << b) | (input.s.low >> (bits_in_dword - b));
+ }
+ return result.all;
}
-#endif /* CRT_HAS_128BIT */
+#endif // CRT_HAS_128BIT
diff --git a/contrib/libs/cxxsupp/builtins/ashrdi3.c b/contrib/libs/cxxsupp/builtins/ashrdi3.c
index 14c878bb77..934a5c47fd 100644
--- a/contrib/libs/cxxsupp/builtins/ashrdi3.c
+++ b/contrib/libs/cxxsupp/builtins/ashrdi3.c
@@ -1,44 +1,39 @@
-/*===-- ashrdi3.c - Implement __ashrdi3 -----------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __ashrdi3 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- ashrdi3.c - Implement __ashrdi3 -----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __ashrdi3 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
-/* Returns: arithmetic a >> b */
+// Returns: arithmetic a >> b
-/* Precondition: 0 <= b < bits_in_dword */
+// Precondition: 0 <= b < bits_in_dword
-ARM_EABI_FNALIAS(lasr, ashrdi3)
-
-COMPILER_RT_ABI di_int
-__ashrdi3(di_int a, si_int b)
-{
- const int bits_in_word = (int)(sizeof(si_int) * CHAR_BIT);
- dwords input;
- dwords result;
- input.all = a;
- if (b & bits_in_word) /* bits_in_word <= b < bits_in_dword */
- {
- /* result.s.high = input.s.high < 0 ? -1 : 0 */
- result.s.high = input.s.high >> (bits_in_word - 1);
- result.s.low = input.s.high >> (b - bits_in_word);
- }
- else /* 0 <= b < bits_in_word */
- {
- if (b == 0)
- return a;
- result.s.high = input.s.high >> b;
- result.s.low = (input.s.high << (bits_in_word - b)) | (input.s.low >> b);
- }
- return result.all;
+COMPILER_RT_ABI di_int __ashrdi3(di_int a, int b) {
+ const int bits_in_word = (int)(sizeof(si_int) * CHAR_BIT);
+ dwords input;
+ dwords result;
+ input.all = a;
+ if (b & bits_in_word) /* bits_in_word <= b < bits_in_dword */ {
+ // result.s.high = input.s.high < 0 ? -1 : 0
+ result.s.high = input.s.high >> (bits_in_word - 1);
+ result.s.low = input.s.high >> (b - bits_in_word);
+ } else /* 0 <= b < bits_in_word */ {
+ if (b == 0)
+ return a;
+ result.s.high = input.s.high >> b;
+ result.s.low = (input.s.high << (bits_in_word - b)) | (input.s.low >> b);
+ }
+ return result.all;
}
+
+#if defined(__ARM_EABI__)
+COMPILER_RT_ALIAS(__ashrdi3, __aeabi_lasr)
+#endif
diff --git a/contrib/libs/cxxsupp/builtins/ashrti3.c b/contrib/libs/cxxsupp/builtins/ashrti3.c
index f78205d961..f573b6d6cc 100644
--- a/contrib/libs/cxxsupp/builtins/ashrti3.c
+++ b/contrib/libs/cxxsupp/builtins/ashrti3.c
@@ -1,46 +1,39 @@
-/* ===-- ashrti3.c - Implement __ashrti3 -----------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __ashrti3 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- ashrti3.c - Implement __ashrti3 -----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __ashrti3 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
#ifdef CRT_HAS_128BIT
-/* Returns: arithmetic a >> b */
+// Returns: arithmetic a >> b
-/* Precondition: 0 <= b < bits_in_tword */
+// Precondition: 0 <= b < bits_in_tword
-COMPILER_RT_ABI ti_int
-__ashrti3(ti_int a, si_int b)
-{
- const int bits_in_dword = (int)(sizeof(di_int) * CHAR_BIT);
- twords input;
- twords result;
- input.all = a;
- if (b & bits_in_dword) /* bits_in_dword <= b < bits_in_tword */
- {
- /* result.s.high = input.s.high < 0 ? -1 : 0 */
- result.s.high = input.s.high >> (bits_in_dword - 1);
- result.s.low = input.s.high >> (b - bits_in_dword);
- }
- else /* 0 <= b < bits_in_dword */
- {
- if (b == 0)
- return a;
- result.s.high = input.s.high >> b;
- result.s.low = (input.s.high << (bits_in_dword - b)) | (input.s.low >> b);
- }
- return result.all;
+COMPILER_RT_ABI ti_int __ashrti3(ti_int a, si_int b) {
+ const int bits_in_dword = (int)(sizeof(di_int) * CHAR_BIT);
+ twords input;
+ twords result;
+ input.all = a;
+ if (b & bits_in_dword) /* bits_in_dword <= b < bits_in_tword */ {
+ // result.s.high = input.s.high < 0 ? -1 : 0
+ result.s.high = input.s.high >> (bits_in_dword - 1);
+ result.s.low = input.s.high >> (b - bits_in_dword);
+ } else /* 0 <= b < bits_in_dword */ {
+ if (b == 0)
+ return a;
+ result.s.high = input.s.high >> b;
+ result.s.low = (input.s.high << (bits_in_dword - b)) | (input.s.low >> b);
+ }
+ return result.all;
}
-#endif /* CRT_HAS_128BIT */
+#endif // CRT_HAS_128BIT
diff --git a/contrib/libs/cxxsupp/builtins/assembly.h b/contrib/libs/cxxsupp/builtins/assembly.h
index c28970534c..69a3d8620f 100644
--- a/contrib/libs/cxxsupp/builtins/assembly.h
+++ b/contrib/libs/cxxsupp/builtins/assembly.h
@@ -1,23 +1,27 @@
-/* ===-- assembly.h - compiler-rt assembler support macros -----------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file defines macros for use in compiler-rt assembler source.
- * This file is not part of the interface of this library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- assembly.h - compiler-rt assembler support macros -----------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines macros for use in compiler-rt assembler source.
+// This file is not part of the interface of this library.
+//
+//===----------------------------------------------------------------------===//
#ifndef COMPILERRT_ASSEMBLY_H
#define COMPILERRT_ASSEMBLY_H
-#if defined(__POWERPC__) || defined(__powerpc__) || defined(__ppc__)
-#define SEPARATOR @
+#if defined(__linux__) && defined(__CET__)
+#if __has_include(<cet.h>)
+#include <cet.h>
+#endif
+#endif
+
+#if defined(__APPLE__) && defined(__aarch64__)
+#define SEPARATOR %%
#else
#define SEPARATOR ;
#endif
@@ -30,18 +34,27 @@
#define SYMBOL_IS_FUNC(name)
#define CONST_SECTION .const
+#define NO_EXEC_STACK_DIRECTIVE
+
#elif defined(__ELF__)
#define HIDDEN(name) .hidden name
#define LOCAL_LABEL(name) .L_##name
#define FILE_LEVEL_DIRECTIVE
-#if defined(__arm__)
+#if defined(__arm__) || defined(__aarch64__)
#define SYMBOL_IS_FUNC(name) .type name,%function
#else
#define SYMBOL_IS_FUNC(name) .type name,@function
#endif
#define CONST_SECTION .section .rodata
+#if defined(__GNU__) || defined(__FreeBSD__) || defined(__Fuchsia__) || \
+ defined(__linux__)
+#define NO_EXEC_STACK_DIRECTIVE .section .note.GNU-stack,"",%progbits
+#else
+#define NO_EXEC_STACK_DIRECTIVE
+#endif
+
#else // !__APPLE__ && !__ELF__
#define HIDDEN(name)
@@ -54,13 +67,107 @@
.endef
#define CONST_SECTION .section .rdata,"rd"
+#define NO_EXEC_STACK_DIRECTIVE
+
+#endif
+
+#if defined(__arm__) || defined(__aarch64__)
+#define FUNC_ALIGN \
+ .text SEPARATOR \
+ .balign 16 SEPARATOR
+#else
+#define FUNC_ALIGN
+#endif
+
+// BTI and PAC gnu property note
+#define NT_GNU_PROPERTY_TYPE_0 5
+#define GNU_PROPERTY_AARCH64_FEATURE_1_AND 0xc0000000
+#define GNU_PROPERTY_AARCH64_FEATURE_1_BTI 1
+#define GNU_PROPERTY_AARCH64_FEATURE_1_PAC 2
+
+#if defined(__ARM_FEATURE_BTI_DEFAULT)
+#define BTI_FLAG GNU_PROPERTY_AARCH64_FEATURE_1_BTI
+#else
+#define BTI_FLAG 0
+#endif
+
+#if __ARM_FEATURE_PAC_DEFAULT & 3
+#define PAC_FLAG GNU_PROPERTY_AARCH64_FEATURE_1_PAC
+#else
+#define PAC_FLAG 0
+#endif
+
+#define GNU_PROPERTY(type, value) \
+ .pushsection .note.gnu.property, "a" SEPARATOR \
+ .p2align 3 SEPARATOR \
+ .word 4 SEPARATOR \
+ .word 16 SEPARATOR \
+ .word NT_GNU_PROPERTY_TYPE_0 SEPARATOR \
+ .asciz "GNU" SEPARATOR \
+ .word type SEPARATOR \
+ .word 4 SEPARATOR \
+ .word value SEPARATOR \
+ .word 0 SEPARATOR \
+ .popsection
+
+#if BTI_FLAG != 0
+#define BTI_C hint #34
+#define BTI_J hint #36
+#else
+#define BTI_C
+#define BTI_J
+#endif
+
+#if (BTI_FLAG | PAC_FLAG) != 0
+#define GNU_PROPERTY_BTI_PAC \
+ GNU_PROPERTY(GNU_PROPERTY_AARCH64_FEATURE_1_AND, BTI_FLAG | PAC_FLAG)
+#else
+#define GNU_PROPERTY_BTI_PAC
+#endif
+
+#if defined(__clang__) || defined(__GCC_HAVE_DWARF2_CFI_ASM)
+#define CFI_START .cfi_startproc
+#define CFI_END .cfi_endproc
+#else
+#define CFI_START
+#define CFI_END
#endif
#if defined(__arm__)
+
+// Determine actual [ARM][THUMB[1][2]] ISA using compiler predefined macros:
+// - for '-mthumb -march=armv6' compiler defines '__thumb__'
+// - for '-mthumb -march=armv7' compiler defines '__thumb__' and '__thumb2__'
+#if defined(__thumb2__) || defined(__thumb__)
+#define DEFINE_CODE_STATE .thumb SEPARATOR
+#define DECLARE_FUNC_ENCODING .thumb_func SEPARATOR
+#if defined(__thumb2__)
+#define USE_THUMB_2
+#define IT(cond) it cond
+#define ITT(cond) itt cond
+#define ITE(cond) ite cond
+#else
+#define USE_THUMB_1
+#define IT(cond)
+#define ITT(cond)
+#define ITE(cond)
+#endif // defined(__thumb__2)
+#else // !defined(__thumb2__) && !defined(__thumb__)
+#define DEFINE_CODE_STATE .arm SEPARATOR
+#define DECLARE_FUNC_ENCODING
+#define IT(cond)
+#define ITT(cond)
+#define ITE(cond)
+#endif
+
+#if defined(USE_THUMB_1) && defined(USE_THUMB_2)
+#error "USE_THUMB_1 and USE_THUMB_2 can't be defined together."
+#endif
+
#if defined(__ARM_ARCH_4T__) || __ARM_ARCH >= 5
#define ARM_HAS_BX
#endif
-#if !defined(__ARM_FEATURE_CLZ) && \
+#if !defined(__ARM_FEATURE_CLZ) && !defined(USE_THUMB_1) && \
(__ARM_ARCH >= 6 || (__ARM_ARCH == 5 && !defined(__ARM_ARCH_5__)))
#define __ARM_FEATURE_CLZ
#endif
@@ -82,40 +189,47 @@
JMP(ip)
#endif
-#if __ARM_ARCH_ISA_THUMB == 2
-#define IT(cond) it cond
-#define ITT(cond) itt cond
-#else
-#define IT(cond)
-#define ITT(cond)
-#endif
-
-#if __ARM_ARCH_ISA_THUMB == 2
+#if defined(USE_THUMB_2)
#define WIDE(op) op.w
#else
#define WIDE(op) op
#endif
+#else // !defined(__arm)
+#define DECLARE_FUNC_ENCODING
+#define DEFINE_CODE_STATE
#endif
-#define GLUE2(a, b) a##b
-#define GLUE(a, b) GLUE2(a, b)
+#define GLUE2_(a, b) a##b
+#define GLUE(a, b) GLUE2_(a, b)
+#define GLUE2(a, b) GLUE2_(a, b)
+#define GLUE3_(a, b, c) a##b##c
+#define GLUE3(a, b, c) GLUE3_(a, b, c)
+#define GLUE4_(a, b, c, d) a##b##c##d
+#define GLUE4(a, b, c, d) GLUE4_(a, b, c, d)
+
#define SYMBOL_NAME(name) GLUE(__USER_LABEL_PREFIX__, name)
#ifdef VISIBILITY_HIDDEN
#define DECLARE_SYMBOL_VISIBILITY(name) \
HIDDEN(SYMBOL_NAME(name)) SEPARATOR
+#define DECLARE_SYMBOL_VISIBILITY_UNMANGLED(name) \
+ HIDDEN(name) SEPARATOR
#else
#define DECLARE_SYMBOL_VISIBILITY(name)
+#define DECLARE_SYMBOL_VISIBILITY_UNMANGLED(name)
#endif
#define DEFINE_COMPILERRT_FUNCTION(name) \
+ DEFINE_CODE_STATE \
FILE_LEVEL_DIRECTIVE SEPARATOR \
.globl SYMBOL_NAME(name) SEPARATOR \
SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \
DECLARE_SYMBOL_VISIBILITY(name) \
+ DECLARE_FUNC_ENCODING \
SYMBOL_NAME(name):
#define DEFINE_COMPILERRT_THUMB_FUNCTION(name) \
+ DEFINE_CODE_STATE \
FILE_LEVEL_DIRECTIVE SEPARATOR \
.globl SYMBOL_NAME(name) SEPARATOR \
SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \
@@ -124,21 +238,36 @@
SYMBOL_NAME(name):
#define DEFINE_COMPILERRT_PRIVATE_FUNCTION(name) \
+ DEFINE_CODE_STATE \
FILE_LEVEL_DIRECTIVE SEPARATOR \
.globl SYMBOL_NAME(name) SEPARATOR \
SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \
HIDDEN(SYMBOL_NAME(name)) SEPARATOR \
+ DECLARE_FUNC_ENCODING \
SYMBOL_NAME(name):
#define DEFINE_COMPILERRT_PRIVATE_FUNCTION_UNMANGLED(name) \
+ DEFINE_CODE_STATE \
.globl name SEPARATOR \
SYMBOL_IS_FUNC(name) SEPARATOR \
HIDDEN(name) SEPARATOR \
+ DECLARE_FUNC_ENCODING \
name:
+#define DEFINE_COMPILERRT_OUTLINE_FUNCTION_UNMANGLED(name) \
+ DEFINE_CODE_STATE \
+ FUNC_ALIGN \
+ .globl name SEPARATOR \
+ SYMBOL_IS_FUNC(name) SEPARATOR \
+ DECLARE_SYMBOL_VISIBILITY_UNMANGLED(name) SEPARATOR \
+ CFI_START SEPARATOR \
+ DECLARE_FUNC_ENCODING \
+ name: SEPARATOR BTI_C
+
#define DEFINE_COMPILERRT_FUNCTION_ALIAS(name, target) \
.globl SYMBOL_NAME(name) SEPARATOR \
SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \
+ DECLARE_SYMBOL_VISIBILITY(SYMBOL_NAME(name)) SEPARATOR \
.set SYMBOL_NAME(name), SYMBOL_NAME(target) SEPARATOR
#if defined(__ARM_EABI__)
@@ -151,8 +280,13 @@
#ifdef __ELF__
#define END_COMPILERRT_FUNCTION(name) \
.size SYMBOL_NAME(name), . - SYMBOL_NAME(name)
+#define END_COMPILERRT_OUTLINE_FUNCTION(name) \
+ CFI_END SEPARATOR \
+ .size SYMBOL_NAME(name), . - SYMBOL_NAME(name)
#else
#define END_COMPILERRT_FUNCTION(name)
+#define END_COMPILERRT_OUTLINE_FUNCTION(name) \
+ CFI_END
#endif
-#endif /* COMPILERRT_ASSEMBLY_H */
+#endif // COMPILERRT_ASSEMBLY_H
diff --git a/contrib/libs/cxxsupp/builtins/atomic.c b/contrib/libs/cxxsupp/builtins/atomic.c
index f1ddc3e0c5..852bb20f08 100644
--- a/contrib/libs/cxxsupp/builtins/atomic.c
+++ b/contrib/libs/cxxsupp/builtins/atomic.c
@@ -1,47 +1,53 @@
-/*===-- atomic.c - Implement support functions for atomic operations.------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- *===----------------------------------------------------------------------===
- *
- * atomic.c defines a set of functions for performing atomic accesses on
- * arbitrary-sized memory locations. This design uses locks that should
- * be fast in the uncontended case, for two reasons:
- *
- * 1) This code must work with C programs that do not link to anything
- * (including pthreads) and so it should not depend on any pthread
- * functions.
- * 2) Atomic operations, rather than explicit mutexes, are most commonly used
- * on code where contended operations are rate.
- *
- * To avoid needing a per-object lock, this code allocates an array of
- * locks and hashes the object pointers to find the one that it should use.
- * For operations that must be atomic on two locations, the lower lock is
- * always acquired first, to avoid deadlock.
- *
- *===----------------------------------------------------------------------===
- */
+//===-- atomic.c - Implement support functions for atomic operations.------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// atomic.c defines a set of functions for performing atomic accesses on
+// arbitrary-sized memory locations. This design uses locks that should
+// be fast in the uncontended case, for two reasons:
+//
+// 1) This code must work with C programs that do not link to anything
+// (including pthreads) and so it should not depend on any pthread
+// functions.
+// 2) Atomic operations, rather than explicit mutexes, are most commonly used
+// on code where contended operations are rate.
+//
+// To avoid needing a per-object lock, this code allocates an array of
+// locks and hashes the object pointers to find the one that it should use.
+// For operations that must be atomic on two locations, the lower lock is
+// always acquired first, to avoid deadlock.
+//
+//===----------------------------------------------------------------------===//
+#include <stdbool.h>
+#include <stddef.h>
#include <stdint.h>
-#include <string.h>
#include "assembly.h"
+// We use __builtin_mem* here to avoid dependencies on libc-provided headers.
+#define memcpy __builtin_memcpy
+#define memcmp __builtin_memcmp
+
// Clang objects if you redefine a builtin. This little hack allows us to
// define a function with the same name as an intrinsic.
#pragma redefine_extname __atomic_load_c SYMBOL_NAME(__atomic_load)
#pragma redefine_extname __atomic_store_c SYMBOL_NAME(__atomic_store)
#pragma redefine_extname __atomic_exchange_c SYMBOL_NAME(__atomic_exchange)
-#pragma redefine_extname __atomic_compare_exchange_c SYMBOL_NAME(__atomic_compare_exchange)
+#pragma redefine_extname __atomic_compare_exchange_c SYMBOL_NAME( \
+ __atomic_compare_exchange)
+#pragma redefine_extname __atomic_is_lock_free_c SYMBOL_NAME( \
+ __atomic_is_lock_free)
/// Number of locks. This allocates one page on 32-bit platforms, two on
/// 64-bit. This can be specified externally if a different trade between
/// memory usage and contention probability is required for a given platform.
#ifndef SPINLOCK_COUNT
-#define SPINLOCK_COUNT (1<<10)
+#define SPINLOCK_COUNT (1 << 10)
#endif
static const long SPINLOCK_MASK = SPINLOCK_COUNT - 1;
@@ -50,43 +56,44 @@ static const long SPINLOCK_MASK = SPINLOCK_COUNT - 1;
// defined. Each platform should define the Lock type, and corresponding
// lock() and unlock() functions.
////////////////////////////////////////////////////////////////////////////////
-#ifdef __FreeBSD__
+#if defined(__FreeBSD__) || defined(__DragonFly__)
#include <errno.h>
+// clang-format off
#include <sys/types.h>
#include <machine/atomic.h>
#include <sys/umtx.h>
+// clang-format on
typedef struct _usem Lock;
__inline static void unlock(Lock *l) {
- __c11_atomic_store((_Atomic(uint32_t)*)&l->_count, 1, __ATOMIC_RELEASE);
+ __c11_atomic_store((_Atomic(uint32_t) *)&l->_count, 1, __ATOMIC_RELEASE);
__c11_atomic_thread_fence(__ATOMIC_SEQ_CST);
if (l->_has_waiters)
- _umtx_op(l, UMTX_OP_SEM_WAKE, 1, 0, 0);
+ _umtx_op(l, UMTX_OP_SEM_WAKE, 1, 0, 0);
}
__inline static void lock(Lock *l) {
uint32_t old = 1;
- while (!__c11_atomic_compare_exchange_weak((_Atomic(uint32_t)*)&l->_count, &old,
- 0, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED)) {
+ while (!__c11_atomic_compare_exchange_weak((_Atomic(uint32_t) *)&l->_count,
+ &old, 0, __ATOMIC_ACQUIRE,
+ __ATOMIC_RELAXED)) {
_umtx_op(l, UMTX_OP_SEM_WAIT, 0, 0, 0);
old = 1;
}
}
/// locks for atomic operations
-static Lock locks[SPINLOCK_COUNT] = { [0 ... SPINLOCK_COUNT-1] = {0,1,0} };
+static Lock locks[SPINLOCK_COUNT] = {[0 ... SPINLOCK_COUNT - 1] = {0, 1, 0}};
#elif defined(__APPLE__)
#include <libkern/OSAtomic.h>
typedef OSSpinLock Lock;
-__inline static void unlock(Lock *l) {
- OSSpinLockUnlock(l);
-}
+__inline static void unlock(Lock *l) { OSSpinLockUnlock(l); }
/// Locks a lock. In the current implementation, this is potentially
/// unbounded in the contended case.
-__inline static void lock(Lock *l) {
- OSSpinLockLock(l);
-}
+__inline static void lock(Lock *l) { OSSpinLockLock(l); }
static Lock locks[SPINLOCK_COUNT]; // initialized to OS_SPINLOCK_INIT which is 0
#else
+_Static_assert(__atomic_always_lock_free(sizeof(uintptr_t), 0),
+ "Implementation assumes lock-free pointer-size cmpxchg");
typedef _Atomic(uintptr_t) Lock;
/// Unlock a lock. This is a release operation.
__inline static void unlock(Lock *l) {
@@ -97,20 +104,19 @@ __inline static void unlock(Lock *l) {
__inline static void lock(Lock *l) {
uintptr_t old = 0;
while (!__c11_atomic_compare_exchange_weak(l, &old, 1, __ATOMIC_ACQUIRE,
- __ATOMIC_RELAXED))
+ __ATOMIC_RELAXED))
old = 0;
}
/// locks for atomic operations
static Lock locks[SPINLOCK_COUNT];
#endif
-
-/// Returns a lock to use for a given pointer.
+/// Returns a lock to use for a given pointer.
static __inline Lock *lock_for_pointer(void *ptr) {
intptr_t hash = (intptr_t)ptr;
// Disregard the lowest 4 bits. We want all values that may be part of the
// same memory operation to hash to the same value and therefore use the same
- // lock.
+ // lock.
hash >>= 4;
// Use the next bits as the basis for the hash
intptr_t low = hash & SPINLOCK_MASK;
@@ -122,48 +128,58 @@ static __inline Lock *lock_for_pointer(void *ptr) {
return locks + (hash & SPINLOCK_MASK);
}
-/// Macros for determining whether a size is lock free. Clang can not yet
-/// codegen __atomic_is_lock_free(16), so for now we assume 16-byte values are
-/// not lock free.
-#define IS_LOCK_FREE_1 __c11_atomic_is_lock_free(1)
-#define IS_LOCK_FREE_2 __c11_atomic_is_lock_free(2)
-#define IS_LOCK_FREE_4 __c11_atomic_is_lock_free(4)
-#define IS_LOCK_FREE_8 __c11_atomic_is_lock_free(8)
-#define IS_LOCK_FREE_16 0
+/// Macros for determining whether a size is lock free.
+#define ATOMIC_ALWAYS_LOCK_FREE_OR_ALIGNED_LOCK_FREE(size, p) \
+ (__atomic_always_lock_free(size, p) || \
+ (__atomic_always_lock_free(size, 0) && ((uintptr_t)p % size) == 0))
+#define IS_LOCK_FREE_1(p) ATOMIC_ALWAYS_LOCK_FREE_OR_ALIGNED_LOCK_FREE(1, p)
+#define IS_LOCK_FREE_2(p) ATOMIC_ALWAYS_LOCK_FREE_OR_ALIGNED_LOCK_FREE(2, p)
+#define IS_LOCK_FREE_4(p) ATOMIC_ALWAYS_LOCK_FREE_OR_ALIGNED_LOCK_FREE(4, p)
+#define IS_LOCK_FREE_8(p) ATOMIC_ALWAYS_LOCK_FREE_OR_ALIGNED_LOCK_FREE(8, p)
+#define IS_LOCK_FREE_16(p) ATOMIC_ALWAYS_LOCK_FREE_OR_ALIGNED_LOCK_FREE(16, p)
/// Macro that calls the compiler-generated lock-free versions of functions
/// when they exist.
-#define LOCK_FREE_CASES() \
- do {\
- switch (size) {\
- case 2:\
- if (IS_LOCK_FREE_2) {\
- LOCK_FREE_ACTION(uint16_t);\
- }\
- case 4:\
- if (IS_LOCK_FREE_4) {\
- LOCK_FREE_ACTION(uint32_t);\
- }\
- case 8:\
- if (IS_LOCK_FREE_8) {\
- LOCK_FREE_ACTION(uint64_t);\
- }\
- case 16:\
- if (IS_LOCK_FREE_16) {\
- /* FIXME: __uint128_t isn't available on 32 bit platforms.
- LOCK_FREE_ACTION(__uint128_t);*/\
- }\
- }\
+#define TRY_LOCK_FREE_CASE(n, type, ptr) \
+ case n: \
+ if (IS_LOCK_FREE_##n(ptr)) { \
+ LOCK_FREE_ACTION(type); \
+ } \
+ break;
+#ifdef __SIZEOF_INT128__
+#define TRY_LOCK_FREE_CASE_16(p) TRY_LOCK_FREE_CASE(16, __uint128_t, p)
+#else
+#define TRY_LOCK_FREE_CASE_16(p) /* __uint128_t not available */
+#endif
+
+#define LOCK_FREE_CASES(ptr) \
+ do { \
+ switch (size) { \
+ TRY_LOCK_FREE_CASE(1, uint8_t, ptr) \
+ TRY_LOCK_FREE_CASE(2, uint16_t, ptr) \
+ TRY_LOCK_FREE_CASE(4, uint32_t, ptr) \
+ TRY_LOCK_FREE_CASE(8, uint64_t, ptr) \
+ TRY_LOCK_FREE_CASE_16(ptr) /* __uint128_t may not be supported */ \
+ default: \
+ break; \
+ } \
} while (0)
+/// Whether atomic operations for the given size (and alignment) are lock-free.
+bool __atomic_is_lock_free_c(size_t size, void *ptr) {
+#define LOCK_FREE_ACTION(type) return true;
+ LOCK_FREE_CASES(ptr);
+#undef LOCK_FREE_ACTION
+ return false;
+}
/// An atomic load operation. This is atomic with respect to the source
/// pointer only.
void __atomic_load_c(int size, void *src, void *dest, int model) {
-#define LOCK_FREE_ACTION(type) \
- *((type*)dest) = __c11_atomic_load((_Atomic(type)*)src, model);\
- return;
- LOCK_FREE_CASES();
+#define LOCK_FREE_ACTION(type) \
+ *((type *)dest) = __c11_atomic_load((_Atomic(type) *)src, model); \
+ return;
+ LOCK_FREE_CASES(src);
#undef LOCK_FREE_ACTION
Lock *l = lock_for_pointer(src);
lock(l);
@@ -174,10 +190,10 @@ void __atomic_load_c(int size, void *src, void *dest, int model) {
/// An atomic store operation. This is atomic with respect to the destination
/// pointer only.
void __atomic_store_c(int size, void *dest, void *src, int model) {
-#define LOCK_FREE_ACTION(type) \
- __c11_atomic_store((_Atomic(type)*)dest, *(type*)dest, model);\
- return;
- LOCK_FREE_CASES();
+#define LOCK_FREE_ACTION(type) \
+ __c11_atomic_store((_Atomic(type) *)dest, *(type *)src, model); \
+ return;
+ LOCK_FREE_CASES(dest);
#undef LOCK_FREE_ACTION
Lock *l = lock_for_pointer(dest);
lock(l);
@@ -189,13 +205,14 @@ void __atomic_store_c(int size, void *dest, void *src, int model) {
/// to the value at *expected, then this copies value at *desired to *ptr. If
/// they are not, then this stores the current value from *ptr in *expected.
///
-/// This function returns 1 if the exchange takes place or 0 if it fails.
+/// This function returns 1 if the exchange takes place or 0 if it fails.
int __atomic_compare_exchange_c(int size, void *ptr, void *expected,
- void *desired, int success, int failure) {
-#define LOCK_FREE_ACTION(type) \
- return __c11_atomic_compare_exchange_strong((_Atomic(type)*)ptr, (type*)expected,\
- *(type*)desired, success, failure)
- LOCK_FREE_CASES();
+ void *desired, int success, int failure) {
+#define LOCK_FREE_ACTION(type) \
+ return __c11_atomic_compare_exchange_strong( \
+ (_Atomic(type) *)ptr, (type *)expected, *(type *)desired, success, \
+ failure)
+ LOCK_FREE_CASES(ptr);
#undef LOCK_FREE_ACTION
Lock *l = lock_for_pointer(ptr);
lock(l);
@@ -212,11 +229,11 @@ int __atomic_compare_exchange_c(int size, void *ptr, void *expected,
/// Performs an atomic exchange operation between two pointers. This is atomic
/// with respect to the target address.
void __atomic_exchange_c(int size, void *ptr, void *val, void *old, int model) {
-#define LOCK_FREE_ACTION(type) \
- *(type*)old = __c11_atomic_exchange((_Atomic(type)*)ptr, *(type*)val,\
- model);\
- return;
- LOCK_FREE_CASES();
+#define LOCK_FREE_ACTION(type) \
+ *(type *)old = \
+ __c11_atomic_exchange((_Atomic(type) *)ptr, *(type *)val, model); \
+ return;
+ LOCK_FREE_CASES(ptr);
#undef LOCK_FREE_ACTION
Lock *l = lock_for_pointer(ptr);
lock(l);
@@ -229,90 +246,109 @@ void __atomic_exchange_c(int size, void *ptr, void *val, void *old, int model) {
// Where the size is known at compile time, the compiler may emit calls to
// specialised versions of the above functions.
////////////////////////////////////////////////////////////////////////////////
-#define OPTIMISED_CASES\
- OPTIMISED_CASE(1, IS_LOCK_FREE_1, uint8_t)\
- OPTIMISED_CASE(2, IS_LOCK_FREE_2, uint16_t)\
- OPTIMISED_CASE(4, IS_LOCK_FREE_4, uint32_t)\
- OPTIMISED_CASE(8, IS_LOCK_FREE_8, uint64_t)\
- /* FIXME: __uint128_t isn't available on 32 bit platforms.
- OPTIMISED_CASE(16, IS_LOCK_FREE_16, __uint128_t)*/\
+#ifdef __SIZEOF_INT128__
+#define OPTIMISED_CASES \
+ OPTIMISED_CASE(1, IS_LOCK_FREE_1, uint8_t) \
+ OPTIMISED_CASE(2, IS_LOCK_FREE_2, uint16_t) \
+ OPTIMISED_CASE(4, IS_LOCK_FREE_4, uint32_t) \
+ OPTIMISED_CASE(8, IS_LOCK_FREE_8, uint64_t) \
+ OPTIMISED_CASE(16, IS_LOCK_FREE_16, __uint128_t)
+#else
+#define OPTIMISED_CASES \
+ OPTIMISED_CASE(1, IS_LOCK_FREE_1, uint8_t) \
+ OPTIMISED_CASE(2, IS_LOCK_FREE_2, uint16_t) \
+ OPTIMISED_CASE(4, IS_LOCK_FREE_4, uint32_t) \
+ OPTIMISED_CASE(8, IS_LOCK_FREE_8, uint64_t)
+#endif
-#define OPTIMISED_CASE(n, lockfree, type)\
-type __atomic_load_##n(type *src, int model) {\
- if (lockfree)\
- return __c11_atomic_load((_Atomic(type)*)src, model);\
- Lock *l = lock_for_pointer(src);\
- lock(l);\
- type val = *src;\
- unlock(l);\
- return val;\
-}
+#define OPTIMISED_CASE(n, lockfree, type) \
+ type __atomic_load_##n(type *src, int model) { \
+ if (lockfree(src)) \
+ return __c11_atomic_load((_Atomic(type) *)src, model); \
+ Lock *l = lock_for_pointer(src); \
+ lock(l); \
+ type val = *src; \
+ unlock(l); \
+ return val; \
+ }
OPTIMISED_CASES
#undef OPTIMISED_CASE
-#define OPTIMISED_CASE(n, lockfree, type)\
-void __atomic_store_##n(type *dest, type val, int model) {\
- if (lockfree) {\
- __c11_atomic_store((_Atomic(type)*)dest, val, model);\
- return;\
- }\
- Lock *l = lock_for_pointer(dest);\
- lock(l);\
- *dest = val;\
- unlock(l);\
- return;\
-}
+#define OPTIMISED_CASE(n, lockfree, type) \
+ void __atomic_store_##n(type *dest, type val, int model) { \
+ if (lockfree(dest)) { \
+ __c11_atomic_store((_Atomic(type) *)dest, val, model); \
+ return; \
+ } \
+ Lock *l = lock_for_pointer(dest); \
+ lock(l); \
+ *dest = val; \
+ unlock(l); \
+ return; \
+ }
OPTIMISED_CASES
#undef OPTIMISED_CASE
-#define OPTIMISED_CASE(n, lockfree, type)\
-type __atomic_exchange_##n(type *dest, type val, int model) {\
- if (lockfree)\
- return __c11_atomic_exchange((_Atomic(type)*)dest, val, model);\
- Lock *l = lock_for_pointer(dest);\
- lock(l);\
- type tmp = *dest;\
- *dest = val;\
- unlock(l);\
- return tmp;\
-}
+#define OPTIMISED_CASE(n, lockfree, type) \
+ type __atomic_exchange_##n(type *dest, type val, int model) { \
+ if (lockfree(dest)) \
+ return __c11_atomic_exchange((_Atomic(type) *)dest, val, model); \
+ Lock *l = lock_for_pointer(dest); \
+ lock(l); \
+ type tmp = *dest; \
+ *dest = val; \
+ unlock(l); \
+ return tmp; \
+ }
OPTIMISED_CASES
#undef OPTIMISED_CASE
-#define OPTIMISED_CASE(n, lockfree, type)\
-int __atomic_compare_exchange_##n(type *ptr, type *expected, type desired,\
- int success, int failure) {\
- if (lockfree)\
- return __c11_atomic_compare_exchange_strong((_Atomic(type)*)ptr, expected, desired,\
- success, failure);\
- Lock *l = lock_for_pointer(ptr);\
- lock(l);\
- if (*ptr == *expected) {\
- *ptr = desired;\
- unlock(l);\
- return 1;\
- }\
- *expected = *ptr;\
- unlock(l);\
- return 0;\
-}
+#define OPTIMISED_CASE(n, lockfree, type) \
+ bool __atomic_compare_exchange_##n(type *ptr, type *expected, type desired, \
+ int success, int failure) { \
+ if (lockfree(ptr)) \
+ return __c11_atomic_compare_exchange_strong( \
+ (_Atomic(type) *)ptr, expected, desired, success, failure); \
+ Lock *l = lock_for_pointer(ptr); \
+ lock(l); \
+ if (*ptr == *expected) { \
+ *ptr = desired; \
+ unlock(l); \
+ return true; \
+ } \
+ *expected = *ptr; \
+ unlock(l); \
+ return false; \
+ }
OPTIMISED_CASES
#undef OPTIMISED_CASE
////////////////////////////////////////////////////////////////////////////////
// Atomic read-modify-write operations for integers of various sizes.
////////////////////////////////////////////////////////////////////////////////
-#define ATOMIC_RMW(n, lockfree, type, opname, op) \
-type __atomic_fetch_##opname##_##n(type *ptr, type val, int model) {\
- if (lockfree) \
- return __c11_atomic_fetch_##opname((_Atomic(type)*)ptr, val, model);\
- Lock *l = lock_for_pointer(ptr);\
- lock(l);\
- type tmp = *ptr;\
- *ptr = tmp op val;\
- unlock(l);\
- return tmp;\
-}
+#define ATOMIC_RMW(n, lockfree, type, opname, op) \
+ type __atomic_fetch_##opname##_##n(type *ptr, type val, int model) { \
+ if (lockfree(ptr)) \
+ return __c11_atomic_fetch_##opname((_Atomic(type) *)ptr, val, model); \
+ Lock *l = lock_for_pointer(ptr); \
+ lock(l); \
+ type tmp = *ptr; \
+ *ptr = tmp op val; \
+ unlock(l); \
+ return tmp; \
+ }
+
+#define ATOMIC_RMW_NAND(n, lockfree, type) \
+ type __atomic_fetch_nand_##n(type *ptr, type val, int model) { \
+ if (lockfree(ptr)) \
+ return __c11_atomic_fetch_nand((_Atomic(type) *)ptr, val, model); \
+ Lock *l = lock_for_pointer(ptr); \
+ lock(l); \
+ type tmp = *ptr; \
+ *ptr = ~(tmp & val); \
+ unlock(l); \
+ return tmp; \
+ }
#define OPTIMISED_CASE(n, lockfree, type) ATOMIC_RMW(n, lockfree, type, add, +)
OPTIMISED_CASES
@@ -329,3 +365,9 @@ OPTIMISED_CASES
#define OPTIMISED_CASE(n, lockfree, type) ATOMIC_RMW(n, lockfree, type, xor, ^)
OPTIMISED_CASES
#undef OPTIMISED_CASE
+// Allow build with clang without __c11_atomic_fetch_nand builtin (pre-14)
+#if __has_builtin(__c11_atomic_fetch_nand)
+#define OPTIMISED_CASE(n, lockfree, type) ATOMIC_RMW_NAND(n, lockfree, type)
+OPTIMISED_CASES
+#undef OPTIMISED_CASE
+#endif
diff --git a/contrib/libs/cxxsupp/builtins/atomic_flag_clear.c b/contrib/libs/cxxsupp/builtins/atomic_flag_clear.c
index da912af643..983e5d7f07 100644
--- a/contrib/libs/cxxsupp/builtins/atomic_flag_clear.c
+++ b/contrib/libs/cxxsupp/builtins/atomic_flag_clear.c
@@ -1,16 +1,14 @@
-/*===-- atomic_flag_clear.c -------------------------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- *===------------------------------------------------------------------------===
- *
- * This file implements atomic_flag_clear from C11's stdatomic.h.
- *
- *===------------------------------------------------------------------------===
- */
+//===-- atomic_flag_clear.c -----------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements atomic_flag_clear from C11's stdatomic.h.
+//
+//===----------------------------------------------------------------------===//
#ifndef __has_include
#define __has_include(inc) 0
diff --git a/contrib/libs/cxxsupp/builtins/atomic_flag_clear_explicit.c b/contrib/libs/cxxsupp/builtins/atomic_flag_clear_explicit.c
index 1059b787f1..e61c064768 100644
--- a/contrib/libs/cxxsupp/builtins/atomic_flag_clear_explicit.c
+++ b/contrib/libs/cxxsupp/builtins/atomic_flag_clear_explicit.c
@@ -1,16 +1,14 @@
-/*===-- atomic_flag_clear_explicit.c ----------------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- *===------------------------------------------------------------------------===
- *
- * This file implements atomic_flag_clear_explicit from C11's stdatomic.h.
- *
- *===------------------------------------------------------------------------===
- */
+//===-- atomic_flag_clear_explicit.c --------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements atomic_flag_clear_explicit from C11's stdatomic.h.
+//
+//===----------------------------------------------------------------------===//
#ifndef __has_include
#define __has_include(inc) 0
diff --git a/contrib/libs/cxxsupp/builtins/atomic_flag_test_and_set.c b/contrib/libs/cxxsupp/builtins/atomic_flag_test_and_set.c
index e8811d39ef..ee22b08b56 100644
--- a/contrib/libs/cxxsupp/builtins/atomic_flag_test_and_set.c
+++ b/contrib/libs/cxxsupp/builtins/atomic_flag_test_and_set.c
@@ -1,16 +1,14 @@
-/*===-- atomic_flag_test_and_set.c ------------------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- *===------------------------------------------------------------------------===
- *
- * This file implements atomic_flag_test_and_set from C11's stdatomic.h.
- *
- *===------------------------------------------------------------------------===
- */
+//===-- atomic_flag_test_and_set.c ----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements atomic_flag_test_and_set from C11's stdatomic.h.
+//
+//===----------------------------------------------------------------------===//
#ifndef __has_include
#define __has_include(inc) 0
diff --git a/contrib/libs/cxxsupp/builtins/atomic_flag_test_and_set_explicit.c b/contrib/libs/cxxsupp/builtins/atomic_flag_test_and_set_explicit.c
index 5c8c2df905..8c9d039942 100644
--- a/contrib/libs/cxxsupp/builtins/atomic_flag_test_and_set_explicit.c
+++ b/contrib/libs/cxxsupp/builtins/atomic_flag_test_and_set_explicit.c
@@ -1,16 +1,14 @@
-/*===-- atomic_flag_test_and_set_explicit.c ---------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- *===------------------------------------------------------------------------===
- *
- * This file implements atomic_flag_test_and_set_explicit from C11's stdatomic.h
- *
- *===------------------------------------------------------------------------===
- */
+//===-- atomic_flag_test_and_set_explicit.c -------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements atomic_flag_test_and_set_explicit from C11's stdatomic.h
+//
+//===----------------------------------------------------------------------===//
#ifndef __has_include
#define __has_include(inc) 0
diff --git a/contrib/libs/cxxsupp/builtins/atomic_signal_fence.c b/contrib/libs/cxxsupp/builtins/atomic_signal_fence.c
index 9ccc2ae60a..f4f5169d30 100644
--- a/contrib/libs/cxxsupp/builtins/atomic_signal_fence.c
+++ b/contrib/libs/cxxsupp/builtins/atomic_signal_fence.c
@@ -1,16 +1,14 @@
-/*===-- atomic_signal_fence.c -----------------------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- *===------------------------------------------------------------------------===
- *
- * This file implements atomic_signal_fence from C11's stdatomic.h.
- *
- *===------------------------------------------------------------------------===
- */
+//===-- atomic_signal_fence.c ---------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements atomic_signal_fence from C11's stdatomic.h.
+//
+//===----------------------------------------------------------------------===//
#ifndef __has_include
#define __has_include(inc) 0
diff --git a/contrib/libs/cxxsupp/builtins/atomic_thread_fence.c b/contrib/libs/cxxsupp/builtins/atomic_thread_fence.c
index d22560151b..5659ecb0b1 100644
--- a/contrib/libs/cxxsupp/builtins/atomic_thread_fence.c
+++ b/contrib/libs/cxxsupp/builtins/atomic_thread_fence.c
@@ -1,16 +1,14 @@
-/*===-- atomic_thread_fence.c -----------------------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- *===------------------------------------------------------------------------===
- *
- * This file implements atomic_thread_fence from C11's stdatomic.h.
- *
- *===------------------------------------------------------------------------===
- */
+//===-- atomic_thread_fence.c ---------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements atomic_thread_fence from C11's stdatomic.h.
+//
+//===----------------------------------------------------------------------===//
#ifndef __has_include
#define __has_include(inc) 0
diff --git a/contrib/libs/cxxsupp/builtins/avr/divmodhi4.S b/contrib/libs/cxxsupp/builtins/avr/divmodhi4.S
new file mode 100644
index 0000000000..37171331f4
--- /dev/null
+++ b/contrib/libs/cxxsupp/builtins/avr/divmodhi4.S
@@ -0,0 +1,57 @@
+//===------------- divmodhi4.S - sint16 div & mod -------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// As described at
+// https://gcc.gnu.org/wiki/avr-gcc#Exceptions_to_the_Calling_Convention, the
+// prototype is `struct {sint16, sint16} __divmodhi4(sint16, sint16)`.
+// The sint16 quotient is returned via R23:R22, and the sint16 remainder is
+// returned via R25:R24, while registers R21/R26/27/Rtmp and bit T in SREG
+// are clobbered.
+//
+//===----------------------------------------------------------------------===//
+
+ .text
+ .align 2
+
+#ifdef __AVR_TINY__
+ .set __tmp_reg__, 16
+#else
+ .set __tmp_reg__, 0
+#endif
+
+ .globl __divmodhi4
+ .type __divmodhi4, @function
+
+__divmodhi4:
+ bst r25, 7
+ mov __tmp_reg__, r23
+ brtc __divmodhi4_a
+ com __tmp_reg__
+ rcall __divmodhi4_b
+
+__divmodhi4_a:
+ sbrc r23, 7
+ rcall __divmodhi4_c
+ rcall __udivmodhi4 ; Call __udivmodhi4 to do real calculation.
+ sbrc __tmp_reg__, 7
+ rcall __divmodhi4_c
+ brtc __divmodhi4_exit
+
+__divmodhi4_b:
+ com r25
+ neg r24
+ sbci r25, 255
+ ret ; Return quotient via R23:R22 and remainder via R25:R24.
+
+__divmodhi4_c:
+ com r23
+ neg r22
+ sbci r23, 255
+
+__divmodhi4_exit:
+ ret ; Return quotient via R23:R22 and remainder via R25:r24.
diff --git a/contrib/libs/cxxsupp/builtins/avr/divmodqi4.S b/contrib/libs/cxxsupp/builtins/avr/divmodqi4.S
new file mode 100644
index 0000000000..66cfc0c69b
--- /dev/null
+++ b/contrib/libs/cxxsupp/builtins/avr/divmodqi4.S
@@ -0,0 +1,44 @@
+//===------------- divmodqi4.S - sint8 div & mod --------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// As described at
+// https://gcc.gnu.org/wiki/avr-gcc#Exceptions_to_the_Calling_Convention, the
+// prototype is `struct {sint8, sint8} __divmodqi4(sint8, sint8)`.
+// The sint8 quotient is returned via R24, and the sint8 remainder is returned
+// via R25, while registers R23/Rtmp and bit T in SREG are clobbered.
+//
+//===----------------------------------------------------------------------===//
+
+ .text
+ .align 2
+
+#ifdef __AVR_TINY__
+ .set __tmp_reg__, 16
+#else
+ .set __tmp_reg__, 0
+#endif
+
+ .globl __divmodqi4
+ .type __divmodqi4, @function
+
+__divmodqi4:
+ bst r24, 7
+ mov __tmp_reg__, r24
+ eor __tmp_reg__, r22
+ sbrc r24, 7
+ neg r24
+ sbrc r22, 7
+ neg r22
+ rcall __udivmodqi4 ; Call __udivmodqi4 to do real calculation.
+ brtc __divmodqi4_1
+ neg r25
+
+__divmodqi4_1:
+ sbrc __tmp_reg__, 7
+ neg r24
+ ret ; Return quotient via R24 and remainder via R25.
diff --git a/contrib/libs/cxxsupp/builtins/avr/exit.S b/contrib/libs/cxxsupp/builtins/avr/exit.S
new file mode 100644
index 0000000000..3cd9c5dafd
--- /dev/null
+++ b/contrib/libs/cxxsupp/builtins/avr/exit.S
@@ -0,0 +1,18 @@
+//===------------ exit.S - global terminator for AVR ----------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+ .text
+ .align 2
+
+ .globl _exit
+ .type _exit, @function
+
+_exit:
+ cli ; Disable all interrupts.
+__stop_program:
+ rjmp __stop_program ; Fall into an infinite loop.
diff --git a/contrib/libs/cxxsupp/builtins/avr/mulhi3.S b/contrib/libs/cxxsupp/builtins/avr/mulhi3.S
new file mode 100644
index 0000000000..d65f52ff27
--- /dev/null
+++ b/contrib/libs/cxxsupp/builtins/avr/mulhi3.S
@@ -0,0 +1,71 @@
+//===------------ mulhi3.S - int16 multiplication -------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// The corresponding C code is something like:
+//
+// int __mulhi3(int A, int B) {
+// int S = 0;
+// while (A != 0) {
+// if (A & 1)
+// S += B;
+// A = ((unsigned int) A) >> 1;
+// B <<= 1;
+// }
+// return S;
+// }
+//
+// __mulhi3 has special ABI, as the implementation of libgcc, R25:R24 is used
+// to return result, while Rtmp/R21/R22/R23 are clobbered.
+//
+//===----------------------------------------------------------------------===//
+
+ .text
+ .align 2
+
+#ifdef __AVR_TINY__
+ .set __tmp_reg__, 16
+ .set __zero_reg__, 17
+#else
+ .set __tmp_reg__, 0
+ .set __zero_reg__, 1
+#endif
+
+ .globl __mulhi3
+ .type __mulhi3, @function
+
+__mulhi3:
+ ; Use Rzero:Rtmp to store the result.
+ clr __tmp_reg__
+ clr __zero_reg__ ; S = 0;
+
+__mulhi3_loop:
+ clr r21
+ cp r24, r21
+ cpc r25, r21
+ breq __mulhi3_end ; while (A != 0) {
+
+ mov r21, r24
+ andi r21, 1
+ breq __mulhi3_loop_a ; if (A & 1)
+ add __tmp_reg__, r22
+ adc __zero_reg__, r23 ; S += B;
+
+__mulhi3_loop_a:
+ lsr r25
+ ror r24 ; A = ((unsigned int) A) >> 1;
+ lsl r22
+ rol r23 ; B <<= 1;
+ rjmp __mulhi3_loop ; }
+
+__mulhi3_end:
+ ; Return the result via R25:R24.
+ mov r24, __tmp_reg__
+ mov r25, __zero_reg__
+ ; Restore __zero_reg__ to 0.
+ clr __zero_reg__
+ ret ; return S;
diff --git a/contrib/libs/cxxsupp/builtins/avr/mulqi3.S b/contrib/libs/cxxsupp/builtins/avr/mulqi3.S
new file mode 100644
index 0000000000..914735cc64
--- /dev/null
+++ b/contrib/libs/cxxsupp/builtins/avr/mulqi3.S
@@ -0,0 +1,53 @@
+//===------------ mulhi3.S - int8 multiplication --------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// The corresponding C code is something like:
+//
+// char __mulqi3(char A, char B) {
+// int S = 0;
+// while (A != 0) {
+// if (A & 1)
+// S += B;
+// B <<= 1;
+// A = ((unsigned char) A) >> 1;
+// }
+// return S;
+// }
+//
+// __mulqi3 has special ABI, as the implementation of libgcc, the result is
+// returned via R24, while Rtmp and R22 are clobbered.
+//
+//===----------------------------------------------------------------------===//
+
+ .text
+ .align 2
+
+#ifdef __AVR_TINY__
+ .set __tmp_reg__, 16
+#else
+ .set __tmp_reg__, 0
+#endif
+
+ .globl __mulqi3
+ .type __mulqi3, @function
+
+__mulqi3:
+ clr __tmp_reg__ ; S = 0;
+
+__mulqi3_loop:
+ cpi r24, 0
+ breq __mulqi3_end ; while (A != 0) {
+ sbrc r24, 0 ; if (A & 1)
+ add __tmp_reg__, r22 ; S += B;
+ add r22, r22 ; B <<= 1;
+ lsr r24 ; A = ((unsigned char) A) >> 1;
+ rjmp __mulqi3_loop ; }
+
+__mulqi3_end:
+ mov r24, __tmp_reg__
+ ret ; return S;
diff --git a/contrib/libs/cxxsupp/builtins/avr/udivmodhi4.S b/contrib/libs/cxxsupp/builtins/avr/udivmodhi4.S
new file mode 100644
index 0000000000..0e52b86ec7
--- /dev/null
+++ b/contrib/libs/cxxsupp/builtins/avr/udivmodhi4.S
@@ -0,0 +1,49 @@
+//===------------ udivmodhi4.S - uint16 div & mod -------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// As described at
+// https://gcc.gnu.org/wiki/avr-gcc#Exceptions_to_the_Calling_Convention, the
+// prototype is `struct {uint16, uint16} __udivmodhi4(uint16, uint16)`.
+// The uint16 quotient is returned via R23:R22, and the uint16 remainder is
+// returned via R25:R24, while R21/R26/R27 are clobbered.
+//
+//===----------------------------------------------------------------------===//
+
+ .text
+ .align 2
+
+ .globl __udivmodhi4
+ .type __udivmodhi4, @function
+
+__udivmodhi4:
+ sub r26, r26
+ sub r27, r27 ; Initialize the remainder to zero.
+ ldi r21, 17 ; Only loop 16 rounds for uint16.
+
+__udivmodhi4_loop:
+ adc r24, r24
+ adc r25, r25
+ dec r21
+ breq __udivmodhi4_end
+ adc r26, r26
+ adc r27, r27
+ cp r26, r22
+ cpc r27, r23 ; Compare with the divisor.
+ brcs __udivmodhi4_loop
+ sub r26, r22
+ sbc r27, r23 ; Subtract the divisor.
+ rjmp __udivmodhi4_loop
+
+__udivmodhi4_end:
+ com r24
+ com r25
+ mov r22, r24
+ mov r23, r25 ; The quotient is returned in R23:R22.
+ mov r24, r26
+ mov r25, r27 ; The remainder is returned in in R25:R24.
+ ret
diff --git a/contrib/libs/cxxsupp/builtins/avr/udivmodqi4.S b/contrib/libs/cxxsupp/builtins/avr/udivmodqi4.S
new file mode 100644
index 0000000000..99aec34429
--- /dev/null
+++ b/contrib/libs/cxxsupp/builtins/avr/udivmodqi4.S
@@ -0,0 +1,39 @@
+//===------------ udivmodqi4.S - uint8 div & mod --------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// As described at
+// https://gcc.gnu.org/wiki/avr-gcc#Exceptions_to_the_Calling_Convention, the
+// prototype is `struct {uint8, uint8} __udivmodqi4(uint8, uint8)`.
+// The uint8 quotient is returned via R24, and the uint8 remainder is returned
+// via R25, while R23 is clobbered.
+//
+//===----------------------------------------------------------------------===//
+
+ .text
+ .align 2
+
+ .globl __udivmodqi4
+ .type __udivmodqi4, @function
+
+__udivmodqi4:
+ sub r25, r25 ; Initialize the remainder to zero.
+ ldi r23, 9 ; Only loop 8 rounds for uint8.
+
+__udivmodqi4_loop:
+ adc r24, r24
+ dec r23
+ breq __udivmodqi4_end
+ adc r25, r25
+ cp r25, r22 ; Compare with the divisor.
+ brcs __udivmodqi4_loop
+ sub r25, r22 ; Subtract the divisor.
+ rjmp __udivmodqi4_loop
+
+__udivmodqi4_end:
+ com r24 ; The uint8 quotient is returned via R24.
+ ret ; The uint8 remainder is returned via R25.
diff --git a/contrib/libs/cxxsupp/builtins/bswapdi2.c b/contrib/libs/cxxsupp/builtins/bswapdi2.c
new file mode 100644
index 0000000000..cd049f58e3
--- /dev/null
+++ b/contrib/libs/cxxsupp/builtins/bswapdi2.c
@@ -0,0 +1,25 @@
+//===-- bswapdi2.c - Implement __bswapdi2 ---------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __bswapdi2 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
+
+#include "int_lib.h"
+
+COMPILER_RT_ABI uint64_t __bswapdi2(uint64_t u) {
+ return (
+ (((u)&0xff00000000000000ULL) >> 56) |
+ (((u)&0x00ff000000000000ULL) >> 40) |
+ (((u)&0x0000ff0000000000ULL) >> 24) |
+ (((u)&0x000000ff00000000ULL) >> 8) |
+ (((u)&0x00000000ff000000ULL) << 8) |
+ (((u)&0x0000000000ff0000ULL) << 24) |
+ (((u)&0x000000000000ff00ULL) << 40) |
+ (((u)&0x00000000000000ffULL) << 56));
+}
diff --git a/contrib/libs/cxxsupp/builtins/bswapsi2.c b/contrib/libs/cxxsupp/builtins/bswapsi2.c
new file mode 100644
index 0000000000..ec566d61a2
--- /dev/null
+++ b/contrib/libs/cxxsupp/builtins/bswapsi2.c
@@ -0,0 +1,20 @@
+//===-- bswapsi2.c - Implement __bswapsi2 ---------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __bswapsi2 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
+
+#include "int_lib.h"
+
+COMPILER_RT_ABI uint32_t __bswapsi2(uint32_t u) {
+ return ((((u)&0xff000000) >> 24) |
+ (((u)&0x00ff0000) >> 8) |
+ (((u)&0x0000ff00) << 8) |
+ (((u)&0x000000ff) << 24));
+}
diff --git a/contrib/libs/cxxsupp/builtins/clear_cache.c b/contrib/libs/cxxsupp/builtins/clear_cache.c
index 8eec068939..8993761eb3 100644
--- a/contrib/libs/cxxsupp/builtins/clear_cache.c
+++ b/contrib/libs/cxxsupp/builtins/clear_cache.c
@@ -1,159 +1,208 @@
-/* ===-- clear_cache.c - Implement __clear_cache ---------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- clear_cache.c - Implement __clear_cache ---------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
+#if defined(__linux__)
+#include <assert.h>
+#endif
#include <stddef.h>
#if __APPLE__
- #include <libkern/OSCacheControl.h>
+#include <libkern/OSCacheControl.h>
+#endif
+
+#if defined(_WIN32)
+// Forward declare Win32 APIs since the GCC mode driver does not handle the
+// newer SDKs as well as needed.
+uint32_t FlushInstructionCache(uintptr_t hProcess, void *lpBaseAddress,
+ uintptr_t dwSize);
+uintptr_t GetCurrentProcess(void);
#endif
-#if (defined(__FreeBSD__) || defined(__Bitrig__)) && defined(__arm__)
- #include <sys/types.h>
- #include <machine/sysarch.h>
+
+#if defined(__FreeBSD__) && defined(__arm__)
+// clang-format off
+#include <sys/types.h>
+#include <machine/sysarch.h>
+// clang-format on
#endif
#if defined(__NetBSD__) && defined(__arm__)
- #include <machine/sysarch.h>
+#include <machine/sysarch.h>
#endif
-#if defined(__mips__)
- #include <sys/cachectl.h>
- #include <sys/syscall.h>
- #include <unistd.h>
- #if defined(__ANDROID__) && defined(__LP64__)
- /*
- * clear_mips_cache - Invalidates instruction cache for Mips.
- */
- static void clear_mips_cache(const void* Addr, size_t Size) {
- asm volatile (
- ".set push\n"
- ".set noreorder\n"
- ".set noat\n"
- "beq %[Size], $zero, 20f\n" /* If size == 0, branch around. */
- "nop\n"
- "daddu %[Size], %[Addr], %[Size]\n" /* Calculate end address + 1 */
- "rdhwr $v0, $1\n" /* Get step size for SYNCI.
- $1 is $HW_SYNCI_Step */
- "beq $v0, $zero, 20f\n" /* If no caches require
- synchronization, branch
- around. */
- "nop\n"
- "10:\n"
- "synci 0(%[Addr])\n" /* Synchronize all caches around
- address. */
- "daddu %[Addr], %[Addr], $v0\n" /* Add step size. */
- "sltu $at, %[Addr], %[Size]\n" /* Compare current with end
- address. */
- "bne $at, $zero, 10b\n" /* Branch if more to do. */
- "nop\n"
- "sync\n" /* Clear memory hazards. */
- "20:\n"
- "bal 30f\n"
- "nop\n"
- "30:\n"
- "daddiu $ra, $ra, 12\n" /* $ra has a value of $pc here.
- Add offset of 12 to point to the
- instruction after the last nop.
- */
- "jr.hb $ra\n" /* Return, clearing instruction
- hazards. */
- "nop\n"
- ".set pop\n"
- : [Addr] "+r"(Addr), [Size] "+r"(Size)
- :: "at", "ra", "v0", "memory"
- );
- }
- #endif
+#if defined(__OpenBSD__) && (defined(__arm__) || defined(__mips__) || defined(__riscv))
+// clang-format off
+#include <sys/types.h>
+#include <machine/sysarch.h>
+// clang-format on
#endif
-#if defined(__ANDROID__) && defined(__arm__)
- #include <asm/unistd.h>
+#if defined(__linux__) && defined(__mips__)
+#include <sys/cachectl.h>
+#include <sys/syscall.h>
+#include <unistd.h>
#endif
-/*
- * The compiler generates calls to __clear_cache() when creating
- * trampoline functions on the stack for use with nested functions.
- * It is expected to invalidate the instruction cache for the
- * specified range.
- */
+#if defined(__linux__) && defined(__riscv)
+// to get platform-specific syscall definitions
+#include <linux/unistd.h>
+#endif
+
+// The compiler generates calls to __clear_cache() when creating
+// trampoline functions on the stack for use with nested functions.
+// It is expected to invalidate the instruction cache for the
+// specified range.
void __clear_cache(void *start, void *end) {
-#if __i386__ || __x86_64__
-/*
- * Intel processors have a unified instruction and data cache
- * so there is nothing to do
- */
+#if __i386__ || __x86_64__ || defined(_M_IX86) || defined(_M_X64)
+// Intel processors have a unified instruction and data cache
+// so there is nothing to do
+#elif defined(_WIN32) && (defined(__arm__) || defined(__aarch64__))
+ FlushInstructionCache(GetCurrentProcess(), start, end - start);
#elif defined(__arm__) && !defined(__APPLE__)
- #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__Bitrig__)
- struct arm_sync_icache_args arg;
-
- arg.addr = (uintptr_t)start;
- arg.len = (uintptr_t)end - (uintptr_t)start;
-
- sysarch(ARM_SYNC_ICACHE, &arg);
- #elif defined(__ANDROID__)
- int start_reg __asm("r0") = (int) (intptr_t) start;
- const register int end_reg __asm("r1") = (int) (intptr_t) end;
- const register int flags __asm("r2") = 0;
- const register int syscall_nr __asm("r7") = __ARM_NR_cacheflush;
- __asm __volatile("svc 0x0" : "=r"(start_reg)
- : "r"(syscall_nr), "r"(start_reg), "r"(end_reg), "r"(flags) : "r0");
- if (start_reg != 0) {
- compilerrt_abort();
- }
- #else
- compilerrt_abort();
- #endif
+#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
+ struct arm_sync_icache_args arg;
+
+ arg.addr = (uintptr_t)start;
+ arg.len = (uintptr_t)end - (uintptr_t)start;
+
+ sysarch(ARM_SYNC_ICACHE, &arg);
+#elif defined(__linux__)
+// We used to include asm/unistd.h for the __ARM_NR_cacheflush define, but
+// it also brought many other unused defines, as well as a dependency on
+// kernel headers to be installed.
+//
+// This value is stable at least since Linux 3.13 and should remain so for
+// compatibility reasons, warranting it's re-definition here.
+#define __ARM_NR_cacheflush 0x0f0002
+ register int start_reg __asm("r0") = (int)(intptr_t)start;
+ const register int end_reg __asm("r1") = (int)(intptr_t)end;
+ const register int flags __asm("r2") = 0;
+ const register int syscall_nr __asm("r7") = __ARM_NR_cacheflush;
+ __asm __volatile("svc 0x0"
+ : "=r"(start_reg)
+ : "r"(syscall_nr), "r"(start_reg), "r"(end_reg), "r"(flags));
+ assert(start_reg == 0 && "Cache flush syscall failed.");
+#else
+ compilerrt_abort();
+#endif
+#elif defined(__linux__) && defined(__loongarch__)
+ __asm__ volatile("ibar 0");
#elif defined(__mips__)
- const uintptr_t start_int = (uintptr_t) start;
- const uintptr_t end_int = (uintptr_t) end;
- #if defined(__ANDROID__) && defined(__LP64__)
- // Call synci implementation for short address range.
- const uintptr_t address_range_limit = 256;
- if ((end_int - start_int) <= address_range_limit) {
- clear_mips_cache(start, (end_int - start_int));
- } else {
- syscall(__NR_cacheflush, start, (end_int - start_int), BCACHE);
- }
- #else
- syscall(__NR_cacheflush, start, (end_int - start_int), BCACHE);
- #endif
+ const uintptr_t start_int = (uintptr_t)start;
+ const uintptr_t end_int = (uintptr_t)end;
+ uintptr_t synci_step;
+ __asm__ volatile("rdhwr %0, $1" : "=r"(synci_step));
+ if (synci_step != 0) {
+#if __mips_isa_rev >= 6
+ for (uintptr_t p = start_int; p < end_int; p += synci_step)
+ __asm__ volatile("synci 0(%0)" : : "r"(p));
+
+ // The last "move $at, $0" is the target of jr.hb instead of delay slot.
+ __asm__ volatile(".set noat\n"
+ "sync\n"
+ "addiupc $at, 12\n"
+ "jr.hb $at\n"
+ "move $at, $0\n"
+ ".set at");
+#else
+ // Pre-R6 may not be globalized. And some implementations may give strange
+ // synci_step. So, let's use libc call for it.
+ cacheflush(start, end_int - start_int, BCACHE);
+#endif
+ }
#elif defined(__aarch64__) && !defined(__APPLE__)
- uint64_t xstart = (uint64_t)(uintptr_t) start;
- uint64_t xend = (uint64_t)(uintptr_t) end;
+ uint64_t xstart = (uint64_t)(uintptr_t)start;
+ uint64_t xend = (uint64_t)(uintptr_t)end;
+
+ // Get Cache Type Info.
+ static uint64_t ctr_el0 = 0;
+ if (ctr_el0 == 0)
+ __asm __volatile("mrs %0, ctr_el0" : "=r"(ctr_el0));
+
+ // The DC and IC instructions must use 64-bit registers so we don't use
+ // uintptr_t in case this runs in an IPL32 environment.
uint64_t addr;
- // Get Cache Type Info
- uint64_t ctr_el0;
- __asm __volatile("mrs %0, ctr_el0" : "=r"(ctr_el0));
-
- /*
- * dc & ic instructions must use 64bit registers so we don't use
- * uintptr_t in case this runs in an IPL32 environment.
- */
- const size_t dcache_line_size = 4 << ((ctr_el0 >> 16) & 15);
- for (addr = xstart; addr < xend; addr += dcache_line_size)
- __asm __volatile("dc cvau, %0" :: "r"(addr));
+ // If CTR_EL0.IDC is set, data cache cleaning to the point of unification
+ // is not required for instruction to data coherence.
+ if (((ctr_el0 >> 28) & 0x1) == 0x0) {
+ const size_t dcache_line_size = 4 << ((ctr_el0 >> 16) & 15);
+ for (addr = xstart & ~(dcache_line_size - 1); addr < xend;
+ addr += dcache_line_size)
+ __asm __volatile("dc cvau, %0" ::"r"(addr));
+ }
__asm __volatile("dsb ish");
- const size_t icache_line_size = 4 << ((ctr_el0 >> 0) & 15);
- for (addr = xstart; addr < xend; addr += icache_line_size)
- __asm __volatile("ic ivau, %0" :: "r"(addr));
+ // If CTR_EL0.DIC is set, instruction cache invalidation to the point of
+ // unification is not required for instruction to data coherence.
+ if (((ctr_el0 >> 29) & 0x1) == 0x0) {
+ const size_t icache_line_size = 4 << ((ctr_el0 >> 0) & 15);
+ for (addr = xstart & ~(icache_line_size - 1); addr < xend;
+ addr += icache_line_size)
+ __asm __volatile("ic ivau, %0" ::"r"(addr));
+ __asm __volatile("dsb ish");
+ }
__asm __volatile("isb sy");
+#elif defined(__powerpc__)
+ // Newer CPUs have a bigger line size made of multiple blocks, so the
+ // following value is a minimal common denominator for what used to be
+ // a single block cache line and is therefore inneficient.
+ const size_t line_size = 32;
+ const size_t len = (uintptr_t)end - (uintptr_t)start;
+
+ const uintptr_t mask = ~(line_size - 1);
+ const uintptr_t start_line = ((uintptr_t)start) & mask;
+ const uintptr_t end_line = ((uintptr_t)start + len + line_size - 1) & mask;
+
+ for (uintptr_t line = start_line; line < end_line; line += line_size)
+ __asm__ volatile("dcbf 0, %0" : : "r"(line));
+ __asm__ volatile("sync");
+
+ for (uintptr_t line = start_line; line < end_line; line += line_size)
+ __asm__ volatile("icbi 0, %0" : : "r"(line));
+ __asm__ volatile("isync");
+#elif defined(__sparc__)
+ const size_t dword_size = 8;
+ const size_t len = (uintptr_t)end - (uintptr_t)start;
+
+ const uintptr_t mask = ~(dword_size - 1);
+ const uintptr_t start_dword = ((uintptr_t)start) & mask;
+ const uintptr_t end_dword = ((uintptr_t)start + len + dword_size - 1) & mask;
+
+ for (uintptr_t dword = start_dword; dword < end_dword; dword += dword_size)
+ __asm__ volatile("flush %0" : : "r"(dword));
+#elif defined(__riscv) && defined(__linux__)
+ // See: arch/riscv/include/asm/cacheflush.h, arch/riscv/kernel/sys_riscv.c
+ register void *start_reg __asm("a0") = start;
+ const register void *end_reg __asm("a1") = end;
+ // "0" means that we clear cache for all threads (SYS_RISCV_FLUSH_ICACHE_ALL)
+ const register long flags __asm("a2") = 0;
+ const register long syscall_nr __asm("a7") = __NR_riscv_flush_icache;
+ __asm __volatile("ecall"
+ : "=r"(start_reg)
+ : "r"(start_reg), "r"(end_reg), "r"(flags), "r"(syscall_nr));
+ assert(start_reg == 0 && "Cache flush syscall failed.");
+#elif defined(__riscv) && defined(__OpenBSD__)
+ struct riscv_sync_icache_args arg;
+
+ arg.addr = (uintptr_t)start;
+ arg.len = (uintptr_t)end - (uintptr_t)start;
+
+ sysarch(RISCV_SYNC_ICACHE, &arg);
+#elif defined(__ve__)
+ __asm__ volatile("fencec 2");
+#else
+#if __APPLE__
+ // On Darwin, sys_icache_invalidate() provides this functionality
+ sys_icache_invalidate(start, end - start);
#else
- #if __APPLE__
- /* On Darwin, sys_icache_invalidate() provides this functionality */
- sys_icache_invalidate(start, end-start);
- #else
- compilerrt_abort();
- #endif
+ compilerrt_abort();
+#endif
#endif
}
-
diff --git a/contrib/libs/cxxsupp/builtins/clzdi2.c b/contrib/libs/cxxsupp/builtins/clzdi2.c
index b9e64da492..12c17982a5 100644
--- a/contrib/libs/cxxsupp/builtins/clzdi2.c
+++ b/contrib/libs/cxxsupp/builtins/clzdi2.c
@@ -1,29 +1,35 @@
-/* ===-- clzdi2.c - Implement __clzdi2 -------------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __clzdi2 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- clzdi2.c - Implement __clzdi2 -------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __clzdi2 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
-/* Returns: the number of leading 0-bits */
+// Returns: the number of leading 0-bits
-/* Precondition: a != 0 */
+#if !defined(__clang__) && \
+ ((defined(__sparc__) && defined(__arch64__)) || defined(__mips64) || \
+ (defined(__riscv) && __SIZEOF_POINTER__ >= 8))
+// On 64-bit architectures with neither a native clz instruction nor a native
+// ctz instruction, gcc resolves __builtin_clz to __clzdi2 rather than
+// __clzsi2, leading to infinite recursion.
+#define __builtin_clz(a) __clzsi2(a)
+extern int __clzsi2(si_int);
+#endif
-COMPILER_RT_ABI si_int
-__clzdi2(di_int a)
-{
- dwords x;
- x.all = a;
- const si_int f = -(x.s.high == 0);
- return __builtin_clz((x.s.high & ~f) | (x.s.low & f)) +
- (f & ((si_int)(sizeof(si_int) * CHAR_BIT)));
+// Precondition: a != 0
+
+COMPILER_RT_ABI int __clzdi2(di_int a) {
+ dwords x;
+ x.all = a;
+ const si_int f = -(x.s.high == 0);
+ return clzsi((x.s.high & ~f) | (x.s.low & f)) +
+ (f & ((si_int)(sizeof(si_int) * CHAR_BIT)));
}
diff --git a/contrib/libs/cxxsupp/builtins/clzsi2.c b/contrib/libs/cxxsupp/builtins/clzsi2.c
index 25b8ed2c4c..d75f56d937 100644
--- a/contrib/libs/cxxsupp/builtins/clzsi2.c
+++ b/contrib/libs/cxxsupp/builtins/clzsi2.c
@@ -1,53 +1,48 @@
-/* ===-- clzsi2.c - Implement __clzsi2 -------------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __clzsi2 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- clzsi2.c - Implement __clzsi2 -------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __clzsi2 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
-/* Returns: the number of leading 0-bits */
+// Returns: the number of leading 0-bits
-/* Precondition: a != 0 */
+// Precondition: a != 0
-COMPILER_RT_ABI si_int
-__clzsi2(si_int a)
-{
- su_int x = (su_int)a;
- si_int t = ((x & 0xFFFF0000) == 0) << 4; /* if (x is small) t = 16 else 0 */
- x >>= 16 - t; /* x = [0 - 0xFFFF] */
- su_int r = t; /* r = [0, 16] */
- /* return r + clz(x) */
- t = ((x & 0xFF00) == 0) << 3;
- x >>= 8 - t; /* x = [0 - 0xFF] */
- r += t; /* r = [0, 8, 16, 24] */
- /* return r + clz(x) */
- t = ((x & 0xF0) == 0) << 2;
- x >>= 4 - t; /* x = [0 - 0xF] */
- r += t; /* r = [0, 4, 8, 12, 16, 20, 24, 28] */
- /* return r + clz(x) */
- t = ((x & 0xC) == 0) << 1;
- x >>= 2 - t; /* x = [0 - 3] */
- r += t; /* r = [0 - 30] and is even */
- /* return r + clz(x) */
-/* switch (x)
- * {
- * case 0:
- * return r + 2;
- * case 1:
- * return r + 1;
- * case 2:
- * case 3:
- * return r;
- * }
- */
- return r + ((2 - x) & -((x & 2) == 0));
+COMPILER_RT_ABI int __clzsi2(si_int a) {
+ su_int x = (su_int)a;
+ si_int t = ((x & 0xFFFF0000) == 0) << 4; // if (x is small) t = 16 else 0
+ x >>= 16 - t; // x = [0 - 0xFFFF]
+ su_int r = t; // r = [0, 16]
+ // return r + clz(x)
+ t = ((x & 0xFF00) == 0) << 3;
+ x >>= 8 - t; // x = [0 - 0xFF]
+ r += t; // r = [0, 8, 16, 24]
+ // return r + clz(x)
+ t = ((x & 0xF0) == 0) << 2;
+ x >>= 4 - t; // x = [0 - 0xF]
+ r += t; // r = [0, 4, 8, 12, 16, 20, 24, 28]
+ // return r + clz(x)
+ t = ((x & 0xC) == 0) << 1;
+ x >>= 2 - t; // x = [0 - 3]
+ r += t; // r = [0 - 30] and is even
+ // return r + clz(x)
+ // switch (x)
+ // {
+ // case 0:
+ // return r + 2;
+ // case 1:
+ // return r + 1;
+ // case 2:
+ // case 3:
+ // return r;
+ // }
+ return r + ((2 - x) & -((x & 2) == 0));
}
diff --git a/contrib/libs/cxxsupp/builtins/clzti2.c b/contrib/libs/cxxsupp/builtins/clzti2.c
index 15a7b3c900..25d30119f2 100644
--- a/contrib/libs/cxxsupp/builtins/clzti2.c
+++ b/contrib/libs/cxxsupp/builtins/clzti2.c
@@ -1,33 +1,29 @@
-/* ===-- clzti2.c - Implement __clzti2 -------------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __clzti2 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- clzti2.c - Implement __clzti2 -------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __clzti2 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
#ifdef CRT_HAS_128BIT
-/* Returns: the number of leading 0-bits */
+// Returns: the number of leading 0-bits
-/* Precondition: a != 0 */
+// Precondition: a != 0
-COMPILER_RT_ABI si_int
-__clzti2(ti_int a)
-{
- twords x;
- x.all = a;
- const di_int f = -(x.s.high == 0);
- return __builtin_clzll((x.s.high & ~f) | (x.s.low & f)) +
- ((si_int)f & ((si_int)(sizeof(di_int) * CHAR_BIT)));
+COMPILER_RT_ABI int __clzti2(ti_int a) {
+ twords x;
+ x.all = a;
+ const di_int f = -(x.s.high == 0);
+ return __builtin_clzll((x.s.high & ~f) | (x.s.low & f)) +
+ ((si_int)f & ((si_int)(sizeof(di_int) * CHAR_BIT)));
}
-#endif /* CRT_HAS_128BIT */
+#endif // CRT_HAS_128BIT
diff --git a/contrib/libs/cxxsupp/builtins/cmpdi2.c b/contrib/libs/cxxsupp/builtins/cmpdi2.c
index 52634d9c33..951db85b50 100644
--- a/contrib/libs/cxxsupp/builtins/cmpdi2.c
+++ b/contrib/libs/cxxsupp/builtins/cmpdi2.c
@@ -1,51 +1,42 @@
-/* ===-- cmpdi2.c - Implement __cmpdi2 -------------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __cmpdi2 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- cmpdi2.c - Implement __cmpdi2 -------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __cmpdi2 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
-/* Returns: if (a < b) returns 0
-* if (a == b) returns 1
-* if (a > b) returns 2
-*/
+// Returns: if (a < b) returns 0
+// if (a == b) returns 1
+// if (a > b) returns 2
-COMPILER_RT_ABI si_int
-__cmpdi2(di_int a, di_int b)
-{
- dwords x;
- x.all = a;
- dwords y;
- y.all = b;
- if (x.s.high < y.s.high)
- return 0;
- if (x.s.high > y.s.high)
- return 2;
- if (x.s.low < y.s.low)
- return 0;
- if (x.s.low > y.s.low)
- return 2;
- return 1;
+COMPILER_RT_ABI si_int __cmpdi2(di_int a, di_int b) {
+ dwords x;
+ x.all = a;
+ dwords y;
+ y.all = b;
+ if (x.s.high < y.s.high)
+ return 0;
+ if (x.s.high > y.s.high)
+ return 2;
+ if (x.s.low < y.s.low)
+ return 0;
+ if (x.s.low > y.s.low)
+ return 2;
+ return 1;
}
#ifdef __ARM_EABI__
-/* Returns: if (a < b) returns -1
-* if (a == b) returns 0
-* if (a > b) returns 1
-*/
-COMPILER_RT_ABI si_int
-__aeabi_lcmp(di_int a, di_int b)
-{
- return __cmpdi2(a, b) - 1;
+// Returns: if (a < b) returns -1
+// if (a == b) returns 0
+// if (a > b) returns 1
+COMPILER_RT_ABI si_int __aeabi_lcmp(di_int a, di_int b) {
+ return __cmpdi2(a, b) - 1;
}
#endif
-
diff --git a/contrib/libs/cxxsupp/builtins/cmpti2.c b/contrib/libs/cxxsupp/builtins/cmpti2.c
index 2c8b56e29a..7f0ee1b515 100644
--- a/contrib/libs/cxxsupp/builtins/cmpti2.c
+++ b/contrib/libs/cxxsupp/builtins/cmpti2.c
@@ -1,42 +1,37 @@
-/* ===-- cmpti2.c - Implement __cmpti2 -------------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __cmpti2 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- cmpti2.c - Implement __cmpti2 -------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __cmpti2 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
#ifdef CRT_HAS_128BIT
-/* Returns: if (a < b) returns 0
- * if (a == b) returns 1
- * if (a > b) returns 2
- */
+// Returns: if (a < b) returns 0
+// if (a == b) returns 1
+// if (a > b) returns 2
-COMPILER_RT_ABI si_int
-__cmpti2(ti_int a, ti_int b)
-{
- twords x;
- x.all = a;
- twords y;
- y.all = b;
- if (x.s.high < y.s.high)
- return 0;
- if (x.s.high > y.s.high)
- return 2;
- if (x.s.low < y.s.low)
- return 0;
- if (x.s.low > y.s.low)
- return 2;
- return 1;
+COMPILER_RT_ABI si_int __cmpti2(ti_int a, ti_int b) {
+ twords x;
+ x.all = a;
+ twords y;
+ y.all = b;
+ if (x.s.high < y.s.high)
+ return 0;
+ if (x.s.high > y.s.high)
+ return 2;
+ if (x.s.low < y.s.low)
+ return 0;
+ if (x.s.low > y.s.low)
+ return 2;
+ return 1;
}
-#endif /* CRT_HAS_128BIT */
+#endif // CRT_HAS_128BIT
diff --git a/contrib/libs/cxxsupp/builtins/comparedf2.c b/contrib/libs/cxxsupp/builtins/comparedf2.c
index 9e29752231..e1fc12c54d 100644
--- a/contrib/libs/cxxsupp/builtins/comparedf2.c
+++ b/contrib/libs/cxxsupp/builtins/comparedf2.c
@@ -1,9 +1,8 @@
//===-- lib/comparedf2.c - Double-precision comparisons -----------*- C -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -40,107 +39,39 @@
#define DOUBLE_PRECISION
#include "fp_lib.h"
-enum LE_RESULT {
- LE_LESS = -1,
- LE_EQUAL = 0,
- LE_GREATER = 1,
- LE_UNORDERED = 1
-};
+#include "fp_compare_impl.inc"
-COMPILER_RT_ABI enum LE_RESULT
-__ledf2(fp_t a, fp_t b) {
-
- const srep_t aInt = toRep(a);
- const srep_t bInt = toRep(b);
- const rep_t aAbs = aInt & absMask;
- const rep_t bAbs = bInt & absMask;
-
- // If either a or b is NaN, they are unordered.
- if (aAbs > infRep || bAbs > infRep) return LE_UNORDERED;
-
- // If a and b are both zeros, they are equal.
- if ((aAbs | bAbs) == 0) return LE_EQUAL;
-
- // If at least one of a and b is positive, we get the same result comparing
- // a and b as signed integers as we would with a floating-point compare.
- if ((aInt & bInt) >= 0) {
- if (aInt < bInt) return LE_LESS;
- else if (aInt == bInt) return LE_EQUAL;
- else return LE_GREATER;
- }
-
- // Otherwise, both are negative, so we need to flip the sense of the
- // comparison to get the correct result. (This assumes a twos- or ones-
- // complement integer representation; if integers are represented in a
- // sign-magnitude representation, then this flip is incorrect).
- else {
- if (aInt > bInt) return LE_LESS;
- else if (aInt == bInt) return LE_EQUAL;
- else return LE_GREATER;
- }
-}
+COMPILER_RT_ABI CMP_RESULT __ledf2(fp_t a, fp_t b) { return __leXf2__(a, b); }
#if defined(__ELF__)
// Alias for libgcc compatibility
-FNALIAS(__cmpdf2, __ledf2);
+COMPILER_RT_ALIAS(__ledf2, __cmpdf2)
#endif
+COMPILER_RT_ALIAS(__ledf2, __eqdf2)
+COMPILER_RT_ALIAS(__ledf2, __ltdf2)
+COMPILER_RT_ALIAS(__ledf2, __nedf2)
-enum GE_RESULT {
- GE_LESS = -1,
- GE_EQUAL = 0,
- GE_GREATER = 1,
- GE_UNORDERED = -1 // Note: different from LE_UNORDERED
-};
-
-COMPILER_RT_ABI enum GE_RESULT
-__gedf2(fp_t a, fp_t b) {
-
- const srep_t aInt = toRep(a);
- const srep_t bInt = toRep(b);
- const rep_t aAbs = aInt & absMask;
- const rep_t bAbs = bInt & absMask;
-
- if (aAbs > infRep || bAbs > infRep) return GE_UNORDERED;
- if ((aAbs | bAbs) == 0) return GE_EQUAL;
- if ((aInt & bInt) >= 0) {
- if (aInt < bInt) return GE_LESS;
- else if (aInt == bInt) return GE_EQUAL;
- else return GE_GREATER;
- } else {
- if (aInt > bInt) return GE_LESS;
- else if (aInt == bInt) return GE_EQUAL;
- else return GE_GREATER;
- }
-}
-
-ARM_EABI_FNALIAS(dcmpun, unorddf2)
-
-COMPILER_RT_ABI int
-__unorddf2(fp_t a, fp_t b) {
- const rep_t aAbs = toRep(a) & absMask;
- const rep_t bAbs = toRep(b) & absMask;
- return aAbs > infRep || bAbs > infRep;
-}
+COMPILER_RT_ABI CMP_RESULT __gedf2(fp_t a, fp_t b) { return __geXf2__(a, b); }
-// The following are alternative names for the preceding routines.
+COMPILER_RT_ALIAS(__gedf2, __gtdf2)
-COMPILER_RT_ABI enum LE_RESULT
-__eqdf2(fp_t a, fp_t b) {
- return __ledf2(a, b);
+COMPILER_RT_ABI CMP_RESULT __unorddf2(fp_t a, fp_t b) {
+ return __unordXf2__(a, b);
}
-COMPILER_RT_ABI enum LE_RESULT
-__ltdf2(fp_t a, fp_t b) {
- return __ledf2(a, b);
-}
-
-COMPILER_RT_ABI enum LE_RESULT
-__nedf2(fp_t a, fp_t b) {
- return __ledf2(a, b);
-}
-
-COMPILER_RT_ABI enum GE_RESULT
-__gtdf2(fp_t a, fp_t b) {
- return __gedf2(a, b);
-}
+#if defined(__ARM_EABI__)
+#if defined(COMPILER_RT_ARMHF_TARGET)
+AEABI_RTABI int __aeabi_dcmpun(fp_t a, fp_t b) { return __unorddf2(a, b); }
+#else
+COMPILER_RT_ALIAS(__unorddf2, __aeabi_dcmpun)
+#endif
+#endif
+#if defined(_WIN32) && !defined(__MINGW32__)
+// The alias mechanism doesn't work on Windows except for MinGW, so emit
+// wrapper functions.
+int __eqdf2(fp_t a, fp_t b) { return __ledf2(a, b); }
+int __ltdf2(fp_t a, fp_t b) { return __ledf2(a, b); }
+int __nedf2(fp_t a, fp_t b) { return __ledf2(a, b); }
+int __gtdf2(fp_t a, fp_t b) { return __gedf2(a, b); }
+#endif
diff --git a/contrib/libs/cxxsupp/builtins/comparesf2.c b/contrib/libs/cxxsupp/builtins/comparesf2.c
index 1fd50636ab..b8a955448f 100644
--- a/contrib/libs/cxxsupp/builtins/comparesf2.c
+++ b/contrib/libs/cxxsupp/builtins/comparesf2.c
@@ -1,9 +1,8 @@
//===-- lib/comparesf2.c - Single-precision comparisons -----------*- C -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -40,106 +39,39 @@
#define SINGLE_PRECISION
#include "fp_lib.h"
-enum LE_RESULT {
- LE_LESS = -1,
- LE_EQUAL = 0,
- LE_GREATER = 1,
- LE_UNORDERED = 1
-};
+#include "fp_compare_impl.inc"
-COMPILER_RT_ABI enum LE_RESULT
-__lesf2(fp_t a, fp_t b) {
-
- const srep_t aInt = toRep(a);
- const srep_t bInt = toRep(b);
- const rep_t aAbs = aInt & absMask;
- const rep_t bAbs = bInt & absMask;
-
- // If either a or b is NaN, they are unordered.
- if (aAbs > infRep || bAbs > infRep) return LE_UNORDERED;
-
- // If a and b are both zeros, they are equal.
- if ((aAbs | bAbs) == 0) return LE_EQUAL;
-
- // If at least one of a and b is positive, we get the same result comparing
- // a and b as signed integers as we would with a fp_ting-point compare.
- if ((aInt & bInt) >= 0) {
- if (aInt < bInt) return LE_LESS;
- else if (aInt == bInt) return LE_EQUAL;
- else return LE_GREATER;
- }
-
- // Otherwise, both are negative, so we need to flip the sense of the
- // comparison to get the correct result. (This assumes a twos- or ones-
- // complement integer representation; if integers are represented in a
- // sign-magnitude representation, then this flip is incorrect).
- else {
- if (aInt > bInt) return LE_LESS;
- else if (aInt == bInt) return LE_EQUAL;
- else return LE_GREATER;
- }
-}
+COMPILER_RT_ABI CMP_RESULT __lesf2(fp_t a, fp_t b) { return __leXf2__(a, b); }
#if defined(__ELF__)
// Alias for libgcc compatibility
-FNALIAS(__cmpsf2, __lesf2);
+COMPILER_RT_ALIAS(__lesf2, __cmpsf2)
#endif
+COMPILER_RT_ALIAS(__lesf2, __eqsf2)
+COMPILER_RT_ALIAS(__lesf2, __ltsf2)
+COMPILER_RT_ALIAS(__lesf2, __nesf2)
-enum GE_RESULT {
- GE_LESS = -1,
- GE_EQUAL = 0,
- GE_GREATER = 1,
- GE_UNORDERED = -1 // Note: different from LE_UNORDERED
-};
-
-COMPILER_RT_ABI enum GE_RESULT
-__gesf2(fp_t a, fp_t b) {
-
- const srep_t aInt = toRep(a);
- const srep_t bInt = toRep(b);
- const rep_t aAbs = aInt & absMask;
- const rep_t bAbs = bInt & absMask;
-
- if (aAbs > infRep || bAbs > infRep) return GE_UNORDERED;
- if ((aAbs | bAbs) == 0) return GE_EQUAL;
- if ((aInt & bInt) >= 0) {
- if (aInt < bInt) return GE_LESS;
- else if (aInt == bInt) return GE_EQUAL;
- else return GE_GREATER;
- } else {
- if (aInt > bInt) return GE_LESS;
- else if (aInt == bInt) return GE_EQUAL;
- else return GE_GREATER;
- }
-}
-
-ARM_EABI_FNALIAS(fcmpun, unordsf2)
-
-COMPILER_RT_ABI int
-__unordsf2(fp_t a, fp_t b) {
- const rep_t aAbs = toRep(a) & absMask;
- const rep_t bAbs = toRep(b) & absMask;
- return aAbs > infRep || bAbs > infRep;
-}
-
-// The following are alternative names for the preceding routines.
+COMPILER_RT_ABI CMP_RESULT __gesf2(fp_t a, fp_t b) { return __geXf2__(a, b); }
-COMPILER_RT_ABI enum LE_RESULT
-__eqsf2(fp_t a, fp_t b) {
- return __lesf2(a, b);
-}
+COMPILER_RT_ALIAS(__gesf2, __gtsf2)
-COMPILER_RT_ABI enum LE_RESULT
-__ltsf2(fp_t a, fp_t b) {
- return __lesf2(a, b);
+COMPILER_RT_ABI CMP_RESULT __unordsf2(fp_t a, fp_t b) {
+ return __unordXf2__(a, b);
}
-COMPILER_RT_ABI enum LE_RESULT
-__nesf2(fp_t a, fp_t b) {
- return __lesf2(a, b);
-}
+#if defined(__ARM_EABI__)
+#if defined(COMPILER_RT_ARMHF_TARGET)
+AEABI_RTABI int __aeabi_fcmpun(fp_t a, fp_t b) { return __unordsf2(a, b); }
+#else
+COMPILER_RT_ALIAS(__unordsf2, __aeabi_fcmpun)
+#endif
+#endif
-COMPILER_RT_ABI enum GE_RESULT
-__gtsf2(fp_t a, fp_t b) {
- return __gesf2(a, b);
-}
+#if defined(_WIN32) && !defined(__MINGW32__)
+// The alias mechanism doesn't work on Windows except for MinGW, so emit
+// wrapper functions.
+int __eqsf2(fp_t a, fp_t b) { return __lesf2(a, b); }
+int __ltsf2(fp_t a, fp_t b) { return __lesf2(a, b); }
+int __nesf2(fp_t a, fp_t b) { return __lesf2(a, b); }
+int __gtsf2(fp_t a, fp_t b) { return __gesf2(a, b); }
+#endif
diff --git a/contrib/libs/cxxsupp/builtins/comparetf2.c b/contrib/libs/cxxsupp/builtins/comparetf2.c
index c0ad8ed0ae..f159245413 100644
--- a/contrib/libs/cxxsupp/builtins/comparetf2.c
+++ b/contrib/libs/cxxsupp/builtins/comparetf2.c
@@ -1,9 +1,8 @@
//===-- lib/comparetf2.c - Quad-precision comparisons -------------*- C -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -41,98 +40,24 @@
#include "fp_lib.h"
#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT)
-enum LE_RESULT {
- LE_LESS = -1,
- LE_EQUAL = 0,
- LE_GREATER = 1,
- LE_UNORDERED = 1
-};
-
-COMPILER_RT_ABI enum LE_RESULT __letf2(fp_t a, fp_t b) {
-
- const srep_t aInt = toRep(a);
- const srep_t bInt = toRep(b);
- const rep_t aAbs = aInt & absMask;
- const rep_t bAbs = bInt & absMask;
+#include "fp_compare_impl.inc"
- // If either a or b is NaN, they are unordered.
- if (aAbs > infRep || bAbs > infRep) return LE_UNORDERED;
-
- // If a and b are both zeros, they are equal.
- if ((aAbs | bAbs) == 0) return LE_EQUAL;
-
- // If at least one of a and b is positive, we get the same result comparing
- // a and b as signed integers as we would with a floating-point compare.
- if ((aInt & bInt) >= 0) {
- if (aInt < bInt) return LE_LESS;
- else if (aInt == bInt) return LE_EQUAL;
- else return LE_GREATER;
- }
- else {
- // Otherwise, both are negative, so we need to flip the sense of the
- // comparison to get the correct result. (This assumes a twos- or ones-
- // complement integer representation; if integers are represented in a
- // sign-magnitude representation, then this flip is incorrect).
- if (aInt > bInt) return LE_LESS;
- else if (aInt == bInt) return LE_EQUAL;
- else return LE_GREATER;
- }
-}
+COMPILER_RT_ABI CMP_RESULT __letf2(fp_t a, fp_t b) { return __leXf2__(a, b); }
#if defined(__ELF__)
// Alias for libgcc compatibility
-FNALIAS(__cmptf2, __letf2);
+COMPILER_RT_ALIAS(__letf2, __cmptf2)
#endif
+COMPILER_RT_ALIAS(__letf2, __eqtf2)
+COMPILER_RT_ALIAS(__letf2, __lttf2)
+COMPILER_RT_ALIAS(__letf2, __netf2)
-enum GE_RESULT {
- GE_LESS = -1,
- GE_EQUAL = 0,
- GE_GREATER = 1,
- GE_UNORDERED = -1 // Note: different from LE_UNORDERED
-};
-
-COMPILER_RT_ABI enum GE_RESULT __getf2(fp_t a, fp_t b) {
-
- const srep_t aInt = toRep(a);
- const srep_t bInt = toRep(b);
- const rep_t aAbs = aInt & absMask;
- const rep_t bAbs = bInt & absMask;
-
- if (aAbs > infRep || bAbs > infRep) return GE_UNORDERED;
- if ((aAbs | bAbs) == 0) return GE_EQUAL;
- if ((aInt & bInt) >= 0) {
- if (aInt < bInt) return GE_LESS;
- else if (aInt == bInt) return GE_EQUAL;
- else return GE_GREATER;
- } else {
- if (aInt > bInt) return GE_LESS;
- else if (aInt == bInt) return GE_EQUAL;
- else return GE_GREATER;
- }
-}
-
-COMPILER_RT_ABI int __unordtf2(fp_t a, fp_t b) {
- const rep_t aAbs = toRep(a) & absMask;
- const rep_t bAbs = toRep(b) & absMask;
- return aAbs > infRep || bAbs > infRep;
-}
+COMPILER_RT_ABI CMP_RESULT __getf2(fp_t a, fp_t b) { return __geXf2__(a, b); }
-// The following are alternative names for the preceding routines.
-
-COMPILER_RT_ABI enum LE_RESULT __eqtf2(fp_t a, fp_t b) {
- return __letf2(a, b);
-}
-
-COMPILER_RT_ABI enum LE_RESULT __lttf2(fp_t a, fp_t b) {
- return __letf2(a, b);
-}
-
-COMPILER_RT_ABI enum LE_RESULT __netf2(fp_t a, fp_t b) {
- return __letf2(a, b);
-}
+COMPILER_RT_ALIAS(__getf2, __gttf2)
-COMPILER_RT_ABI enum GE_RESULT __gttf2(fp_t a, fp_t b) {
- return __getf2(a, b);
+COMPILER_RT_ABI CMP_RESULT __unordtf2(fp_t a, fp_t b) {
+ return __unordXf2__(a, b);
}
#endif
diff --git a/contrib/libs/cxxsupp/builtins/cpu_model.c b/contrib/libs/cxxsupp/builtins/cpu_model.c
new file mode 100644
index 0000000000..bc853f207c
--- /dev/null
+++ b/contrib/libs/cxxsupp/builtins/cpu_model.c
@@ -0,0 +1,1357 @@
+//===-- cpu_model.c - Support for __cpu_model builtin ------------*- C -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is based on LLVM's lib/Support/Host.cpp.
+// It implements the operating system Host concept and builtin
+// __cpu_model for the compiler_rt library for x86 and
+// __aarch64_have_lse_atomics, __aarch64_cpu_features for AArch64.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __has_attribute
+#define __has_attribute(attr) 0
+#endif
+
+#if __has_attribute(constructor)
+#if __GNUC__ >= 9
+// Ordinarily init priorities below 101 are disallowed as they are reserved for the
+// implementation. However, we are the implementation, so silence the diagnostic,
+// since it doesn't apply to us.
+#pragma GCC diagnostic ignored "-Wprio-ctor-dtor"
+#endif
+// We're choosing init priority 90 to force our constructors to run before any
+// constructors in the end user application (starting at priority 101). This value
+// matches the libgcc choice for the same functions.
+#define CONSTRUCTOR_ATTRIBUTE __attribute__((constructor(90)))
+#else
+// FIXME: For MSVC, we should make a function pointer global in .CRT$X?? so that
+// this runs during initialization.
+#define CONSTRUCTOR_ATTRIBUTE
+#endif
+
+#if (defined(__i386__) || defined(_M_IX86) || defined(__x86_64__) || \
+ defined(_M_X64)) && \
+ (defined(__GNUC__) || defined(__clang__) || defined(_MSC_VER))
+
+#include <assert.h>
+
+#define bool int
+#define true 1
+#define false 0
+
+#ifdef _MSC_VER
+#include <intrin.h>
+#endif
+
+enum VendorSignatures {
+ SIG_INTEL = 0x756e6547, // Genu
+ SIG_AMD = 0x68747541, // Auth
+};
+
+enum ProcessorVendors {
+ VENDOR_INTEL = 1,
+ VENDOR_AMD,
+ VENDOR_OTHER,
+ VENDOR_MAX
+};
+
+enum ProcessorTypes {
+ INTEL_BONNELL = 1,
+ INTEL_CORE2,
+ INTEL_COREI7,
+ AMDFAM10H,
+ AMDFAM15H,
+ INTEL_SILVERMONT,
+ INTEL_KNL,
+ AMD_BTVER1,
+ AMD_BTVER2,
+ AMDFAM17H,
+ INTEL_KNM,
+ INTEL_GOLDMONT,
+ INTEL_GOLDMONT_PLUS,
+ INTEL_TREMONT,
+ AMDFAM19H,
+ ZHAOXIN_FAM7H,
+ INTEL_SIERRAFOREST,
+ INTEL_GRANDRIDGE,
+ CPU_TYPE_MAX
+};
+
+enum ProcessorSubtypes {
+ INTEL_COREI7_NEHALEM = 1,
+ INTEL_COREI7_WESTMERE,
+ INTEL_COREI7_SANDYBRIDGE,
+ AMDFAM10H_BARCELONA,
+ AMDFAM10H_SHANGHAI,
+ AMDFAM10H_ISTANBUL,
+ AMDFAM15H_BDVER1,
+ AMDFAM15H_BDVER2,
+ AMDFAM15H_BDVER3,
+ AMDFAM15H_BDVER4,
+ AMDFAM17H_ZNVER1,
+ INTEL_COREI7_IVYBRIDGE,
+ INTEL_COREI7_HASWELL,
+ INTEL_COREI7_BROADWELL,
+ INTEL_COREI7_SKYLAKE,
+ INTEL_COREI7_SKYLAKE_AVX512,
+ INTEL_COREI7_CANNONLAKE,
+ INTEL_COREI7_ICELAKE_CLIENT,
+ INTEL_COREI7_ICELAKE_SERVER,
+ AMDFAM17H_ZNVER2,
+ INTEL_COREI7_CASCADELAKE,
+ INTEL_COREI7_TIGERLAKE,
+ INTEL_COREI7_COOPERLAKE,
+ INTEL_COREI7_SAPPHIRERAPIDS,
+ INTEL_COREI7_ALDERLAKE,
+ AMDFAM19H_ZNVER3,
+ INTEL_COREI7_ROCKETLAKE,
+ ZHAOXIN_FAM7H_LUJIAZUI,
+ AMDFAM19H_ZNVER4,
+ INTEL_COREI7_GRANITERAPIDS,
+ CPU_SUBTYPE_MAX
+};
+
+enum ProcessorFeatures {
+ FEATURE_CMOV = 0,
+ FEATURE_MMX,
+ FEATURE_POPCNT,
+ FEATURE_SSE,
+ FEATURE_SSE2,
+ FEATURE_SSE3,
+ FEATURE_SSSE3,
+ FEATURE_SSE4_1,
+ FEATURE_SSE4_2,
+ FEATURE_AVX,
+ FEATURE_AVX2,
+ FEATURE_SSE4_A,
+ FEATURE_FMA4,
+ FEATURE_XOP,
+ FEATURE_FMA,
+ FEATURE_AVX512F,
+ FEATURE_BMI,
+ FEATURE_BMI2,
+ FEATURE_AES,
+ FEATURE_PCLMUL,
+ FEATURE_AVX512VL,
+ FEATURE_AVX512BW,
+ FEATURE_AVX512DQ,
+ FEATURE_AVX512CD,
+ FEATURE_AVX512ER,
+ FEATURE_AVX512PF,
+ FEATURE_AVX512VBMI,
+ FEATURE_AVX512IFMA,
+ FEATURE_AVX5124VNNIW,
+ FEATURE_AVX5124FMAPS,
+ FEATURE_AVX512VPOPCNTDQ,
+ FEATURE_AVX512VBMI2,
+ FEATURE_GFNI,
+ FEATURE_VPCLMULQDQ,
+ FEATURE_AVX512VNNI,
+ FEATURE_AVX512BITALG,
+ FEATURE_AVX512BF16,
+ FEATURE_AVX512VP2INTERSECT,
+ CPU_FEATURE_MAX
+};
+
+// The check below for i386 was copied from clang's cpuid.h (__get_cpuid_max).
+// Check motivated by bug reports for OpenSSL crashing on CPUs without CPUID
+// support. Consequently, for i386, the presence of CPUID is checked first
+// via the corresponding eflags bit.
+static bool isCpuIdSupported(void) {
+#if defined(__GNUC__) || defined(__clang__)
+#if defined(__i386__)
+ int __cpuid_supported;
+ __asm__(" pushfl\n"
+ " popl %%eax\n"
+ " movl %%eax,%%ecx\n"
+ " xorl $0x00200000,%%eax\n"
+ " pushl %%eax\n"
+ " popfl\n"
+ " pushfl\n"
+ " popl %%eax\n"
+ " movl $0,%0\n"
+ " cmpl %%eax,%%ecx\n"
+ " je 1f\n"
+ " movl $1,%0\n"
+ "1:"
+ : "=r"(__cpuid_supported)
+ :
+ : "eax", "ecx");
+ if (!__cpuid_supported)
+ return false;
+#endif
+ return true;
+#endif
+ return true;
+}
+
+// This code is copied from lib/Support/Host.cpp.
+// Changes to either file should be mirrored in the other.
+
+/// getX86CpuIDAndInfo - Execute the specified cpuid and return the 4 values in
+/// the specified arguments. If we can't run cpuid on the host, return true.
+static bool getX86CpuIDAndInfo(unsigned value, unsigned *rEAX, unsigned *rEBX,
+ unsigned *rECX, unsigned *rEDX) {
+#if defined(__GNUC__) || defined(__clang__)
+#if defined(__x86_64__)
+ // gcc doesn't know cpuid would clobber ebx/rbx. Preserve it manually.
+ // FIXME: should we save this for Clang?
+ __asm__("movq\t%%rbx, %%rsi\n\t"
+ "cpuid\n\t"
+ "xchgq\t%%rbx, %%rsi\n\t"
+ : "=a"(*rEAX), "=S"(*rEBX), "=c"(*rECX), "=d"(*rEDX)
+ : "a"(value));
+ return false;
+#elif defined(__i386__)
+ __asm__("movl\t%%ebx, %%esi\n\t"
+ "cpuid\n\t"
+ "xchgl\t%%ebx, %%esi\n\t"
+ : "=a"(*rEAX), "=S"(*rEBX), "=c"(*rECX), "=d"(*rEDX)
+ : "a"(value));
+ return false;
+#else
+ return true;
+#endif
+#elif defined(_MSC_VER)
+ // The MSVC intrinsic is portable across x86 and x64.
+ int registers[4];
+ __cpuid(registers, value);
+ *rEAX = registers[0];
+ *rEBX = registers[1];
+ *rECX = registers[2];
+ *rEDX = registers[3];
+ return false;
+#else
+ return true;
+#endif
+}
+
+/// getX86CpuIDAndInfoEx - Execute the specified cpuid with subleaf and return
+/// the 4 values in the specified arguments. If we can't run cpuid on the host,
+/// return true.
+static bool getX86CpuIDAndInfoEx(unsigned value, unsigned subleaf,
+ unsigned *rEAX, unsigned *rEBX, unsigned *rECX,
+ unsigned *rEDX) {
+#if defined(__GNUC__) || defined(__clang__)
+#if defined(__x86_64__)
+ // gcc doesn't know cpuid would clobber ebx/rbx. Preserve it manually.
+ // FIXME: should we save this for Clang?
+ __asm__("movq\t%%rbx, %%rsi\n\t"
+ "cpuid\n\t"
+ "xchgq\t%%rbx, %%rsi\n\t"
+ : "=a"(*rEAX), "=S"(*rEBX), "=c"(*rECX), "=d"(*rEDX)
+ : "a"(value), "c"(subleaf));
+ return false;
+#elif defined(__i386__)
+ __asm__("movl\t%%ebx, %%esi\n\t"
+ "cpuid\n\t"
+ "xchgl\t%%ebx, %%esi\n\t"
+ : "=a"(*rEAX), "=S"(*rEBX), "=c"(*rECX), "=d"(*rEDX)
+ : "a"(value), "c"(subleaf));
+ return false;
+#else
+ return true;
+#endif
+#elif defined(_MSC_VER)
+ int registers[4];
+ __cpuidex(registers, value, subleaf);
+ *rEAX = registers[0];
+ *rEBX = registers[1];
+ *rECX = registers[2];
+ *rEDX = registers[3];
+ return false;
+#else
+ return true;
+#endif
+}
+
+// Read control register 0 (XCR0). Used to detect features such as AVX.
+static bool getX86XCR0(unsigned *rEAX, unsigned *rEDX) {
+#if defined(__GNUC__) || defined(__clang__)
+ // Check xgetbv; this uses a .byte sequence instead of the instruction
+ // directly because older assemblers do not include support for xgetbv and
+ // there is no easy way to conditionally compile based on the assembler used.
+ __asm__(".byte 0x0f, 0x01, 0xd0" : "=a"(*rEAX), "=d"(*rEDX) : "c"(0));
+ return false;
+#elif defined(_MSC_FULL_VER) && defined(_XCR_XFEATURE_ENABLED_MASK)
+ unsigned long long Result = _xgetbv(_XCR_XFEATURE_ENABLED_MASK);
+ *rEAX = Result;
+ *rEDX = Result >> 32;
+ return false;
+#else
+ return true;
+#endif
+}
+
+static void detectX86FamilyModel(unsigned EAX, unsigned *Family,
+ unsigned *Model) {
+ *Family = (EAX >> 8) & 0xf; // Bits 8 - 11
+ *Model = (EAX >> 4) & 0xf; // Bits 4 - 7
+ if (*Family == 6 || *Family == 0xf) {
+ if (*Family == 0xf)
+ // Examine extended family ID if family ID is F.
+ *Family += (EAX >> 20) & 0xff; // Bits 20 - 27
+ // Examine extended model ID if family ID is 6 or F.
+ *Model += ((EAX >> 16) & 0xf) << 4; // Bits 16 - 19
+ }
+}
+
+static const char *
+getIntelProcessorTypeAndSubtype(unsigned Family, unsigned Model,
+ const unsigned *Features,
+ unsigned *Type, unsigned *Subtype) {
+#define testFeature(F) \
+ (Features[F / 32] & (1 << (F % 32))) != 0
+
+ // We select CPU strings to match the code in Host.cpp, but we don't use them
+ // in compiler-rt.
+ const char *CPU = 0;
+
+ switch (Family) {
+ case 6:
+ switch (Model) {
+ case 0x0f: // Intel Core 2 Duo processor, Intel Core 2 Duo mobile
+ // processor, Intel Core 2 Quad processor, Intel Core 2 Quad
+ // mobile processor, Intel Core 2 Extreme processor, Intel
+ // Pentium Dual-Core processor, Intel Xeon processor, model
+ // 0Fh. All processors are manufactured using the 65 nm process.
+ case 0x16: // Intel Celeron processor model 16h. All processors are
+ // manufactured using the 65 nm process
+ CPU = "core2";
+ *Type = INTEL_CORE2;
+ break;
+ case 0x17: // Intel Core 2 Extreme processor, Intel Xeon processor, model
+ // 17h. All processors are manufactured using the 45 nm process.
+ //
+ // 45nm: Penryn , Wolfdale, Yorkfield (XE)
+ case 0x1d: // Intel Xeon processor MP. All processors are manufactured using
+ // the 45 nm process.
+ CPU = "penryn";
+ *Type = INTEL_CORE2;
+ break;
+ case 0x1a: // Intel Core i7 processor and Intel Xeon processor. All
+ // processors are manufactured using the 45 nm process.
+ case 0x1e: // Intel(R) Core(TM) i7 CPU 870 @ 2.93GHz.
+ // As found in a Summer 2010 model iMac.
+ case 0x1f:
+ case 0x2e: // Nehalem EX
+ CPU = "nehalem";
+ *Type = INTEL_COREI7;
+ *Subtype = INTEL_COREI7_NEHALEM;
+ break;
+ case 0x25: // Intel Core i7, laptop version.
+ case 0x2c: // Intel Core i7 processor and Intel Xeon processor. All
+ // processors are manufactured using the 32 nm process.
+ case 0x2f: // Westmere EX
+ CPU = "westmere";
+ *Type = INTEL_COREI7;
+ *Subtype = INTEL_COREI7_WESTMERE;
+ break;
+ case 0x2a: // Intel Core i7 processor. All processors are manufactured
+ // using the 32 nm process.
+ case 0x2d:
+ CPU = "sandybridge";
+ *Type = INTEL_COREI7;
+ *Subtype = INTEL_COREI7_SANDYBRIDGE;
+ break;
+ case 0x3a:
+ case 0x3e: // Ivy Bridge EP
+ CPU = "ivybridge";
+ *Type = INTEL_COREI7;
+ *Subtype = INTEL_COREI7_IVYBRIDGE;
+ break;
+
+ // Haswell:
+ case 0x3c:
+ case 0x3f:
+ case 0x45:
+ case 0x46:
+ CPU = "haswell";
+ *Type = INTEL_COREI7;
+ *Subtype = INTEL_COREI7_HASWELL;
+ break;
+
+ // Broadwell:
+ case 0x3d:
+ case 0x47:
+ case 0x4f:
+ case 0x56:
+ CPU = "broadwell";
+ *Type = INTEL_COREI7;
+ *Subtype = INTEL_COREI7_BROADWELL;
+ break;
+
+ // Skylake:
+ case 0x4e: // Skylake mobile
+ case 0x5e: // Skylake desktop
+ case 0x8e: // Kaby Lake mobile
+ case 0x9e: // Kaby Lake desktop
+ case 0xa5: // Comet Lake-H/S
+ case 0xa6: // Comet Lake-U
+ CPU = "skylake";
+ *Type = INTEL_COREI7;
+ *Subtype = INTEL_COREI7_SKYLAKE;
+ break;
+
+ // Rocketlake:
+ case 0xa7:
+ CPU = "rocketlake";
+ *Type = INTEL_COREI7;
+ *Subtype = INTEL_COREI7_ROCKETLAKE;
+ break;
+
+ // Skylake Xeon:
+ case 0x55:
+ *Type = INTEL_COREI7;
+ if (testFeature(FEATURE_AVX512BF16)) {
+ CPU = "cooperlake";
+ *Subtype = INTEL_COREI7_COOPERLAKE;
+ } else if (testFeature(FEATURE_AVX512VNNI)) {
+ CPU = "cascadelake";
+ *Subtype = INTEL_COREI7_CASCADELAKE;
+ } else {
+ CPU = "skylake-avx512";
+ *Subtype = INTEL_COREI7_SKYLAKE_AVX512;
+ }
+ break;
+
+ // Cannonlake:
+ case 0x66:
+ CPU = "cannonlake";
+ *Type = INTEL_COREI7;
+ *Subtype = INTEL_COREI7_CANNONLAKE;
+ break;
+
+ // Icelake:
+ case 0x7d:
+ case 0x7e:
+ CPU = "icelake-client";
+ *Type = INTEL_COREI7;
+ *Subtype = INTEL_COREI7_ICELAKE_CLIENT;
+ break;
+
+ // Tigerlake:
+ case 0x8c:
+ case 0x8d:
+ CPU = "tigerlake";
+ *Type = INTEL_COREI7;
+ *Subtype = INTEL_COREI7_TIGERLAKE;
+ break;
+
+ // Alderlake:
+ case 0x97:
+ case 0x9a:
+ // Raptorlake:
+ case 0xb7:
+ // Meteorlake:
+ case 0xaa:
+ case 0xac:
+ CPU = "alderlake";
+ *Type = INTEL_COREI7;
+ *Subtype = INTEL_COREI7_ALDERLAKE;
+ break;
+
+ // Icelake Xeon:
+ case 0x6a:
+ case 0x6c:
+ CPU = "icelake-server";
+ *Type = INTEL_COREI7;
+ *Subtype = INTEL_COREI7_ICELAKE_SERVER;
+ break;
+
+ // Emerald Rapids:
+ case 0xcf:
+ // Sapphire Rapids:
+ case 0x8f:
+ CPU = "sapphirerapids";
+ *Type = INTEL_COREI7;
+ *Subtype = INTEL_COREI7_SAPPHIRERAPIDS;
+ break;
+
+ // Granite Rapids:
+ case 0xae:
+ case 0xad:
+ CPU = "graniterapids";
+ *Type = INTEL_COREI7;
+ *Subtype = INTEL_COREI7_GRANITERAPIDS;
+ break;
+
+ case 0x1c: // Most 45 nm Intel Atom processors
+ case 0x26: // 45 nm Atom Lincroft
+ case 0x27: // 32 nm Atom Medfield
+ case 0x35: // 32 nm Atom Midview
+ case 0x36: // 32 nm Atom Midview
+ CPU = "bonnell";
+ *Type = INTEL_BONNELL;
+ break;
+
+ // Atom Silvermont codes from the Intel software optimization guide.
+ case 0x37:
+ case 0x4a:
+ case 0x4d:
+ case 0x5a:
+ case 0x5d:
+ case 0x4c: // really airmont
+ CPU = "silvermont";
+ *Type = INTEL_SILVERMONT;
+ break;
+ // Goldmont:
+ case 0x5c: // Apollo Lake
+ case 0x5f: // Denverton
+ CPU = "goldmont";
+ *Type = INTEL_GOLDMONT;
+ break; // "goldmont"
+ case 0x7a:
+ CPU = "goldmont-plus";
+ *Type = INTEL_GOLDMONT_PLUS;
+ break;
+ case 0x86:
+ CPU = "tremont";
+ *Type = INTEL_TREMONT;
+ break;
+
+ // Sierraforest:
+ case 0xaf:
+ CPU = "sierraforest";
+ *Type = INTEL_SIERRAFOREST;
+ break;
+
+ // Grandridge:
+ case 0xb6:
+ CPU = "grandridge";
+ *Type = INTEL_GRANDRIDGE;
+ break;
+
+ case 0x57:
+ CPU = "knl";
+ *Type = INTEL_KNL;
+ break;
+
+ case 0x85:
+ CPU = "knm";
+ *Type = INTEL_KNM;
+ break;
+
+ default: // Unknown family 6 CPU.
+ break;
+ }
+ break;
+ default:
+ break; // Unknown.
+ }
+
+ return CPU;
+}
+
+static const char *
+getAMDProcessorTypeAndSubtype(unsigned Family, unsigned Model,
+ const unsigned *Features,
+ unsigned *Type, unsigned *Subtype) {
+ // We select CPU strings to match the code in Host.cpp, but we don't use them
+ // in compiler-rt.
+ const char *CPU = 0;
+
+ switch (Family) {
+ case 16:
+ CPU = "amdfam10";
+ *Type = AMDFAM10H;
+ switch (Model) {
+ case 2:
+ *Subtype = AMDFAM10H_BARCELONA;
+ break;
+ case 4:
+ *Subtype = AMDFAM10H_SHANGHAI;
+ break;
+ case 8:
+ *Subtype = AMDFAM10H_ISTANBUL;
+ break;
+ }
+ break;
+ case 20:
+ CPU = "btver1";
+ *Type = AMD_BTVER1;
+ break;
+ case 21:
+ CPU = "bdver1";
+ *Type = AMDFAM15H;
+ if (Model >= 0x60 && Model <= 0x7f) {
+ CPU = "bdver4";
+ *Subtype = AMDFAM15H_BDVER4;
+ break; // 60h-7Fh: Excavator
+ }
+ if (Model >= 0x30 && Model <= 0x3f) {
+ CPU = "bdver3";
+ *Subtype = AMDFAM15H_BDVER3;
+ break; // 30h-3Fh: Steamroller
+ }
+ if ((Model >= 0x10 && Model <= 0x1f) || Model == 0x02) {
+ CPU = "bdver2";
+ *Subtype = AMDFAM15H_BDVER2;
+ break; // 02h, 10h-1Fh: Piledriver
+ }
+ if (Model <= 0x0f) {
+ *Subtype = AMDFAM15H_BDVER1;
+ break; // 00h-0Fh: Bulldozer
+ }
+ break;
+ case 22:
+ CPU = "btver2";
+ *Type = AMD_BTVER2;
+ break;
+ case 23:
+ CPU = "znver1";
+ *Type = AMDFAM17H;
+ if ((Model >= 0x30 && Model <= 0x3f) || Model == 0x71) {
+ CPU = "znver2";
+ *Subtype = AMDFAM17H_ZNVER2;
+ break; // 30h-3fh, 71h: Zen2
+ }
+ if (Model <= 0x0f) {
+ *Subtype = AMDFAM17H_ZNVER1;
+ break; // 00h-0Fh: Zen1
+ }
+ break;
+ case 25:
+ CPU = "znver3";
+ *Type = AMDFAM19H;
+ if (Model <= 0x0f || (Model >= 0x20 && Model <= 0x5f)) {
+ // Family 19h Models 00h-0Fh - Zen3
+ // Family 19h Models 20h-2Fh - Zen3
+ // Family 19h Models 30h-3Fh - Zen3
+ // Family 19h Models 40h-4Fh - Zen3+
+ // Family 19h Models 50h-5Fh - Zen3+
+ *Subtype = AMDFAM19H_ZNVER3;
+ break;
+ }
+ if ((Model >= 0x10 && Model <= 0x1f) ||
+ (Model >= 0x60 && Model <= 0x74) ||
+ (Model >= 0x78 && Model <= 0x7b) ||
+ (Model >= 0xA0 && Model <= 0xAf)) {
+ CPU = "znver4";
+ *Subtype = AMDFAM19H_ZNVER4;
+ break; // "znver4"
+ }
+ break;
+ default:
+ break; // Unknown AMD CPU.
+ }
+
+ return CPU;
+}
+
+static void getAvailableFeatures(unsigned ECX, unsigned EDX, unsigned MaxLeaf,
+ unsigned *Features) {
+ unsigned EAX, EBX;
+
+#define setFeature(F) \
+ Features[F / 32] |= 1U << (F % 32)
+
+ if ((EDX >> 15) & 1)
+ setFeature(FEATURE_CMOV);
+ if ((EDX >> 23) & 1)
+ setFeature(FEATURE_MMX);
+ if ((EDX >> 25) & 1)
+ setFeature(FEATURE_SSE);
+ if ((EDX >> 26) & 1)
+ setFeature(FEATURE_SSE2);
+
+ if ((ECX >> 0) & 1)
+ setFeature(FEATURE_SSE3);
+ if ((ECX >> 1) & 1)
+ setFeature(FEATURE_PCLMUL);
+ if ((ECX >> 9) & 1)
+ setFeature(FEATURE_SSSE3);
+ if ((ECX >> 12) & 1)
+ setFeature(FEATURE_FMA);
+ if ((ECX >> 19) & 1)
+ setFeature(FEATURE_SSE4_1);
+ if ((ECX >> 20) & 1)
+ setFeature(FEATURE_SSE4_2);
+ if ((ECX >> 23) & 1)
+ setFeature(FEATURE_POPCNT);
+ if ((ECX >> 25) & 1)
+ setFeature(FEATURE_AES);
+
+ // If CPUID indicates support for XSAVE, XRESTORE and AVX, and XGETBV
+ // indicates that the AVX registers will be saved and restored on context
+ // switch, then we have full AVX support.
+ const unsigned AVXBits = (1 << 27) | (1 << 28);
+ bool HasAVX = ((ECX & AVXBits) == AVXBits) && !getX86XCR0(&EAX, &EDX) &&
+ ((EAX & 0x6) == 0x6);
+#if defined(__APPLE__)
+ // Darwin lazily saves the AVX512 context on first use: trust that the OS will
+ // save the AVX512 context if we use AVX512 instructions, even the bit is not
+ // set right now.
+ bool HasAVX512Save = true;
+#else
+ // AVX512 requires additional context to be saved by the OS.
+ bool HasAVX512Save = HasAVX && ((EAX & 0xe0) == 0xe0);
+#endif
+
+ if (HasAVX)
+ setFeature(FEATURE_AVX);
+
+ bool HasLeaf7 =
+ MaxLeaf >= 0x7 && !getX86CpuIDAndInfoEx(0x7, 0x0, &EAX, &EBX, &ECX, &EDX);
+
+ if (HasLeaf7 && ((EBX >> 3) & 1))
+ setFeature(FEATURE_BMI);
+ if (HasLeaf7 && ((EBX >> 5) & 1) && HasAVX)
+ setFeature(FEATURE_AVX2);
+ if (HasLeaf7 && ((EBX >> 8) & 1))
+ setFeature(FEATURE_BMI2);
+ if (HasLeaf7 && ((EBX >> 16) & 1) && HasAVX512Save)
+ setFeature(FEATURE_AVX512F);
+ if (HasLeaf7 && ((EBX >> 17) & 1) && HasAVX512Save)
+ setFeature(FEATURE_AVX512DQ);
+ if (HasLeaf7 && ((EBX >> 21) & 1) && HasAVX512Save)
+ setFeature(FEATURE_AVX512IFMA);
+ if (HasLeaf7 && ((EBX >> 26) & 1) && HasAVX512Save)
+ setFeature(FEATURE_AVX512PF);
+ if (HasLeaf7 && ((EBX >> 27) & 1) && HasAVX512Save)
+ setFeature(FEATURE_AVX512ER);
+ if (HasLeaf7 && ((EBX >> 28) & 1) && HasAVX512Save)
+ setFeature(FEATURE_AVX512CD);
+ if (HasLeaf7 && ((EBX >> 30) & 1) && HasAVX512Save)
+ setFeature(FEATURE_AVX512BW);
+ if (HasLeaf7 && ((EBX >> 31) & 1) && HasAVX512Save)
+ setFeature(FEATURE_AVX512VL);
+
+ if (HasLeaf7 && ((ECX >> 1) & 1) && HasAVX512Save)
+ setFeature(FEATURE_AVX512VBMI);
+ if (HasLeaf7 && ((ECX >> 6) & 1) && HasAVX512Save)
+ setFeature(FEATURE_AVX512VBMI2);
+ if (HasLeaf7 && ((ECX >> 8) & 1))
+ setFeature(FEATURE_GFNI);
+ if (HasLeaf7 && ((ECX >> 10) & 1) && HasAVX)
+ setFeature(FEATURE_VPCLMULQDQ);
+ if (HasLeaf7 && ((ECX >> 11) & 1) && HasAVX512Save)
+ setFeature(FEATURE_AVX512VNNI);
+ if (HasLeaf7 && ((ECX >> 12) & 1) && HasAVX512Save)
+ setFeature(FEATURE_AVX512BITALG);
+ if (HasLeaf7 && ((ECX >> 14) & 1) && HasAVX512Save)
+ setFeature(FEATURE_AVX512VPOPCNTDQ);
+
+ if (HasLeaf7 && ((EDX >> 2) & 1) && HasAVX512Save)
+ setFeature(FEATURE_AVX5124VNNIW);
+ if (HasLeaf7 && ((EDX >> 3) & 1) && HasAVX512Save)
+ setFeature(FEATURE_AVX5124FMAPS);
+ if (HasLeaf7 && ((EDX >> 8) & 1) && HasAVX512Save)
+ setFeature(FEATURE_AVX512VP2INTERSECT);
+
+ bool HasLeaf7Subleaf1 =
+ MaxLeaf >= 0x7 && !getX86CpuIDAndInfoEx(0x7, 0x1, &EAX, &EBX, &ECX, &EDX);
+ if (HasLeaf7Subleaf1 && ((EAX >> 5) & 1) && HasAVX512Save)
+ setFeature(FEATURE_AVX512BF16);
+
+ unsigned MaxExtLevel;
+ getX86CpuIDAndInfo(0x80000000, &MaxExtLevel, &EBX, &ECX, &EDX);
+
+ bool HasExtLeaf1 = MaxExtLevel >= 0x80000001 &&
+ !getX86CpuIDAndInfo(0x80000001, &EAX, &EBX, &ECX, &EDX);
+ if (HasExtLeaf1 && ((ECX >> 6) & 1))
+ setFeature(FEATURE_SSE4_A);
+ if (HasExtLeaf1 && ((ECX >> 11) & 1))
+ setFeature(FEATURE_XOP);
+ if (HasExtLeaf1 && ((ECX >> 16) & 1))
+ setFeature(FEATURE_FMA4);
+#undef setFeature
+}
+
+#ifndef _WIN32
+__attribute__((visibility("hidden")))
+#endif
+int __cpu_indicator_init(void) CONSTRUCTOR_ATTRIBUTE;
+
+#ifndef _WIN32
+__attribute__((visibility("hidden")))
+#endif
+struct __processor_model {
+ unsigned int __cpu_vendor;
+ unsigned int __cpu_type;
+ unsigned int __cpu_subtype;
+ unsigned int __cpu_features[1];
+} __cpu_model = {0, 0, 0, {0}};
+
+#ifndef _WIN32
+__attribute__((visibility("hidden")))
+#endif
+unsigned int __cpu_features2 = 0;
+
+// A constructor function that is sets __cpu_model and __cpu_features2 with
+// the right values. This needs to run only once. This constructor is
+// given the highest priority and it should run before constructors without
+// the priority set. However, it still runs after ifunc initializers and
+// needs to be called explicitly there.
+
+int CONSTRUCTOR_ATTRIBUTE __cpu_indicator_init(void) {
+ unsigned EAX, EBX, ECX, EDX;
+ unsigned MaxLeaf = 5;
+ unsigned Vendor;
+ unsigned Model, Family;
+ unsigned Features[(CPU_FEATURE_MAX + 31) / 32] = {0};
+
+ // This function needs to run just once.
+ if (__cpu_model.__cpu_vendor)
+ return 0;
+
+ if (!isCpuIdSupported() ||
+ getX86CpuIDAndInfo(0, &MaxLeaf, &Vendor, &ECX, &EDX) || MaxLeaf < 1) {
+ __cpu_model.__cpu_vendor = VENDOR_OTHER;
+ return -1;
+ }
+
+ getX86CpuIDAndInfo(1, &EAX, &EBX, &ECX, &EDX);
+ detectX86FamilyModel(EAX, &Family, &Model);
+
+ // Find available features.
+ getAvailableFeatures(ECX, EDX, MaxLeaf, &Features[0]);
+
+ assert((sizeof(Features)/sizeof(Features[0])) == 2);
+ __cpu_model.__cpu_features[0] = Features[0];
+ __cpu_features2 = Features[1];
+
+ if (Vendor == SIG_INTEL) {
+ // Get CPU type.
+ getIntelProcessorTypeAndSubtype(Family, Model, &Features[0],
+ &(__cpu_model.__cpu_type),
+ &(__cpu_model.__cpu_subtype));
+ __cpu_model.__cpu_vendor = VENDOR_INTEL;
+ } else if (Vendor == SIG_AMD) {
+ // Get CPU type.
+ getAMDProcessorTypeAndSubtype(Family, Model, &Features[0],
+ &(__cpu_model.__cpu_type),
+ &(__cpu_model.__cpu_subtype));
+ __cpu_model.__cpu_vendor = VENDOR_AMD;
+ } else
+ __cpu_model.__cpu_vendor = VENDOR_OTHER;
+
+ assert(__cpu_model.__cpu_vendor < VENDOR_MAX);
+ assert(__cpu_model.__cpu_type < CPU_TYPE_MAX);
+ assert(__cpu_model.__cpu_subtype < CPU_SUBTYPE_MAX);
+
+ return 0;
+}
+#elif defined(__aarch64__)
+
+#ifndef AT_HWCAP
+#define AT_HWCAP 16
+#endif
+#ifndef HWCAP_CPUID
+#define HWCAP_CPUID (1 << 11)
+#endif
+#ifndef HWCAP_FP
+#define HWCAP_FP (1 << 0)
+#endif
+#ifndef HWCAP_ASIMD
+#define HWCAP_ASIMD (1 << 1)
+#endif
+#ifndef HWCAP_AES
+#define HWCAP_AES (1 << 3)
+#endif
+#ifndef HWCAP_PMULL
+#define HWCAP_PMULL (1 << 4)
+#endif
+#ifndef HWCAP_SHA1
+#define HWCAP_SHA1 (1 << 5)
+#endif
+#ifndef HWCAP_SHA2
+#define HWCAP_SHA2 (1 << 6)
+#endif
+#ifndef HWCAP_ATOMICS
+#define HWCAP_ATOMICS (1 << 8)
+#endif
+#ifndef HWCAP_FPHP
+#define HWCAP_FPHP (1 << 9)
+#endif
+#ifndef HWCAP_ASIMDHP
+#define HWCAP_ASIMDHP (1 << 10)
+#endif
+#ifndef HWCAP_ASIMDRDM
+#define HWCAP_ASIMDRDM (1 << 12)
+#endif
+#ifndef HWCAP_JSCVT
+#define HWCAP_JSCVT (1 << 13)
+#endif
+#ifndef HWCAP_FCMA
+#define HWCAP_FCMA (1 << 14)
+#endif
+#ifndef HWCAP_LRCPC
+#define HWCAP_LRCPC (1 << 15)
+#endif
+#ifndef HWCAP_DCPOP
+#define HWCAP_DCPOP (1 << 16)
+#endif
+#ifndef HWCAP_SHA3
+#define HWCAP_SHA3 (1 << 17)
+#endif
+#ifndef HWCAP_SM3
+#define HWCAP_SM3 (1 << 18)
+#endif
+#ifndef HWCAP_SM4
+#define HWCAP_SM4 (1 << 19)
+#endif
+#ifndef HWCAP_ASIMDDP
+#define HWCAP_ASIMDDP (1 << 20)
+#endif
+#ifndef HWCAP_SHA512
+#define HWCAP_SHA512 (1 << 21)
+#endif
+#ifndef HWCAP_SVE
+#define HWCAP_SVE (1 << 22)
+#endif
+#ifndef HWCAP_ASIMDFHM
+#define HWCAP_ASIMDFHM (1 << 23)
+#endif
+#ifndef HWCAP_DIT
+#define HWCAP_DIT (1 << 24)
+#endif
+#ifndef HWCAP_ILRCPC
+#define HWCAP_ILRCPC (1 << 26)
+#endif
+#ifndef HWCAP_FLAGM
+#define HWCAP_FLAGM (1 << 27)
+#endif
+#ifndef HWCAP_SSBS
+#define HWCAP_SSBS (1 << 28)
+#endif
+#ifndef HWCAP_SB
+#define HWCAP_SB (1 << 29)
+#endif
+
+#ifndef AT_HWCAP2
+#define AT_HWCAP2 26
+#endif
+#ifndef HWCAP2_DCPODP
+#define HWCAP2_DCPODP (1 << 0)
+#endif
+#ifndef HWCAP2_SVE2
+#define HWCAP2_SVE2 (1 << 1)
+#endif
+#ifndef HWCAP2_SVEAES
+#define HWCAP2_SVEAES (1 << 2)
+#endif
+#ifndef HWCAP2_SVEPMULL
+#define HWCAP2_SVEPMULL (1 << 3)
+#endif
+#ifndef HWCAP2_SVEBITPERM
+#define HWCAP2_SVEBITPERM (1 << 4)
+#endif
+#ifndef HWCAP2_SVESHA3
+#define HWCAP2_SVESHA3 (1 << 5)
+#endif
+#ifndef HWCAP2_SVESM4
+#define HWCAP2_SVESM4 (1 << 6)
+#endif
+#ifndef HWCAP2_FLAGM2
+#define HWCAP2_FLAGM2 (1 << 7)
+#endif
+#ifndef HWCAP2_FRINT
+#define HWCAP2_FRINT (1 << 8)
+#endif
+#ifndef HWCAP2_SVEI8MM
+#define HWCAP2_SVEI8MM (1 << 9)
+#endif
+#ifndef HWCAP2_SVEF32MM
+#define HWCAP2_SVEF32MM (1 << 10)
+#endif
+#ifndef HWCAP2_SVEF64MM
+#define HWCAP2_SVEF64MM (1 << 11)
+#endif
+#ifndef HWCAP2_SVEBF16
+#define HWCAP2_SVEBF16 (1 << 12)
+#endif
+#ifndef HWCAP2_I8MM
+#define HWCAP2_I8MM (1 << 13)
+#endif
+#ifndef HWCAP2_BF16
+#define HWCAP2_BF16 (1 << 14)
+#endif
+#ifndef HWCAP2_DGH
+#define HWCAP2_DGH (1 << 15)
+#endif
+#ifndef HWCAP2_RNG
+#define HWCAP2_RNG (1 << 16)
+#endif
+#ifndef HWCAP2_BTI
+#define HWCAP2_BTI (1 << 17)
+#endif
+#ifndef HWCAP2_MTE
+#define HWCAP2_MTE (1 << 18)
+#endif
+#ifndef HWCAP2_RPRES
+#define HWCAP2_RPRES (1 << 21)
+#endif
+#ifndef HWCAP2_MTE3
+#define HWCAP2_MTE3 (1 << 22)
+#endif
+#ifndef HWCAP2_SME
+#define HWCAP2_SME (1 << 23)
+#endif
+#ifndef HWCAP2_SME_I16I64
+#define HWCAP2_SME_I16I64 (1 << 24)
+#endif
+#ifndef HWCAP2_SME_F64F64
+#define HWCAP2_SME_F64F64 (1 << 25)
+#endif
+#ifndef HWCAP2_WFXT
+#define HWCAP2_WFXT (1UL << 31)
+#endif
+#ifndef HWCAP2_EBF16
+#define HWCAP2_EBF16 (1UL << 32)
+#endif
+#ifndef HWCAP2_SVE_EBF16
+#define HWCAP2_SVE_EBF16 (1UL << 33)
+#endif
+
+// LSE support detection for out-of-line atomics
+// using HWCAP and Auxiliary vector
+_Bool __aarch64_have_lse_atomics
+ __attribute__((visibility("hidden"), nocommon));
+
+#if defined(__has_include)
+#if __has_include(<sys/auxv.h>)
+#include <sys/auxv.h>
+#if __has_include(<asm/hwcap.h>)
+#include <asm/hwcap.h>
+
+#if defined(__ANDROID__)
+#include <string.h>
+#include <sys/system_properties.h>
+#elif defined(__Fuchsia__)
+
+#include <zircon/syscalls.h>
+#endif
+
+// Detect Exynos 9810 CPU
+#define IF_EXYNOS9810 \
+ char arch[PROP_VALUE_MAX]; \
+ if (__system_property_get("ro.arch", arch) > 0 && \
+ strncmp(arch, "exynos9810", sizeof("exynos9810") - 1) == 0)
+
+static void CONSTRUCTOR_ATTRIBUTE init_have_lse_atomics(void) {
+#if defined(__FreeBSD__)
+ unsigned long hwcap;
+ int result = elf_aux_info(AT_HWCAP, &hwcap, sizeof hwcap);
+ __aarch64_have_lse_atomics = result == 0 && (hwcap & HWCAP_ATOMICS) != 0;
+#elif defined(__Fuchsia__)
+ // This ensures the vDSO is a direct link-time dependency of anything that
+ // needs this initializer code.
+#pragma comment(lib, "zircon")
+ uint32_t features;
+ zx_status_t status = _zx_system_get_features(ZX_FEATURE_KIND_CPU, &features);
+ __aarch64_have_lse_atomics =
+ status == ZX_OK && (features & ZX_ARM64_FEATURE_ISA_ATOMICS) != 0;
+#else
+ unsigned long hwcap = getauxval(AT_HWCAP);
+ _Bool result = (hwcap & HWCAP_ATOMICS) != 0;
+#if defined(__ANDROID__)
+ if (result) {
+ // Some cores in the Exynos 9810 CPU are ARMv8.2 and others are ARMv8.0;
+ // only the former support LSE atomics. However, the kernel in the
+ // initial Android 8.0 release of Galaxy S9/S9+ devices incorrectly
+ // reported the feature as being supported.
+ //
+ // The kernel appears to have been corrected to mark it unsupported as of
+ // the Android 9.0 release on those devices, and this issue has not been
+ // observed anywhere else. Thus, this workaround may be removed if
+ // compiler-rt ever drops support for Android 8.0.
+ IF_EXYNOS9810 result = false;
+ }
+#endif // defined(__ANDROID__)
+ __aarch64_have_lse_atomics = result;
+#endif // defined(__FreeBSD__)
+}
+
+#if !defined(DISABLE_AARCH64_FMV)
+// CPUFeatures must correspond to the same AArch64 features in
+// AArch64TargetParser.h
+enum CPUFeatures {
+ FEAT_RNG,
+ FEAT_FLAGM,
+ FEAT_FLAGM2,
+ FEAT_FP16FML,
+ FEAT_DOTPROD,
+ FEAT_SM4,
+ FEAT_RDM,
+ FEAT_LSE,
+ FEAT_FP,
+ FEAT_SIMD,
+ FEAT_CRC,
+ FEAT_SHA1,
+ FEAT_SHA2,
+ FEAT_SHA3,
+ FEAT_AES,
+ FEAT_PMULL,
+ FEAT_FP16,
+ FEAT_DIT,
+ FEAT_DPB,
+ FEAT_DPB2,
+ FEAT_JSCVT,
+ FEAT_FCMA,
+ FEAT_RCPC,
+ FEAT_RCPC2,
+ FEAT_FRINTTS,
+ FEAT_DGH,
+ FEAT_I8MM,
+ FEAT_BF16,
+ FEAT_EBF16,
+ FEAT_RPRES,
+ FEAT_SVE,
+ FEAT_SVE_BF16,
+ FEAT_SVE_EBF16,
+ FEAT_SVE_I8MM,
+ FEAT_SVE_F32MM,
+ FEAT_SVE_F64MM,
+ FEAT_SVE2,
+ FEAT_SVE_AES,
+ FEAT_SVE_PMULL128,
+ FEAT_SVE_BITPERM,
+ FEAT_SVE_SHA3,
+ FEAT_SVE_SM4,
+ FEAT_SME,
+ FEAT_MEMTAG,
+ FEAT_MEMTAG2,
+ FEAT_MEMTAG3,
+ FEAT_SB,
+ FEAT_PREDRES,
+ FEAT_SSBS,
+ FEAT_SSBS2,
+ FEAT_BTI,
+ FEAT_LS64,
+ FEAT_LS64_V,
+ FEAT_LS64_ACCDATA,
+ FEAT_WFXT,
+ FEAT_SME_F64,
+ FEAT_SME_I64,
+ FEAT_SME2,
+ FEAT_MAX
+};
+
+// Architecture features used
+// in Function Multi Versioning
+struct {
+ unsigned long long features;
+ // As features grows new fields could be added
+} __aarch64_cpu_features __attribute__((visibility("hidden"), nocommon));
+
+void init_cpu_features_resolver(unsigned long hwcap, unsigned long hwcap2) {
+#define setCPUFeature(F) __aarch64_cpu_features.features |= 1ULL << F
+#define getCPUFeature(id, ftr) __asm__("mrs %0, " #id : "=r"(ftr))
+#define extractBits(val, start, number) \
+ (val & ((1ULL << number) - 1ULL) << start) >> start
+ if (hwcap & HWCAP_CRC32)
+ setCPUFeature(FEAT_CRC);
+ if (hwcap & HWCAP_PMULL)
+ setCPUFeature(FEAT_PMULL);
+ if (hwcap & HWCAP_FLAGM)
+ setCPUFeature(FEAT_FLAGM);
+ if (hwcap2 & HWCAP2_FLAGM2) {
+ setCPUFeature(FEAT_FLAGM);
+ setCPUFeature(FEAT_FLAGM2);
+ }
+ if (hwcap & HWCAP_SM3 && hwcap & HWCAP_SM4)
+ setCPUFeature(FEAT_SM4);
+ if (hwcap & HWCAP_ASIMDDP)
+ setCPUFeature(FEAT_DOTPROD);
+ if (hwcap & HWCAP_ASIMDFHM)
+ setCPUFeature(FEAT_FP16FML);
+ if (hwcap & HWCAP_FPHP) {
+ setCPUFeature(FEAT_FP16);
+ setCPUFeature(FEAT_FP);
+ }
+ if (hwcap & HWCAP_DIT)
+ setCPUFeature(FEAT_DIT);
+ if (hwcap & HWCAP_ASIMDRDM)
+ setCPUFeature(FEAT_RDM);
+ if (hwcap & HWCAP_ILRCPC)
+ setCPUFeature(FEAT_RCPC2);
+ if (hwcap & HWCAP_AES)
+ setCPUFeature(FEAT_AES);
+ if (hwcap & HWCAP_SHA1)
+ setCPUFeature(FEAT_SHA1);
+ if (hwcap & HWCAP_SHA2)
+ setCPUFeature(FEAT_SHA2);
+ if (hwcap & HWCAP_JSCVT)
+ setCPUFeature(FEAT_JSCVT);
+ if (hwcap & HWCAP_FCMA)
+ setCPUFeature(FEAT_FCMA);
+ if (hwcap & HWCAP_SB)
+ setCPUFeature(FEAT_SB);
+ if (hwcap & HWCAP_SSBS)
+ setCPUFeature(FEAT_SSBS2);
+ if (hwcap2 & HWCAP2_MTE) {
+ setCPUFeature(FEAT_MEMTAG);
+ setCPUFeature(FEAT_MEMTAG2);
+ }
+ if (hwcap2 & HWCAP2_MTE3) {
+ setCPUFeature(FEAT_MEMTAG);
+ setCPUFeature(FEAT_MEMTAG2);
+ setCPUFeature(FEAT_MEMTAG3);
+ }
+ if (hwcap2 & HWCAP2_SVEAES)
+ setCPUFeature(FEAT_SVE_AES);
+ if (hwcap2 & HWCAP2_SVEPMULL) {
+ setCPUFeature(FEAT_SVE_AES);
+ setCPUFeature(FEAT_SVE_PMULL128);
+ }
+ if (hwcap2 & HWCAP2_SVEBITPERM)
+ setCPUFeature(FEAT_SVE_BITPERM);
+ if (hwcap2 & HWCAP2_SVESHA3)
+ setCPUFeature(FEAT_SVE_SHA3);
+ if (hwcap2 & HWCAP2_SVESM4)
+ setCPUFeature(FEAT_SVE_SM4);
+ if (hwcap2 & HWCAP2_DCPODP)
+ setCPUFeature(FEAT_DPB2);
+ if (hwcap & HWCAP_ATOMICS)
+ setCPUFeature(FEAT_LSE);
+ if (hwcap2 & HWCAP2_RNG)
+ setCPUFeature(FEAT_RNG);
+ if (hwcap2 & HWCAP2_I8MM)
+ setCPUFeature(FEAT_I8MM);
+ if (hwcap2 & HWCAP2_EBF16)
+ setCPUFeature(FEAT_EBF16);
+ if (hwcap2 & HWCAP2_SVE_EBF16)
+ setCPUFeature(FEAT_SVE_EBF16);
+ if (hwcap2 & HWCAP2_DGH)
+ setCPUFeature(FEAT_DGH);
+ if (hwcap2 & HWCAP2_FRINT)
+ setCPUFeature(FEAT_FRINTTS);
+ if (hwcap2 & HWCAP2_SVEI8MM)
+ setCPUFeature(FEAT_SVE_I8MM);
+ if (hwcap2 & HWCAP2_SVEF32MM)
+ setCPUFeature(FEAT_SVE_F32MM);
+ if (hwcap2 & HWCAP2_SVEF64MM)
+ setCPUFeature(FEAT_SVE_F64MM);
+ if (hwcap2 & HWCAP2_BTI)
+ setCPUFeature(FEAT_BTI);
+ if (hwcap2 & HWCAP2_RPRES)
+ setCPUFeature(FEAT_RPRES);
+ if (hwcap2 & HWCAP2_WFXT)
+ setCPUFeature(FEAT_WFXT);
+ if (hwcap2 & HWCAP2_SME)
+ setCPUFeature(FEAT_SME);
+ if (hwcap2 & HWCAP2_SME_I16I64)
+ setCPUFeature(FEAT_SME_I64);
+ if (hwcap2 & HWCAP2_SME_F64F64)
+ setCPUFeature(FEAT_SME_F64);
+ if (hwcap & HWCAP_CPUID) {
+ unsigned long ftr;
+ getCPUFeature(ID_AA64PFR1_EL1, ftr);
+ // ID_AA64PFR1_EL1.MTE >= 0b0001
+ if (extractBits(ftr, 8, 4) >= 0x1)
+ setCPUFeature(FEAT_MEMTAG);
+ // ID_AA64PFR1_EL1.SSBS == 0b0001
+ if (extractBits(ftr, 4, 4) == 0x1)
+ setCPUFeature(FEAT_SSBS);
+ // ID_AA64PFR1_EL1.SME == 0b0010
+ if (extractBits(ftr, 24, 4) == 0x2)
+ setCPUFeature(FEAT_SME2);
+ getCPUFeature(ID_AA64PFR0_EL1, ftr);
+ // ID_AA64PFR0_EL1.FP != 0b1111
+ if (extractBits(ftr, 16, 4) != 0xF) {
+ setCPUFeature(FEAT_FP);
+ // ID_AA64PFR0_EL1.AdvSIMD has the same value as ID_AA64PFR0_EL1.FP
+ setCPUFeature(FEAT_SIMD);
+ }
+ // ID_AA64PFR0_EL1.SVE != 0b0000
+ if (extractBits(ftr, 32, 4) != 0x0) {
+ // get ID_AA64ZFR0_EL1, that name supported
+ // if sve enabled only
+ getCPUFeature(S3_0_C0_C4_4, ftr);
+ // ID_AA64ZFR0_EL1.SVEver == 0b0000
+ if (extractBits(ftr, 0, 4) == 0x0)
+ setCPUFeature(FEAT_SVE);
+ // ID_AA64ZFR0_EL1.SVEver == 0b0001
+ if (extractBits(ftr, 0, 4) == 0x1)
+ setCPUFeature(FEAT_SVE2);
+ // ID_AA64ZFR0_EL1.BF16 != 0b0000
+ if (extractBits(ftr, 20, 4) != 0x0)
+ setCPUFeature(FEAT_SVE_BF16);
+ }
+ getCPUFeature(ID_AA64ISAR0_EL1, ftr);
+ // ID_AA64ISAR0_EL1.SHA3 != 0b0000
+ if (extractBits(ftr, 32, 4) != 0x0)
+ setCPUFeature(FEAT_SHA3);
+ getCPUFeature(ID_AA64ISAR1_EL1, ftr);
+ // ID_AA64ISAR1_EL1.DPB >= 0b0001
+ if (extractBits(ftr, 0, 4) >= 0x1)
+ setCPUFeature(FEAT_DPB);
+ // ID_AA64ISAR1_EL1.LRCPC != 0b0000
+ if (extractBits(ftr, 20, 4) != 0x0)
+ setCPUFeature(FEAT_RCPC);
+ // ID_AA64ISAR1_EL1.SPECRES == 0b0001
+ if (extractBits(ftr, 40, 4) == 0x2)
+ setCPUFeature(FEAT_PREDRES);
+ // ID_AA64ISAR1_EL1.BF16 != 0b0000
+ if (extractBits(ftr, 44, 4) != 0x0)
+ setCPUFeature(FEAT_BF16);
+ // ID_AA64ISAR1_EL1.LS64 >= 0b0001
+ if (extractBits(ftr, 60, 4) >= 0x1)
+ setCPUFeature(FEAT_LS64);
+ // ID_AA64ISAR1_EL1.LS64 >= 0b0010
+ if (extractBits(ftr, 60, 4) >= 0x2)
+ setCPUFeature(FEAT_LS64_V);
+ // ID_AA64ISAR1_EL1.LS64 >= 0b0011
+ if (extractBits(ftr, 60, 4) >= 0x3)
+ setCPUFeature(FEAT_LS64_ACCDATA);
+ } else {
+ // Set some features in case of no CPUID support
+ if (hwcap & (HWCAP_FP | HWCAP_FPHP)) {
+ setCPUFeature(FEAT_FP);
+ // FP and AdvSIMD fields have the same value
+ setCPUFeature(FEAT_SIMD);
+ }
+ if (hwcap & HWCAP_DCPOP || hwcap2 & HWCAP2_DCPODP)
+ setCPUFeature(FEAT_DPB);
+ if (hwcap & HWCAP_LRCPC || hwcap & HWCAP_ILRCPC)
+ setCPUFeature(FEAT_RCPC);
+ if (hwcap2 & HWCAP2_BF16 || hwcap2 & HWCAP2_EBF16)
+ setCPUFeature(FEAT_BF16);
+ if (hwcap2 & HWCAP2_SVEBF16)
+ setCPUFeature(FEAT_SVE_BF16);
+ if (hwcap2 & HWCAP2_SVE2 && hwcap & HWCAP_SVE)
+ setCPUFeature(FEAT_SVE2);
+ if (hwcap & HWCAP_SHA3)
+ setCPUFeature(FEAT_SHA3);
+ }
+}
+
+void CONSTRUCTOR_ATTRIBUTE init_cpu_features(void) {
+ unsigned long hwcap;
+ unsigned long hwcap2;
+ // CPU features already initialized.
+ if (__aarch64_cpu_features.features)
+ return;
+ setCPUFeature(FEAT_MAX);
+#if defined(__FreeBSD__)
+ int res = 0;
+ res = elf_aux_info(AT_HWCAP, &hwcap, sizeof hwcap);
+ res |= elf_aux_info(AT_HWCAP2, &hwcap2, sizeof hwcap2);
+ if (res)
+ return;
+#else
+#if defined(__ANDROID__)
+ // Don't set any CPU features,
+ // detection could be wrong on Exynos 9810.
+ IF_EXYNOS9810 return;
+#endif // defined(__ANDROID__)
+ hwcap = getauxval(AT_HWCAP);
+ hwcap2 = getauxval(AT_HWCAP2);
+#endif // defined(__FreeBSD__)
+ init_cpu_features_resolver(hwcap, hwcap2);
+#undef extractBits
+#undef getCPUFeature
+#undef setCPUFeature
+#undef IF_EXYNOS9810
+}
+#endif // !defined(DISABLE_AARCH64_FMV)
+#endif // defined(__has_include)
+#endif // __has_include(<sys/auxv.h>)
+#endif // __has_include(<asm/hwcap.h>)
+#endif // defined(__aarch64__)
diff --git a/contrib/libs/cxxsupp/builtins/ctzdi2.c b/contrib/libs/cxxsupp/builtins/ctzdi2.c
index db3c6fdc08..26c908d876 100644
--- a/contrib/libs/cxxsupp/builtins/ctzdi2.c
+++ b/contrib/libs/cxxsupp/builtins/ctzdi2.c
@@ -1,29 +1,35 @@
-/* ===-- ctzdi2.c - Implement __ctzdi2 -------------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __ctzdi2 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- ctzdi2.c - Implement __ctzdi2 -------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __ctzdi2 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
-/* Returns: the number of trailing 0-bits */
+// Returns: the number of trailing 0-bits
-/* Precondition: a != 0 */
+#if !defined(__clang__) && \
+ ((defined(__sparc__) && defined(__arch64__)) || defined(__mips64) || \
+ (defined(__riscv) && __SIZEOF_POINTER__ >= 8))
+// On 64-bit architectures with neither a native clz instruction nor a native
+// ctz instruction, gcc resolves __builtin_ctz to __ctzdi2 rather than
+// __ctzsi2, leading to infinite recursion.
+#define __builtin_ctz(a) __ctzsi2(a)
+extern int __ctzsi2(si_int);
+#endif
-COMPILER_RT_ABI si_int
-__ctzdi2(di_int a)
-{
- dwords x;
- x.all = a;
- const si_int f = -(x.s.low == 0);
- return __builtin_ctz((x.s.high & f) | (x.s.low & ~f)) +
- (f & ((si_int)(sizeof(si_int) * CHAR_BIT)));
+// Precondition: a != 0
+
+COMPILER_RT_ABI int __ctzdi2(di_int a) {
+ dwords x;
+ x.all = a;
+ const si_int f = -(x.s.low == 0);
+ return ctzsi((x.s.high & f) | (x.s.low & ~f)) +
+ (f & ((si_int)(sizeof(si_int) * CHAR_BIT)));
}
diff --git a/contrib/libs/cxxsupp/builtins/ctzsi2.c b/contrib/libs/cxxsupp/builtins/ctzsi2.c
index c69486ea44..ed95c60579 100644
--- a/contrib/libs/cxxsupp/builtins/ctzsi2.c
+++ b/contrib/libs/cxxsupp/builtins/ctzsi2.c
@@ -1,57 +1,53 @@
-/* ===-- ctzsi2.c - Implement __ctzsi2 -------------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __ctzsi2 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- ctzsi2.c - Implement __ctzsi2 -------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __ctzsi2 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
-/* Returns: the number of trailing 0-bits */
+// Returns: the number of trailing 0-bits
-/* Precondition: a != 0 */
+// Precondition: a != 0
-COMPILER_RT_ABI si_int
-__ctzsi2(si_int a)
-{
- su_int x = (su_int)a;
- si_int t = ((x & 0x0000FFFF) == 0) << 4; /* if (x has no small bits) t = 16 else 0 */
- x >>= t; /* x = [0 - 0xFFFF] + higher garbage bits */
- su_int r = t; /* r = [0, 16] */
- /* return r + ctz(x) */
- t = ((x & 0x00FF) == 0) << 3;
- x >>= t; /* x = [0 - 0xFF] + higher garbage bits */
- r += t; /* r = [0, 8, 16, 24] */
- /* return r + ctz(x) */
- t = ((x & 0x0F) == 0) << 2;
- x >>= t; /* x = [0 - 0xF] + higher garbage bits */
- r += t; /* r = [0, 4, 8, 12, 16, 20, 24, 28] */
- /* return r + ctz(x) */
- t = ((x & 0x3) == 0) << 1;
- x >>= t;
- x &= 3; /* x = [0 - 3] */
- r += t; /* r = [0 - 30] and is even */
- /* return r + ctz(x) */
+COMPILER_RT_ABI int __ctzsi2(si_int a) {
+ su_int x = (su_int)a;
+ si_int t = ((x & 0x0000FFFF) == 0)
+ << 4; // if (x has no small bits) t = 16 else 0
+ x >>= t; // x = [0 - 0xFFFF] + higher garbage bits
+ su_int r = t; // r = [0, 16]
+ // return r + ctz(x)
+ t = ((x & 0x00FF) == 0) << 3;
+ x >>= t; // x = [0 - 0xFF] + higher garbage bits
+ r += t; // r = [0, 8, 16, 24]
+ // return r + ctz(x)
+ t = ((x & 0x0F) == 0) << 2;
+ x >>= t; // x = [0 - 0xF] + higher garbage bits
+ r += t; // r = [0, 4, 8, 12, 16, 20, 24, 28]
+ // return r + ctz(x)
+ t = ((x & 0x3) == 0) << 1;
+ x >>= t;
+ x &= 3; // x = [0 - 3]
+ r += t; // r = [0 - 30] and is even
+ // return r + ctz(x)
-/* The branch-less return statement below is equivalent
- * to the following switch statement:
- * switch (x)
- * {
- * case 0:
- * return r + 2;
- * case 2:
- * return r + 1;
- * case 1:
- * case 3:
- * return r;
- * }
- */
- return r + ((2 - (x >> 1)) & -((x & 1) == 0));
+ // The branch-less return statement below is equivalent
+ // to the following switch statement:
+ // switch (x)
+ // {
+ // case 0:
+ // return r + 2;
+ // case 2:
+ // return r + 1;
+ // case 1:
+ // case 3:
+ // return r;
+ // }
+ return r + ((2 - (x >> 1)) & -((x & 1) == 0));
}
diff --git a/contrib/libs/cxxsupp/builtins/ctzti2.c b/contrib/libs/cxxsupp/builtins/ctzti2.c
index 45de682700..fb136d0de1 100644
--- a/contrib/libs/cxxsupp/builtins/ctzti2.c
+++ b/contrib/libs/cxxsupp/builtins/ctzti2.c
@@ -1,33 +1,29 @@
-/* ===-- ctzti2.c - Implement __ctzti2 -------------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __ctzti2 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- ctzti2.c - Implement __ctzti2 -------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __ctzti2 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
#ifdef CRT_HAS_128BIT
-/* Returns: the number of trailing 0-bits */
+// Returns: the number of trailing 0-bits
-/* Precondition: a != 0 */
+// Precondition: a != 0
-COMPILER_RT_ABI si_int
-__ctzti2(ti_int a)
-{
- twords x;
- x.all = a;
- const di_int f = -(x.s.low == 0);
- return __builtin_ctzll((x.s.high & f) | (x.s.low & ~f)) +
- ((si_int)f & ((si_int)(sizeof(di_int) * CHAR_BIT)));
+COMPILER_RT_ABI int __ctzti2(ti_int a) {
+ twords x;
+ x.all = a;
+ const di_int f = -(x.s.low == 0);
+ return __builtin_ctzll((x.s.high & f) | (x.s.low & ~f)) +
+ ((si_int)f & ((si_int)(sizeof(di_int) * CHAR_BIT)));
}
-#endif /* CRT_HAS_128BIT */
+#endif // CRT_HAS_128BIT
diff --git a/contrib/libs/cxxsupp/builtins/divdc3.c b/contrib/libs/cxxsupp/builtins/divdc3.c
index 3c88390b5e..5581182f3b 100644
--- a/contrib/libs/cxxsupp/builtins/divdc3.c
+++ b/contrib/libs/cxxsupp/builtins/divdc3.c
@@ -1,60 +1,55 @@
-/* ===-- divdc3.c - Implement __divdc3 -------------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __divdc3 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- divdc3.c - Implement __divdc3 -------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __divdc3 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
+#define DOUBLE_PRECISION
+#include "fp_lib.h"
#include "int_lib.h"
#include "int_math.h"
-/* Returns: the quotient of (a + ib) / (c + id) */
+// Returns: the quotient of (a + ib) / (c + id)
-COMPILER_RT_ABI Dcomplex
-__divdc3(double __a, double __b, double __c, double __d)
-{
- int __ilogbw = 0;
- double __logbw = crt_logb(crt_fmax(crt_fabs(__c), crt_fabs(__d)));
- if (crt_isfinite(__logbw))
- {
- __ilogbw = (int)__logbw;
- __c = crt_scalbn(__c, -__ilogbw);
- __d = crt_scalbn(__d, -__ilogbw);
+COMPILER_RT_ABI Dcomplex __divdc3(double __a, double __b, double __c,
+ double __d) {
+ int __ilogbw = 0;
+ double __logbw = __compiler_rt_logb(__compiler_rt_fmax(crt_fabs(__c),
+ crt_fabs(__d)));
+ if (crt_isfinite(__logbw)) {
+ __ilogbw = (int)__logbw;
+ __c = __compiler_rt_scalbn(__c, -__ilogbw);
+ __d = __compiler_rt_scalbn(__d, -__ilogbw);
+ }
+ double __denom = __c * __c + __d * __d;
+ Dcomplex z;
+ COMPLEX_REAL(z) =
+ __compiler_rt_scalbn((__a * __c + __b * __d) / __denom, -__ilogbw);
+ COMPLEX_IMAGINARY(z) =
+ __compiler_rt_scalbn((__b * __c - __a * __d) / __denom, -__ilogbw);
+ if (crt_isnan(COMPLEX_REAL(z)) && crt_isnan(COMPLEX_IMAGINARY(z))) {
+ if ((__denom == 0.0) && (!crt_isnan(__a) || !crt_isnan(__b))) {
+ COMPLEX_REAL(z) = crt_copysign(CRT_INFINITY, __c) * __a;
+ COMPLEX_IMAGINARY(z) = crt_copysign(CRT_INFINITY, __c) * __b;
+ } else if ((crt_isinf(__a) || crt_isinf(__b)) && crt_isfinite(__c) &&
+ crt_isfinite(__d)) {
+ __a = crt_copysign(crt_isinf(__a) ? 1.0 : 0.0, __a);
+ __b = crt_copysign(crt_isinf(__b) ? 1.0 : 0.0, __b);
+ COMPLEX_REAL(z) = CRT_INFINITY * (__a * __c + __b * __d);
+ COMPLEX_IMAGINARY(z) = CRT_INFINITY * (__b * __c - __a * __d);
+ } else if (crt_isinf(__logbw) && __logbw > 0.0 && crt_isfinite(__a) &&
+ crt_isfinite(__b)) {
+ __c = crt_copysign(crt_isinf(__c) ? 1.0 : 0.0, __c);
+ __d = crt_copysign(crt_isinf(__d) ? 1.0 : 0.0, __d);
+ COMPLEX_REAL(z) = 0.0 * (__a * __c + __b * __d);
+ COMPLEX_IMAGINARY(z) = 0.0 * (__b * __c - __a * __d);
}
- double __denom = __c * __c + __d * __d;
- Dcomplex z;
- COMPLEX_REAL(z) = crt_scalbn((__a * __c + __b * __d) / __denom, -__ilogbw);
- COMPLEX_IMAGINARY(z) = crt_scalbn((__b * __c - __a * __d) / __denom, -__ilogbw);
- if (crt_isnan(COMPLEX_REAL(z)) && crt_isnan(COMPLEX_IMAGINARY(z)))
- {
- if ((__denom == 0.0) && (!crt_isnan(__a) || !crt_isnan(__b)))
- {
- COMPLEX_REAL(z) = crt_copysign(CRT_INFINITY, __c) * __a;
- COMPLEX_IMAGINARY(z) = crt_copysign(CRT_INFINITY, __c) * __b;
- }
- else if ((crt_isinf(__a) || crt_isinf(__b)) &&
- crt_isfinite(__c) && crt_isfinite(__d))
- {
- __a = crt_copysign(crt_isinf(__a) ? 1.0 : 0.0, __a);
- __b = crt_copysign(crt_isinf(__b) ? 1.0 : 0.0, __b);
- COMPLEX_REAL(z) = CRT_INFINITY * (__a * __c + __b * __d);
- COMPLEX_IMAGINARY(z) = CRT_INFINITY * (__b * __c - __a * __d);
- }
- else if (crt_isinf(__logbw) && __logbw > 0.0 &&
- crt_isfinite(__a) && crt_isfinite(__b))
- {
- __c = crt_copysign(crt_isinf(__c) ? 1.0 : 0.0, __c);
- __d = crt_copysign(crt_isinf(__d) ? 1.0 : 0.0, __d);
- COMPLEX_REAL(z) = 0.0 * (__a * __c + __b * __d);
- COMPLEX_IMAGINARY(z) = 0.0 * (__b * __c - __a * __d);
- }
- }
- return z;
+ }
+ return z;
}
diff --git a/contrib/libs/cxxsupp/builtins/divdf3.c b/contrib/libs/cxxsupp/builtins/divdf3.c
index ab44c2b25f..4c11759e0c 100644
--- a/contrib/libs/cxxsupp/builtins/divdf3.c
+++ b/contrib/libs/cxxsupp/builtins/divdf3.c
@@ -1,185 +1,29 @@
//===-- lib/divdf3.c - Double-precision division ------------------*- C -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file implements double-precision soft-float division
// with the IEEE-754 default rounding (to nearest, ties to even).
//
-// For simplicity, this implementation currently flushes denormals to zero.
-// It should be a fairly straightforward exercise to implement gradual
-// underflow with correct rounding.
-//
//===----------------------------------------------------------------------===//
#define DOUBLE_PRECISION
-#include "fp_lib.h"
-ARM_EABI_FNALIAS(ddiv, divdf3)
+#define NUMBER_OF_HALF_ITERATIONS 3
+#define NUMBER_OF_FULL_ITERATIONS 1
+
+#include "fp_div_impl.inc"
+
+COMPILER_RT_ABI fp_t __divdf3(fp_t a, fp_t b) { return __divXf3__(a, b); }
-COMPILER_RT_ABI fp_t
-__divdf3(fp_t a, fp_t b) {
-
- const unsigned int aExponent = toRep(a) >> significandBits & maxExponent;
- const unsigned int bExponent = toRep(b) >> significandBits & maxExponent;
- const rep_t quotientSign = (toRep(a) ^ toRep(b)) & signBit;
-
- rep_t aSignificand = toRep(a) & significandMask;
- rep_t bSignificand = toRep(b) & significandMask;
- int scale = 0;
-
- // Detect if a or b is zero, denormal, infinity, or NaN.
- if (aExponent-1U >= maxExponent-1U || bExponent-1U >= maxExponent-1U) {
-
- const rep_t aAbs = toRep(a) & absMask;
- const rep_t bAbs = toRep(b) & absMask;
-
- // NaN / anything = qNaN
- if (aAbs > infRep) return fromRep(toRep(a) | quietBit);
- // anything / NaN = qNaN
- if (bAbs > infRep) return fromRep(toRep(b) | quietBit);
-
- if (aAbs == infRep) {
- // infinity / infinity = NaN
- if (bAbs == infRep) return fromRep(qnanRep);
- // infinity / anything else = +/- infinity
- else return fromRep(aAbs | quotientSign);
- }
-
- // anything else / infinity = +/- 0
- if (bAbs == infRep) return fromRep(quotientSign);
-
- if (!aAbs) {
- // zero / zero = NaN
- if (!bAbs) return fromRep(qnanRep);
- // zero / anything else = +/- zero
- else return fromRep(quotientSign);
- }
- // anything else / zero = +/- infinity
- if (!bAbs) return fromRep(infRep | quotientSign);
-
- // one or both of a or b is denormal, the other (if applicable) is a
- // normal number. Renormalize one or both of a and b, and set scale to
- // include the necessary exponent adjustment.
- if (aAbs < implicitBit) scale += normalize(&aSignificand);
- if (bAbs < implicitBit) scale -= normalize(&bSignificand);
- }
-
- // Or in the implicit significand bit. (If we fell through from the
- // denormal path it was already set by normalize( ), but setting it twice
- // won't hurt anything.)
- aSignificand |= implicitBit;
- bSignificand |= implicitBit;
- int quotientExponent = aExponent - bExponent + scale;
-
- // Align the significand of b as a Q31 fixed-point number in the range
- // [1, 2.0) and get a Q32 approximate reciprocal using a small minimax
- // polynomial approximation: reciprocal = 3/4 + 1/sqrt(2) - b/2. This
- // is accurate to about 3.5 binary digits.
- const uint32_t q31b = bSignificand >> 21;
- uint32_t recip32 = UINT32_C(0x7504f333) - q31b;
-
- // Now refine the reciprocal estimate using a Newton-Raphson iteration:
- //
- // x1 = x0 * (2 - x0 * b)
- //
- // This doubles the number of correct binary digits in the approximation
- // with each iteration, so after three iterations, we have about 28 binary
- // digits of accuracy.
- uint32_t correction32;
- correction32 = -((uint64_t)recip32 * q31b >> 32);
- recip32 = (uint64_t)recip32 * correction32 >> 31;
- correction32 = -((uint64_t)recip32 * q31b >> 32);
- recip32 = (uint64_t)recip32 * correction32 >> 31;
- correction32 = -((uint64_t)recip32 * q31b >> 32);
- recip32 = (uint64_t)recip32 * correction32 >> 31;
-
- // recip32 might have overflowed to exactly zero in the preceding
- // computation if the high word of b is exactly 1.0. This would sabotage
- // the full-width final stage of the computation that follows, so we adjust
- // recip32 downward by one bit.
- recip32--;
-
- // We need to perform one more iteration to get us to 56 binary digits;
- // The last iteration needs to happen with extra precision.
- const uint32_t q63blo = bSignificand << 11;
- uint64_t correction, reciprocal;
- correction = -((uint64_t)recip32*q31b + ((uint64_t)recip32*q63blo >> 32));
- uint32_t cHi = correction >> 32;
- uint32_t cLo = correction;
- reciprocal = (uint64_t)recip32*cHi + ((uint64_t)recip32*cLo >> 32);
-
- // We already adjusted the 32-bit estimate, now we need to adjust the final
- // 64-bit reciprocal estimate downward to ensure that it is strictly smaller
- // than the infinitely precise exact reciprocal. Because the computation
- // of the Newton-Raphson step is truncating at every step, this adjustment
- // is small; most of the work is already done.
- reciprocal -= 2;
-
- // The numerical reciprocal is accurate to within 2^-56, lies in the
- // interval [0.5, 1.0), and is strictly smaller than the true reciprocal
- // of b. Multiplying a by this reciprocal thus gives a numerical q = a/b
- // in Q53 with the following properties:
- //
- // 1. q < a/b
- // 2. q is in the interval [0.5, 2.0)
- // 3. the error in q is bounded away from 2^-53 (actually, we have a
- // couple of bits to spare, but this is all we need).
-
- // We need a 64 x 64 multiply high to compute q, which isn't a basic
- // operation in C, so we need to be a little bit fussy.
- rep_t quotient, quotientLo;
- wideMultiply(aSignificand << 2, reciprocal, &quotient, &quotientLo);
-
- // Two cases: quotient is in [0.5, 1.0) or quotient is in [1.0, 2.0).
- // In either case, we are going to compute a residual of the form
- //
- // r = a - q*b
- //
- // We know from the construction of q that r satisfies:
- //
- // 0 <= r < ulp(q)*b
- //
- // if r is greater than 1/2 ulp(q)*b, then q rounds up. Otherwise, we
- // already have the correct result. The exact halfway case cannot occur.
- // We also take this time to right shift quotient if it falls in the [1,2)
- // range and adjust the exponent accordingly.
- rep_t residual;
- if (quotient < (implicitBit << 1)) {
- residual = (aSignificand << 53) - quotient * bSignificand;
- quotientExponent--;
- } else {
- quotient >>= 1;
- residual = (aSignificand << 52) - quotient * bSignificand;
- }
-
- const int writtenExponent = quotientExponent + exponentBias;
-
- if (writtenExponent >= maxExponent) {
- // If we have overflowed the exponent, return infinity.
- return fromRep(infRep | quotientSign);
- }
-
- else if (writtenExponent < 1) {
- // Flush denormals to zero. In the future, it would be nice to add
- // code to round them correctly.
- return fromRep(quotientSign);
- }
-
- else {
- const bool round = (residual << 1) > bSignificand;
- // Clear the implicit bit
- rep_t absResult = quotient & significandMask;
- // Insert the exponent
- absResult |= (rep_t)writtenExponent << significandBits;
- // Round
- absResult += round;
- // Insert the sign and return
- const double result = fromRep(absResult | quotientSign);
- return result;
- }
-}
+#if defined(__ARM_EABI__)
+#if defined(COMPILER_RT_ARMHF_TARGET)
+AEABI_RTABI fp_t __aeabi_ddiv(fp_t a, fp_t b) { return __divdf3(a, b); }
+#else
+COMPILER_RT_ALIAS(__divdf3, __aeabi_ddiv)
+#endif
+#endif
diff --git a/contrib/libs/cxxsupp/builtins/divdi3.c b/contrib/libs/cxxsupp/builtins/divdi3.c
index b8eebcb204..d71e138d99 100644
--- a/contrib/libs/cxxsupp/builtins/divdi3.c
+++ b/contrib/libs/cxxsupp/builtins/divdi3.c
@@ -1,29 +1,22 @@
-/* ===-- divdi3.c - Implement __divdi3 -------------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __divdi3 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- divdi3.c - Implement __divdi3 -------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __divdi3 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
-/* Returns: a / b */
+// Returns: a / b
-COMPILER_RT_ABI di_int
-__divdi3(di_int a, di_int b)
-{
- const int bits_in_dword_m1 = (int)(sizeof(di_int) * CHAR_BIT) - 1;
- di_int s_a = a >> bits_in_dword_m1; /* s_a = a < 0 ? -1 : 0 */
- di_int s_b = b >> bits_in_dword_m1; /* s_b = b < 0 ? -1 : 0 */
- a = (a ^ s_a) - s_a; /* negate if s_a == -1 */
- b = (b ^ s_b) - s_b; /* negate if s_b == -1 */
- s_a ^= s_b; /*sign of quotient */
- return (__udivmoddi4(a, b, (du_int*)0) ^ s_a) - s_a; /* negate if s_a == -1 */
-}
+#define fixint_t di_int
+#define fixuint_t du_int
+#define COMPUTE_UDIV(a, b) __udivmoddi4((a), (b), (du_int *)0)
+#include "int_div_impl.inc"
+
+COMPILER_RT_ABI di_int __divdi3(di_int a, di_int b) { return __divXi3(a, b); }
diff --git a/contrib/libs/cxxsupp/builtins/divmoddi4.c b/contrib/libs/cxxsupp/builtins/divmoddi4.c
index 0d4df67a63..e7cbbb1aaa 100644
--- a/contrib/libs/cxxsupp/builtins/divmoddi4.c
+++ b/contrib/libs/cxxsupp/builtins/divmoddi4.c
@@ -1,25 +1,28 @@
-/*===-- divmoddi4.c - Implement __divmoddi4 --------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __divmoddi4 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- divmoddi4.c - Implement __divmoddi4 -------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __divmoddi4 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
-/* Returns: a / b, *rem = a % b */
+// Returns: a / b, *rem = a % b
-COMPILER_RT_ABI di_int
-__divmoddi4(di_int a, di_int b, di_int* rem)
-{
- di_int d = __divdi3(a,b);
- *rem = a - (d*b);
- return d;
+COMPILER_RT_ABI di_int __divmoddi4(di_int a, di_int b, di_int *rem) {
+ const int bits_in_dword_m1 = (int)(sizeof(di_int) * CHAR_BIT) - 1;
+ di_int s_a = a >> bits_in_dword_m1; // s_a = a < 0 ? -1 : 0
+ di_int s_b = b >> bits_in_dword_m1; // s_b = b < 0 ? -1 : 0
+ a = (a ^ s_a) - s_a; // negate if s_a == -1
+ b = (b ^ s_b) - s_b; // negate if s_b == -1
+ s_b ^= s_a; // sign of quotient
+ du_int r;
+ di_int q = (__udivmoddi4(a, b, &r) ^ s_b) - s_b; // negate if s_b == -1
+ *rem = (r ^ s_a) - s_a; // negate if s_a == -1
+ return q;
}
diff --git a/contrib/libs/cxxsupp/builtins/divmodsi4.c b/contrib/libs/cxxsupp/builtins/divmodsi4.c
index dabe287439..a85e2993b4 100644
--- a/contrib/libs/cxxsupp/builtins/divmodsi4.c
+++ b/contrib/libs/cxxsupp/builtins/divmodsi4.c
@@ -1,27 +1,29 @@
-/*===-- divmodsi4.c - Implement __divmodsi4 --------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __divmodsi4 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- divmodsi4.c - Implement __divmodsi4
+//--------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __divmodsi4 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
-/* Returns: a / b, *rem = a % b */
+// Returns: a / b, *rem = a % b
-COMPILER_RT_ABI si_int
-__divmodsi4(si_int a, si_int b, si_int* rem)
-{
- si_int d = __divsi3(a,b);
- *rem = a - (d*b);
- return d;
+COMPILER_RT_ABI si_int __divmodsi4(si_int a, si_int b, si_int *rem) {
+ const int bits_in_word_m1 = (int)(sizeof(si_int) * CHAR_BIT) - 1;
+ si_int s_a = a >> bits_in_word_m1; // s_a = a < 0 ? -1 : 0
+ si_int s_b = b >> bits_in_word_m1; // s_b = b < 0 ? -1 : 0
+ a = (a ^ s_a) - s_a; // negate if s_a == -1
+ b = (b ^ s_b) - s_b; // negate if s_b == -1
+ s_b ^= s_a; // sign of quotient
+ su_int r;
+ si_int q = (__udivmodsi4(a, b, &r) ^ s_b) - s_b; // negate if s_b == -1
+ *rem = (r ^ s_a) - s_a; // negate if s_a == -1
+ return q;
}
-
-
diff --git a/contrib/libs/cxxsupp/builtins/divmodti4.c b/contrib/libs/cxxsupp/builtins/divmodti4.c
new file mode 100644
index 0000000000..b243ba4ef8
--- /dev/null
+++ b/contrib/libs/cxxsupp/builtins/divmodti4.c
@@ -0,0 +1,32 @@
+//===-- divmodti4.c - Implement __divmodti4 -------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __divmodti4 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
+
+#include "int_lib.h"
+
+#ifdef CRT_HAS_128BIT
+
+// Returns: a / b, *rem = a % b
+
+COMPILER_RT_ABI ti_int __divmodti4(ti_int a, ti_int b, ti_int *rem) {
+ const int bits_in_tword_m1 = (int)(sizeof(ti_int) * CHAR_BIT) - 1;
+ ti_int s_a = a >> bits_in_tword_m1; // s_a = a < 0 ? -1 : 0
+ ti_int s_b = b >> bits_in_tword_m1; // s_b = b < 0 ? -1 : 0
+ a = (a ^ s_a) - s_a; // negate if s_a == -1
+ b = (b ^ s_b) - s_b; // negate if s_b == -1
+ s_b ^= s_a; // sign of quotient
+ tu_int r;
+ ti_int q = (__udivmodti4(a, b, &r) ^ s_b) - s_b; // negate if s_b == -1
+ *rem = (r ^ s_a) - s_a; // negate if s_a == -1
+ return q;
+}
+
+#endif // CRT_HAS_128BIT
diff --git a/contrib/libs/cxxsupp/builtins/divsc3.c b/contrib/libs/cxxsupp/builtins/divsc3.c
index 42a48315e6..aa4fd8e79e 100644
--- a/contrib/libs/cxxsupp/builtins/divsc3.c
+++ b/contrib/libs/cxxsupp/builtins/divsc3.c
@@ -1,60 +1,54 @@
-/*===-- divsc3.c - Implement __divsc3 -------------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __divsc3 for the compiler_rt library.
- *
- *===----------------------------------------------------------------------===
- */
+//===-- divsc3.c - Implement __divsc3 -------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __divsc3 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
+#define SINGLE_PRECISION
+#include "fp_lib.h"
#include "int_lib.h"
#include "int_math.h"
-/* Returns: the quotient of (a + ib) / (c + id) */
+// Returns: the quotient of (a + ib) / (c + id)
-COMPILER_RT_ABI Fcomplex
-__divsc3(float __a, float __b, float __c, float __d)
-{
- int __ilogbw = 0;
- float __logbw = crt_logbf(crt_fmaxf(crt_fabsf(__c), crt_fabsf(__d)));
- if (crt_isfinite(__logbw))
- {
- __ilogbw = (int)__logbw;
- __c = crt_scalbnf(__c, -__ilogbw);
- __d = crt_scalbnf(__d, -__ilogbw);
+COMPILER_RT_ABI Fcomplex __divsc3(float __a, float __b, float __c, float __d) {
+ int __ilogbw = 0;
+ float __logbw =
+ __compiler_rt_logbf(__compiler_rt_fmaxf(crt_fabsf(__c), crt_fabsf(__d)));
+ if (crt_isfinite(__logbw)) {
+ __ilogbw = (int)__logbw;
+ __c = __compiler_rt_scalbnf(__c, -__ilogbw);
+ __d = __compiler_rt_scalbnf(__d, -__ilogbw);
+ }
+ float __denom = __c * __c + __d * __d;
+ Fcomplex z;
+ COMPLEX_REAL(z) =
+ __compiler_rt_scalbnf((__a * __c + __b * __d) / __denom, -__ilogbw);
+ COMPLEX_IMAGINARY(z) =
+ __compiler_rt_scalbnf((__b * __c - __a * __d) / __denom, -__ilogbw);
+ if (crt_isnan(COMPLEX_REAL(z)) && crt_isnan(COMPLEX_IMAGINARY(z))) {
+ if ((__denom == 0) && (!crt_isnan(__a) || !crt_isnan(__b))) {
+ COMPLEX_REAL(z) = crt_copysignf(CRT_INFINITY, __c) * __a;
+ COMPLEX_IMAGINARY(z) = crt_copysignf(CRT_INFINITY, __c) * __b;
+ } else if ((crt_isinf(__a) || crt_isinf(__b)) && crt_isfinite(__c) &&
+ crt_isfinite(__d)) {
+ __a = crt_copysignf(crt_isinf(__a) ? 1 : 0, __a);
+ __b = crt_copysignf(crt_isinf(__b) ? 1 : 0, __b);
+ COMPLEX_REAL(z) = CRT_INFINITY * (__a * __c + __b * __d);
+ COMPLEX_IMAGINARY(z) = CRT_INFINITY * (__b * __c - __a * __d);
+ } else if (crt_isinf(__logbw) && __logbw > 0 && crt_isfinite(__a) &&
+ crt_isfinite(__b)) {
+ __c = crt_copysignf(crt_isinf(__c) ? 1 : 0, __c);
+ __d = crt_copysignf(crt_isinf(__d) ? 1 : 0, __d);
+ COMPLEX_REAL(z) = 0 * (__a * __c + __b * __d);
+ COMPLEX_IMAGINARY(z) = 0 * (__b * __c - __a * __d);
}
- float __denom = __c * __c + __d * __d;
- Fcomplex z;
- COMPLEX_REAL(z) = crt_scalbnf((__a * __c + __b * __d) / __denom, -__ilogbw);
- COMPLEX_IMAGINARY(z) = crt_scalbnf((__b * __c - __a * __d) / __denom, -__ilogbw);
- if (crt_isnan(COMPLEX_REAL(z)) && crt_isnan(COMPLEX_IMAGINARY(z)))
- {
- if ((__denom == 0) && (!crt_isnan(__a) || !crt_isnan(__b)))
- {
- COMPLEX_REAL(z) = crt_copysignf(CRT_INFINITY, __c) * __a;
- COMPLEX_IMAGINARY(z) = crt_copysignf(CRT_INFINITY, __c) * __b;
- }
- else if ((crt_isinf(__a) || crt_isinf(__b)) &&
- crt_isfinite(__c) && crt_isfinite(__d))
- {
- __a = crt_copysignf(crt_isinf(__a) ? 1 : 0, __a);
- __b = crt_copysignf(crt_isinf(__b) ? 1 : 0, __b);
- COMPLEX_REAL(z) = CRT_INFINITY * (__a * __c + __b * __d);
- COMPLEX_IMAGINARY(z) = CRT_INFINITY * (__b * __c - __a * __d);
- }
- else if (crt_isinf(__logbw) && __logbw > 0 &&
- crt_isfinite(__a) && crt_isfinite(__b))
- {
- __c = crt_copysignf(crt_isinf(__c) ? 1 : 0, __c);
- __d = crt_copysignf(crt_isinf(__d) ? 1 : 0, __d);
- COMPLEX_REAL(z) = 0 * (__a * __c + __b * __d);
- COMPLEX_IMAGINARY(z) = 0 * (__b * __c - __a * __d);
- }
- }
- return z;
+ }
+ return z;
}
diff --git a/contrib/libs/cxxsupp/builtins/divsf3.c b/contrib/libs/cxxsupp/builtins/divsf3.c
index de2e376125..5744c01524 100644
--- a/contrib/libs/cxxsupp/builtins/divsf3.c
+++ b/contrib/libs/cxxsupp/builtins/divsf3.c
@@ -1,169 +1,30 @@
//===-- lib/divsf3.c - Single-precision division ------------------*- C -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file implements single-precision soft-float division
// with the IEEE-754 default rounding (to nearest, ties to even).
//
-// For simplicity, this implementation currently flushes denormals to zero.
-// It should be a fairly straightforward exercise to implement gradual
-// underflow with correct rounding.
-//
//===----------------------------------------------------------------------===//
#define SINGLE_PRECISION
-#include "fp_lib.h"
-ARM_EABI_FNALIAS(fdiv, divsf3)
+#define NUMBER_OF_HALF_ITERATIONS 0
+#define NUMBER_OF_FULL_ITERATIONS 3
+#define USE_NATIVE_FULL_ITERATIONS
+
+#include "fp_div_impl.inc"
-COMPILER_RT_ABI fp_t
-__divsf3(fp_t a, fp_t b) {
-
- const unsigned int aExponent = toRep(a) >> significandBits & maxExponent;
- const unsigned int bExponent = toRep(b) >> significandBits & maxExponent;
- const rep_t quotientSign = (toRep(a) ^ toRep(b)) & signBit;
-
- rep_t aSignificand = toRep(a) & significandMask;
- rep_t bSignificand = toRep(b) & significandMask;
- int scale = 0;
-
- // Detect if a or b is zero, denormal, infinity, or NaN.
- if (aExponent-1U >= maxExponent-1U || bExponent-1U >= maxExponent-1U) {
-
- const rep_t aAbs = toRep(a) & absMask;
- const rep_t bAbs = toRep(b) & absMask;
-
- // NaN / anything = qNaN
- if (aAbs > infRep) return fromRep(toRep(a) | quietBit);
- // anything / NaN = qNaN
- if (bAbs > infRep) return fromRep(toRep(b) | quietBit);
-
- if (aAbs == infRep) {
- // infinity / infinity = NaN
- if (bAbs == infRep) return fromRep(qnanRep);
- // infinity / anything else = +/- infinity
- else return fromRep(aAbs | quotientSign);
- }
-
- // anything else / infinity = +/- 0
- if (bAbs == infRep) return fromRep(quotientSign);
-
- if (!aAbs) {
- // zero / zero = NaN
- if (!bAbs) return fromRep(qnanRep);
- // zero / anything else = +/- zero
- else return fromRep(quotientSign);
- }
- // anything else / zero = +/- infinity
- if (!bAbs) return fromRep(infRep | quotientSign);
-
- // one or both of a or b is denormal, the other (if applicable) is a
- // normal number. Renormalize one or both of a and b, and set scale to
- // include the necessary exponent adjustment.
- if (aAbs < implicitBit) scale += normalize(&aSignificand);
- if (bAbs < implicitBit) scale -= normalize(&bSignificand);
- }
-
- // Or in the implicit significand bit. (If we fell through from the
- // denormal path it was already set by normalize( ), but setting it twice
- // won't hurt anything.)
- aSignificand |= implicitBit;
- bSignificand |= implicitBit;
- int quotientExponent = aExponent - bExponent + scale;
-
- // Align the significand of b as a Q31 fixed-point number in the range
- // [1, 2.0) and get a Q32 approximate reciprocal using a small minimax
- // polynomial approximation: reciprocal = 3/4 + 1/sqrt(2) - b/2. This
- // is accurate to about 3.5 binary digits.
- uint32_t q31b = bSignificand << 8;
- uint32_t reciprocal = UINT32_C(0x7504f333) - q31b;
-
- // Now refine the reciprocal estimate using a Newton-Raphson iteration:
- //
- // x1 = x0 * (2 - x0 * b)
- //
- // This doubles the number of correct binary digits in the approximation
- // with each iteration, so after three iterations, we have about 28 binary
- // digits of accuracy.
- uint32_t correction;
- correction = -((uint64_t)reciprocal * q31b >> 32);
- reciprocal = (uint64_t)reciprocal * correction >> 31;
- correction = -((uint64_t)reciprocal * q31b >> 32);
- reciprocal = (uint64_t)reciprocal * correction >> 31;
- correction = -((uint64_t)reciprocal * q31b >> 32);
- reciprocal = (uint64_t)reciprocal * correction >> 31;
-
- // Exhaustive testing shows that the error in reciprocal after three steps
- // is in the interval [-0x1.f58108p-31, 0x1.d0e48cp-29], in line with our
- // expectations. We bump the reciprocal by a tiny value to force the error
- // to be strictly positive (in the range [0x1.4fdfp-37,0x1.287246p-29], to
- // be specific). This also causes 1/1 to give a sensible approximation
- // instead of zero (due to overflow).
- reciprocal -= 2;
-
- // The numerical reciprocal is accurate to within 2^-28, lies in the
- // interval [0x1.000000eep-1, 0x1.fffffffcp-1], and is strictly smaller
- // than the true reciprocal of b. Multiplying a by this reciprocal thus
- // gives a numerical q = a/b in Q24 with the following properties:
- //
- // 1. q < a/b
- // 2. q is in the interval [0x1.000000eep-1, 0x1.fffffffcp0)
- // 3. the error in q is at most 2^-24 + 2^-27 -- the 2^24 term comes
- // from the fact that we truncate the product, and the 2^27 term
- // is the error in the reciprocal of b scaled by the maximum
- // possible value of a. As a consequence of this error bound,
- // either q or nextafter(q) is the correctly rounded
- rep_t quotient = (uint64_t)reciprocal*(aSignificand << 1) >> 32;
-
- // Two cases: quotient is in [0.5, 1.0) or quotient is in [1.0, 2.0).
- // In either case, we are going to compute a residual of the form
- //
- // r = a - q*b
- //
- // We know from the construction of q that r satisfies:
- //
- // 0 <= r < ulp(q)*b
- //
- // if r is greater than 1/2 ulp(q)*b, then q rounds up. Otherwise, we
- // already have the correct result. The exact halfway case cannot occur.
- // We also take this time to right shift quotient if it falls in the [1,2)
- // range and adjust the exponent accordingly.
- rep_t residual;
- if (quotient < (implicitBit << 1)) {
- residual = (aSignificand << 24) - quotient * bSignificand;
- quotientExponent--;
- } else {
- quotient >>= 1;
- residual = (aSignificand << 23) - quotient * bSignificand;
- }
+COMPILER_RT_ABI fp_t __divsf3(fp_t a, fp_t b) { return __divXf3__(a, b); }
- const int writtenExponent = quotientExponent + exponentBias;
-
- if (writtenExponent >= maxExponent) {
- // If we have overflowed the exponent, return infinity.
- return fromRep(infRep | quotientSign);
- }
-
- else if (writtenExponent < 1) {
- // Flush denormals to zero. In the future, it would be nice to add
- // code to round them correctly.
- return fromRep(quotientSign);
- }
-
- else {
- const bool round = (residual << 1) > bSignificand;
- // Clear the implicit bit
- rep_t absResult = quotient & significandMask;
- // Insert the exponent
- absResult |= (rep_t)writtenExponent << significandBits;
- // Round
- absResult += round;
- // Insert the sign and return
- return fromRep(absResult | quotientSign);
- }
-}
+#if defined(__ARM_EABI__)
+#if defined(COMPILER_RT_ARMHF_TARGET)
+AEABI_RTABI fp_t __aeabi_fdiv(fp_t a, fp_t b) { return __divsf3(a, b); }
+#else
+COMPILER_RT_ALIAS(__divsf3, __aeabi_fdiv)
+#endif
+#endif
diff --git a/contrib/libs/cxxsupp/builtins/divsi3.c b/contrib/libs/cxxsupp/builtins/divsi3.c
index bab4aefda3..f514407477 100644
--- a/contrib/libs/cxxsupp/builtins/divsi3.c
+++ b/contrib/libs/cxxsupp/builtins/divsi3.c
@@ -1,37 +1,30 @@
-/* ===-- divsi3.c - Implement __divsi3 -------------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __divsi3 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- divsi3.c - Implement __divsi3 -------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __divsi3 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
-/* Returns: a / b */
+// Returns: a / b
-ARM_EABI_FNALIAS(idiv, divsi3)
+#define fixint_t si_int
+#define fixuint_t su_int
+// On CPUs without unsigned hardware division support,
+// this calls __udivsi3 (notice the cast to su_int).
+// On CPUs with unsigned hardware division support,
+// this uses the unsigned division instruction.
+#define COMPUTE_UDIV(a, b) ((su_int)(a) / (su_int)(b))
+#include "int_div_impl.inc"
-COMPILER_RT_ABI si_int
-__divsi3(si_int a, si_int b)
-{
- const int bits_in_word_m1 = (int)(sizeof(si_int) * CHAR_BIT) - 1;
- si_int s_a = a >> bits_in_word_m1; /* s_a = a < 0 ? -1 : 0 */
- si_int s_b = b >> bits_in_word_m1; /* s_b = b < 0 ? -1 : 0 */
- a = (a ^ s_a) - s_a; /* negate if s_a == -1 */
- b = (b ^ s_b) - s_b; /* negate if s_b == -1 */
- s_a ^= s_b; /* sign of quotient */
- /*
- * On CPUs without unsigned hardware division support,
- * this calls __udivsi3 (notice the cast to su_int).
- * On CPUs with unsigned hardware division support,
- * this uses the unsigned division instruction.
- */
- return ((su_int)a/(su_int)b ^ s_a) - s_a; /* negate if s_a == -1 */
-}
+COMPILER_RT_ABI si_int __divsi3(si_int a, si_int b) { return __divXi3(a, b); }
+
+#if defined(__ARM_EABI__)
+COMPILER_RT_ALIAS(__divsi3, __aeabi_idiv)
+#endif
diff --git a/contrib/libs/cxxsupp/builtins/divtc3.c b/contrib/libs/cxxsupp/builtins/divtc3.c
index 04693df471..0e4799295f 100644
--- a/contrib/libs/cxxsupp/builtins/divtc3.c
+++ b/contrib/libs/cxxsupp/builtins/divtc3.c
@@ -1,60 +1,55 @@
-/*===-- divtc3.c - Implement __divtc3 -------------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __divtc3 for the compiler_rt library.
- *
- *===----------------------------------------------------------------------===
- */
+//===-- divtc3.c - Implement __divtc3 -------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __divtc3 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
+#define QUAD_PRECISION
+#include "fp_lib.h"
#include "int_lib.h"
#include "int_math.h"
-/* Returns: the quotient of (a + ib) / (c + id) */
+// Returns: the quotient of (a + ib) / (c + id)
-COMPILER_RT_ABI long double _Complex
-__divtc3(long double __a, long double __b, long double __c, long double __d)
-{
- int __ilogbw = 0;
- long double __logbw = crt_logbl(crt_fmaxl(crt_fabsl(__c), crt_fabsl(__d)));
- if (crt_isfinite(__logbw))
- {
- __ilogbw = (int)__logbw;
- __c = crt_scalbnl(__c, -__ilogbw);
- __d = crt_scalbnl(__d, -__ilogbw);
+COMPILER_RT_ABI Lcomplex __divtc3(long double __a, long double __b,
+ long double __c, long double __d) {
+ int __ilogbw = 0;
+ long double __logbw =
+ __compiler_rt_logbl(__compiler_rt_fmaxl(crt_fabsl(__c), crt_fabsl(__d)));
+ if (crt_isfinite(__logbw)) {
+ __ilogbw = (int)__logbw;
+ __c = __compiler_rt_scalbnl(__c, -__ilogbw);
+ __d = __compiler_rt_scalbnl(__d, -__ilogbw);
+ }
+ long double __denom = __c * __c + __d * __d;
+ Lcomplex z;
+ COMPLEX_REAL(z) =
+ __compiler_rt_scalbnl((__a * __c + __b * __d) / __denom, -__ilogbw);
+ COMPLEX_IMAGINARY(z) =
+ __compiler_rt_scalbnl((__b * __c - __a * __d) / __denom, -__ilogbw);
+ if (crt_isnan(COMPLEX_REAL(z)) && crt_isnan(COMPLEX_IMAGINARY(z))) {
+ if ((__denom == 0.0) && (!crt_isnan(__a) || !crt_isnan(__b))) {
+ COMPLEX_REAL(z) = crt_copysignl(CRT_INFINITY, __c) * __a;
+ COMPLEX_IMAGINARY(z) = crt_copysignl(CRT_INFINITY, __c) * __b;
+ } else if ((crt_isinf(__a) || crt_isinf(__b)) && crt_isfinite(__c) &&
+ crt_isfinite(__d)) {
+ __a = crt_copysignl(crt_isinf(__a) ? 1.0 : 0.0, __a);
+ __b = crt_copysignl(crt_isinf(__b) ? 1.0 : 0.0, __b);
+ COMPLEX_REAL(z) = CRT_INFINITY * (__a * __c + __b * __d);
+ COMPLEX_IMAGINARY(z) = CRT_INFINITY * (__b * __c - __a * __d);
+ } else if (crt_isinf(__logbw) && __logbw > 0.0 && crt_isfinite(__a) &&
+ crt_isfinite(__b)) {
+ __c = crt_copysignl(crt_isinf(__c) ? 1.0 : 0.0, __c);
+ __d = crt_copysignl(crt_isinf(__d) ? 1.0 : 0.0, __d);
+ COMPLEX_REAL(z) = 0.0 * (__a * __c + __b * __d);
+ COMPLEX_IMAGINARY(z) = 0.0 * (__b * __c - __a * __d);
}
- long double __denom = __c * __c + __d * __d;
- long double _Complex z;
- __real__ z = crt_scalbnl((__a * __c + __b * __d) / __denom, -__ilogbw);
- __imag__ z = crt_scalbnl((__b * __c - __a * __d) / __denom, -__ilogbw);
- if (crt_isnan(__real__ z) && crt_isnan(__imag__ z))
- {
- if ((__denom == 0.0) && (!crt_isnan(__a) || !crt_isnan(__b)))
- {
- __real__ z = crt_copysignl(CRT_INFINITY, __c) * __a;
- __imag__ z = crt_copysignl(CRT_INFINITY, __c) * __b;
- }
- else if ((crt_isinf(__a) || crt_isinf(__b)) &&
- crt_isfinite(__c) && crt_isfinite(__d))
- {
- __a = crt_copysignl(crt_isinf(__a) ? 1.0 : 0.0, __a);
- __b = crt_copysignl(crt_isinf(__b) ? 1.0 : 0.0, __b);
- __real__ z = CRT_INFINITY * (__a * __c + __b * __d);
- __imag__ z = CRT_INFINITY * (__b * __c - __a * __d);
- }
- else if (crt_isinf(__logbw) && __logbw > 0.0 &&
- crt_isfinite(__a) && crt_isfinite(__b))
- {
- __c = crt_copysignl(crt_isinf(__c) ? 1.0 : 0.0, __c);
- __d = crt_copysignl(crt_isinf(__d) ? 1.0 : 0.0, __d);
- __real__ z = 0.0 * (__a * __c + __b * __d);
- __imag__ z = 0.0 * (__b * __c - __a * __d);
- }
- }
- return z;
+ }
+ return z;
}
diff --git a/contrib/libs/cxxsupp/builtins/divtf3.c b/contrib/libs/cxxsupp/builtins/divtf3.c
index e81dab826b..5bcc9a8e4a 100644
--- a/contrib/libs/cxxsupp/builtins/divtf3.c
+++ b/contrib/libs/cxxsupp/builtins/divtf3.c
@@ -1,203 +1,26 @@
//===-- lib/divtf3.c - Quad-precision division --------------------*- C -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file implements quad-precision soft-float division
// with the IEEE-754 default rounding (to nearest, ties to even).
//
-// For simplicity, this implementation currently flushes denormals to zero.
-// It should be a fairly straightforward exercise to implement gradual
-// underflow with correct rounding.
-//
//===----------------------------------------------------------------------===//
#define QUAD_PRECISION
#include "fp_lib.h"
#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT)
-COMPILER_RT_ABI fp_t __divtf3(fp_t a, fp_t b) {
-
- const unsigned int aExponent = toRep(a) >> significandBits & maxExponent;
- const unsigned int bExponent = toRep(b) >> significandBits & maxExponent;
- const rep_t quotientSign = (toRep(a) ^ toRep(b)) & signBit;
-
- rep_t aSignificand = toRep(a) & significandMask;
- rep_t bSignificand = toRep(b) & significandMask;
- int scale = 0;
-
- // Detect if a or b is zero, denormal, infinity, or NaN.
- if (aExponent-1U >= maxExponent-1U || bExponent-1U >= maxExponent-1U) {
-
- const rep_t aAbs = toRep(a) & absMask;
- const rep_t bAbs = toRep(b) & absMask;
-
- // NaN / anything = qNaN
- if (aAbs > infRep) return fromRep(toRep(a) | quietBit);
- // anything / NaN = qNaN
- if (bAbs > infRep) return fromRep(toRep(b) | quietBit);
-
- if (aAbs == infRep) {
- // infinity / infinity = NaN
- if (bAbs == infRep) return fromRep(qnanRep);
- // infinity / anything else = +/- infinity
- else return fromRep(aAbs | quotientSign);
- }
-
- // anything else / infinity = +/- 0
- if (bAbs == infRep) return fromRep(quotientSign);
-
- if (!aAbs) {
- // zero / zero = NaN
- if (!bAbs) return fromRep(qnanRep);
- // zero / anything else = +/- zero
- else return fromRep(quotientSign);
- }
- // anything else / zero = +/- infinity
- if (!bAbs) return fromRep(infRep | quotientSign);
-
- // one or both of a or b is denormal, the other (if applicable) is a
- // normal number. Renormalize one or both of a and b, and set scale to
- // include the necessary exponent adjustment.
- if (aAbs < implicitBit) scale += normalize(&aSignificand);
- if (bAbs < implicitBit) scale -= normalize(&bSignificand);
- }
-
- // Or in the implicit significand bit. (If we fell through from the
- // denormal path it was already set by normalize( ), but setting it twice
- // won't hurt anything.)
- aSignificand |= implicitBit;
- bSignificand |= implicitBit;
- int quotientExponent = aExponent - bExponent + scale;
-
- // Align the significand of b as a Q63 fixed-point number in the range
- // [1, 2.0) and get a Q64 approximate reciprocal using a small minimax
- // polynomial approximation: reciprocal = 3/4 + 1/sqrt(2) - b/2. This
- // is accurate to about 3.5 binary digits.
- const uint64_t q63b = bSignificand >> 49;
- uint64_t recip64 = UINT64_C(0x7504f333F9DE6484) - q63b;
- // 0x7504f333F9DE6484 / 2^64 + 1 = 3/4 + 1/sqrt(2)
-
- // Now refine the reciprocal estimate using a Newton-Raphson iteration:
- //
- // x1 = x0 * (2 - x0 * b)
- //
- // This doubles the number of correct binary digits in the approximation
- // with each iteration.
- uint64_t correction64;
- correction64 = -((rep_t)recip64 * q63b >> 64);
- recip64 = (rep_t)recip64 * correction64 >> 63;
- correction64 = -((rep_t)recip64 * q63b >> 64);
- recip64 = (rep_t)recip64 * correction64 >> 63;
- correction64 = -((rep_t)recip64 * q63b >> 64);
- recip64 = (rep_t)recip64 * correction64 >> 63;
- correction64 = -((rep_t)recip64 * q63b >> 64);
- recip64 = (rep_t)recip64 * correction64 >> 63;
- correction64 = -((rep_t)recip64 * q63b >> 64);
- recip64 = (rep_t)recip64 * correction64 >> 63;
-
- // recip64 might have overflowed to exactly zero in the preceeding
- // computation if the high word of b is exactly 1.0. This would sabotage
- // the full-width final stage of the computation that follows, so we adjust
- // recip64 downward by one bit.
- recip64--;
-
- // We need to perform one more iteration to get us to 112 binary digits;
- // The last iteration needs to happen with extra precision.
- const uint64_t q127blo = bSignificand << 15;
- rep_t correction, reciprocal;
-
- // NOTE: This operation is equivalent to __multi3, which is not implemented
- // in some architechure
- rep_t r64q63, r64q127, r64cH, r64cL, dummy;
- wideMultiply((rep_t)recip64, (rep_t)q63b, &dummy, &r64q63);
- wideMultiply((rep_t)recip64, (rep_t)q127blo, &dummy, &r64q127);
-
- correction = -(r64q63 + (r64q127 >> 64));
-
- uint64_t cHi = correction >> 64;
- uint64_t cLo = correction;
-
- wideMultiply((rep_t)recip64, (rep_t)cHi, &dummy, &r64cH);
- wideMultiply((rep_t)recip64, (rep_t)cLo, &dummy, &r64cL);
-
- reciprocal = r64cH + (r64cL >> 64);
-
- // We already adjusted the 64-bit estimate, now we need to adjust the final
- // 128-bit reciprocal estimate downward to ensure that it is strictly smaller
- // than the infinitely precise exact reciprocal. Because the computation
- // of the Newton-Raphson step is truncating at every step, this adjustment
- // is small; most of the work is already done.
- reciprocal -= 2;
-
- // The numerical reciprocal is accurate to within 2^-112, lies in the
- // interval [0.5, 1.0), and is strictly smaller than the true reciprocal
- // of b. Multiplying a by this reciprocal thus gives a numerical q = a/b
- // in Q127 with the following properties:
- //
- // 1. q < a/b
- // 2. q is in the interval [0.5, 2.0)
- // 3. the error in q is bounded away from 2^-113 (actually, we have a
- // couple of bits to spare, but this is all we need).
-
- // We need a 128 x 128 multiply high to compute q, which isn't a basic
- // operation in C, so we need to be a little bit fussy.
- rep_t quotient, quotientLo;
- wideMultiply(aSignificand << 2, reciprocal, &quotient, &quotientLo);
-
- // Two cases: quotient is in [0.5, 1.0) or quotient is in [1.0, 2.0).
- // In either case, we are going to compute a residual of the form
- //
- // r = a - q*b
- //
- // We know from the construction of q that r satisfies:
- //
- // 0 <= r < ulp(q)*b
- //
- // if r is greater than 1/2 ulp(q)*b, then q rounds up. Otherwise, we
- // already have the correct result. The exact halfway case cannot occur.
- // We also take this time to right shift quotient if it falls in the [1,2)
- // range and adjust the exponent accordingly.
- rep_t residual;
- rep_t qb;
- if (quotient < (implicitBit << 1)) {
- wideMultiply(quotient, bSignificand, &dummy, &qb);
- residual = (aSignificand << 113) - qb;
- quotientExponent--;
- } else {
- quotient >>= 1;
- wideMultiply(quotient, bSignificand, &dummy, &qb);
- residual = (aSignificand << 112) - qb;
- }
+#define NUMBER_OF_HALF_ITERATIONS 4
+#define NUMBER_OF_FULL_ITERATIONS 1
- const int writtenExponent = quotientExponent + exponentBias;
+#include "fp_div_impl.inc"
- if (writtenExponent >= maxExponent) {
- // If we have overflowed the exponent, return infinity.
- return fromRep(infRep | quotientSign);
- }
- else if (writtenExponent < 1) {
- // Flush denormals to zero. In the future, it would be nice to add
- // code to round them correctly.
- return fromRep(quotientSign);
- }
- else {
- const bool round = (residual << 1) >= bSignificand;
- // Clear the implicit bit
- rep_t absResult = quotient & significandMask;
- // Insert the exponent
- absResult |= (rep_t)writtenExponent << significandBits;
- // Round
- absResult += round;
- // Insert the sign and return
- const long double result = fromRep(absResult | quotientSign);
- return result;
- }
-}
+COMPILER_RT_ABI fp_t __divtf3(fp_t a, fp_t b) { return __divXf3__(a, b); }
#endif
diff --git a/contrib/libs/cxxsupp/builtins/divti3.c b/contrib/libs/cxxsupp/builtins/divti3.c
index c73eae28fe..80f2130b59 100644
--- a/contrib/libs/cxxsupp/builtins/divti3.c
+++ b/contrib/libs/cxxsupp/builtins/divti3.c
@@ -1,33 +1,26 @@
-/* ===-- divti3.c - Implement __divti3 -------------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __divti3 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- divti3.c - Implement __divti3 -------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __divti3 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
#ifdef CRT_HAS_128BIT
-/* Returns: a / b */
+// Returns: a / b
-COMPILER_RT_ABI ti_int
-__divti3(ti_int a, ti_int b)
-{
- const int bits_in_tword_m1 = (int)(sizeof(ti_int) * CHAR_BIT) - 1;
- ti_int s_a = a >> bits_in_tword_m1; /* s_a = a < 0 ? -1 : 0 */
- ti_int s_b = b >> bits_in_tword_m1; /* s_b = b < 0 ? -1 : 0 */
- a = (a ^ s_a) - s_a; /* negate if s_a == -1 */
- b = (b ^ s_b) - s_b; /* negate if s_b == -1 */
- s_a ^= s_b; /* sign of quotient */
- return (__udivmodti4(a, b, (tu_int*)0) ^ s_a) - s_a; /* negate if s_a == -1 */
-}
+#define fixint_t ti_int
+#define fixuint_t tu_int
+#define COMPUTE_UDIV(a, b) __udivmodti4((a), (b), (tu_int *)0)
+#include "int_div_impl.inc"
-#endif /* CRT_HAS_128BIT */
+COMPILER_RT_ABI ti_int __divti3(ti_int a, ti_int b) { return __divXi3(a, b); }
+
+#endif // CRT_HAS_128BIT
diff --git a/contrib/libs/cxxsupp/builtins/divxc3.c b/contrib/libs/cxxsupp/builtins/divxc3.c
index 6f49280e5f..97ffd2eac2 100644
--- a/contrib/libs/cxxsupp/builtins/divxc3.c
+++ b/contrib/libs/cxxsupp/builtins/divxc3.c
@@ -1,63 +1,55 @@
-/* ===-- divxc3.c - Implement __divxc3 -------------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __divxc3 for the compiler_rt library.
- *
- */
+//===-- divxc3.c - Implement __divxc3 -------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __divxc3 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#if !_ARCH_PPC
#include "int_lib.h"
#include "int_math.h"
-/* Returns: the quotient of (a + ib) / (c + id) */
+// Returns: the quotient of (a + ib) / (c + id)
-COMPILER_RT_ABI Lcomplex
-__divxc3(long double __a, long double __b, long double __c, long double __d)
-{
- int __ilogbw = 0;
- long double __logbw = crt_logbl(crt_fmaxl(crt_fabsl(__c), crt_fabsl(__d)));
- if (crt_isfinite(__logbw))
- {
- __ilogbw = (int)__logbw;
- __c = crt_scalbnl(__c, -__ilogbw);
- __d = crt_scalbnl(__d, -__ilogbw);
+COMPILER_RT_ABI Lcomplex __divxc3(long double __a, long double __b,
+ long double __c, long double __d) {
+ int __ilogbw = 0;
+ long double __logbw = crt_logbl(crt_fmaxl(crt_fabsl(__c), crt_fabsl(__d)));
+ if (crt_isfinite(__logbw)) {
+ __ilogbw = (int)__logbw;
+ __c = crt_scalbnl(__c, -__ilogbw);
+ __d = crt_scalbnl(__d, -__ilogbw);
+ }
+ long double __denom = __c * __c + __d * __d;
+ Lcomplex z;
+ COMPLEX_REAL(z) = crt_scalbnl((__a * __c + __b * __d) / __denom, -__ilogbw);
+ COMPLEX_IMAGINARY(z) =
+ crt_scalbnl((__b * __c - __a * __d) / __denom, -__ilogbw);
+ if (crt_isnan(COMPLEX_REAL(z)) && crt_isnan(COMPLEX_IMAGINARY(z))) {
+ if ((__denom == 0) && (!crt_isnan(__a) || !crt_isnan(__b))) {
+ COMPLEX_REAL(z) = crt_copysignl(CRT_INFINITY, __c) * __a;
+ COMPLEX_IMAGINARY(z) = crt_copysignl(CRT_INFINITY, __c) * __b;
+ } else if ((crt_isinf(__a) || crt_isinf(__b)) && crt_isfinite(__c) &&
+ crt_isfinite(__d)) {
+ __a = crt_copysignl(crt_isinf(__a) ? 1 : 0, __a);
+ __b = crt_copysignl(crt_isinf(__b) ? 1 : 0, __b);
+ COMPLEX_REAL(z) = CRT_INFINITY * (__a * __c + __b * __d);
+ COMPLEX_IMAGINARY(z) = CRT_INFINITY * (__b * __c - __a * __d);
+ } else if (crt_isinf(__logbw) && __logbw > 0 && crt_isfinite(__a) &&
+ crt_isfinite(__b)) {
+ __c = crt_copysignl(crt_isinf(__c) ? 1 : 0, __c);
+ __d = crt_copysignl(crt_isinf(__d) ? 1 : 0, __d);
+ COMPLEX_REAL(z) = 0 * (__a * __c + __b * __d);
+ COMPLEX_IMAGINARY(z) = 0 * (__b * __c - __a * __d);
}
- long double __denom = __c * __c + __d * __d;
- Lcomplex z;
- COMPLEX_REAL(z) = crt_scalbnl((__a * __c + __b * __d) / __denom, -__ilogbw);
- COMPLEX_IMAGINARY(z) = crt_scalbnl((__b * __c - __a * __d) / __denom, -__ilogbw);
- if (crt_isnan(COMPLEX_REAL(z)) && crt_isnan(COMPLEX_IMAGINARY(z)))
- {
- if ((__denom == 0) && (!crt_isnan(__a) || !crt_isnan(__b)))
- {
- COMPLEX_REAL(z) = crt_copysignl(CRT_INFINITY, __c) * __a;
- COMPLEX_IMAGINARY(z) = crt_copysignl(CRT_INFINITY, __c) * __b;
- }
- else if ((crt_isinf(__a) || crt_isinf(__b)) &&
- crt_isfinite(__c) && crt_isfinite(__d))
- {
- __a = crt_copysignl(crt_isinf(__a) ? 1 : 0, __a);
- __b = crt_copysignl(crt_isinf(__b) ? 1 : 0, __b);
- COMPLEX_REAL(z) = CRT_INFINITY * (__a * __c + __b * __d);
- COMPLEX_IMAGINARY(z) = CRT_INFINITY * (__b * __c - __a * __d);
- }
- else if (crt_isinf(__logbw) && __logbw > 0 &&
- crt_isfinite(__a) && crt_isfinite(__b))
- {
- __c = crt_copysignl(crt_isinf(__c) ? 1 : 0, __c);
- __d = crt_copysignl(crt_isinf(__d) ? 1 : 0, __d);
- COMPLEX_REAL(z) = 0 * (__a * __c + __b * __d);
- COMPLEX_IMAGINARY(z) = 0 * (__b * __c - __a * __d);
- }
- }
- return z;
+ }
+ return z;
}
#endif
diff --git a/contrib/libs/cxxsupp/builtins/emutls.c b/contrib/libs/cxxsupp/builtins/emutls.c
index 09e79568bd..390ffb25f6 100644
--- a/contrib/libs/cxxsupp/builtins/emutls.c
+++ b/contrib/libs/cxxsupp/builtins/emutls.c
@@ -1,183 +1,408 @@
-/* ===---------- emutls.c - Implements __emutls_get_address ---------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- */
-#include <pthread.h>
+//===---------- emutls.c - Implements __emutls_get_address ---------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "int_lib.h"
-#include "int_util.h"
-/* Default is not to use posix_memalign, so systems like Android
- * can use thread local data without heavier POSIX memory allocators.
- */
+#ifdef __BIONIC__
+// There are 4 pthread key cleanup rounds on Bionic. Delay emutls deallocation
+// to round 2. We need to delay deallocation because:
+// - Android versions older than M lack __cxa_thread_atexit_impl, so apps
+// use a pthread key destructor to call C++ destructors.
+// - Apps might use __thread/thread_local variables in pthread destructors.
+// We can't wait until the final two rounds, because jemalloc needs two rounds
+// after the final malloc/free call to free its thread-specific data (see
+// https://reviews.llvm.org/D46978#1107507).
+#define EMUTLS_SKIP_DESTRUCTOR_ROUNDS 1
+#else
+#define EMUTLS_SKIP_DESTRUCTOR_ROUNDS 0
+#endif
+
+#if defined(_MSC_VER) && !defined(__clang__)
+// MSVC raises a warning about a nonstandard extension being used for the 0
+// sized element in this array. Disable this for warn-as-error builds.
+#pragma warning(push)
+#pragma warning(disable : 4200)
+#endif
+
+typedef struct emutls_address_array {
+ uintptr_t skip_destructor_rounds;
+ uintptr_t size; // number of elements in the 'data' array
+ void *data[];
+} emutls_address_array;
+
+#if defined(_MSC_VER) && !defined(__clang__)
+#pragma warning(pop)
+#endif
+
+static void emutls_shutdown(emutls_address_array *array);
+
+#ifndef _WIN32
+
+#include <pthread.h>
+
+static pthread_mutex_t emutls_mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_key_t emutls_pthread_key;
+static bool emutls_key_created = false;
+
+typedef unsigned int gcc_word __attribute__((mode(word)));
+typedef unsigned int gcc_pointer __attribute__((mode(pointer)));
+
+// Default is not to use posix_memalign, so systems like Android
+// can use thread local data without heavier POSIX memory allocators.
#ifndef EMUTLS_USE_POSIX_MEMALIGN
#define EMUTLS_USE_POSIX_MEMALIGN 0
#endif
-/* For every TLS variable xyz,
- * there is one __emutls_control variable named __emutls_v.xyz.
- * If xyz has non-zero initial value, __emutls_v.xyz's "value"
- * will point to __emutls_t.xyz, which has the initial value.
- */
-typedef struct __emutls_control {
- size_t size; /* size of the object in bytes */
- size_t align; /* alignment of the object in bytes */
- union {
- uintptr_t index; /* data[index-1] is the object address */
- void* address; /* object address, when in single thread env */
- } object;
- void* value; /* null or non-zero initial value for the object */
-} __emutls_control;
-
static __inline void *emutls_memalign_alloc(size_t align, size_t size) {
- void *base;
+ void *base;
#if EMUTLS_USE_POSIX_MEMALIGN
- if (posix_memalign(&base, align, size) != 0)
- abort();
+ if (posix_memalign(&base, align, size) != 0)
+ abort();
#else
- #define EXTRA_ALIGN_PTR_BYTES (align - 1 + sizeof(void*))
- char* object;
- if ((object = malloc(EXTRA_ALIGN_PTR_BYTES + size)) == NULL)
- abort();
- base = (void*)(((uintptr_t)(object + EXTRA_ALIGN_PTR_BYTES))
- & ~(uintptr_t)(align - 1));
-
- ((void**)base)[-1] = object;
+#define EXTRA_ALIGN_PTR_BYTES (align - 1 + sizeof(void *))
+ char *object;
+ if ((object = (char *)malloc(EXTRA_ALIGN_PTR_BYTES + size)) == NULL)
+ abort();
+ base = (void *)(((uintptr_t)(object + EXTRA_ALIGN_PTR_BYTES)) &
+ ~(uintptr_t)(align - 1));
+
+ ((void **)base)[-1] = object;
#endif
- return base;
+ return base;
}
static __inline void emutls_memalign_free(void *base) {
#if EMUTLS_USE_POSIX_MEMALIGN
- free(base);
+ free(base);
#else
- /* The mallocated address is in ((void**)base)[-1] */
- free(((void**)base)[-1]);
+ // The mallocated address is in ((void**)base)[-1]
+ free(((void **)base)[-1]);
#endif
}
-/* Emulated TLS objects are always allocated at run-time. */
-static __inline void *emutls_allocate_object(__emutls_control *control) {
- /* Use standard C types, check with gcc's emutls.o. */
- typedef unsigned int gcc_word __attribute__((mode(word)));
- typedef unsigned int gcc_pointer __attribute__((mode(pointer)));
- COMPILE_TIME_ASSERT(sizeof(size_t) == sizeof(gcc_word));
- COMPILE_TIME_ASSERT(sizeof(uintptr_t) == sizeof(gcc_pointer));
- COMPILE_TIME_ASSERT(sizeof(uintptr_t) == sizeof(void*));
-
- size_t size = control->size;
- size_t align = control->align;
- if (align < sizeof(void*))
- align = sizeof(void*);
- /* Make sure that align is power of 2. */
- if ((align & (align - 1)) != 0)
- abort();
-
- void* base = emutls_memalign_alloc(align, size);
- if (control->value)
- memcpy(base, control->value, size);
- else
- memset(base, 0, size);
- return base;
+static __inline void emutls_setspecific(emutls_address_array *value) {
+ pthread_setspecific(emutls_pthread_key, (void *)value);
}
-static pthread_mutex_t emutls_mutex = PTHREAD_MUTEX_INITIALIZER;
+static __inline emutls_address_array *emutls_getspecific(void) {
+ return (emutls_address_array *)pthread_getspecific(emutls_pthread_key);
+}
-static size_t emutls_num_object = 0; /* number of allocated TLS objects */
+static void emutls_key_destructor(void *ptr) {
+ emutls_address_array *array = (emutls_address_array *)ptr;
+ if (array->skip_destructor_rounds > 0) {
+ // emutls is deallocated using a pthread key destructor. These
+ // destructors are called in several rounds to accommodate destructor
+ // functions that (re)initialize key values with pthread_setspecific.
+ // Delay the emutls deallocation to accommodate other end-of-thread
+ // cleanup tasks like calling thread_local destructors (e.g. the
+ // __cxa_thread_atexit fallback in libc++abi).
+ array->skip_destructor_rounds--;
+ emutls_setspecific(array);
+ } else {
+ emutls_shutdown(array);
+ free(ptr);
+ }
+}
-typedef struct emutls_address_array {
- uintptr_t size; /* number of elements in the 'data' array */
- void* data[];
-} emutls_address_array;
+static __inline void emutls_init(void) {
+ if (pthread_key_create(&emutls_pthread_key, emutls_key_destructor) != 0)
+ abort();
+ emutls_key_created = true;
+}
-static pthread_key_t emutls_pthread_key;
+static __inline void emutls_init_once(void) {
+ static pthread_once_t once = PTHREAD_ONCE_INIT;
+ pthread_once(&once, emutls_init);
+}
+
+static __inline void emutls_lock(void) { pthread_mutex_lock(&emutls_mutex); }
+
+static __inline void emutls_unlock(void) { pthread_mutex_unlock(&emutls_mutex); }
+
+#else // _WIN32
+
+#include <assert.h>
+#include <malloc.h>
+#include <stdio.h>
+#include <windows.h>
-static void emutls_key_destructor(void* ptr) {
- emutls_address_array* array = (emutls_address_array*)ptr;
+static LPCRITICAL_SECTION emutls_mutex;
+static DWORD emutls_tls_index = TLS_OUT_OF_INDEXES;
+
+typedef uintptr_t gcc_word;
+typedef void *gcc_pointer;
+
+static void win_error(DWORD last_err, const char *hint) {
+ char *buffer = NULL;
+ if (FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_MAX_WIDTH_MASK,
+ NULL, last_err, 0, (LPSTR)&buffer, 1, NULL)) {
+ fprintf(stderr, "Windows error: %s\n", buffer);
+ } else {
+ fprintf(stderr, "Unknown Windows error: %s\n", hint);
+ }
+ LocalFree(buffer);
+}
+
+static __inline void win_abort(DWORD last_err, const char *hint) {
+ win_error(last_err, hint);
+ abort();
+}
+
+static __inline void *emutls_memalign_alloc(size_t align, size_t size) {
+ void *base = _aligned_malloc(size, align);
+ if (!base)
+ win_abort(GetLastError(), "_aligned_malloc");
+ return base;
+}
+
+static __inline void emutls_memalign_free(void *base) { _aligned_free(base); }
+
+static void emutls_exit(void) {
+ if (emutls_mutex) {
+ DeleteCriticalSection(emutls_mutex);
+ _aligned_free(emutls_mutex);
+ emutls_mutex = NULL;
+ }
+ if (emutls_tls_index != TLS_OUT_OF_INDEXES) {
+ emutls_shutdown((emutls_address_array *)TlsGetValue(emutls_tls_index));
+ TlsFree(emutls_tls_index);
+ emutls_tls_index = TLS_OUT_OF_INDEXES;
+ }
+}
+
+static BOOL CALLBACK emutls_init(PINIT_ONCE p0, PVOID p1, PVOID *p2) {
+ (void)p0;
+ (void)p1;
+ (void)p2;
+ emutls_mutex =
+ (LPCRITICAL_SECTION)_aligned_malloc(sizeof(CRITICAL_SECTION), 16);
+ if (!emutls_mutex) {
+ win_error(GetLastError(), "_aligned_malloc");
+ return FALSE;
+ }
+ InitializeCriticalSection(emutls_mutex);
+
+ emutls_tls_index = TlsAlloc();
+ if (emutls_tls_index == TLS_OUT_OF_INDEXES) {
+ emutls_exit();
+ win_error(GetLastError(), "TlsAlloc");
+ return FALSE;
+ }
+ atexit(&emutls_exit);
+ return TRUE;
+}
+
+static __inline void emutls_init_once(void) {
+ static INIT_ONCE once;
+ InitOnceExecuteOnce(&once, emutls_init, NULL, NULL);
+}
+
+static __inline void emutls_lock(void) { EnterCriticalSection(emutls_mutex); }
+
+static __inline void emutls_unlock(void) { LeaveCriticalSection(emutls_mutex); }
+
+static __inline void emutls_setspecific(emutls_address_array *value) {
+ if (TlsSetValue(emutls_tls_index, (LPVOID)value) == 0)
+ win_abort(GetLastError(), "TlsSetValue");
+}
+
+static __inline emutls_address_array *emutls_getspecific(void) {
+ LPVOID value = TlsGetValue(emutls_tls_index);
+ if (value == NULL) {
+ const DWORD err = GetLastError();
+ if (err != ERROR_SUCCESS)
+ win_abort(err, "TlsGetValue");
+ }
+ return (emutls_address_array *)value;
+}
+
+// Provide atomic load/store functions for emutls_get_index if built with MSVC.
+#if !defined(__ATOMIC_RELEASE)
+#include <intrin.h>
+
+enum { __ATOMIC_ACQUIRE = 2, __ATOMIC_RELEASE = 3 };
+
+static __inline uintptr_t __atomic_load_n(void *ptr, unsigned type) {
+ assert(type == __ATOMIC_ACQUIRE);
+ // These return the previous value - but since we do an OR with 0,
+ // it's equivalent to a plain load.
+#ifdef _WIN64
+ return InterlockedOr64(ptr, 0);
+#else
+ return InterlockedOr(ptr, 0);
+#endif
+}
+
+static __inline void __atomic_store_n(void *ptr, uintptr_t val, unsigned type) {
+ assert(type == __ATOMIC_RELEASE);
+ InterlockedExchangePointer((void *volatile *)ptr, (void *)val);
+}
+
+#endif // __ATOMIC_RELEASE
+
+#endif // _WIN32
+
+static size_t emutls_num_object = 0; // number of allocated TLS objects
+
+// Free the allocated TLS data
+static void emutls_shutdown(emutls_address_array *array) {
+ if (array) {
uintptr_t i;
for (i = 0; i < array->size; ++i) {
- if (array->data[i])
- emutls_memalign_free(array->data[i]);
+ if (array->data[i])
+ emutls_memalign_free(array->data[i]);
}
- free(ptr);
+ }
}
-static void emutls_init(void) {
- if (pthread_key_create(&emutls_pthread_key, emutls_key_destructor) != 0)
- abort();
+// For every TLS variable xyz,
+// there is one __emutls_control variable named __emutls_v.xyz.
+// If xyz has non-zero initial value, __emutls_v.xyz's "value"
+// will point to __emutls_t.xyz, which has the initial value.
+typedef struct __emutls_control {
+ // Must use gcc_word here, instead of size_t, to match GCC. When
+ // gcc_word is larger than size_t, the upper extra bits are all
+ // zeros. We can use variables of size_t to operate on size and
+ // align.
+ gcc_word size; // size of the object in bytes
+ gcc_word align; // alignment of the object in bytes
+ union {
+ uintptr_t index; // data[index-1] is the object address
+ void *address; // object address, when in single thread env
+ } object;
+ void *value; // null or non-zero initial value for the object
+} __emutls_control;
+
+// Emulated TLS objects are always allocated at run-time.
+static __inline void *emutls_allocate_object(__emutls_control *control) {
+ // Use standard C types, check with gcc's emutls.o.
+ COMPILE_TIME_ASSERT(sizeof(uintptr_t) == sizeof(gcc_pointer));
+ COMPILE_TIME_ASSERT(sizeof(uintptr_t) == sizeof(void *));
+
+ size_t size = control->size;
+ size_t align = control->align;
+ void *base;
+ if (align < sizeof(void *))
+ align = sizeof(void *);
+ // Make sure that align is power of 2.
+ if ((align & (align - 1)) != 0)
+ abort();
+
+ base = emutls_memalign_alloc(align, size);
+ if (control->value)
+ memcpy(base, control->value, size);
+ else
+ memset(base, 0, size);
+ return base;
}
-/* Returns control->object.index; set index if not allocated yet. */
+// Returns control->object.index; set index if not allocated yet.
static __inline uintptr_t emutls_get_index(__emutls_control *control) {
- uintptr_t index = __atomic_load_n(&control->object.index, __ATOMIC_ACQUIRE);
+ uintptr_t index = __atomic_load_n(&control->object.index, __ATOMIC_ACQUIRE);
+ if (!index) {
+ emutls_init_once();
+ emutls_lock();
+ index = control->object.index;
if (!index) {
- static pthread_once_t once = PTHREAD_ONCE_INIT;
- pthread_once(&once, emutls_init);
- pthread_mutex_lock(&emutls_mutex);
- index = control->object.index;
- if (!index) {
- index = ++emutls_num_object;
- __atomic_store_n(&control->object.index, index, __ATOMIC_RELEASE);
- }
- pthread_mutex_unlock(&emutls_mutex);
+ index = ++emutls_num_object;
+ __atomic_store_n(&control->object.index, index, __ATOMIC_RELEASE);
}
- return index;
+ emutls_unlock();
+ }
+ return index;
}
-/* Updates newly allocated thread local emutls_address_array. */
+// Updates newly allocated thread local emutls_address_array.
static __inline void emutls_check_array_set_size(emutls_address_array *array,
uintptr_t size) {
- if (array == NULL)
- abort();
- array->size = size;
- pthread_setspecific(emutls_pthread_key, (void*)array);
+ if (array == NULL)
+ abort();
+ array->size = size;
+ emutls_setspecific(array);
}
-/* Returns the new 'data' array size, number of elements,
- * which must be no smaller than the given index.
- */
+// Returns the new 'data' array size, number of elements,
+// which must be no smaller than the given index.
static __inline uintptr_t emutls_new_data_array_size(uintptr_t index) {
- /* Need to allocate emutls_address_array with one extra slot
- * to store the data array size.
- * Round up the emutls_address_array size to multiple of 16.
- */
- return ((index + 1 + 15) & ~((uintptr_t)15)) - 1;
+ // Need to allocate emutls_address_array with extra slots
+ // to store the header.
+ // Round up the emutls_address_array size to multiple of 16.
+ uintptr_t header_words = sizeof(emutls_address_array) / sizeof(void *);
+ return ((index + header_words + 15) & ~((uintptr_t)15)) - header_words;
+}
+
+// Returns the size in bytes required for an emutls_address_array with
+// N number of elements for data field.
+static __inline uintptr_t emutls_asize(uintptr_t N) {
+ return N * sizeof(void *) + sizeof(emutls_address_array);
}
-/* Returns the thread local emutls_address_array.
- * Extends its size if necessary to hold address at index.
- */
+// Returns the thread local emutls_address_array.
+// Extends its size if necessary to hold address at index.
static __inline emutls_address_array *
emutls_get_address_array(uintptr_t index) {
- emutls_address_array* array = pthread_getspecific(emutls_pthread_key);
- if (array == NULL) {
- uintptr_t new_size = emutls_new_data_array_size(index);
- array = calloc(new_size + 1, sizeof(void*));
- emutls_check_array_set_size(array, new_size);
- } else if (index > array->size) {
- uintptr_t orig_size = array->size;
- uintptr_t new_size = emutls_new_data_array_size(index);
- array = realloc(array, (new_size + 1) * sizeof(void*));
- if (array)
- memset(array->data + orig_size, 0,
- (new_size - orig_size) * sizeof(void*));
- emutls_check_array_set_size(array, new_size);
+ emutls_address_array *array = emutls_getspecific();
+ if (array == NULL) {
+ uintptr_t new_size = emutls_new_data_array_size(index);
+ array = (emutls_address_array *)malloc(emutls_asize(new_size));
+ if (array) {
+ memset(array->data, 0, new_size * sizeof(void *));
+ array->skip_destructor_rounds = EMUTLS_SKIP_DESTRUCTOR_ROUNDS;
}
- return array;
+ emutls_check_array_set_size(array, new_size);
+ } else if (index > array->size) {
+ uintptr_t orig_size = array->size;
+ uintptr_t new_size = emutls_new_data_array_size(index);
+ array = (emutls_address_array *)realloc(array, emutls_asize(new_size));
+ if (array)
+ memset(array->data + orig_size, 0,
+ (new_size - orig_size) * sizeof(void *));
+ emutls_check_array_set_size(array, new_size);
+ }
+ return array;
}
-void* __emutls_get_address(__emutls_control* control) {
- uintptr_t index = emutls_get_index(control);
- emutls_address_array* array = emutls_get_address_array(index);
- if (array->data[index - 1] == NULL)
- array->data[index - 1] = emutls_allocate_object(control);
- return array->data[index - 1];
+#ifndef _WIN32
+// Our emulated TLS implementation relies on local state (e.g. for the pthread
+// key), and if we duplicate this state across different shared libraries,
+// accesses to the same TLS variable from different shared libraries will yield
+// different results (see https://github.com/android/ndk/issues/1551 for an
+// example). __emutls_get_address is the only external entry point for emulated
+// TLS, and by making it default visibility and weak, we can rely on the dynamic
+// linker to coalesce multiple copies at runtime and ensure a single unique copy
+// of TLS state. This is a best effort; it won't work if the user is linking
+// with -Bsymbolic or -Bsymbolic-functions, and it also won't work on Windows,
+// where the dynamic linker has no notion of coalescing weak symbols at runtime.
+// A more robust solution would be to create a separate shared library for
+// emulated TLS, to ensure a single copy of its state.
+__attribute__((visibility("default"), weak))
+#endif
+void *__emutls_get_address(__emutls_control *control) {
+ uintptr_t index = emutls_get_index(control);
+ emutls_address_array *array = emutls_get_address_array(index--);
+ if (array->data[index] == NULL)
+ array->data[index] = emutls_allocate_object(control);
+ return array->data[index];
}
+
+#ifdef __BIONIC__
+// Called by Bionic on dlclose to delete the emutls pthread key.
+__attribute__((visibility("hidden"))) void __emutls_unregister_key(void) {
+ if (emutls_key_created) {
+ pthread_key_delete(emutls_pthread_key);
+ emutls_key_created = false;
+ }
+}
+#endif
diff --git a/contrib/libs/cxxsupp/builtins/enable_execute_stack.c b/contrib/libs/cxxsupp/builtins/enable_execute_stack.c
index 0dc3482c44..e18de4eaeb 100644
--- a/contrib/libs/cxxsupp/builtins/enable_execute_stack.c
+++ b/contrib/libs/cxxsupp/builtins/enable_execute_stack.c
@@ -1,12 +1,10 @@
-/* ===-- enable_execute_stack.c - Implement __enable_execute_stack ---------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- enable_execute_stack.c - Implement __enable_execute_stack ---------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
@@ -14,59 +12,56 @@
#include <sys/mman.h>
#endif
-/* #include "config.h"
- * FIXME: CMake - include when cmake system is ready.
- * Remove #define HAVE_SYSCONF 1 line.
- */
+// #include "config.h"
+// FIXME: CMake - include when cmake system is ready.
+// Remove #define HAVE_SYSCONF 1 line.
#define HAVE_SYSCONF 1
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
-#include <Windows.h>
+#include <windows.h>
#else
#ifndef __APPLE__
#include <unistd.h>
-#endif /* __APPLE__ */
-#endif /* _WIN32 */
+#endif // __APPLE__
+#endif // _WIN32
#if __LP64__
- #define TRAMPOLINE_SIZE 48
+#define TRAMPOLINE_SIZE 48
#else
- #define TRAMPOLINE_SIZE 40
+#define TRAMPOLINE_SIZE 40
#endif
-/*
- * The compiler generates calls to __enable_execute_stack() when creating
- * trampoline functions on the stack for use with nested functions.
- * It is expected to mark the page(s) containing the address
- * and the next 48 bytes as executable. Since the stack is normally rw-
- * that means changing the protection on those page(s) to rwx.
- */
+// The compiler generates calls to __enable_execute_stack() when creating
+// trampoline functions on the stack for use with nested functions.
+// It is expected to mark the page(s) containing the address
+// and the next 48 bytes as executable. Since the stack is normally rw-
+// that means changing the protection on those page(s) to rwx.
-COMPILER_RT_ABI void
-__enable_execute_stack(void* addr)
-{
+COMPILER_RT_ABI void __enable_execute_stack(void *addr) {
#if _WIN32
- MEMORY_BASIC_INFORMATION mbi;
- if (!VirtualQuery (addr, &mbi, sizeof(mbi)))
- return; /* We should probably assert here because there is no return value */
- VirtualProtect (mbi.BaseAddress, mbi.RegionSize, PAGE_EXECUTE_READWRITE, &mbi.Protect);
+ MEMORY_BASIC_INFORMATION mbi;
+ if (!VirtualQuery(addr, &mbi, sizeof(mbi)))
+ return; // We should probably assert here because there is no return value
+ VirtualProtect(mbi.BaseAddress, mbi.RegionSize, PAGE_EXECUTE_READWRITE,
+ &mbi.Protect);
#else
#if __APPLE__
- /* On Darwin, pagesize is always 4096 bytes */
- const uintptr_t pageSize = 4096;
+ // On Darwin, pagesize is always 4096 bytes
+ const uintptr_t pageSize = 4096;
#elif !defined(HAVE_SYSCONF)
#error "HAVE_SYSCONF not defined! See enable_execute_stack.c"
#else
- const uintptr_t pageSize = sysconf(_SC_PAGESIZE);
-#endif /* __APPLE__ */
+ const uintptr_t pageSize = sysconf(_SC_PAGESIZE);
+#endif // __APPLE__
- const uintptr_t pageAlignMask = ~(pageSize-1);
- uintptr_t p = (uintptr_t)addr;
- unsigned char* startPage = (unsigned char*)(p & pageAlignMask);
- unsigned char* endPage = (unsigned char*)((p+TRAMPOLINE_SIZE+pageSize) & pageAlignMask);
- size_t length = endPage - startPage;
- (void) mprotect((void *)startPage, length, PROT_READ | PROT_WRITE | PROT_EXEC);
+ const uintptr_t pageAlignMask = ~(pageSize - 1);
+ uintptr_t p = (uintptr_t)addr;
+ unsigned char *startPage = (unsigned char *)(p & pageAlignMask);
+ unsigned char *endPage =
+ (unsigned char *)((p + TRAMPOLINE_SIZE + pageSize) & pageAlignMask);
+ size_t length = endPage - startPage;
+ (void)mprotect((void *)startPage, length, PROT_READ | PROT_WRITE | PROT_EXEC);
#endif
}
diff --git a/contrib/libs/cxxsupp/builtins/eprintf.c b/contrib/libs/cxxsupp/builtins/eprintf.c
index 89f34b1545..daf90b4993 100644
--- a/contrib/libs/cxxsupp/builtins/eprintf.c
+++ b/contrib/libs/cxxsupp/builtins/eprintf.c
@@ -1,35 +1,29 @@
-/* ===---------- eprintf.c - Implements __eprintf --------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- */
-
-
+//===---------- eprintf.c - Implements __eprintf --------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
#include <stdio.h>
-
-/*
- * __eprintf() was used in an old version of <assert.h>.
- * It can eventually go away, but it is needed when linking
- * .o files built with the old <assert.h>.
- *
- * It should never be exported from a dylib, so it is marked
- * visibility hidden.
- */
+// __eprintf() was used in an old version of <assert.h>.
+// It can eventually go away, but it is needed when linking
+// .o files built with the old <assert.h>.
+//
+// It should never be exported from a dylib, so it is marked
+// visibility hidden.
+#ifndef DONT_DEFINE_EPRINTF
#ifndef _WIN32
__attribute__((visibility("hidden")))
#endif
COMPILER_RT_ABI void
-__eprintf(const char* format, const char* assertion_expression,
- const char* line, const char* file)
-{
- fprintf(stderr, format, assertion_expression, line, file);
- fflush(stderr);
- compilerrt_abort();
+__eprintf(const char *format, const char *assertion_expression,
+ const char *line, const char *file) {
+ fprintf(stderr, format, assertion_expression, line, file);
+ fflush(stderr);
+ compilerrt_abort();
}
+#endif
diff --git a/contrib/libs/cxxsupp/builtins/extenddftf2.c b/contrib/libs/cxxsupp/builtins/extenddftf2.c
index 86dab8f03a..ddf470ecd6 100644
--- a/contrib/libs/cxxsupp/builtins/extenddftf2.c
+++ b/contrib/libs/cxxsupp/builtins/extenddftf2.c
@@ -1,12 +1,10 @@
//===-- lib/extenddftf2.c - double -> quad conversion -------------*- C -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
-//
#define QUAD_PRECISION
#include "fp_lib.h"
@@ -16,8 +14,8 @@
#define DST_QUAD
#include "fp_extend_impl.inc"
-COMPILER_RT_ABI long double __extenddftf2(double a) {
- return __extendXfYf2__(a);
+COMPILER_RT_ABI fp_t __extenddftf2(double a) {
+ return __extendXfYf2__(a);
}
#endif
diff --git a/contrib/libs/cxxsupp/builtins/extendhfsf2.c b/contrib/libs/cxxsupp/builtins/extendhfsf2.c
index 27115a48c1..0159ab09d3 100644
--- a/contrib/libs/cxxsupp/builtins/extendhfsf2.c
+++ b/contrib/libs/cxxsupp/builtins/extendhfsf2.c
@@ -1,25 +1,27 @@
//===-- lib/extendhfsf2.c - half -> single conversion -------------*- C -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
-//
#define SRC_HALF
#define DST_SINGLE
#include "fp_extend_impl.inc"
-ARM_EABI_FNALIAS(h2f, extendhfsf2)
-
// Use a forwarding definition and noinline to implement a poor man's alias,
// as there isn't a good cross-platform way of defining one.
-COMPILER_RT_ABI NOINLINE float __extendhfsf2(uint16_t a) {
- return __extendXfYf2__(a);
+COMPILER_RT_ABI NOINLINE float __extendhfsf2(src_t a) {
+ return __extendXfYf2__(a);
}
-COMPILER_RT_ABI float __gnu_h2f_ieee(uint16_t a) {
- return __extendhfsf2(a);
-}
+COMPILER_RT_ABI float __gnu_h2f_ieee(src_t a) { return __extendhfsf2(a); }
+
+#if defined(__ARM_EABI__)
+#if defined(COMPILER_RT_ARMHF_TARGET)
+AEABI_RTABI float __aeabi_h2f(src_t a) { return __extendhfsf2(a); }
+#else
+COMPILER_RT_ALIAS(__extendhfsf2, __aeabi_h2f)
+#endif
+#endif
diff --git a/contrib/libs/cxxsupp/builtins/extendhftf2.c b/contrib/libs/cxxsupp/builtins/extendhftf2.c
new file mode 100644
index 0000000000..aefe9737d3
--- /dev/null
+++ b/contrib/libs/cxxsupp/builtins/extendhftf2.c
@@ -0,0 +1,23 @@
+//===-- lib/extendhftf2.c - half -> quad conversion ---------------*- C -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#define QUAD_PRECISION
+#include "fp_lib.h"
+
+#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT) && \
+ defined(COMPILER_RT_HAS_FLOAT16)
+#define SRC_HALF
+#define DST_QUAD
+#include "fp_extend_impl.inc"
+
+COMPILER_RT_ABI long double __extendhftf2(_Float16 a) {
+ return __extendXfYf2__(a);
+}
+
+#endif
diff --git a/contrib/libs/cxxsupp/builtins/extendsfdf2.c b/contrib/libs/cxxsupp/builtins/extendsfdf2.c
index 7a267c2f47..8132d57e6b 100644
--- a/contrib/libs/cxxsupp/builtins/extendsfdf2.c
+++ b/contrib/libs/cxxsupp/builtins/extendsfdf2.c
@@ -1,19 +1,21 @@
//===-- lib/extendsfdf2.c - single -> double conversion -----------*- C -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
-//
#define SRC_SINGLE
#define DST_DOUBLE
#include "fp_extend_impl.inc"
-ARM_EABI_FNALIAS(f2d, extendsfdf2)
+COMPILER_RT_ABI double __extendsfdf2(float a) { return __extendXfYf2__(a); }
-COMPILER_RT_ABI double __extendsfdf2(float a) {
- return __extendXfYf2__(a);
-}
+#if defined(__ARM_EABI__)
+#if defined(COMPILER_RT_ARMHF_TARGET)
+AEABI_RTABI double __aeabi_f2d(float a) { return __extendsfdf2(a); }
+#else
+COMPILER_RT_ALIAS(__extendsfdf2, __aeabi_f2d)
+#endif
+#endif
diff --git a/contrib/libs/cxxsupp/builtins/extendsftf2.c b/contrib/libs/cxxsupp/builtins/extendsftf2.c
index 2eeeba2848..cf1fd2face 100644
--- a/contrib/libs/cxxsupp/builtins/extendsftf2.c
+++ b/contrib/libs/cxxsupp/builtins/extendsftf2.c
@@ -1,12 +1,10 @@
//===-- lib/extendsftf2.c - single -> quad conversion -------------*- C -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
-//
#define QUAD_PRECISION
#include "fp_lib.h"
@@ -16,8 +14,8 @@
#define DST_QUAD
#include "fp_extend_impl.inc"
-COMPILER_RT_ABI long double __extendsftf2(float a) {
- return __extendXfYf2__(a);
+COMPILER_RT_ABI fp_t __extendsftf2(float a) {
+ return __extendXfYf2__(a);
}
#endif
diff --git a/contrib/libs/cxxsupp/builtins/ffsdi2.c b/contrib/libs/cxxsupp/builtins/ffsdi2.c
index a5ac9900ff..beae553043 100644
--- a/contrib/libs/cxxsupp/builtins/ffsdi2.c
+++ b/contrib/libs/cxxsupp/builtins/ffsdi2.c
@@ -1,33 +1,27 @@
-/* ===-- ffsdi2.c - Implement __ffsdi2 -------------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __ffsdi2 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- ffsdi2.c - Implement __ffsdi2 -------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __ffsdi2 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
-/* Returns: the index of the least significant 1-bit in a, or
- * the value zero if a is zero. The least significant bit is index one.
- */
+// Returns: the index of the least significant 1-bit in a, or
+// the value zero if a is zero. The least significant bit is index one.
-COMPILER_RT_ABI si_int
-__ffsdi2(di_int a)
-{
- dwords x;
- x.all = a;
- if (x.s.low == 0)
- {
- if (x.s.high == 0)
- return 0;
- return __builtin_ctz(x.s.high) + (1 + sizeof(si_int) * CHAR_BIT);
- }
- return __builtin_ctz(x.s.low) + 1;
+COMPILER_RT_ABI int __ffsdi2(di_int a) {
+ dwords x;
+ x.all = a;
+ if (x.s.low == 0) {
+ if (x.s.high == 0)
+ return 0;
+ return ctzsi(x.s.high) + (1 + sizeof(si_int) * CHAR_BIT);
+ }
+ return ctzsi(x.s.low) + 1;
}
diff --git a/contrib/libs/cxxsupp/builtins/ffssi2.c b/contrib/libs/cxxsupp/builtins/ffssi2.c
new file mode 100644
index 0000000000..ddb52927f8
--- /dev/null
+++ b/contrib/libs/cxxsupp/builtins/ffssi2.c
@@ -0,0 +1,23 @@
+//===-- ffssi2.c - Implement __ffssi2 -------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __ffssi2 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
+
+#include "int_lib.h"
+
+// Returns: the index of the least significant 1-bit in a, or
+// the value zero if a is zero. The least significant bit is index one.
+
+COMPILER_RT_ABI int __ffssi2(si_int a) {
+ if (a == 0) {
+ return 0;
+ }
+ return ctzsi(a) + 1;
+}
diff --git a/contrib/libs/cxxsupp/builtins/ffsti2.c b/contrib/libs/cxxsupp/builtins/ffsti2.c
index dcdb3bd7f8..a2177d148a 100644
--- a/contrib/libs/cxxsupp/builtins/ffsti2.c
+++ b/contrib/libs/cxxsupp/builtins/ffsti2.c
@@ -1,37 +1,31 @@
-/* ===-- ffsti2.c - Implement __ffsti2 -------------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __ffsti2 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- ffsti2.c - Implement __ffsti2 -------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __ffsti2 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
#ifdef CRT_HAS_128BIT
-/* Returns: the index of the least significant 1-bit in a, or
- * the value zero if a is zero. The least significant bit is index one.
- */
+// Returns: the index of the least significant 1-bit in a, or
+// the value zero if a is zero. The least significant bit is index one.
-COMPILER_RT_ABI si_int
-__ffsti2(ti_int a)
-{
- twords x;
- x.all = a;
- if (x.s.low == 0)
- {
- if (x.s.high == 0)
- return 0;
- return __builtin_ctzll(x.s.high) + (1 + sizeof(di_int) * CHAR_BIT);
- }
- return __builtin_ctzll(x.s.low) + 1;
+COMPILER_RT_ABI int __ffsti2(ti_int a) {
+ twords x;
+ x.all = a;
+ if (x.s.low == 0) {
+ if (x.s.high == 0)
+ return 0;
+ return __builtin_ctzll(x.s.high) + (1 + sizeof(di_int) * CHAR_BIT);
+ }
+ return __builtin_ctzll(x.s.low) + 1;
}
-#endif /* CRT_HAS_128BIT */
+#endif // CRT_HAS_128BIT
diff --git a/contrib/libs/cxxsupp/builtins/fixdfdi.c b/contrib/libs/cxxsupp/builtins/fixdfdi.c
index 14283ef42e..a48facb685 100644
--- a/contrib/libs/cxxsupp/builtins/fixdfdi.c
+++ b/contrib/libs/cxxsupp/builtins/fixdfdi.c
@@ -1,46 +1,48 @@
-/* ===-- fixdfdi.c - Implement __fixdfdi -----------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- fixdfdi.c - Implement __fixdfdi -----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
#define DOUBLE_PRECISION
#include "fp_lib.h"
-ARM_EABI_FNALIAS(d2lz, fixdfdi)
-#ifndef __SOFT_FP__
-/* Support for systems that have hardware floating-point; can set the invalid
- * flag as a side-effect of computation.
- */
+#ifndef __SOFTFP__
+// Support for systems that have hardware floating-point; can set the invalid
+// flag as a side-effect of computation.
COMPILER_RT_ABI du_int __fixunsdfdi(double a);
-COMPILER_RT_ABI di_int
-__fixdfdi(double a)
-{
- if (a < 0.0) {
- return -__fixunsdfdi(-a);
- }
- return __fixunsdfdi(a);
+COMPILER_RT_ABI di_int __fixdfdi(double a) {
+ if (a < 0.0) {
+ return -__fixunsdfdi(-a);
+ }
+ return __fixunsdfdi(a);
}
#else
-/* Support for systems that don't have hardware floating-point; there are no
- * flags to set, and we don't want to code-gen to an unknown soft-float
- * implementation.
- */
+// Support for systems that don't have hardware floating-point; there are no
+// flags to set, and we don't want to code-gen to an unknown soft-float
+// implementation.
typedef di_int fixint_t;
typedef du_int fixuint_t;
#include "fp_fixint_impl.inc"
-COMPILER_RT_ABI di_int
-__fixdfdi(fp_t a) {
- return __fixint(a);
-}
+COMPILER_RT_ABI di_int __fixdfdi(fp_t a) { return __fixint(a); }
+
+#endif
+
+#if defined(__ARM_EABI__)
+#if defined(COMPILER_RT_ARMHF_TARGET)
+AEABI_RTABI di_int __aeabi_d2lz(fp_t a) { return __fixdfdi(a); }
+#else
+COMPILER_RT_ALIAS(__fixdfdi, __aeabi_d2lz)
+#endif
+#endif
+#if defined(__MINGW32__) && defined(__arm__)
+COMPILER_RT_ALIAS(__fixdfdi, __dtoi64)
#endif
diff --git a/contrib/libs/cxxsupp/builtins/fixdfsi.c b/contrib/libs/cxxsupp/builtins/fixdfsi.c
index 704e65bc43..f54649993c 100644
--- a/contrib/libs/cxxsupp/builtins/fixdfsi.c
+++ b/contrib/libs/cxxsupp/builtins/fixdfsi.c
@@ -1,12 +1,10 @@
-/* ===-- fixdfsi.c - Implement __fixdfsi -----------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- fixdfsi.c - Implement __fixdfsi -----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
#define DOUBLE_PRECISION
#include "fp_lib.h"
@@ -14,9 +12,12 @@ typedef si_int fixint_t;
typedef su_int fixuint_t;
#include "fp_fixint_impl.inc"
-ARM_EABI_FNALIAS(d2iz, fixdfsi)
+COMPILER_RT_ABI si_int __fixdfsi(fp_t a) { return __fixint(a); }
-COMPILER_RT_ABI si_int
-__fixdfsi(fp_t a) {
- return __fixint(a);
-}
+#if defined(__ARM_EABI__)
+#if defined(COMPILER_RT_ARMHF_TARGET)
+AEABI_RTABI si_int __aeabi_d2iz(fp_t a) { return __fixdfsi(a); }
+#else
+COMPILER_RT_ALIAS(__fixdfsi, __aeabi_d2iz)
+#endif
+#endif
diff --git a/contrib/libs/cxxsupp/builtins/fixdfti.c b/contrib/libs/cxxsupp/builtins/fixdfti.c
index aaf225e74f..90ca8959da 100644
--- a/contrib/libs/cxxsupp/builtins/fixdfti.c
+++ b/contrib/libs/cxxsupp/builtins/fixdfti.c
@@ -1,12 +1,10 @@
-/* ===-- fixdfti.c - Implement __fixdfti -----------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- fixdfti.c - Implement __fixdfti -----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
@@ -18,9 +16,6 @@ typedef ti_int fixint_t;
typedef tu_int fixuint_t;
#include "fp_fixint_impl.inc"
-COMPILER_RT_ABI ti_int
-__fixdfti(fp_t a) {
- return __fixint(a);
-}
+COMPILER_RT_ABI ti_int __fixdfti(fp_t a) { return __fixint(a); }
-#endif /* CRT_HAS_128BIT */
+#endif // CRT_HAS_128BIT
diff --git a/contrib/libs/cxxsupp/builtins/fixsfdi.c b/contrib/libs/cxxsupp/builtins/fixsfdi.c
index fab47e272a..3a66fb9e2f 100644
--- a/contrib/libs/cxxsupp/builtins/fixsfdi.c
+++ b/contrib/libs/cxxsupp/builtins/fixsfdi.c
@@ -1,47 +1,48 @@
-/* ===-- fixsfdi.c - Implement __fixsfdi -----------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- fixsfdi.c - Implement __fixsfdi -----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
#define SINGLE_PRECISION
#include "fp_lib.h"
-ARM_EABI_FNALIAS(f2lz, fixsfdi)
-
-#ifndef __SOFT_FP__
-/* Support for systems that have hardware floating-point; can set the invalid
- * flag as a side-effect of computation.
- */
+#ifndef __SOFTFP__
+// Support for systems that have hardware floating-point; can set the invalid
+// flag as a side-effect of computation.
COMPILER_RT_ABI du_int __fixunssfdi(float a);
-COMPILER_RT_ABI di_int
-__fixsfdi(float a)
-{
- if (a < 0.0f) {
- return -__fixunssfdi(-a);
- }
- return __fixunssfdi(a);
+COMPILER_RT_ABI di_int __fixsfdi(float a) {
+ if (a < 0.0f) {
+ return -__fixunssfdi(-a);
+ }
+ return __fixunssfdi(a);
}
#else
-/* Support for systems that don't have hardware floating-point; there are no
- * flags to set, and we don't want to code-gen to an unknown soft-float
- * implementation.
- */
+// Support for systems that don't have hardware floating-point; there are no
+// flags to set, and we don't want to code-gen to an unknown soft-float
+// implementation.
typedef di_int fixint_t;
typedef du_int fixuint_t;
#include "fp_fixint_impl.inc"
-COMPILER_RT_ABI di_int
-__fixsfdi(fp_t a) {
- return __fixint(a);
-}
+COMPILER_RT_ABI di_int __fixsfdi(fp_t a) { return __fixint(a); }
+
+#endif
+
+#if defined(__ARM_EABI__)
+#if defined(COMPILER_RT_ARMHF_TARGET)
+AEABI_RTABI di_int __aeabi_f2lz(fp_t a) { return __fixsfdi(a); }
+#else
+COMPILER_RT_ALIAS(__fixsfdi, __aeabi_f2lz)
+#endif
+#endif
+#if defined(__MINGW32__) && defined(__arm__)
+COMPILER_RT_ALIAS(__fixsfdi, __stoi64)
#endif
diff --git a/contrib/libs/cxxsupp/builtins/fixsfsi.c b/contrib/libs/cxxsupp/builtins/fixsfsi.c
index f045536d68..d83d7e7222 100644
--- a/contrib/libs/cxxsupp/builtins/fixsfsi.c
+++ b/contrib/libs/cxxsupp/builtins/fixsfsi.c
@@ -1,12 +1,10 @@
-/* ===-- fixsfsi.c - Implement __fixsfsi -----------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- fixsfsi.c - Implement __fixsfsi -----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
#define SINGLE_PRECISION
#include "fp_lib.h"
@@ -14,9 +12,12 @@ typedef si_int fixint_t;
typedef su_int fixuint_t;
#include "fp_fixint_impl.inc"
-ARM_EABI_FNALIAS(f2iz, fixsfsi)
+COMPILER_RT_ABI si_int __fixsfsi(fp_t a) { return __fixint(a); }
-COMPILER_RT_ABI si_int
-__fixsfsi(fp_t a) {
- return __fixint(a);
-}
+#if defined(__ARM_EABI__)
+#if defined(COMPILER_RT_ARMHF_TARGET)
+AEABI_RTABI si_int __aeabi_f2iz(fp_t a) { return __fixsfsi(a); }
+#else
+COMPILER_RT_ALIAS(__fixsfsi, __aeabi_f2iz)
+#endif
+#endif
diff --git a/contrib/libs/cxxsupp/builtins/fixsfti.c b/contrib/libs/cxxsupp/builtins/fixsfti.c
index 3a159b3e18..3c01b75e2b 100644
--- a/contrib/libs/cxxsupp/builtins/fixsfti.c
+++ b/contrib/libs/cxxsupp/builtins/fixsfti.c
@@ -1,12 +1,10 @@
-/* ===-- fixsfti.c - Implement __fixsfti -----------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- fixsfti.c - Implement __fixsfti -----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
@@ -18,9 +16,6 @@ typedef ti_int fixint_t;
typedef tu_int fixuint_t;
#include "fp_fixint_impl.inc"
-COMPILER_RT_ABI ti_int
-__fixsfti(fp_t a) {
- return __fixint(a);
-}
+COMPILER_RT_ABI ti_int __fixsfti(fp_t a) { return __fixint(a); }
-#endif /* CRT_HAS_128BIT */
+#endif // CRT_HAS_128BIT
diff --git a/contrib/libs/cxxsupp/builtins/fixtfdi.c b/contrib/libs/cxxsupp/builtins/fixtfdi.c
index bc9dea1f4f..fe570e6b37 100644
--- a/contrib/libs/cxxsupp/builtins/fixtfdi.c
+++ b/contrib/libs/cxxsupp/builtins/fixtfdi.c
@@ -1,12 +1,10 @@
-/* ===-- fixtfdi.c - Implement __fixtfdi -----------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- fixtfdi.c - Implement __fixtfdi -----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
#define QUAD_PRECISION
#include "fp_lib.h"
@@ -16,8 +14,5 @@ typedef di_int fixint_t;
typedef du_int fixuint_t;
#include "fp_fixint_impl.inc"
-COMPILER_RT_ABI di_int
-__fixtfdi(fp_t a) {
- return __fixint(a);
-}
+COMPILER_RT_ABI di_int __fixtfdi(fp_t a) { return __fixint(a); }
#endif
diff --git a/contrib/libs/cxxsupp/builtins/fixtfsi.c b/contrib/libs/cxxsupp/builtins/fixtfsi.c
index feb3de8850..a32bd964ca 100644
--- a/contrib/libs/cxxsupp/builtins/fixtfsi.c
+++ b/contrib/libs/cxxsupp/builtins/fixtfsi.c
@@ -1,12 +1,10 @@
-/* ===-- fixtfsi.c - Implement __fixtfsi -----------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- fixtfsi.c - Implement __fixtfsi -----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
#define QUAD_PRECISION
#include "fp_lib.h"
@@ -16,8 +14,5 @@ typedef si_int fixint_t;
typedef su_int fixuint_t;
#include "fp_fixint_impl.inc"
-COMPILER_RT_ABI si_int
-__fixtfsi(fp_t a) {
- return __fixint(a);
-}
+COMPILER_RT_ABI si_int __fixtfsi(fp_t a) { return __fixint(a); }
#endif
diff --git a/contrib/libs/cxxsupp/builtins/fixtfti.c b/contrib/libs/cxxsupp/builtins/fixtfti.c
index ee4ada85cb..19f84ce389 100644
--- a/contrib/libs/cxxsupp/builtins/fixtfti.c
+++ b/contrib/libs/cxxsupp/builtins/fixtfti.c
@@ -1,12 +1,10 @@
-/* ===-- fixtfti.c - Implement __fixtfti -----------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- fixtfti.c - Implement __fixtfti -----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
#define QUAD_PRECISION
#include "fp_lib.h"
@@ -16,8 +14,5 @@ typedef ti_int fixint_t;
typedef tu_int fixuint_t;
#include "fp_fixint_impl.inc"
-COMPILER_RT_ABI ti_int
-__fixtfti(fp_t a) {
- return __fixint(a);
-}
+COMPILER_RT_ABI ti_int __fixtfti(fp_t a) { return __fixint(a); }
#endif
diff --git a/contrib/libs/cxxsupp/builtins/fixunsdfdi.c b/contrib/libs/cxxsupp/builtins/fixunsdfdi.c
index 4b0bc9e1d0..f15f86788e 100644
--- a/contrib/libs/cxxsupp/builtins/fixunsdfdi.c
+++ b/contrib/libs/cxxsupp/builtins/fixunsdfdi.c
@@ -1,44 +1,46 @@
-/* ===-- fixunsdfdi.c - Implement __fixunsdfdi -----------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- fixunsdfdi.c - Implement __fixunsdfdi -----------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
#define DOUBLE_PRECISION
#include "fp_lib.h"
-ARM_EABI_FNALIAS(d2ulz, fixunsdfdi)
+#ifndef __SOFTFP__
+// Support for systems that have hardware floating-point; can set the invalid
+// flag as a side-effect of computation.
-#ifndef __SOFT_FP__
-/* Support for systems that have hardware floating-point; can set the invalid
- * flag as a side-effect of computation.
- */
-
-COMPILER_RT_ABI du_int
-__fixunsdfdi(double a)
-{
- if (a <= 0.0) return 0;
- su_int high = a / 4294967296.f; /* a / 0x1p32f; */
- su_int low = a - (double)high * 4294967296.f; /* high * 0x1p32f; */
- return ((du_int)high << 32) | low;
+COMPILER_RT_ABI du_int __fixunsdfdi(double a) {
+ if (a <= 0.0)
+ return 0;
+ su_int high = a / 4294967296.f; // a / 0x1p32f;
+ su_int low = a - (double)high * 4294967296.f; // high * 0x1p32f;
+ return ((du_int)high << 32) | low;
}
#else
-/* Support for systems that don't have hardware floating-point; there are no
- * flags to set, and we don't want to code-gen to an unknown soft-float
- * implementation.
- */
+// Support for systems that don't have hardware floating-point; there are no
+// flags to set, and we don't want to code-gen to an unknown soft-float
+// implementation.
typedef du_int fixuint_t;
#include "fp_fixuint_impl.inc"
-COMPILER_RT_ABI du_int
-__fixunsdfdi(fp_t a) {
- return __fixuint(a);
-}
+COMPILER_RT_ABI du_int __fixunsdfdi(fp_t a) { return __fixuint(a); }
+
+#endif
+
+#if defined(__ARM_EABI__)
+#if defined(COMPILER_RT_ARMHF_TARGET)
+AEABI_RTABI du_int __aeabi_d2ulz(fp_t a) { return __fixunsdfdi(a); }
+#else
+COMPILER_RT_ALIAS(__fixunsdfdi, __aeabi_d2ulz)
+#endif
+#endif
+#if defined(__MINGW32__) && defined(__arm__)
+COMPILER_RT_ALIAS(__fixunsdfdi, __dtou64)
#endif
diff --git a/contrib/libs/cxxsupp/builtins/fixunsdfsi.c b/contrib/libs/cxxsupp/builtins/fixunsdfsi.c
index 232d342d77..3db2adec09 100644
--- a/contrib/libs/cxxsupp/builtins/fixunsdfsi.c
+++ b/contrib/libs/cxxsupp/builtins/fixunsdfsi.c
@@ -1,21 +1,22 @@
-/* ===-- fixunsdfsi.c - Implement __fixunsdfsi -----------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- fixunsdfsi.c - Implement __fixunsdfsi -----------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
#define DOUBLE_PRECISION
#include "fp_lib.h"
typedef su_int fixuint_t;
#include "fp_fixuint_impl.inc"
-ARM_EABI_FNALIAS(d2uiz, fixunsdfsi)
+COMPILER_RT_ABI su_int __fixunsdfsi(fp_t a) { return __fixuint(a); }
-COMPILER_RT_ABI su_int
-__fixunsdfsi(fp_t a) {
- return __fixuint(a);
-}
+#if defined(__ARM_EABI__)
+#if defined(COMPILER_RT_ARMHF_TARGET)
+AEABI_RTABI su_int __aeabi_d2uiz(fp_t a) { return __fixunsdfsi(a); }
+#else
+COMPILER_RT_ALIAS(__fixunsdfsi, __aeabi_d2uiz)
+#endif
+#endif
diff --git a/contrib/libs/cxxsupp/builtins/fixunsdfti.c b/contrib/libs/cxxsupp/builtins/fixunsdfti.c
index f8046a0263..be497d0e16 100644
--- a/contrib/libs/cxxsupp/builtins/fixunsdfti.c
+++ b/contrib/libs/cxxsupp/builtins/fixunsdfti.c
@@ -1,12 +1,10 @@
-/* ===-- fixunsdfti.c - Implement __fixunsdfti -----------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- fixunsdfti.c - Implement __fixunsdfti -----------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
@@ -16,8 +14,5 @@
typedef tu_int fixuint_t;
#include "fp_fixuint_impl.inc"
-COMPILER_RT_ABI tu_int
-__fixunsdfti(fp_t a) {
- return __fixuint(a);
-}
-#endif /* CRT_HAS_128BIT */
+COMPILER_RT_ABI tu_int __fixunsdfti(fp_t a) { return __fixuint(a); }
+#endif // CRT_HAS_128BIT
diff --git a/contrib/libs/cxxsupp/builtins/fixunssfdi.c b/contrib/libs/cxxsupp/builtins/fixunssfdi.c
index f8ebab854f..e8f600df97 100644
--- a/contrib/libs/cxxsupp/builtins/fixunssfdi.c
+++ b/contrib/libs/cxxsupp/builtins/fixunssfdi.c
@@ -1,45 +1,47 @@
-/* ===-- fixunssfdi.c - Implement __fixunssfdi -----------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- fixunssfdi.c - Implement __fixunssfdi -----------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
#define SINGLE_PRECISION
#include "fp_lib.h"
-ARM_EABI_FNALIAS(f2ulz, fixunssfdi)
-
-#ifndef __SOFT_FP__
-/* Support for systems that have hardware floating-point; can set the invalid
- * flag as a side-effect of computation.
- */
-
-COMPILER_RT_ABI du_int
-__fixunssfdi(float a)
-{
- if (a <= 0.0f) return 0;
- double da = a;
- su_int high = da / 4294967296.f; /* da / 0x1p32f; */
- su_int low = da - (double)high * 4294967296.f; /* high * 0x1p32f; */
- return ((du_int)high << 32) | low;
+#ifndef __SOFTFP__
+// Support for systems that have hardware floating-point; can set the invalid
+// flag as a side-effect of computation.
+
+COMPILER_RT_ABI du_int __fixunssfdi(float a) {
+ if (a <= 0.0f)
+ return 0;
+ double da = a;
+ su_int high = da / 4294967296.f; // da / 0x1p32f;
+ su_int low = da - (double)high * 4294967296.f; // high * 0x1p32f;
+ return ((du_int)high << 32) | low;
}
#else
-/* Support for systems that don't have hardware floating-point; there are no
- * flags to set, and we don't want to code-gen to an unknown soft-float
- * implementation.
- */
+// Support for systems that don't have hardware floating-point; there are no
+// flags to set, and we don't want to code-gen to an unknown soft-float
+// implementation.
typedef du_int fixuint_t;
#include "fp_fixuint_impl.inc"
-COMPILER_RT_ABI du_int
-__fixunssfdi(fp_t a) {
- return __fixuint(a);
-}
+COMPILER_RT_ABI du_int __fixunssfdi(fp_t a) { return __fixuint(a); }
+
+#endif
+
+#if defined(__ARM_EABI__)
+#if defined(COMPILER_RT_ARMHF_TARGET)
+AEABI_RTABI du_int __aeabi_f2ulz(fp_t a) { return __fixunssfdi(a); }
+#else
+COMPILER_RT_ALIAS(__fixunssfdi, __aeabi_f2ulz)
+#endif
+#endif
+#if defined(__MINGW32__) && defined(__arm__)
+COMPILER_RT_ALIAS(__fixunssfdi, __stou64)
#endif
diff --git a/contrib/libs/cxxsupp/builtins/fixunssfsi.c b/contrib/libs/cxxsupp/builtins/fixunssfsi.c
index cc2b05bd84..738c1bb956 100644
--- a/contrib/libs/cxxsupp/builtins/fixunssfsi.c
+++ b/contrib/libs/cxxsupp/builtins/fixunssfsi.c
@@ -1,25 +1,26 @@
-/* ===-- fixunssfsi.c - Implement __fixunssfsi -----------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __fixunssfsi for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- fixunssfsi.c - Implement __fixunssfsi -----------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __fixunssfsi for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#define SINGLE_PRECISION
#include "fp_lib.h"
typedef su_int fixuint_t;
#include "fp_fixuint_impl.inc"
-ARM_EABI_FNALIAS(f2uiz, fixunssfsi)
+COMPILER_RT_ABI su_int __fixunssfsi(fp_t a) { return __fixuint(a); }
-COMPILER_RT_ABI su_int
-__fixunssfsi(fp_t a) {
- return __fixuint(a);
-}
+#if defined(__ARM_EABI__)
+#if defined(COMPILER_RT_ARMHF_TARGET)
+AEABI_RTABI su_int __aeabi_f2uiz(fp_t a) { return __fixunssfsi(a); }
+#else
+COMPILER_RT_ALIAS(__fixunssfsi, __aeabi_f2uiz)
+#endif
+#endif
diff --git a/contrib/libs/cxxsupp/builtins/fixunssfti.c b/contrib/libs/cxxsupp/builtins/fixunssfti.c
index 862d7bd6c7..5525d77f26 100644
--- a/contrib/libs/cxxsupp/builtins/fixunssfti.c
+++ b/contrib/libs/cxxsupp/builtins/fixunssfti.c
@@ -1,16 +1,14 @@
-/* ===-- fixunssfti.c - Implement __fixunssfti -----------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __fixunssfti for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- fixunssfti.c - Implement __fixunssfti -----------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __fixunssfti for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#define SINGLE_PRECISION
#include "fp_lib.h"
@@ -19,8 +17,5 @@
typedef tu_int fixuint_t;
#include "fp_fixuint_impl.inc"
-COMPILER_RT_ABI tu_int
-__fixunssfti(fp_t a) {
- return __fixuint(a);
-}
+COMPILER_RT_ABI tu_int __fixunssfti(fp_t a) { return __fixuint(a); }
#endif
diff --git a/contrib/libs/cxxsupp/builtins/fixunstfdi.c b/contrib/libs/cxxsupp/builtins/fixunstfdi.c
index b2995f6583..a0805e63db 100644
--- a/contrib/libs/cxxsupp/builtins/fixunstfdi.c
+++ b/contrib/libs/cxxsupp/builtins/fixunstfdi.c
@@ -1,12 +1,10 @@
-/* ===-- fixunstfdi.c - Implement __fixunstfdi -----------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- fixunstfdi.c - Implement __fixunstfdi -----------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
#define QUAD_PRECISION
#include "fp_lib.h"
@@ -15,8 +13,5 @@
typedef du_int fixuint_t;
#include "fp_fixuint_impl.inc"
-COMPILER_RT_ABI du_int
-__fixunstfdi(fp_t a) {
- return __fixuint(a);
-}
+COMPILER_RT_ABI du_int __fixunstfdi(fp_t a) { return __fixuint(a); }
#endif
diff --git a/contrib/libs/cxxsupp/builtins/fixunstfsi.c b/contrib/libs/cxxsupp/builtins/fixunstfsi.c
index b5d3f6a7d3..3a1320ed3e 100644
--- a/contrib/libs/cxxsupp/builtins/fixunstfsi.c
+++ b/contrib/libs/cxxsupp/builtins/fixunstfsi.c
@@ -1,12 +1,10 @@
-/* ===-- fixunstfsi.c - Implement __fixunstfsi -----------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- fixunstfsi.c - Implement __fixunstfsi -----------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
#define QUAD_PRECISION
#include "fp_lib.h"
@@ -15,8 +13,5 @@
typedef su_int fixuint_t;
#include "fp_fixuint_impl.inc"
-COMPILER_RT_ABI su_int
-__fixunstfsi(fp_t a) {
- return __fixuint(a);
-}
+COMPILER_RT_ABI su_int __fixunstfsi(fp_t a) { return __fixuint(a); }
#endif
diff --git a/contrib/libs/cxxsupp/builtins/fixunstfti.c b/contrib/libs/cxxsupp/builtins/fixunstfti.c
index 22ff9dfc03..23cd1ab615 100644
--- a/contrib/libs/cxxsupp/builtins/fixunstfti.c
+++ b/contrib/libs/cxxsupp/builtins/fixunstfti.c
@@ -1,12 +1,10 @@
-/* ===-- fixunstfsi.c - Implement __fixunstfsi -----------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- fixunstfsi.c - Implement __fixunstfsi -----------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
#define QUAD_PRECISION
#include "fp_lib.h"
@@ -15,8 +13,5 @@
typedef tu_int fixuint_t;
#include "fp_fixuint_impl.inc"
-COMPILER_RT_ABI tu_int
-__fixunstfti(fp_t a) {
- return __fixuint(a);
-}
+COMPILER_RT_ABI tu_int __fixunstfti(fp_t a) { return __fixuint(a); }
#endif
diff --git a/contrib/libs/cxxsupp/builtins/fixunsxfdi.c b/contrib/libs/cxxsupp/builtins/fixunsxfdi.c
index 075304e78d..c8a8061b2c 100644
--- a/contrib/libs/cxxsupp/builtins/fixunsxfdi.c
+++ b/contrib/libs/cxxsupp/builtins/fixunsxfdi.c
@@ -1,46 +1,50 @@
-/* ===-- fixunsxfdi.c - Implement __fixunsxfdi -----------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __fixunsxfdi for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- fixunsxfdi.c - Implement __fixunsxfdi -----------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __fixunsxfdi for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#if !_ARCH_PPC
#include "int_lib.h"
-/* Returns: convert a to a unsigned long long, rounding toward zero.
- * Negative values all become zero.
- */
-
-/* Assumption: long double is an intel 80 bit floating point type padded with 6 bytes
- * du_int is a 64 bit integral type
- * value in long double is representable in du_int or is negative
- * (no range checking performed)
- */
-
-/* gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee eeee |
- * 1mmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm
- */
-
-COMPILER_RT_ABI du_int
-__fixunsxfdi(long double a)
-{
- long_double_bits fb;
- fb.f = a;
- int e = (fb.u.high.s.low & 0x00007FFF) - 16383;
- if (e < 0 || (fb.u.high.s.low & 0x00008000))
- return 0;
- if ((unsigned)e > sizeof(du_int) * CHAR_BIT)
- return ~(du_int)0;
- return fb.u.low.all >> (63 - e);
+// Returns: convert a to a unsigned long long, rounding toward zero.
+// Negative values all become zero.
+
+// Assumption: long double is an intel 80 bit floating point type padded with 6
+// bytes du_int is a 64 bit integral type value in long double is representable
+// in du_int or is negative (no range checking performed)
+
+// gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee
+// eeee | 1mmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm
+// mmmm mmmm mmmm
+
+#if defined(_MSC_VER) && !defined(__clang__)
+// MSVC throws a warning about 'uninitialized variable use' here,
+// disable it for builds that warn-as-error
+#pragma warning(push)
+#pragma warning(disable : 4700)
+#endif
+
+COMPILER_RT_ABI du_int __fixunsxfdi(long double a) {
+ long_double_bits fb;
+ fb.f = a;
+ int e = (fb.u.high.s.low & 0x00007FFF) - 16383;
+ if (e < 0 || (fb.u.high.s.low & 0x00008000))
+ return 0;
+ if ((unsigned)e > sizeof(du_int) * CHAR_BIT)
+ return ~(du_int)0;
+ return fb.u.low.all >> (63 - e);
}
+#if defined(_MSC_VER) && !defined(__clang__)
+#pragma warning(pop)
#endif
+
+#endif //!_ARCH_PPC
diff --git a/contrib/libs/cxxsupp/builtins/fixunsxfsi.c b/contrib/libs/cxxsupp/builtins/fixunsxfsi.c
index c3c70f743d..154abcbd35 100644
--- a/contrib/libs/cxxsupp/builtins/fixunsxfsi.c
+++ b/contrib/libs/cxxsupp/builtins/fixunsxfsi.c
@@ -1,45 +1,50 @@
-/* ===-- fixunsxfsi.c - Implement __fixunsxfsi -----------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __fixunsxfsi for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- fixunsxfsi.c - Implement __fixunsxfsi -----------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __fixunsxfsi for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#if !_ARCH_PPC
#include "int_lib.h"
-/* Returns: convert a to a unsigned int, rounding toward zero.
- * Negative values all become zero.
- */
-
-/* Assumption: long double is an intel 80 bit floating point type padded with 6 bytes
- * su_int is a 32 bit integral type
- * value in long double is representable in su_int or is negative
- */
-
-/* gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee eeee |
- * 1mmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm
- */
-
-COMPILER_RT_ABI su_int
-__fixunsxfsi(long double a)
-{
- long_double_bits fb;
- fb.f = a;
- int e = (fb.u.high.s.low & 0x00007FFF) - 16383;
- if (e < 0 || (fb.u.high.s.low & 0x00008000))
- return 0;
- if ((unsigned)e > sizeof(su_int) * CHAR_BIT)
- return ~(su_int)0;
- return fb.u.low.s.high >> (31 - e);
+// Returns: convert a to a unsigned int, rounding toward zero.
+// Negative values all become zero.
+
+// Assumption: long double is an intel 80 bit floating point type padded with 6
+// bytes su_int is a 32 bit integral type value in long double is representable
+// in su_int or is negative
+
+// gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee
+// eeee | 1mmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm
+// mmmm mmmm mmmm
+
+#if defined(_MSC_VER) && !defined(__clang__)
+// MSVC throws a warning about 'uninitialized variable use' here,
+// disable it for builds that warn-as-error
+#pragma warning(push)
+#pragma warning(disable : 4700)
+#endif
+
+COMPILER_RT_ABI su_int __fixunsxfsi(long double a) {
+ long_double_bits fb;
+ fb.f = a;
+ int e = (fb.u.high.s.low & 0x00007FFF) - 16383;
+ if (e < 0 || (fb.u.high.s.low & 0x00008000))
+ return 0;
+ if ((unsigned)e > sizeof(su_int) * CHAR_BIT)
+ return ~(su_int)0;
+ return fb.u.low.s.high >> (31 - e);
}
-#endif /* !_ARCH_PPC */
+#if defined(_MSC_VER) && !defined(__clang__)
+#pragma warning(pop)
+#endif
+
+#endif // !_ARCH_PPC
diff --git a/contrib/libs/cxxsupp/builtins/fixunsxfti.c b/contrib/libs/cxxsupp/builtins/fixunsxfti.c
index fb39d00ff5..508554e4f8 100644
--- a/contrib/libs/cxxsupp/builtins/fixunsxfti.c
+++ b/contrib/libs/cxxsupp/builtins/fixunsxfti.c
@@ -1,50 +1,44 @@
-/* ===-- fixunsxfti.c - Implement __fixunsxfti -----------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __fixunsxfti for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- fixunsxfti.c - Implement __fixunsxfti -----------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __fixunsxfti for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
#ifdef CRT_HAS_128BIT
-/* Returns: convert a to a unsigned long long, rounding toward zero.
- * Negative values all become zero.
- */
+// Returns: convert a to a unsigned long long, rounding toward zero.
+// Negative values all become zero.
-/* Assumption: long double is an intel 80 bit floating point type padded with 6 bytes
- * tu_int is a 128 bit integral type
- * value in long double is representable in tu_int or is negative
- */
+// Assumption: long double is an intel 80 bit floating point type padded with 6
+// bytes tu_int is a 128 bit integral type value in long double is representable
+// in tu_int or is negative
-/* gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee eeee |
- * 1mmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm
- */
+// gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee
+// eeee | 1mmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm
+// mmmm mmmm mmmm
-COMPILER_RT_ABI tu_int
-__fixunsxfti(long double a)
-{
- long_double_bits fb;
- fb.f = a;
- int e = (fb.u.high.s.low & 0x00007FFF) - 16383;
- if (e < 0 || (fb.u.high.s.low & 0x00008000))
- return 0;
- if ((unsigned)e > sizeof(tu_int) * CHAR_BIT)
- return ~(tu_int)0;
- tu_int r = fb.u.low.all;
- if (e > 63)
- r <<= (e - 63);
- else
- r >>= (63 - e);
- return r;
+COMPILER_RT_ABI tu_int __fixunsxfti(long double a) {
+ long_double_bits fb;
+ fb.f = a;
+ int e = (fb.u.high.s.low & 0x00007FFF) - 16383;
+ if (e < 0 || (fb.u.high.s.low & 0x00008000))
+ return 0;
+ if ((unsigned)e > sizeof(tu_int) * CHAR_BIT)
+ return ~(tu_int)0;
+ tu_int r = fb.u.low.all;
+ if (e > 63)
+ r <<= (e - 63);
+ else
+ r >>= (63 - e);
+ return r;
}
-#endif /* CRT_HAS_128BIT */
+#endif // CRT_HAS_128BIT
diff --git a/contrib/libs/cxxsupp/builtins/fixxfdi.c b/contrib/libs/cxxsupp/builtins/fixxfdi.c
index 011787f9e4..86cf3767b7 100644
--- a/contrib/libs/cxxsupp/builtins/fixxfdi.c
+++ b/contrib/libs/cxxsupp/builtins/fixxfdi.c
@@ -1,48 +1,54 @@
-/* ===-- fixxfdi.c - Implement __fixxfdi -----------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __fixxfdi for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- fixxfdi.c - Implement __fixxfdi -----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __fixxfdi for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#if !_ARCH_PPC
#include "int_lib.h"
-/* Returns: convert a to a signed long long, rounding toward zero. */
-
-/* Assumption: long double is an intel 80 bit floating point type padded with 6 bytes
- * di_int is a 64 bit integral type
- * value in long double is representable in di_int (no range checking performed)
- */
-
-/* gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee eeee |
- * 1mmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm
- */
-
-COMPILER_RT_ABI di_int
-__fixxfdi(long double a)
-{
- const di_int di_max = (di_int)((~(du_int)0) / 2);
- const di_int di_min = -di_max - 1;
- long_double_bits fb;
- fb.f = a;
- int e = (fb.u.high.s.low & 0x00007FFF) - 16383;
- if (e < 0)
- return 0;
- if ((unsigned)e >= sizeof(di_int) * CHAR_BIT)
- return a > 0 ? di_max : di_min;
- di_int s = -(si_int)((fb.u.high.s.low & 0x00008000) >> 15);
- di_int r = fb.u.low.all;
- r = (du_int)r >> (63 - e);
- return (r ^ s) - s;
+// Returns: convert a to a signed long long, rounding toward zero.
+
+// Assumption: long double is an intel 80 bit floating point type padded with 6
+// bytes di_int is a 64 bit integral type value in long double is representable
+// in di_int (no range checking performed)
+
+// gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee
+// eeee | 1mmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm
+// mmmm mmmm mmmm
+
+#if defined(_MSC_VER) && !defined(__clang__)
+// MSVC throws a warning about 'uninitialized variable use' here,
+// disable it for builds that warn-as-error
+#pragma warning(push)
+#pragma warning(disable : 4700)
+#endif
+
+COMPILER_RT_ABI di_int __fixxfdi(long double a) {
+ const di_int di_max = (di_int)((~(du_int)0) / 2);
+ const di_int di_min = -di_max - 1;
+ long_double_bits fb;
+ fb.f = a;
+ int e = (fb.u.high.s.low & 0x00007FFF) - 16383;
+ if (e < 0)
+ return 0;
+ if ((unsigned)e >= sizeof(di_int) * CHAR_BIT)
+ return a > 0 ? di_max : di_min;
+ di_int s = -(si_int)((fb.u.high.s.low & 0x00008000) >> 15);
+ di_int r = fb.u.low.all;
+ r = (du_int)r >> (63 - e);
+ return (r ^ s) - s;
}
-#endif /* !_ARCH_PPC */
+#if defined(_MSC_VER) && !defined(__clang__)
+#pragma warning(pop)
+#endif
+
+#endif // !_ARCH_PPC
diff --git a/contrib/libs/cxxsupp/builtins/fixxfti.c b/contrib/libs/cxxsupp/builtins/fixxfti.c
index 968a4f0d5e..90e03116e7 100644
--- a/contrib/libs/cxxsupp/builtins/fixxfti.c
+++ b/contrib/libs/cxxsupp/builtins/fixxfti.c
@@ -1,51 +1,46 @@
-/* ===-- fixxfti.c - Implement __fixxfti -----------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __fixxfti for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- fixxfti.c - Implement __fixxfti -----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __fixxfti for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
#ifdef CRT_HAS_128BIT
-/* Returns: convert a to a signed long long, rounding toward zero. */
+// Returns: convert a to a signed long long, rounding toward zero.
-/* Assumption: long double is an intel 80 bit floating point type padded with 6 bytes
- * ti_int is a 128 bit integral type
- * value in long double is representable in ti_int
- */
+// Assumption: long double is an intel 80 bit floating point type padded with 6
+// bytes ti_int is a 128 bit integral type value in long double is representable
+// in ti_int
-/* gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee eeee |
- * 1mmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm
- */
+// gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee
+// eeee | 1mmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm
+// mmmm mmmm mmmm
-COMPILER_RT_ABI ti_int
-__fixxfti(long double a)
-{
- const ti_int ti_max = (ti_int)((~(tu_int)0) / 2);
- const ti_int ti_min = -ti_max - 1;
- long_double_bits fb;
- fb.f = a;
- int e = (fb.u.high.s.low & 0x00007FFF) - 16383;
- if (e < 0)
- return 0;
- ti_int s = -(si_int)((fb.u.high.s.low & 0x00008000) >> 15);
- ti_int r = fb.u.low.all;
- if ((unsigned)e >= sizeof(ti_int) * CHAR_BIT)
- return a > 0 ? ti_max : ti_min;
- if (e > 63)
- r <<= (e - 63);
- else
- r >>= (63 - e);
- return (r ^ s) - s;
+COMPILER_RT_ABI ti_int __fixxfti(long double a) {
+ const ti_int ti_max = (ti_int)((~(tu_int)0) / 2);
+ const ti_int ti_min = -ti_max - 1;
+ long_double_bits fb;
+ fb.f = a;
+ int e = (fb.u.high.s.low & 0x00007FFF) - 16383;
+ if (e < 0)
+ return 0;
+ ti_int s = -(si_int)((fb.u.high.s.low & 0x00008000) >> 15);
+ ti_int r = fb.u.low.all;
+ if ((unsigned)e >= sizeof(ti_int) * CHAR_BIT)
+ return a > 0 ? ti_max : ti_min;
+ if (e > 63)
+ r <<= (e - 63);
+ else
+ r >>= (63 - e);
+ return (r ^ s) - s;
}
-#endif /* CRT_HAS_128BIT */
+#endif // CRT_HAS_128BIT
diff --git a/contrib/libs/cxxsupp/builtins/floatdidf.c b/contrib/libs/cxxsupp/builtins/floatdidf.c
index a300c9f312..d37c43b1f2 100644
--- a/contrib/libs/cxxsupp/builtins/floatdidf.c
+++ b/contrib/libs/cxxsupp/builtins/floatdidf.c
@@ -1,107 +1,107 @@
-/*===-- floatdidf.c - Implement __floatdidf -------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- *===----------------------------------------------------------------------===
- *
- * This file implements __floatdidf for the compiler_rt library.
- *
- *===----------------------------------------------------------------------===
- */
+//===-- floatdidf.c - Implement __floatdidf -------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __floatdidf for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
-/* Returns: convert a to a double, rounding toward even. */
+// Returns: convert a to a double, rounding toward even.
-/* Assumption: double is a IEEE 64 bit floating point type
- * di_int is a 64 bit integral type
- */
+// Assumption: double is a IEEE 64 bit floating point type
+// di_int is a 64 bit integral type
-/* seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm */
+// seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm
+// mmmm
-ARM_EABI_FNALIAS(l2d, floatdidf)
+#ifndef __SOFTFP__
+// Support for systems that have hardware floating-point; we'll set the inexact
+// flag as a side-effect of this computation.
-#ifndef __SOFT_FP__
-/* Support for systems that have hardware floating-point; we'll set the inexact flag
- * as a side-effect of this computation.
- */
+COMPILER_RT_ABI double __floatdidf(di_int a) {
+ static const double twop52 = 4503599627370496.0; // 0x1.0p52
+ static const double twop32 = 4294967296.0; // 0x1.0p32
-COMPILER_RT_ABI double
-__floatdidf(di_int a)
-{
- static const double twop52 = 4503599627370496.0; // 0x1.0p52
- static const double twop32 = 4294967296.0; // 0x1.0p32
-
- union { int64_t x; double d; } low = { .d = twop52 };
-
- const double high = (int32_t)(a >> 32) * twop32;
- low.x |= a & INT64_C(0x00000000ffffffff);
-
- const double result = (high - twop52) + low.d;
- return result;
+ union {
+ int64_t x;
+ double d;
+ } low = {.d = twop52};
+
+ const double high = (int32_t)(a >> 32) * twop32;
+ low.x |= a & INT64_C(0x00000000ffffffff);
+
+ const double result = (high - twop52) + low.d;
+ return result;
}
#else
-/* Support for systems that don't have hardware floating-point; there are no flags to
- * set, and we don't want to code-gen to an unknown soft-float implementation.
- */
+// Support for systems that don't have hardware floating-point; there are no
+// flags to set, and we don't want to code-gen to an unknown soft-float
+// implementation.
-COMPILER_RT_ABI double
-__floatdidf(di_int a)
-{
- if (a == 0)
- return 0.0;
- const unsigned N = sizeof(di_int) * CHAR_BIT;
- const di_int s = a >> (N-1);
- a = (a ^ s) - s;
- int sd = N - __builtin_clzll(a); /* number of significant digits */
- int e = sd - 1; /* exponent */
- if (sd > DBL_MANT_DIG)
- {
- /* start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
- * finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
- * 12345678901234567890123456
- * 1 = msb 1 bit
- * P = bit DBL_MANT_DIG-1 bits to the right of 1
- * Q = bit DBL_MANT_DIG bits to the right of 1
- * R = "or" of all bits to the right of Q
- */
- switch (sd)
- {
- case DBL_MANT_DIG + 1:
- a <<= 1;
- break;
- case DBL_MANT_DIG + 2:
- break;
- default:
- a = ((du_int)a >> (sd - (DBL_MANT_DIG+2))) |
- ((a & ((du_int)(-1) >> ((N + DBL_MANT_DIG+2) - sd))) != 0);
- };
- /* finish: */
- a |= (a & 4) != 0; /* Or P into R */
- ++a; /* round - this step may add a significant bit */
- a >>= 2; /* dump Q and R */
- /* a is now rounded to DBL_MANT_DIG or DBL_MANT_DIG+1 bits */
- if (a & ((du_int)1 << DBL_MANT_DIG))
- {
- a >>= 1;
- ++e;
- }
- /* a is now rounded to DBL_MANT_DIG bits */
- }
- else
- {
- a <<= (DBL_MANT_DIG - sd);
- /* a is now rounded to DBL_MANT_DIG bits */
+COMPILER_RT_ABI double __floatdidf(di_int a) {
+ if (a == 0)
+ return 0.0;
+ const unsigned N = sizeof(di_int) * CHAR_BIT;
+ const di_int s = a >> (N - 1);
+ a = (a ^ s) - s;
+ int sd = N - __builtin_clzll(a); // number of significant digits
+ int e = sd - 1; // exponent
+ if (sd > DBL_MANT_DIG) {
+ // start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
+ // finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
+ // 12345678901234567890123456
+ // 1 = msb 1 bit
+ // P = bit DBL_MANT_DIG-1 bits to the right of 1
+ // Q = bit DBL_MANT_DIG bits to the right of 1
+ // R = "or" of all bits to the right of Q
+ switch (sd) {
+ case DBL_MANT_DIG + 1:
+ a <<= 1;
+ break;
+ case DBL_MANT_DIG + 2:
+ break;
+ default:
+ a = ((du_int)a >> (sd - (DBL_MANT_DIG + 2))) |
+ ((a & ((du_int)(-1) >> ((N + DBL_MANT_DIG + 2) - sd))) != 0);
+ };
+ // finish:
+ a |= (a & 4) != 0; // Or P into R
+ ++a; // round - this step may add a significant bit
+ a >>= 2; // dump Q and R
+ // a is now rounded to DBL_MANT_DIG or DBL_MANT_DIG+1 bits
+ if (a & ((du_int)1 << DBL_MANT_DIG)) {
+ a >>= 1;
+ ++e;
}
- double_bits fb;
- fb.u.high = ((su_int)s & 0x80000000) | /* sign */
- ((e + 1023) << 20) | /* exponent */
- ((su_int)(a >> 32) & 0x000FFFFF); /* mantissa-high */
- fb.u.low = (su_int)a; /* mantissa-low */
- return fb.f;
+ // a is now rounded to DBL_MANT_DIG bits
+ } else {
+ a <<= (DBL_MANT_DIG - sd);
+ // a is now rounded to DBL_MANT_DIG bits
+ }
+ double_bits fb;
+ fb.u.s.high = ((su_int)s & 0x80000000) | // sign
+ ((su_int)(e + 1023) << 20) | // exponent
+ ((su_int)(a >> 32) & 0x000FFFFF); // mantissa-high
+ fb.u.s.low = (su_int)a; // mantissa-low
+ return fb.f;
}
#endif
+
+#if defined(__ARM_EABI__)
+#if defined(COMPILER_RT_ARMHF_TARGET)
+AEABI_RTABI double __aeabi_l2d(di_int a) { return __floatdidf(a); }
+#else
+COMPILER_RT_ALIAS(__floatdidf, __aeabi_l2d)
+#endif
+#endif
+
+#if defined(__MINGW32__) && defined(__arm__)
+COMPILER_RT_ALIAS(__floatdidf, __i64tod)
+#endif
diff --git a/contrib/libs/cxxsupp/builtins/floatdisf.c b/contrib/libs/cxxsupp/builtins/floatdisf.c
index 3e47580ef5..5c6316431e 100644
--- a/contrib/libs/cxxsupp/builtins/floatdisf.c
+++ b/contrib/libs/cxxsupp/builtins/floatdisf.c
@@ -1,80 +1,79 @@
-/*===-- floatdisf.c - Implement __floatdisf -------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- *===----------------------------------------------------------------------===
- *
- * This file implements __floatdisf for the compiler_rt library.
- *
- *===----------------------------------------------------------------------===
- */
+//===-- floatdisf.c - Implement __floatdisf -------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __floatdisf for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
-/* Returns: convert a to a float, rounding toward even.*/
+// Returns: convert a to a float, rounding toward even.
-/* Assumption: float is a IEEE 32 bit floating point type
- * di_int is a 64 bit integral type
- */
+// Assumption: float is a IEEE 32 bit floating point type
+// di_int is a 64 bit integral type
-/* seee eeee emmm mmmm mmmm mmmm mmmm mmmm */
+// seee eeee emmm mmmm mmmm mmmm mmmm mmmm
#include "int_lib.h"
-ARM_EABI_FNALIAS(l2f, floatdisf)
-
-COMPILER_RT_ABI float
-__floatdisf(di_int a)
-{
- if (a == 0)
- return 0.0F;
- const unsigned N = sizeof(di_int) * CHAR_BIT;
- const di_int s = a >> (N-1);
- a = (a ^ s) - s;
- int sd = N - __builtin_clzll(a); /* number of significant digits */
- int e = sd - 1; /* exponent */
- if (sd > FLT_MANT_DIG)
- {
- /* start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
- * finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
- * 12345678901234567890123456
- * 1 = msb 1 bit
- * P = bit FLT_MANT_DIG-1 bits to the right of 1
- * Q = bit FLT_MANT_DIG bits to the right of 1
- * R = "or" of all bits to the right of Q
- */
- switch (sd)
- {
- case FLT_MANT_DIG + 1:
- a <<= 1;
- break;
- case FLT_MANT_DIG + 2:
- break;
- default:
- a = ((du_int)a >> (sd - (FLT_MANT_DIG+2))) |
- ((a & ((du_int)(-1) >> ((N + FLT_MANT_DIG+2) - sd))) != 0);
- };
- /* finish: */
- a |= (a & 4) != 0; /* Or P into R */
- ++a; /* round - this step may add a significant bit */
- a >>= 2; /* dump Q and R */
- /* a is now rounded to FLT_MANT_DIG or FLT_MANT_DIG+1 bits */
- if (a & ((du_int)1 << FLT_MANT_DIG))
- {
- a >>= 1;
- ++e;
- }
- /* a is now rounded to FLT_MANT_DIG bits */
- }
- else
- {
- a <<= (FLT_MANT_DIG - sd);
- /* a is now rounded to FLT_MANT_DIG bits */
+COMPILER_RT_ABI float __floatdisf(di_int a) {
+ if (a == 0)
+ return 0.0F;
+ const unsigned N = sizeof(di_int) * CHAR_BIT;
+ const di_int s = a >> (N - 1);
+ a = (a ^ s) - s;
+ int sd = N - __builtin_clzll(a); // number of significant digits
+ si_int e = sd - 1; // exponent
+ if (sd > FLT_MANT_DIG) {
+ // start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
+ // finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
+ // 12345678901234567890123456
+ // 1 = msb 1 bit
+ // P = bit FLT_MANT_DIG-1 bits to the right of 1
+ // Q = bit FLT_MANT_DIG bits to the right of 1
+ // R = "or" of all bits to the right of Q
+ switch (sd) {
+ case FLT_MANT_DIG + 1:
+ a <<= 1;
+ break;
+ case FLT_MANT_DIG + 2:
+ break;
+ default:
+ a = ((du_int)a >> (sd - (FLT_MANT_DIG + 2))) |
+ ((a & ((du_int)(-1) >> ((N + FLT_MANT_DIG + 2) - sd))) != 0);
+ };
+ // finish:
+ a |= (a & 4) != 0; // Or P into R
+ ++a; // round - this step may add a significant bit
+ a >>= 2; // dump Q and R
+ // a is now rounded to FLT_MANT_DIG or FLT_MANT_DIG+1 bits
+ if (a & ((du_int)1 << FLT_MANT_DIG)) {
+ a >>= 1;
+ ++e;
}
- float_bits fb;
- fb.u = ((su_int)s & 0x80000000) | /* sign */
- ((e + 127) << 23) | /* exponent */
- ((su_int)a & 0x007FFFFF); /* mantissa */
- return fb.f;
+ // a is now rounded to FLT_MANT_DIG bits
+ } else {
+ a <<= (FLT_MANT_DIG - sd);
+ // a is now rounded to FLT_MANT_DIG bits
+ }
+ float_bits fb;
+ fb.u = ((su_int)s & 0x80000000) | // sign
+ ((e + 127) << 23) | // exponent
+ ((su_int)a & 0x007FFFFF); // mantissa
+ return fb.f;
}
+
+#if defined(__ARM_EABI__)
+#if defined(COMPILER_RT_ARMHF_TARGET)
+AEABI_RTABI float __aeabi_l2f(di_int a) { return __floatdisf(a); }
+#else
+COMPILER_RT_ALIAS(__floatdisf, __aeabi_l2f)
+#endif
+#endif
+
+#if defined(__MINGW32__) && defined(__arm__)
+COMPILER_RT_ALIAS(__floatdisf, __i64tos)
+#endif
diff --git a/contrib/libs/cxxsupp/builtins/floatditf.c b/contrib/libs/cxxsupp/builtins/floatditf.c
index cd51dd8aad..9b07b65825 100644
--- a/contrib/libs/cxxsupp/builtins/floatditf.c
+++ b/contrib/libs/cxxsupp/builtins/floatditf.c
@@ -1,9 +1,8 @@
//===-- lib/floatditf.c - integer -> quad-precision conversion ----*- C -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -19,32 +18,32 @@
#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT)
COMPILER_RT_ABI fp_t __floatditf(di_int a) {
- const int aWidth = sizeof a * CHAR_BIT;
+ const int aWidth = sizeof a * CHAR_BIT;
- // Handle zero as a special case to protect clz
- if (a == 0)
- return fromRep(0);
+ // Handle zero as a special case to protect clz
+ if (a == 0)
+ return fromRep(0);
- // All other cases begin by extracting the sign and absolute value of a
- rep_t sign = 0;
- du_int aAbs = (du_int)a;
- if (a < 0) {
- sign = signBit;
- aAbs = ~(du_int)a + 1U;
- }
+ // All other cases begin by extracting the sign and absolute value of a
+ rep_t sign = 0;
+ du_int aAbs = (du_int)a;
+ if (a < 0) {
+ sign = signBit;
+ aAbs = ~(du_int)a + 1U;
+ }
- // Exponent of (fp_t)a is the width of abs(a).
- const int exponent = (aWidth - 1) - __builtin_clzll(aAbs);
- rep_t result;
+ // Exponent of (fp_t)a is the width of abs(a).
+ const int exponent = (aWidth - 1) - __builtin_clzll(aAbs);
+ rep_t result;
- // Shift a into the significand field, rounding if it is a right-shift
- const int shift = significandBits - exponent;
- result = (rep_t)aAbs << shift ^ implicitBit;
+ // Shift a into the significand field, rounding if it is a right-shift
+ const int shift = significandBits - exponent;
+ result = (rep_t)aAbs << shift ^ implicitBit;
- // Insert the exponent
- result += (rep_t)(exponent + exponentBias) << significandBits;
- // Insert the sign bit and return
- return fromRep(result | sign);
+ // Insert the exponent
+ result += (rep_t)(exponent + exponentBias) << significandBits;
+ // Insert the sign bit and return
+ return fromRep(result | sign);
}
#endif
diff --git a/contrib/libs/cxxsupp/builtins/floatdixf.c b/contrib/libs/cxxsupp/builtins/floatdixf.c
index d39e81d7ca..ad5deb2d4b 100644
--- a/contrib/libs/cxxsupp/builtins/floatdixf.c
+++ b/contrib/libs/cxxsupp/builtins/floatdixf.c
@@ -1,46 +1,41 @@
-/* ===-- floatdixf.c - Implement __floatdixf -------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __floatdixf for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- floatdixf.c - Implement __floatdixf -------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __floatdixf for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#if !_ARCH_PPC
#include "int_lib.h"
-/* Returns: convert a to a long double, rounding toward even. */
+// Returns: convert a to a long double, rounding toward even.
-/* Assumption: long double is a IEEE 80 bit floating point type padded to 128 bits
- * di_int is a 64 bit integral type
- */
+// Assumption: long double is a IEEE 80 bit floating point type padded to 128
+// bits di_int is a 64 bit integral type
-/* gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee eeee |
- * 1mmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm
- */
+// gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee
+// eeee | 1mmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm
+// mmmm mmmm mmmm
-COMPILER_RT_ABI long double
-__floatdixf(di_int a)
-{
- if (a == 0)
- return 0.0;
- const unsigned N = sizeof(di_int) * CHAR_BIT;
- const di_int s = a >> (N-1);
- a = (a ^ s) - s;
- int clz = __builtin_clzll(a);
- int e = (N - 1) - clz ; /* exponent */
- long_double_bits fb;
- fb.u.high.s.low = ((su_int)s & 0x00008000) | /* sign */
- (e + 16383); /* exponent */
- fb.u.low.all = a << clz; /* mantissa */
- return fb.f;
+COMPILER_RT_ABI long double __floatdixf(di_int a) {
+ if (a == 0)
+ return 0.0;
+ const unsigned N = sizeof(di_int) * CHAR_BIT;
+ const di_int s = a >> (N - 1);
+ a = (a ^ s) - s;
+ int clz = __builtin_clzll(a);
+ int e = (N - 1) - clz; // exponent
+ long_double_bits fb;
+ fb.u.high.s.low = ((su_int)s & 0x00008000) | // sign
+ (e + 16383); // exponent
+ fb.u.low.all = a << clz; // mantissa
+ return fb.f;
}
-#endif /* !_ARCH_PPC */
+#endif // !_ARCH_PPC
diff --git a/contrib/libs/cxxsupp/builtins/floatsidf.c b/contrib/libs/cxxsupp/builtins/floatsidf.c
index 1cf99b782a..28cf32f638 100644
--- a/contrib/libs/cxxsupp/builtins/floatsidf.c
+++ b/contrib/libs/cxxsupp/builtins/floatsidf.c
@@ -1,9 +1,8 @@
//===-- lib/floatsidf.c - integer -> double-precision conversion --*- C -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -18,36 +17,41 @@
#include "int_lib.h"
-ARM_EABI_FNALIAS(i2d, floatsidf)
-
-COMPILER_RT_ABI fp_t
-__floatsidf(int a) {
-
- const int aWidth = sizeof a * CHAR_BIT;
-
- // Handle zero as a special case to protect clz
- if (a == 0)
- return fromRep(0);
-
- // All other cases begin by extracting the sign and absolute value of a
- rep_t sign = 0;
- if (a < 0) {
- sign = signBit;
- a = -a;
- }
-
- // Exponent of (fp_t)a is the width of abs(a).
- const int exponent = (aWidth - 1) - __builtin_clz(a);
- rep_t result;
-
- // Shift a into the significand field and clear the implicit bit. Extra
- // cast to unsigned int is necessary to get the correct behavior for
- // the input INT_MIN.
- const int shift = significandBits - exponent;
- result = (rep_t)(unsigned int)a << shift ^ implicitBit;
-
- // Insert the exponent
- result += (rep_t)(exponent + exponentBias) << significandBits;
- // Insert the sign bit and return
- return fromRep(result | sign);
+COMPILER_RT_ABI fp_t __floatsidf(si_int a) {
+
+ const int aWidth = sizeof a * CHAR_BIT;
+
+ // Handle zero as a special case to protect clz
+ if (a == 0)
+ return fromRep(0);
+
+ // All other cases begin by extracting the sign and absolute value of a
+ rep_t sign = 0;
+ if (a < 0) {
+ sign = signBit;
+ a = -a;
+ }
+
+ // Exponent of (fp_t)a is the width of abs(a).
+ const int exponent = (aWidth - 1) - clzsi(a);
+ rep_t result;
+
+ // Shift a into the significand field and clear the implicit bit. Extra
+ // cast to unsigned int is necessary to get the correct behavior for
+ // the input INT_MIN.
+ const int shift = significandBits - exponent;
+ result = (rep_t)(su_int)a << shift ^ implicitBit;
+
+ // Insert the exponent
+ result += (rep_t)(exponent + exponentBias) << significandBits;
+ // Insert the sign bit and return
+ return fromRep(result | sign);
}
+
+#if defined(__ARM_EABI__)
+#if defined(COMPILER_RT_ARMHF_TARGET)
+AEABI_RTABI fp_t __aeabi_i2d(si_int a) { return __floatsidf(a); }
+#else
+COMPILER_RT_ALIAS(__floatsidf, __aeabi_i2d)
+#endif
+#endif
diff --git a/contrib/libs/cxxsupp/builtins/floatsisf.c b/contrib/libs/cxxsupp/builtins/floatsisf.c
index 467dd1d1ea..c01f81e41e 100644
--- a/contrib/libs/cxxsupp/builtins/floatsisf.c
+++ b/contrib/libs/cxxsupp/builtins/floatsisf.c
@@ -1,9 +1,8 @@
//===-- lib/floatsisf.c - integer -> single-precision conversion --*- C -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -18,42 +17,49 @@
#include "int_lib.h"
-ARM_EABI_FNALIAS(i2f, floatsisf)
-
-COMPILER_RT_ABI fp_t
-__floatsisf(int a) {
-
- const int aWidth = sizeof a * CHAR_BIT;
-
- // Handle zero as a special case to protect clz
- if (a == 0)
- return fromRep(0);
-
- // All other cases begin by extracting the sign and absolute value of a
- rep_t sign = 0;
- if (a < 0) {
- sign = signBit;
- a = -a;
- }
-
- // Exponent of (fp_t)a is the width of abs(a).
- const int exponent = (aWidth - 1) - __builtin_clz(a);
- rep_t result;
-
- // Shift a into the significand field, rounding if it is a right-shift
- if (exponent <= significandBits) {
- const int shift = significandBits - exponent;
- result = (rep_t)a << shift ^ implicitBit;
- } else {
- const int shift = exponent - significandBits;
- result = (rep_t)a >> shift ^ implicitBit;
- rep_t round = (rep_t)a << (typeWidth - shift);
- if (round > signBit) result++;
- if (round == signBit) result += result & 1;
- }
-
- // Insert the exponent
- result += (rep_t)(exponent + exponentBias) << significandBits;
- // Insert the sign bit and return
- return fromRep(result | sign);
+COMPILER_RT_ABI fp_t __floatsisf(si_int a) {
+
+ const int aWidth = sizeof a * CHAR_BIT;
+
+ // Handle zero as a special case to protect clz
+ if (a == 0)
+ return fromRep(0);
+
+ // All other cases begin by extracting the sign and absolute value of a
+ rep_t sign = 0;
+ if (a < 0) {
+ sign = signBit;
+ a = -a;
+ }
+
+ // Exponent of (fp_t)a is the width of abs(a).
+ const int exponent = (aWidth - 1) - clzsi(a);
+ rep_t result;
+
+ // Shift a into the significand field, rounding if it is a right-shift
+ if (exponent <= significandBits) {
+ const int shift = significandBits - exponent;
+ result = (rep_t)a << shift ^ implicitBit;
+ } else {
+ const int shift = exponent - significandBits;
+ result = (rep_t)a >> shift ^ implicitBit;
+ rep_t round = (rep_t)a << (typeWidth - shift);
+ if (round > signBit)
+ result++;
+ if (round == signBit)
+ result += result & 1;
+ }
+
+ // Insert the exponent
+ result += (rep_t)(exponent + exponentBias) << significandBits;
+ // Insert the sign bit and return
+ return fromRep(result | sign);
}
+
+#if defined(__ARM_EABI__)
+#if defined(COMPILER_RT_ARMHF_TARGET)
+AEABI_RTABI fp_t __aeabi_i2f(int a) { return __floatsisf(a); }
+#else
+COMPILER_RT_ALIAS(__floatsisf, __aeabi_i2f)
+#endif
+#endif
diff --git a/contrib/libs/cxxsupp/builtins/floatsitf.c b/contrib/libs/cxxsupp/builtins/floatsitf.c
index f0abca363b..80a4ef08fb 100644
--- a/contrib/libs/cxxsupp/builtins/floatsitf.c
+++ b/contrib/libs/cxxsupp/builtins/floatsitf.c
@@ -1,9 +1,8 @@
//===-- lib/floatsitf.c - integer -> quad-precision conversion ----*- C -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -17,34 +16,34 @@
#include "fp_lib.h"
#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT)
-COMPILER_RT_ABI fp_t __floatsitf(int a) {
-
- const int aWidth = sizeof a * CHAR_BIT;
-
- // Handle zero as a special case to protect clz
- if (a == 0)
- return fromRep(0);
-
- // All other cases begin by extracting the sign and absolute value of a
- rep_t sign = 0;
- unsigned aAbs = (unsigned)a;
- if (a < 0) {
- sign = signBit;
- aAbs = ~(unsigned)a + 1U;
- }
-
- // Exponent of (fp_t)a is the width of abs(a).
- const int exponent = (aWidth - 1) - __builtin_clz(aAbs);
- rep_t result;
-
- // Shift a into the significand field and clear the implicit bit.
- const int shift = significandBits - exponent;
- result = (rep_t)aAbs << shift ^ implicitBit;
-
- // Insert the exponent
- result += (rep_t)(exponent + exponentBias) << significandBits;
- // Insert the sign bit and return
- return fromRep(result | sign);
+COMPILER_RT_ABI fp_t __floatsitf(si_int a) {
+
+ const int aWidth = sizeof a * CHAR_BIT;
+
+ // Handle zero as a special case to protect clz
+ if (a == 0)
+ return fromRep(0);
+
+ // All other cases begin by extracting the sign and absolute value of a
+ rep_t sign = 0;
+ su_int aAbs = (su_int)a;
+ if (a < 0) {
+ sign = signBit;
+ aAbs = ~(su_int)a + (su_int)1U;
+ }
+
+ // Exponent of (fp_t)a is the width of abs(a).
+ const int exponent = (aWidth - 1) - clzsi(aAbs);
+ rep_t result;
+
+ // Shift a into the significand field and clear the implicit bit.
+ const int shift = significandBits - exponent;
+ result = (rep_t)aAbs << shift ^ implicitBit;
+
+ // Insert the exponent
+ result += (rep_t)(exponent + exponentBias) << significandBits;
+ // Insert the sign bit and return
+ return fromRep(result | sign);
}
#endif
diff --git a/contrib/libs/cxxsupp/builtins/floattidf.c b/contrib/libs/cxxsupp/builtins/floattidf.c
index 6331ba5737..0a1c04bec8 100644
--- a/contrib/libs/cxxsupp/builtins/floattidf.c
+++ b/contrib/libs/cxxsupp/builtins/floattidf.c
@@ -1,83 +1,73 @@
-/* ===-- floattidf.c - Implement __floattidf -------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __floattidf for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- floattidf.c - Implement __floattidf -------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __floattidf for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
#ifdef CRT_HAS_128BIT
-/* Returns: convert a to a double, rounding toward even.*/
+// Returns: convert a to a double, rounding toward even.
-/* Assumption: double is a IEEE 64 bit floating point type
- * ti_int is a 128 bit integral type
- */
+// Assumption: double is a IEEE 64 bit floating point type
+// ti_int is a 128 bit integral type
-/* seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm */
+// seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm
+// mmmm
-COMPILER_RT_ABI double
-__floattidf(ti_int a)
-{
- if (a == 0)
- return 0.0;
- const unsigned N = sizeof(ti_int) * CHAR_BIT;
- const ti_int s = a >> (N-1);
- a = (a ^ s) - s;
- int sd = N - __clzti2(a); /* number of significant digits */
- int e = sd - 1; /* exponent */
- if (sd > DBL_MANT_DIG)
- {
- /* start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
- * finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
- * 12345678901234567890123456
- * 1 = msb 1 bit
- * P = bit DBL_MANT_DIG-1 bits to the right of 1
- * Q = bit DBL_MANT_DIG bits to the right of 1
- * R = "or" of all bits to the right of Q
- */
- switch (sd)
- {
- case DBL_MANT_DIG + 1:
- a <<= 1;
- break;
- case DBL_MANT_DIG + 2:
- break;
- default:
- a = ((tu_int)a >> (sd - (DBL_MANT_DIG+2))) |
- ((a & ((tu_int)(-1) >> ((N + DBL_MANT_DIG+2) - sd))) != 0);
- };
- /* finish: */
- a |= (a & 4) != 0; /* Or P into R */
- ++a; /* round - this step may add a significant bit */
- a >>= 2; /* dump Q and R */
- /* a is now rounded to DBL_MANT_DIG or DBL_MANT_DIG+1 bits */
- if (a & ((tu_int)1 << DBL_MANT_DIG))
- {
- a >>= 1;
- ++e;
- }
- /* a is now rounded to DBL_MANT_DIG bits */
+COMPILER_RT_ABI double __floattidf(ti_int a) {
+ if (a == 0)
+ return 0.0;
+ const unsigned N = sizeof(ti_int) * CHAR_BIT;
+ const ti_int s = a >> (N - 1);
+ a = (a ^ s) - s;
+ int sd = N - __clzti2(a); // number of significant digits
+ int e = sd - 1; // exponent
+ if (sd > DBL_MANT_DIG) {
+ // start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
+ // finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
+ // 12345678901234567890123456
+ // 1 = msb 1 bit
+ // P = bit DBL_MANT_DIG-1 bits to the right of 1
+ // Q = bit DBL_MANT_DIG bits to the right of 1
+ // R = "or" of all bits to the right of Q
+ switch (sd) {
+ case DBL_MANT_DIG + 1:
+ a <<= 1;
+ break;
+ case DBL_MANT_DIG + 2:
+ break;
+ default:
+ a = ((tu_int)a >> (sd - (DBL_MANT_DIG + 2))) |
+ ((a & ((tu_int)(-1) >> ((N + DBL_MANT_DIG + 2) - sd))) != 0);
+ };
+ // finish:
+ a |= (a & 4) != 0; // Or P into R
+ ++a; // round - this step may add a significant bit
+ a >>= 2; // dump Q and R
+ // a is now rounded to DBL_MANT_DIG or DBL_MANT_DIG+1 bits
+ if (a & ((tu_int)1 << DBL_MANT_DIG)) {
+ a >>= 1;
+ ++e;
}
- else
- {
- a <<= (DBL_MANT_DIG - sd);
- /* a is now rounded to DBL_MANT_DIG bits */
- }
- double_bits fb;
- fb.u.s.high = ((su_int)s & 0x80000000) | /* sign */
- ((e + 1023) << 20) | /* exponent */
- ((su_int)(a >> 32) & 0x000FFFFF); /* mantissa-high */
- fb.u.s.low = (su_int)a; /* mantissa-low */
- return fb.f;
+ // a is now rounded to DBL_MANT_DIG bits
+ } else {
+ a <<= (DBL_MANT_DIG - sd);
+ // a is now rounded to DBL_MANT_DIG bits
+ }
+ double_bits fb;
+ fb.u.s.high = ((su_int)s & 0x80000000) | // sign
+ ((e + 1023) << 20) | // exponent
+ ((su_int)(a >> 32) & 0x000FFFFF); // mantissa-high
+ fb.u.s.low = (su_int)a; // mantissa-low
+ return fb.f;
}
-#endif /* CRT_HAS_128BIT */
+#endif // CRT_HAS_128BIT
diff --git a/contrib/libs/cxxsupp/builtins/floattisf.c b/contrib/libs/cxxsupp/builtins/floattisf.c
index f1b585f2c3..a8fcdbe14c 100644
--- a/contrib/libs/cxxsupp/builtins/floattisf.c
+++ b/contrib/libs/cxxsupp/builtins/floattisf.c
@@ -1,82 +1,71 @@
-/* ===-- floattisf.c - Implement __floattisf -------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __floattisf for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- floattisf.c - Implement __floattisf -------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __floattisf for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
#ifdef CRT_HAS_128BIT
-/* Returns: convert a to a float, rounding toward even. */
+// Returns: convert a to a float, rounding toward even.
-/* Assumption: float is a IEEE 32 bit floating point type
- * ti_int is a 128 bit integral type
- */
+// Assumption: float is a IEEE 32 bit floating point type
+// ti_int is a 128 bit integral type
-/* seee eeee emmm mmmm mmmm mmmm mmmm mmmm */
+// seee eeee emmm mmmm mmmm mmmm mmmm mmmm
-COMPILER_RT_ABI float
-__floattisf(ti_int a)
-{
- if (a == 0)
- return 0.0F;
- const unsigned N = sizeof(ti_int) * CHAR_BIT;
- const ti_int s = a >> (N-1);
- a = (a ^ s) - s;
- int sd = N - __clzti2(a); /* number of significant digits */
- int e = sd - 1; /* exponent */
- if (sd > FLT_MANT_DIG)
- {
- /* start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
- * finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
- * 12345678901234567890123456
- * 1 = msb 1 bit
- * P = bit FLT_MANT_DIG-1 bits to the right of 1
- * Q = bit FLT_MANT_DIG bits to the right of 1
- * R = "or" of all bits to the right of Q
- */
- switch (sd)
- {
- case FLT_MANT_DIG + 1:
- a <<= 1;
- break;
- case FLT_MANT_DIG + 2:
- break;
- default:
- a = ((tu_int)a >> (sd - (FLT_MANT_DIG+2))) |
- ((a & ((tu_int)(-1) >> ((N + FLT_MANT_DIG+2) - sd))) != 0);
- };
- /* finish: */
- a |= (a & 4) != 0; /* Or P into R */
- ++a; /* round - this step may add a significant bit */
- a >>= 2; /* dump Q and R */
- /* a is now rounded to FLT_MANT_DIG or FLT_MANT_DIG+1 bits */
- if (a & ((tu_int)1 << FLT_MANT_DIG))
- {
- a >>= 1;
- ++e;
- }
- /* a is now rounded to FLT_MANT_DIG bits */
+COMPILER_RT_ABI float __floattisf(ti_int a) {
+ if (a == 0)
+ return 0.0F;
+ const unsigned N = sizeof(ti_int) * CHAR_BIT;
+ const ti_int s = a >> (N - 1);
+ a = (a ^ s) - s;
+ int sd = N - __clzti2(a); // number of significant digits
+ int e = sd - 1; // exponent
+ if (sd > FLT_MANT_DIG) {
+ // start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
+ // finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
+ // 12345678901234567890123456
+ // 1 = msb 1 bit
+ // P = bit FLT_MANT_DIG-1 bits to the right of 1
+ // Q = bit FLT_MANT_DIG bits to the right of 1
+ // R = "or" of all bits to the right of Q
+ switch (sd) {
+ case FLT_MANT_DIG + 1:
+ a <<= 1;
+ break;
+ case FLT_MANT_DIG + 2:
+ break;
+ default:
+ a = ((tu_int)a >> (sd - (FLT_MANT_DIG + 2))) |
+ ((a & ((tu_int)(-1) >> ((N + FLT_MANT_DIG + 2) - sd))) != 0);
+ };
+ // finish:
+ a |= (a & 4) != 0; // Or P into R
+ ++a; // round - this step may add a significant bit
+ a >>= 2; // dump Q and R
+ // a is now rounded to FLT_MANT_DIG or FLT_MANT_DIG+1 bits
+ if (a & ((tu_int)1 << FLT_MANT_DIG)) {
+ a >>= 1;
+ ++e;
}
- else
- {
- a <<= (FLT_MANT_DIG - sd);
- /* a is now rounded to FLT_MANT_DIG bits */
- }
- float_bits fb;
- fb.u = ((su_int)s & 0x80000000) | /* sign */
- ((e + 127) << 23) | /* exponent */
- ((su_int)a & 0x007FFFFF); /* mantissa */
- return fb.f;
+ // a is now rounded to FLT_MANT_DIG bits
+ } else {
+ a <<= (FLT_MANT_DIG - sd);
+ // a is now rounded to FLT_MANT_DIG bits
+ }
+ float_bits fb;
+ fb.u = ((su_int)s & 0x80000000) | // sign
+ ((e + 127) << 23) | // exponent
+ ((su_int)a & 0x007FFFFF); // mantissa
+ return fb.f;
}
-#endif /* CRT_HAS_128BIT */
+#endif // CRT_HAS_128BIT
diff --git a/contrib/libs/cxxsupp/builtins/floattitf.c b/contrib/libs/cxxsupp/builtins/floattitf.c
new file mode 100644
index 0000000000..196cbdae14
--- /dev/null
+++ b/contrib/libs/cxxsupp/builtins/floattitf.c
@@ -0,0 +1,78 @@
+//===-- lib/floattitf.c - int128 -> quad-precision conversion -----*- C -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements ti_int to quad-precision conversion for the
+// compiler-rt library in the IEEE-754 default round-to-nearest, ties-to-even
+// mode.
+//
+//===----------------------------------------------------------------------===//
+
+#define QUAD_PRECISION
+#include "fp_lib.h"
+#include "int_lib.h"
+
+// Returns: convert a ti_int to a fp_t, rounding toward even.
+
+// Assumption: fp_t is a IEEE 128 bit floating point type
+// ti_int is a 128 bit integral type
+
+// seee eeee eeee eeee mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm
+// mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm
+// mmmm mmmm mmmm
+
+#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT)
+COMPILER_RT_ABI fp_t __floattitf(ti_int a) {
+ if (a == 0)
+ return 0.0;
+ const unsigned N = sizeof(ti_int) * CHAR_BIT;
+ const ti_int s = a >> (N - 1);
+ a = (a ^ s) - s;
+ int sd = N - __clzti2(a); // number of significant digits
+ int e = sd - 1; // exponent
+ if (sd > LDBL_MANT_DIG) {
+ // start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
+ // finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
+ // 12345678901234567890123456
+ // 1 = msb 1 bit
+ // P = bit LDBL_MANT_DIG-1 bits to the right of 1
+ // Q = bit LDBL_MANT_DIG bits to the right of 1
+ // R = "or" of all bits to the right of Q
+ switch (sd) {
+ case LDBL_MANT_DIG + 1:
+ a <<= 1;
+ break;
+ case LDBL_MANT_DIG + 2:
+ break;
+ default:
+ a = ((tu_int)a >> (sd - (LDBL_MANT_DIG + 2))) |
+ ((a & ((tu_int)(-1) >> ((N + LDBL_MANT_DIG + 2) - sd))) != 0);
+ };
+ // finish:
+ a |= (a & 4) != 0; // Or P into R
+ ++a; // round - this step may add a significant bit
+ a >>= 2; // dump Q and R
+ // a is now rounded to LDBL_MANT_DIG or LDBL_MANT_DIG+1 bits
+ if (a & ((tu_int)1 << LDBL_MANT_DIG)) {
+ a >>= 1;
+ ++e;
+ }
+ // a is now rounded to LDBL_MANT_DIG bits
+ } else {
+ a <<= (LDBL_MANT_DIG - sd);
+ // a is now rounded to LDBL_MANT_DIG bits
+ }
+
+ long_double_bits fb;
+ fb.u.high.all = (s & 0x8000000000000000LL) // sign
+ | (du_int)(e + 16383) << 48 // exponent
+ | ((a >> 64) & 0x0000ffffffffffffLL); // significand
+ fb.u.low.all = (du_int)(a);
+ return fb.f;
+}
+
+#endif
diff --git a/contrib/libs/cxxsupp/builtins/floattixf.c b/contrib/libs/cxxsupp/builtins/floattixf.c
index 1203b3a96e..23796f1bb5 100644
--- a/contrib/libs/cxxsupp/builtins/floattixf.c
+++ b/contrib/libs/cxxsupp/builtins/floattixf.c
@@ -1,84 +1,73 @@
-/* ===-- floattixf.c - Implement __floattixf -------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __floattixf for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- floattixf.c - Implement __floattixf -------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __floattixf for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
#ifdef CRT_HAS_128BIT
-/* Returns: convert a to a long double, rounding toward even. */
+// Returns: convert a to a long double, rounding toward even.
-/* Assumption: long double is a IEEE 80 bit floating point type padded to 128 bits
- * ti_int is a 128 bit integral type
- */
+// Assumption: long double is a IEEE 80 bit floating point type padded to 128
+// bits ti_int is a 128 bit integral type
-/* gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee eeee |
- * 1mmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm
- */
+// gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee
+// eeee | 1mmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm
+// mmmm mmmm mmmm
-COMPILER_RT_ABI long double
-__floattixf(ti_int a)
-{
- if (a == 0)
- return 0.0;
- const unsigned N = sizeof(ti_int) * CHAR_BIT;
- const ti_int s = a >> (N-1);
- a = (a ^ s) - s;
- int sd = N - __clzti2(a); /* number of significant digits */
- int e = sd - 1; /* exponent */
- if (sd > LDBL_MANT_DIG)
- {
- /* start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
- * finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
- * 12345678901234567890123456
- * 1 = msb 1 bit
- * P = bit LDBL_MANT_DIG-1 bits to the right of 1
- * Q = bit LDBL_MANT_DIG bits to the right of 1
- * R = "or" of all bits to the right of Q
- */
- switch (sd)
- {
- case LDBL_MANT_DIG + 1:
- a <<= 1;
- break;
- case LDBL_MANT_DIG + 2:
- break;
- default:
- a = ((tu_int)a >> (sd - (LDBL_MANT_DIG+2))) |
- ((a & ((tu_int)(-1) >> ((N + LDBL_MANT_DIG+2) - sd))) != 0);
- };
- /* finish: */
- a |= (a & 4) != 0; /* Or P into R */
- ++a; /* round - this step may add a significant bit */
- a >>= 2; /* dump Q and R */
- /* a is now rounded to LDBL_MANT_DIG or LDBL_MANT_DIG+1 bits */
- if (a & ((tu_int)1 << LDBL_MANT_DIG))
- {
- a >>= 1;
- ++e;
- }
- /* a is now rounded to LDBL_MANT_DIG bits */
+COMPILER_RT_ABI long double __floattixf(ti_int a) {
+ if (a == 0)
+ return 0.0;
+ const unsigned N = sizeof(ti_int) * CHAR_BIT;
+ const ti_int s = a >> (N - 1);
+ a = (a ^ s) - s;
+ int sd = N - __clzti2(a); // number of significant digits
+ int e = sd - 1; // exponent
+ if (sd > LDBL_MANT_DIG) {
+ // start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
+ // finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
+ // 12345678901234567890123456
+ // 1 = msb 1 bit
+ // P = bit LDBL_MANT_DIG-1 bits to the right of 1
+ // Q = bit LDBL_MANT_DIG bits to the right of 1
+ // R = "or" of all bits to the right of Q
+ switch (sd) {
+ case LDBL_MANT_DIG + 1:
+ a <<= 1;
+ break;
+ case LDBL_MANT_DIG + 2:
+ break;
+ default:
+ a = ((tu_int)a >> (sd - (LDBL_MANT_DIG + 2))) |
+ ((a & ((tu_int)(-1) >> ((N + LDBL_MANT_DIG + 2) - sd))) != 0);
+ };
+ // finish:
+ a |= (a & 4) != 0; // Or P into R
+ ++a; // round - this step may add a significant bit
+ a >>= 2; // dump Q and R
+ // a is now rounded to LDBL_MANT_DIG or LDBL_MANT_DIG+1 bits
+ if (a & ((tu_int)1 << LDBL_MANT_DIG)) {
+ a >>= 1;
+ ++e;
}
- else
- {
- a <<= (LDBL_MANT_DIG - sd);
- /* a is now rounded to LDBL_MANT_DIG bits */
- }
- long_double_bits fb;
- fb.u.high.s.low = ((su_int)s & 0x8000) | /* sign */
- (e + 16383); /* exponent */
- fb.u.low.all = (du_int)a; /* mantissa */
- return fb.f;
+ // a is now rounded to LDBL_MANT_DIG bits
+ } else {
+ a <<= (LDBL_MANT_DIG - sd);
+ // a is now rounded to LDBL_MANT_DIG bits
+ }
+ long_double_bits fb;
+ fb.u.high.s.low = ((su_int)s & 0x8000) | // sign
+ (e + 16383); // exponent
+ fb.u.low.all = (du_int)a; // mantissa
+ return fb.f;
}
-#endif /* CRT_HAS_128BIT */
+#endif // CRT_HAS_128BIT
diff --git a/contrib/libs/cxxsupp/builtins/floatundidf.c b/contrib/libs/cxxsupp/builtins/floatundidf.c
index 67aa86e5e5..2ec802cdc1 100644
--- a/contrib/libs/cxxsupp/builtins/floatundidf.c
+++ b/contrib/libs/cxxsupp/builtins/floatundidf.c
@@ -1,106 +1,110 @@
-/* ===-- floatundidf.c - Implement __floatundidf ---------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __floatundidf for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- floatundidf.c - Implement __floatundidf ---------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __floatundidf for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
-/* Returns: convert a to a double, rounding toward even. */
+// Returns: convert a to a double, rounding toward even.
-/* Assumption: double is a IEEE 64 bit floating point type
- * du_int is a 64 bit integral type
- */
+// Assumption: double is a IEEE 64 bit floating point type
+// du_int is a 64 bit integral type
-/* seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm */
+// seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm
+// mmmm
#include "int_lib.h"
-ARM_EABI_FNALIAS(ul2d, floatundidf)
+#ifndef __SOFTFP__
+// Support for systems that have hardware floating-point; we'll set the inexact
+// flag as a side-effect of this computation.
-#ifndef __SOFT_FP__
-/* Support for systems that have hardware floating-point; we'll set the inexact flag
- * as a side-effect of this computation.
- */
+COMPILER_RT_ABI double __floatundidf(du_int a) {
+ static const double twop52 = 4503599627370496.0; // 0x1.0p52
+ static const double twop84 = 19342813113834066795298816.0; // 0x1.0p84
+ static const double twop84_plus_twop52 =
+ 19342813118337666422669312.0; // 0x1.00000001p84
-COMPILER_RT_ABI double
-__floatundidf(du_int a)
-{
- static const double twop52 = 4503599627370496.0; // 0x1.0p52
- static const double twop84 = 19342813113834066795298816.0; // 0x1.0p84
- static const double twop84_plus_twop52 = 19342813118337666422669312.0; // 0x1.00000001p84
-
- union { uint64_t x; double d; } high = { .d = twop84 };
- union { uint64_t x; double d; } low = { .d = twop52 };
-
- high.x |= a >> 32;
- low.x |= a & UINT64_C(0x00000000ffffffff);
-
- const double result = (high.d - twop84_plus_twop52) + low.d;
- return result;
+ union {
+ uint64_t x;
+ double d;
+ } high = {.d = twop84};
+ union {
+ uint64_t x;
+ double d;
+ } low = {.d = twop52};
+
+ high.x |= a >> 32;
+ low.x |= a & UINT64_C(0x00000000ffffffff);
+
+ const double result = (high.d - twop84_plus_twop52) + low.d;
+ return result;
}
#else
-/* Support for systems that don't have hardware floating-point; there are no flags to
- * set, and we don't want to code-gen to an unknown soft-float implementation.
- */
+// Support for systems that don't have hardware floating-point; there are no
+// flags to set, and we don't want to code-gen to an unknown soft-float
+// implementation.
-COMPILER_RT_ABI double
-__floatundidf(du_int a)
-{
- if (a == 0)
- return 0.0;
- const unsigned N = sizeof(du_int) * CHAR_BIT;
- int sd = N - __builtin_clzll(a); /* number of significant digits */
- int e = sd - 1; /* exponent */
- if (sd > DBL_MANT_DIG)
- {
- /* start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
- * finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
- * 12345678901234567890123456
- * 1 = msb 1 bit
- * P = bit DBL_MANT_DIG-1 bits to the right of 1
- * Q = bit DBL_MANT_DIG bits to the right of 1
- * R = "or" of all bits to the right of Q
- */
- switch (sd)
- {
- case DBL_MANT_DIG + 1:
- a <<= 1;
- break;
- case DBL_MANT_DIG + 2:
- break;
- default:
- a = (a >> (sd - (DBL_MANT_DIG+2))) |
- ((a & ((du_int)(-1) >> ((N + DBL_MANT_DIG+2) - sd))) != 0);
- };
- /* finish: */
- a |= (a & 4) != 0; /* Or P into R */
- ++a; /* round - this step may add a significant bit */
- a >>= 2; /* dump Q and R */
- /* a is now rounded to DBL_MANT_DIG or DBL_MANT_DIG+1 bits */
- if (a & ((du_int)1 << DBL_MANT_DIG))
- {
- a >>= 1;
- ++e;
- }
- /* a is now rounded to DBL_MANT_DIG bits */
- }
- else
- {
- a <<= (DBL_MANT_DIG - sd);
- /* a is now rounded to DBL_MANT_DIG bits */
+COMPILER_RT_ABI double __floatundidf(du_int a) {
+ if (a == 0)
+ return 0.0;
+ const unsigned N = sizeof(du_int) * CHAR_BIT;
+ int sd = N - __builtin_clzll(a); // number of significant digits
+ int e = sd - 1; // exponent
+ if (sd > DBL_MANT_DIG) {
+ // start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
+ // finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
+ // 12345678901234567890123456
+ // 1 = msb 1 bit
+ // P = bit DBL_MANT_DIG-1 bits to the right of 1
+ // Q = bit DBL_MANT_DIG bits to the right of 1
+ // R = "or" of all bits to the right of Q
+ switch (sd) {
+ case DBL_MANT_DIG + 1:
+ a <<= 1;
+ break;
+ case DBL_MANT_DIG + 2:
+ break;
+ default:
+ a = (a >> (sd - (DBL_MANT_DIG + 2))) |
+ ((a & ((du_int)(-1) >> ((N + DBL_MANT_DIG + 2) - sd))) != 0);
+ };
+ // finish:
+ a |= (a & 4) != 0; // Or P into R
+ ++a; // round - this step may add a significant bit
+ a >>= 2; // dump Q and R
+ // a is now rounded to DBL_MANT_DIG or DBL_MANT_DIG+1 bits
+ if (a & ((du_int)1 << DBL_MANT_DIG)) {
+ a >>= 1;
+ ++e;
}
- double_bits fb;
- fb.u.high = ((e + 1023) << 20) | /* exponent */
- ((su_int)(a >> 32) & 0x000FFFFF); /* mantissa-high */
- fb.u.low = (su_int)a; /* mantissa-low */
- return fb.f;
+ // a is now rounded to DBL_MANT_DIG bits
+ } else {
+ a <<= (DBL_MANT_DIG - sd);
+ // a is now rounded to DBL_MANT_DIG bits
+ }
+ double_bits fb;
+ fb.u.s.high = ((su_int)(e + 1023) << 20) | // exponent
+ ((su_int)(a >> 32) & 0x000FFFFF); // mantissa-high
+ fb.u.s.low = (su_int)a; // mantissa-low
+ return fb.f;
}
#endif
+
+#if defined(__ARM_EABI__)
+#if defined(COMPILER_RT_ARMHF_TARGET)
+AEABI_RTABI double __aeabi_ul2d(du_int a) { return __floatundidf(a); }
+#else
+COMPILER_RT_ALIAS(__floatundidf, __aeabi_ul2d)
+#endif
+#endif
+
+#if defined(__MINGW32__) && defined(__arm__)
+COMPILER_RT_ALIAS(__floatundidf, __u64tod)
+#endif
diff --git a/contrib/libs/cxxsupp/builtins/floatundisf.c b/contrib/libs/cxxsupp/builtins/floatundisf.c
index 713a44abc8..2a4157dc5e 100644
--- a/contrib/libs/cxxsupp/builtins/floatundisf.c
+++ b/contrib/libs/cxxsupp/builtins/floatundisf.c
@@ -1,77 +1,76 @@
-/*===-- floatundisf.c - Implement __floatundisf ---------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __floatundisf for the compiler_rt library.
- *
- *===----------------------------------------------------------------------===
- */
+//===-- floatundisf.c - Implement __floatundisf ---------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __floatundisf for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
-/* Returns: convert a to a float, rounding toward even. */
+// Returns: convert a to a float, rounding toward even.
-/* Assumption: float is a IEEE 32 bit floating point type
- * du_int is a 64 bit integral type
- */
+// Assumption: float is a IEEE 32 bit floating point type
+// du_int is a 64 bit integral type
-/* seee eeee emmm mmmm mmmm mmmm mmmm mmmm */
+// seee eeee emmm mmmm mmmm mmmm mmmm mmmm
#include "int_lib.h"
-ARM_EABI_FNALIAS(ul2f, floatundisf)
-
-COMPILER_RT_ABI float
-__floatundisf(du_int a)
-{
- if (a == 0)
- return 0.0F;
- const unsigned N = sizeof(du_int) * CHAR_BIT;
- int sd = N - __builtin_clzll(a); /* number of significant digits */
- int e = sd - 1; /* 8 exponent */
- if (sd > FLT_MANT_DIG)
- {
- /* start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
- * finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
- * 12345678901234567890123456
- * 1 = msb 1 bit
- * P = bit FLT_MANT_DIG-1 bits to the right of 1
- * Q = bit FLT_MANT_DIG bits to the right of 1
- * R = "or" of all bits to the right of Q
- */
- switch (sd)
- {
- case FLT_MANT_DIG + 1:
- a <<= 1;
- break;
- case FLT_MANT_DIG + 2:
- break;
- default:
- a = (a >> (sd - (FLT_MANT_DIG+2))) |
- ((a & ((du_int)(-1) >> ((N + FLT_MANT_DIG+2) - sd))) != 0);
- };
- /* finish: */
- a |= (a & 4) != 0; /* Or P into R */
- ++a; /* round - this step may add a significant bit */
- a >>= 2; /* dump Q and R */
- /* a is now rounded to FLT_MANT_DIG or FLT_MANT_DIG+1 bits */
- if (a & ((du_int)1 << FLT_MANT_DIG))
- {
- a >>= 1;
- ++e;
- }
- /* a is now rounded to FLT_MANT_DIG bits */
- }
- else
- {
- a <<= (FLT_MANT_DIG - sd);
- /* a is now rounded to FLT_MANT_DIG bits */
+COMPILER_RT_ABI float __floatundisf(du_int a) {
+ if (a == 0)
+ return 0.0F;
+ const unsigned N = sizeof(du_int) * CHAR_BIT;
+ int sd = N - __builtin_clzll(a); // number of significant digits
+ si_int e = sd - 1; // 8 exponent
+ if (sd > FLT_MANT_DIG) {
+ // start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
+ // finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
+ // 12345678901234567890123456
+ // 1 = msb 1 bit
+ // P = bit FLT_MANT_DIG-1 bits to the right of 1
+ // Q = bit FLT_MANT_DIG bits to the right of 1
+ // R = "or" of all bits to the right of Q
+ switch (sd) {
+ case FLT_MANT_DIG + 1:
+ a <<= 1;
+ break;
+ case FLT_MANT_DIG + 2:
+ break;
+ default:
+ a = (a >> (sd - (FLT_MANT_DIG + 2))) |
+ ((a & ((du_int)(-1) >> ((N + FLT_MANT_DIG + 2) - sd))) != 0);
+ };
+ // finish:
+ a |= (a & 4) != 0; // Or P into R
+ ++a; // round - this step may add a significant bit
+ a >>= 2; // dump Q and R
+ // a is now rounded to FLT_MANT_DIG or FLT_MANT_DIG+1 bits
+ if (a & ((du_int)1 << FLT_MANT_DIG)) {
+ a >>= 1;
+ ++e;
}
- float_bits fb;
- fb.u = ((e + 127) << 23) | /* exponent */
- ((su_int)a & 0x007FFFFF); /* mantissa */
- return fb.f;
+ // a is now rounded to FLT_MANT_DIG bits
+ } else {
+ a <<= (FLT_MANT_DIG - sd);
+ // a is now rounded to FLT_MANT_DIG bits
+ }
+ float_bits fb;
+ fb.u = ((e + 127) << 23) | // exponent
+ ((su_int)a & 0x007FFFFF); // mantissa
+ return fb.f;
}
+
+#if defined(__ARM_EABI__)
+#if defined(COMPILER_RT_ARMHF_TARGET)
+AEABI_RTABI float __aeabi_ul2f(du_int a) { return __floatundisf(a); }
+#else
+COMPILER_RT_ALIAS(__floatundisf, __aeabi_ul2f)
+#endif
+#endif
+
+#if defined(__MINGW32__) && defined(__arm__)
+COMPILER_RT_ALIAS(__floatundisf, __u64tos)
+#endif
diff --git a/contrib/libs/cxxsupp/builtins/floatunditf.c b/contrib/libs/cxxsupp/builtins/floatunditf.c
index 8098e95e82..8d310851e1 100644
--- a/contrib/libs/cxxsupp/builtins/floatunditf.c
+++ b/contrib/libs/cxxsupp/builtins/floatunditf.c
@@ -1,9 +1,8 @@
//===-- lib/floatunditf.c - uint -> quad-precision conversion -----*- C -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -19,22 +18,23 @@
#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT)
COMPILER_RT_ABI fp_t __floatunditf(du_int a) {
- const int aWidth = sizeof a * CHAR_BIT;
+ const int aWidth = sizeof a * CHAR_BIT;
- // Handle zero as a special case to protect clz
- if (a == 0) return fromRep(0);
+ // Handle zero as a special case to protect clz
+ if (a == 0)
+ return fromRep(0);
- // Exponent of (fp_t)a is the width of abs(a).
- const int exponent = (aWidth - 1) - __builtin_clzll(a);
- rep_t result;
+ // Exponent of (fp_t)a is the width of abs(a).
+ const int exponent = (aWidth - 1) - __builtin_clzll(a);
+ rep_t result;
- // Shift a into the significand field and clear the implicit bit.
- const int shift = significandBits - exponent;
- result = (rep_t)a << shift ^ implicitBit;
+ // Shift a into the significand field and clear the implicit bit.
+ const int shift = significandBits - exponent;
+ result = (rep_t)a << shift ^ implicitBit;
- // Insert the exponent
- result += (rep_t)(exponent + exponentBias) << significandBits;
- return fromRep(result);
+ // Insert the exponent
+ result += (rep_t)(exponent + exponentBias) << significandBits;
+ return fromRep(result);
}
#endif
diff --git a/contrib/libs/cxxsupp/builtins/floatundixf.c b/contrib/libs/cxxsupp/builtins/floatundixf.c
index ca5e06d64d..85264adac1 100644
--- a/contrib/libs/cxxsupp/builtins/floatundixf.c
+++ b/contrib/libs/cxxsupp/builtins/floatundixf.c
@@ -1,42 +1,37 @@
-/* ===-- floatundixf.c - Implement __floatundixf ---------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __floatundixf for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- floatundixf.c - Implement __floatundixf ---------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __floatundixf for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#if !_ARCH_PPC
#include "int_lib.h"
-/* Returns: convert a to a long double, rounding toward even. */
+// Returns: convert a to a long double, rounding toward even.
-/* Assumption: long double is a IEEE 80 bit floating point type padded to 128 bits
- * du_int is a 64 bit integral type
- */
+// Assumption: long double is a IEEE 80 bit floating point type padded to 128
+// bits du_int is a 64 bit integral type
-/* gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee eeee |
- * 1mmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm
- */
-COMPILER_RT_ABI long double
-__floatundixf(du_int a)
-{
- if (a == 0)
- return 0.0;
- const unsigned N = sizeof(du_int) * CHAR_BIT;
- int clz = __builtin_clzll(a);
- int e = (N - 1) - clz ; /* exponent */
- long_double_bits fb;
- fb.u.high.s.low = (e + 16383); /* exponent */
- fb.u.low.all = a << clz; /* mantissa */
- return fb.f;
+// gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee
+// eeee | 1mmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm
+// mmmm mmmm mmmm
+COMPILER_RT_ABI long double __floatundixf(du_int a) {
+ if (a == 0)
+ return 0.0;
+ const unsigned N = sizeof(du_int) * CHAR_BIT;
+ int clz = __builtin_clzll(a);
+ int e = (N - 1) - clz; // exponent
+ long_double_bits fb;
+ fb.u.high.s.low = (e + 16383); // exponent
+ fb.u.low.all = a << clz; // mantissa
+ return fb.f;
}
-#endif /* _ARCH_PPC */
+#endif // _ARCH_PPC
diff --git a/contrib/libs/cxxsupp/builtins/floatunsidf.c b/contrib/libs/cxxsupp/builtins/floatunsidf.c
index 445e18041c..9b3e5fea0e 100644
--- a/contrib/libs/cxxsupp/builtins/floatunsidf.c
+++ b/contrib/libs/cxxsupp/builtins/floatunsidf.c
@@ -1,9 +1,8 @@
//===-- lib/floatunsidf.c - uint -> double-precision conversion ---*- C -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -18,25 +17,31 @@
#include "int_lib.h"
-ARM_EABI_FNALIAS(ui2d, floatunsidf)
-
-COMPILER_RT_ABI fp_t
-__floatunsidf(unsigned int a) {
-
- const int aWidth = sizeof a * CHAR_BIT;
-
- // Handle zero as a special case to protect clz
- if (a == 0) return fromRep(0);
-
- // Exponent of (fp_t)a is the width of abs(a).
- const int exponent = (aWidth - 1) - __builtin_clz(a);
- rep_t result;
-
- // Shift a into the significand field and clear the implicit bit.
- const int shift = significandBits - exponent;
- result = (rep_t)a << shift ^ implicitBit;
-
- // Insert the exponent
- result += (rep_t)(exponent + exponentBias) << significandBits;
- return fromRep(result);
+COMPILER_RT_ABI fp_t __floatunsidf(su_int a) {
+
+ const int aWidth = sizeof a * CHAR_BIT;
+
+ // Handle zero as a special case to protect clz
+ if (a == 0)
+ return fromRep(0);
+
+ // Exponent of (fp_t)a is the width of abs(a).
+ const int exponent = (aWidth - 1) - clzsi(a);
+ rep_t result;
+
+ // Shift a into the significand field and clear the implicit bit.
+ const int shift = significandBits - exponent;
+ result = (rep_t)a << shift ^ implicitBit;
+
+ // Insert the exponent
+ result += (rep_t)(exponent + exponentBias) << significandBits;
+ return fromRep(result);
}
+
+#if defined(__ARM_EABI__)
+#if defined(COMPILER_RT_ARMHF_TARGET)
+AEABI_RTABI fp_t __aeabi_ui2d(su_int a) { return __floatunsidf(a); }
+#else
+COMPILER_RT_ALIAS(__floatunsidf, __aeabi_ui2d)
+#endif
+#endif
diff --git a/contrib/libs/cxxsupp/builtins/floatunsisf.c b/contrib/libs/cxxsupp/builtins/floatunsisf.c
index ea6f161adc..ec062b5943 100644
--- a/contrib/libs/cxxsupp/builtins/floatunsisf.c
+++ b/contrib/libs/cxxsupp/builtins/floatunsisf.c
@@ -1,9 +1,8 @@
//===-- lib/floatunsisf.c - uint -> single-precision conversion ---*- C -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -18,33 +17,41 @@
#include "int_lib.h"
-ARM_EABI_FNALIAS(ui2f, floatunsisf)
-
-COMPILER_RT_ABI fp_t
-__floatunsisf(unsigned int a) {
-
- const int aWidth = sizeof a * CHAR_BIT;
-
- // Handle zero as a special case to protect clz
- if (a == 0) return fromRep(0);
-
- // Exponent of (fp_t)a is the width of abs(a).
- const int exponent = (aWidth - 1) - __builtin_clz(a);
- rep_t result;
-
- // Shift a into the significand field, rounding if it is a right-shift
- if (exponent <= significandBits) {
- const int shift = significandBits - exponent;
- result = (rep_t)a << shift ^ implicitBit;
- } else {
- const int shift = exponent - significandBits;
- result = (rep_t)a >> shift ^ implicitBit;
- rep_t round = (rep_t)a << (typeWidth - shift);
- if (round > signBit) result++;
- if (round == signBit) result += result & 1;
- }
-
- // Insert the exponent
- result += (rep_t)(exponent + exponentBias) << significandBits;
- return fromRep(result);
+COMPILER_RT_ABI fp_t __floatunsisf(su_int a) {
+
+ const int aWidth = sizeof a * CHAR_BIT;
+
+ // Handle zero as a special case to protect clz
+ if (a == 0)
+ return fromRep(0);
+
+ // Exponent of (fp_t)a is the width of abs(a).
+ const int exponent = (aWidth - 1) - clzsi(a);
+ rep_t result;
+
+ // Shift a into the significand field, rounding if it is a right-shift
+ if (exponent <= significandBits) {
+ const int shift = significandBits - exponent;
+ result = (rep_t)a << shift ^ implicitBit;
+ } else {
+ const int shift = exponent - significandBits;
+ result = (rep_t)a >> shift ^ implicitBit;
+ rep_t round = (rep_t)a << (typeWidth - shift);
+ if (round > signBit)
+ result++;
+ if (round == signBit)
+ result += result & 1;
+ }
+
+ // Insert the exponent
+ result += (rep_t)(exponent + exponentBias) << significandBits;
+ return fromRep(result);
}
+
+#if defined(__ARM_EABI__)
+#if defined(COMPILER_RT_ARMHF_TARGET)
+AEABI_RTABI fp_t __aeabi_ui2f(unsigned int a) { return __floatunsisf(a); }
+#else
+COMPILER_RT_ALIAS(__floatunsisf, __aeabi_ui2f)
+#endif
+#endif
diff --git a/contrib/libs/cxxsupp/builtins/floatunsitf.c b/contrib/libs/cxxsupp/builtins/floatunsitf.c
index 1cd1842e70..7ba1fb6000 100644
--- a/contrib/libs/cxxsupp/builtins/floatunsitf.c
+++ b/contrib/libs/cxxsupp/builtins/floatunsitf.c
@@ -1,9 +1,8 @@
//===-- lib/floatunsitf.c - uint -> quad-precision conversion -----*- C -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -17,24 +16,25 @@
#include "fp_lib.h"
#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT)
-COMPILER_RT_ABI fp_t __floatunsitf(unsigned int a) {
+COMPILER_RT_ABI fp_t __floatunsitf(su_int a) {
- const int aWidth = sizeof a * CHAR_BIT;
+ const int aWidth = sizeof a * CHAR_BIT;
- // Handle zero as a special case to protect clz
- if (a == 0) return fromRep(0);
+ // Handle zero as a special case to protect clz
+ if (a == 0)
+ return fromRep(0);
- // Exponent of (fp_t)a is the width of abs(a).
- const int exponent = (aWidth - 1) - __builtin_clz(a);
- rep_t result;
+ // Exponent of (fp_t)a is the width of abs(a).
+ const int exponent = (aWidth - 1) - clzsi(a);
+ rep_t result;
- // Shift a into the significand field and clear the implicit bit.
- const int shift = significandBits - exponent;
- result = (rep_t)a << shift ^ implicitBit;
+ // Shift a into the significand field and clear the implicit bit.
+ const int shift = significandBits - exponent;
+ result = (rep_t)a << shift ^ implicitBit;
- // Insert the exponent
- result += (rep_t)(exponent + exponentBias) << significandBits;
- return fromRep(result);
+ // Insert the exponent
+ result += (rep_t)(exponent + exponentBias) << significandBits;
+ return fromRep(result);
}
#endif
diff --git a/contrib/libs/cxxsupp/builtins/floatuntidf.c b/contrib/libs/cxxsupp/builtins/floatuntidf.c
index 06202d9679..e69e65c1ac 100644
--- a/contrib/libs/cxxsupp/builtins/floatuntidf.c
+++ b/contrib/libs/cxxsupp/builtins/floatuntidf.c
@@ -1,80 +1,70 @@
-/* ===-- floatuntidf.c - Implement __floatuntidf ---------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __floatuntidf for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- floatuntidf.c - Implement __floatuntidf ---------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __floatuntidf for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
#ifdef CRT_HAS_128BIT
-/* Returns: convert a to a double, rounding toward even. */
+// Returns: convert a to a double, rounding toward even.
-/* Assumption: double is a IEEE 64 bit floating point type
- * tu_int is a 128 bit integral type
- */
+// Assumption: double is a IEEE 64 bit floating point type
+// tu_int is a 128 bit integral type
-/* seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm */
+// seee eeee eeee mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm
+// mmmm
-COMPILER_RT_ABI double
-__floatuntidf(tu_int a)
-{
- if (a == 0)
- return 0.0;
- const unsigned N = sizeof(tu_int) * CHAR_BIT;
- int sd = N - __clzti2(a); /* number of significant digits */
- int e = sd - 1; /* exponent */
- if (sd > DBL_MANT_DIG)
- {
- /* start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
- * finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
- * 12345678901234567890123456
- * 1 = msb 1 bit
- * P = bit DBL_MANT_DIG-1 bits to the right of 1
- * Q = bit DBL_MANT_DIG bits to the right of 1
- * R = "or" of all bits to the right of Q
- */
- switch (sd)
- {
- case DBL_MANT_DIG + 1:
- a <<= 1;
- break;
- case DBL_MANT_DIG + 2:
- break;
- default:
- a = (a >> (sd - (DBL_MANT_DIG+2))) |
- ((a & ((tu_int)(-1) >> ((N + DBL_MANT_DIG+2) - sd))) != 0);
- };
- /* finish: */
- a |= (a & 4) != 0; /* Or P into R */
- ++a; /* round - this step may add a significant bit */
- a >>= 2; /* dump Q and R */
- /* a is now rounded to DBL_MANT_DIG or DBL_MANT_DIG+1 bits */
- if (a & ((tu_int)1 << DBL_MANT_DIG))
- {
- a >>= 1;
- ++e;
- }
- /* a is now rounded to DBL_MANT_DIG bits */
+COMPILER_RT_ABI double __floatuntidf(tu_int a) {
+ if (a == 0)
+ return 0.0;
+ const unsigned N = sizeof(tu_int) * CHAR_BIT;
+ int sd = N - __clzti2(a); // number of significant digits
+ int e = sd - 1; // exponent
+ if (sd > DBL_MANT_DIG) {
+ // start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
+ // finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
+ // 12345678901234567890123456
+ // 1 = msb 1 bit
+ // P = bit DBL_MANT_DIG-1 bits to the right of 1
+ // Q = bit DBL_MANT_DIG bits to the right of 1
+ // R = "or" of all bits to the right of Q
+ switch (sd) {
+ case DBL_MANT_DIG + 1:
+ a <<= 1;
+ break;
+ case DBL_MANT_DIG + 2:
+ break;
+ default:
+ a = (a >> (sd - (DBL_MANT_DIG + 2))) |
+ ((a & ((tu_int)(-1) >> ((N + DBL_MANT_DIG + 2) - sd))) != 0);
+ };
+ // finish:
+ a |= (a & 4) != 0; // Or P into R
+ ++a; // round - this step may add a significant bit
+ a >>= 2; // dump Q and R
+ // a is now rounded to DBL_MANT_DIG or DBL_MANT_DIG+1 bits
+ if (a & ((tu_int)1 << DBL_MANT_DIG)) {
+ a >>= 1;
+ ++e;
}
- else
- {
- a <<= (DBL_MANT_DIG - sd);
- /* a is now rounded to DBL_MANT_DIG bits */
- }
- double_bits fb;
- fb.u.s.high = ((e + 1023) << 20) | /* exponent */
- ((su_int)(a >> 32) & 0x000FFFFF); /* mantissa-high */
- fb.u.s.low = (su_int)a; /* mantissa-low */
- return fb.f;
+ // a is now rounded to DBL_MANT_DIG bits
+ } else {
+ a <<= (DBL_MANT_DIG - sd);
+ // a is now rounded to DBL_MANT_DIG bits
+ }
+ double_bits fb;
+ fb.u.s.high = ((e + 1023) << 20) | // exponent
+ ((su_int)(a >> 32) & 0x000FFFFF); // mantissa-high
+ fb.u.s.low = (su_int)a; // mantissa-low
+ return fb.f;
}
-#endif /* CRT_HAS_128BIT */
+#endif // CRT_HAS_128BIT
diff --git a/contrib/libs/cxxsupp/builtins/floatuntisf.c b/contrib/libs/cxxsupp/builtins/floatuntisf.c
index c0dd0275dd..9dec0ab5c5 100644
--- a/contrib/libs/cxxsupp/builtins/floatuntisf.c
+++ b/contrib/libs/cxxsupp/builtins/floatuntisf.c
@@ -1,79 +1,68 @@
-/* ===-- floatuntisf.c - Implement __floatuntisf ---------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __floatuntisf for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- floatuntisf.c - Implement __floatuntisf ---------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __floatuntisf for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
#ifdef CRT_HAS_128BIT
-/* Returns: convert a to a float, rounding toward even. */
+// Returns: convert a to a float, rounding toward even.
-/* Assumption: float is a IEEE 32 bit floating point type
- * tu_int is a 128 bit integral type
- */
+// Assumption: float is a IEEE 32 bit floating point type
+// tu_int is a 128 bit integral type
-/* seee eeee emmm mmmm mmmm mmmm mmmm mmmm */
+// seee eeee emmm mmmm mmmm mmmm mmmm mmmm
-COMPILER_RT_ABI float
-__floatuntisf(tu_int a)
-{
- if (a == 0)
- return 0.0F;
- const unsigned N = sizeof(tu_int) * CHAR_BIT;
- int sd = N - __clzti2(a); /* number of significant digits */
- int e = sd - 1; /* exponent */
- if (sd > FLT_MANT_DIG)
- {
- /* start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
- * finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
- * 12345678901234567890123456
- * 1 = msb 1 bit
- * P = bit FLT_MANT_DIG-1 bits to the right of 1
- * Q = bit FLT_MANT_DIG bits to the right of 1
- * R = "or" of all bits to the right of Q
- */
- switch (sd)
- {
- case FLT_MANT_DIG + 1:
- a <<= 1;
- break;
- case FLT_MANT_DIG + 2:
- break;
- default:
- a = (a >> (sd - (FLT_MANT_DIG+2))) |
- ((a & ((tu_int)(-1) >> ((N + FLT_MANT_DIG+2) - sd))) != 0);
- };
- /* finish: */
- a |= (a & 4) != 0; /* Or P into R */
- ++a; /* round - this step may add a significant bit */
- a >>= 2; /* dump Q and R */
- /* a is now rounded to FLT_MANT_DIG or FLT_MANT_DIG+1 bits */
- if (a & ((tu_int)1 << FLT_MANT_DIG))
- {
- a >>= 1;
- ++e;
- }
- /* a is now rounded to FLT_MANT_DIG bits */
+COMPILER_RT_ABI float __floatuntisf(tu_int a) {
+ if (a == 0)
+ return 0.0F;
+ const unsigned N = sizeof(tu_int) * CHAR_BIT;
+ int sd = N - __clzti2(a); // number of significant digits
+ int e = sd - 1; // exponent
+ if (sd > FLT_MANT_DIG) {
+ // start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
+ // finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
+ // 12345678901234567890123456
+ // 1 = msb 1 bit
+ // P = bit FLT_MANT_DIG-1 bits to the right of 1
+ // Q = bit FLT_MANT_DIG bits to the right of 1
+ // R = "or" of all bits to the right of Q
+ switch (sd) {
+ case FLT_MANT_DIG + 1:
+ a <<= 1;
+ break;
+ case FLT_MANT_DIG + 2:
+ break;
+ default:
+ a = (a >> (sd - (FLT_MANT_DIG + 2))) |
+ ((a & ((tu_int)(-1) >> ((N + FLT_MANT_DIG + 2) - sd))) != 0);
+ };
+ // finish:
+ a |= (a & 4) != 0; // Or P into R
+ ++a; // round - this step may add a significant bit
+ a >>= 2; // dump Q and R
+ // a is now rounded to FLT_MANT_DIG or FLT_MANT_DIG+1 bits
+ if (a & ((tu_int)1 << FLT_MANT_DIG)) {
+ a >>= 1;
+ ++e;
}
- else
- {
- a <<= (FLT_MANT_DIG - sd);
- /* a is now rounded to FLT_MANT_DIG bits */
- }
- float_bits fb;
- fb.u = ((e + 127) << 23) | /* exponent */
- ((su_int)a & 0x007FFFFF); /* mantissa */
- return fb.f;
+ // a is now rounded to FLT_MANT_DIG bits
+ } else {
+ a <<= (FLT_MANT_DIG - sd);
+ // a is now rounded to FLT_MANT_DIG bits
+ }
+ float_bits fb;
+ fb.u = ((e + 127) << 23) | // exponent
+ ((su_int)a & 0x007FFFFF); // mantissa
+ return fb.f;
}
-#endif /* CRT_HAS_128BIT */
+#endif // CRT_HAS_128BIT
diff --git a/contrib/libs/cxxsupp/builtins/floatuntitf.c b/contrib/libs/cxxsupp/builtins/floatuntitf.c
new file mode 100644
index 0000000000..d308d3118d
--- /dev/null
+++ b/contrib/libs/cxxsupp/builtins/floatuntitf.c
@@ -0,0 +1,75 @@
+//===-- lib/floatuntitf.c - uint128 -> quad-precision conversion --*- C -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements tu_int to quad-precision conversion for the
+// compiler-rt library in the IEEE-754 default round-to-nearest, ties-to-even
+// mode.
+//
+//===----------------------------------------------------------------------===//
+
+#define QUAD_PRECISION
+#include "fp_lib.h"
+#include "int_lib.h"
+
+// Returns: convert a tu_int to a fp_t, rounding toward even.
+
+// Assumption: fp_t is a IEEE 128 bit floating point type
+// tu_int is a 128 bit integral type
+
+// seee eeee eeee eeee mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm
+// mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm
+// mmmm mmmm mmmm
+
+#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT)
+COMPILER_RT_ABI fp_t __floatuntitf(tu_int a) {
+ if (a == 0)
+ return 0.0;
+ const unsigned N = sizeof(tu_int) * CHAR_BIT;
+ int sd = N - __clzti2(a); // number of significant digits
+ int e = sd - 1; // exponent
+ if (sd > LDBL_MANT_DIG) {
+ // start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
+ // finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
+ // 12345678901234567890123456
+ // 1 = msb 1 bit
+ // P = bit LDBL_MANT_DIG-1 bits to the right of 1
+ // Q = bit LDBL_MANT_DIG bits to the right of 1
+ // R = "or" of all bits to the right of Q
+ switch (sd) {
+ case LDBL_MANT_DIG + 1:
+ a <<= 1;
+ break;
+ case LDBL_MANT_DIG + 2:
+ break;
+ default:
+ a = (a >> (sd - (LDBL_MANT_DIG + 2))) |
+ ((a & ((tu_int)(-1) >> ((N + LDBL_MANT_DIG + 2) - sd))) != 0);
+ };
+ // finish:
+ a |= (a & 4) != 0; // Or P into R
+ ++a; // round - this step may add a significant bit
+ a >>= 2; // dump Q and R
+ // a is now rounded to LDBL_MANT_DIG or LDBL_MANT_DIG+1 bits
+ if (a & ((tu_int)1 << LDBL_MANT_DIG)) {
+ a >>= 1;
+ ++e;
+ }
+ // a is now rounded to LDBL_MANT_DIG bits
+ } else {
+ a <<= (LDBL_MANT_DIG - sd);
+ // a is now rounded to LDBL_MANT_DIG bits
+ }
+
+ long_double_bits fb;
+ fb.u.high.all = (du_int)(e + 16383) << 48 // exponent
+ | ((a >> 64) & 0x0000ffffffffffffLL); // significand
+ fb.u.low.all = (du_int)(a);
+ return fb.f;
+}
+
+#endif
diff --git a/contrib/libs/cxxsupp/builtins/floatuntixf.c b/contrib/libs/cxxsupp/builtins/floatuntixf.c
index ea81cb1bcd..efd8a27a08 100644
--- a/contrib/libs/cxxsupp/builtins/floatuntixf.c
+++ b/contrib/libs/cxxsupp/builtins/floatuntixf.c
@@ -1,81 +1,70 @@
-/* ===-- floatuntixf.c - Implement __floatuntixf ---------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __floatuntixf for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- floatuntixf.c - Implement __floatuntixf ---------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __floatuntixf for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
#ifdef CRT_HAS_128BIT
-/* Returns: convert a to a long double, rounding toward even. */
+// Returns: convert a to a long double, rounding toward even.
-/* Assumption: long double is a IEEE 80 bit floating point type padded to 128 bits
- * tu_int is a 128 bit integral type
- */
+// Assumption: long double is a IEEE 80 bit floating point type padded to 128
+// bits tu_int is a 128 bit integral type
-/* gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee eeee |
- * 1mmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm
- */
+// gggg gggg gggg gggg gggg gggg gggg gggg | gggg gggg gggg gggg seee eeee eeee
+// eeee | 1mmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm | mmmm mmmm mmmm mmmm mmmm
+// mmmm mmmm mmmm
-COMPILER_RT_ABI long double
-__floatuntixf(tu_int a)
-{
- if (a == 0)
- return 0.0;
- const unsigned N = sizeof(tu_int) * CHAR_BIT;
- int sd = N - __clzti2(a); /* number of significant digits */
- int e = sd - 1; /* exponent */
- if (sd > LDBL_MANT_DIG)
- {
- /* start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
- * finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
- * 12345678901234567890123456
- * 1 = msb 1 bit
- * P = bit LDBL_MANT_DIG-1 bits to the right of 1
- * Q = bit LDBL_MANT_DIG bits to the right of 1
- * R = "or" of all bits to the right of Q
- */
- switch (sd)
- {
- case LDBL_MANT_DIG + 1:
- a <<= 1;
- break;
- case LDBL_MANT_DIG + 2:
- break;
- default:
- a = (a >> (sd - (LDBL_MANT_DIG+2))) |
- ((a & ((tu_int)(-1) >> ((N + LDBL_MANT_DIG+2) - sd))) != 0);
- };
- /* finish: */
- a |= (a & 4) != 0; /* Or P into R */
- ++a; /* round - this step may add a significant bit */
- a >>= 2; /* dump Q and R */
- /* a is now rounded to LDBL_MANT_DIG or LDBL_MANT_DIG+1 bits */
- if (a & ((tu_int)1 << LDBL_MANT_DIG))
- {
- a >>= 1;
- ++e;
- }
- /* a is now rounded to LDBL_MANT_DIG bits */
+COMPILER_RT_ABI long double __floatuntixf(tu_int a) {
+ if (a == 0)
+ return 0.0;
+ const unsigned N = sizeof(tu_int) * CHAR_BIT;
+ int sd = N - __clzti2(a); // number of significant digits
+ int e = sd - 1; // exponent
+ if (sd > LDBL_MANT_DIG) {
+ // start: 0000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQxxxxxxxxxxxxxxxxxx
+ // finish: 000000000000000000000000000000000000001xxxxxxxxxxxxxxxxxxxxxxPQR
+ // 12345678901234567890123456
+ // 1 = msb 1 bit
+ // P = bit LDBL_MANT_DIG-1 bits to the right of 1
+ // Q = bit LDBL_MANT_DIG bits to the right of 1
+ // R = "or" of all bits to the right of Q
+ switch (sd) {
+ case LDBL_MANT_DIG + 1:
+ a <<= 1;
+ break;
+ case LDBL_MANT_DIG + 2:
+ break;
+ default:
+ a = (a >> (sd - (LDBL_MANT_DIG + 2))) |
+ ((a & ((tu_int)(-1) >> ((N + LDBL_MANT_DIG + 2) - sd))) != 0);
+ };
+ // finish:
+ a |= (a & 4) != 0; // Or P into R
+ ++a; // round - this step may add a significant bit
+ a >>= 2; // dump Q and R
+ // a is now rounded to LDBL_MANT_DIG or LDBL_MANT_DIG+1 bits
+ if (a & ((tu_int)1 << LDBL_MANT_DIG)) {
+ a >>= 1;
+ ++e;
}
- else
- {
- a <<= (LDBL_MANT_DIG - sd);
- /* a is now rounded to LDBL_MANT_DIG bits */
- }
- long_double_bits fb;
- fb.u.high.s.low = (e + 16383); /* exponent */
- fb.u.low.all = (du_int)a; /* mantissa */
- return fb.f;
+ // a is now rounded to LDBL_MANT_DIG bits
+ } else {
+ a <<= (LDBL_MANT_DIG - sd);
+ // a is now rounded to LDBL_MANT_DIG bits
+ }
+ long_double_bits fb;
+ fb.u.high.s.low = (e + 16383); // exponent
+ fb.u.low.all = (du_int)a; // mantissa
+ return fb.f;
}
#endif
diff --git a/contrib/libs/cxxsupp/builtins/fp_add_impl.inc b/contrib/libs/cxxsupp/builtins/fp_add_impl.inc
index b47be1b648..7133358df9 100644
--- a/contrib/libs/cxxsupp/builtins/fp_add_impl.inc
+++ b/contrib/libs/cxxsupp/builtins/fp_add_impl.inc
@@ -1,9 +1,8 @@
//===----- lib/fp_add_impl.inc - floaing point addition -----------*- C -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -13,132 +12,161 @@
//===----------------------------------------------------------------------===//
#include "fp_lib.h"
+#include "fp_mode.h"
static __inline fp_t __addXf3__(fp_t a, fp_t b) {
- rep_t aRep = toRep(a);
- rep_t bRep = toRep(b);
- const rep_t aAbs = aRep & absMask;
- const rep_t bAbs = bRep & absMask;
-
- // Detect if a or b is zero, infinity, or NaN.
- if (aAbs - REP_C(1) >= infRep - REP_C(1) ||
- bAbs - REP_C(1) >= infRep - REP_C(1)) {
- // NaN + anything = qNaN
- if (aAbs > infRep) return fromRep(toRep(a) | quietBit);
- // anything + NaN = qNaN
- if (bAbs > infRep) return fromRep(toRep(b) | quietBit);
-
- if (aAbs == infRep) {
- // +/-infinity + -/+infinity = qNaN
- if ((toRep(a) ^ toRep(b)) == signBit) return fromRep(qnanRep);
- // +/-infinity + anything remaining = +/- infinity
- else return a;
- }
-
- // anything remaining + +/-infinity = +/-infinity
- if (bAbs == infRep) return b;
-
- // zero + anything = anything
- if (!aAbs) {
- // but we need to get the sign right for zero + zero
- if (!bAbs) return fromRep(toRep(a) & toRep(b));
- else return b;
- }
-
- // anything + zero = anything
- if (!bAbs) return a;
+ rep_t aRep = toRep(a);
+ rep_t bRep = toRep(b);
+ const rep_t aAbs = aRep & absMask;
+ const rep_t bAbs = bRep & absMask;
+
+ // Detect if a or b is zero, infinity, or NaN.
+ if (aAbs - REP_C(1) >= infRep - REP_C(1) ||
+ bAbs - REP_C(1) >= infRep - REP_C(1)) {
+ // NaN + anything = qNaN
+ if (aAbs > infRep)
+ return fromRep(toRep(a) | quietBit);
+ // anything + NaN = qNaN
+ if (bAbs > infRep)
+ return fromRep(toRep(b) | quietBit);
+
+ if (aAbs == infRep) {
+ // +/-infinity + -/+infinity = qNaN
+ if ((toRep(a) ^ toRep(b)) == signBit)
+ return fromRep(qnanRep);
+ // +/-infinity + anything remaining = +/- infinity
+ else
+ return a;
}
- // Swap a and b if necessary so that a has the larger absolute value.
- if (bAbs > aAbs) {
- const rep_t temp = aRep;
- aRep = bRep;
- bRep = temp;
+ // anything remaining + +/-infinity = +/-infinity
+ if (bAbs == infRep)
+ return b;
+
+ // zero + anything = anything
+ if (!aAbs) {
+ // We need to get the sign right for zero + zero.
+ if (!bAbs)
+ return fromRep(toRep(a) & toRep(b));
+ else
+ return b;
}
- // Extract the exponent and significand from the (possibly swapped) a and b.
- int aExponent = aRep >> significandBits & maxExponent;
- int bExponent = bRep >> significandBits & maxExponent;
- rep_t aSignificand = aRep & significandMask;
- rep_t bSignificand = bRep & significandMask;
-
- // Normalize any denormals, and adjust the exponent accordingly.
- if (aExponent == 0) aExponent = normalize(&aSignificand);
- if (bExponent == 0) bExponent = normalize(&bSignificand);
-
- // The sign of the result is the sign of the larger operand, a. If they
- // have opposite signs, we are performing a subtraction; otherwise addition.
- const rep_t resultSign = aRep & signBit;
- const bool subtraction = (aRep ^ bRep) & signBit;
-
- // Shift the significands to give us round, guard and sticky, and or in the
- // implicit significand bit. (If we fell through from the denormal path it
- // was already set by normalize( ), but setting it twice won't hurt
- // anything.)
- aSignificand = (aSignificand | implicitBit) << 3;
- bSignificand = (bSignificand | implicitBit) << 3;
-
- // Shift the significand of b by the difference in exponents, with a sticky
- // bottom bit to get rounding correct.
- const unsigned int align = aExponent - bExponent;
- if (align) {
- if (align < typeWidth) {
- const bool sticky = bSignificand << (typeWidth - align);
- bSignificand = bSignificand >> align | sticky;
- } else {
- bSignificand = 1; // sticky; b is known to be non-zero.
- }
- }
- if (subtraction) {
- aSignificand -= bSignificand;
- // If a == -b, return +zero.
- if (aSignificand == 0) return fromRep(0);
-
- // If partial cancellation occured, we need to left-shift the result
- // and adjust the exponent:
- if (aSignificand < implicitBit << 3) {
- const int shift = rep_clz(aSignificand) - rep_clz(implicitBit << 3);
- aSignificand <<= shift;
- aExponent -= shift;
- }
+ // anything + zero = anything
+ if (!bAbs)
+ return a;
+ }
+
+ // Swap a and b if necessary so that a has the larger absolute value.
+ if (bAbs > aAbs) {
+ const rep_t temp = aRep;
+ aRep = bRep;
+ bRep = temp;
+ }
+
+ // Extract the exponent and significand from the (possibly swapped) a and b.
+ int aExponent = aRep >> significandBits & maxExponent;
+ int bExponent = bRep >> significandBits & maxExponent;
+ rep_t aSignificand = aRep & significandMask;
+ rep_t bSignificand = bRep & significandMask;
+
+ // Normalize any denormals, and adjust the exponent accordingly.
+ if (aExponent == 0)
+ aExponent = normalize(&aSignificand);
+ if (bExponent == 0)
+ bExponent = normalize(&bSignificand);
+
+ // The sign of the result is the sign of the larger operand, a. If they
+ // have opposite signs, we are performing a subtraction. Otherwise, we
+ // perform addition.
+ const rep_t resultSign = aRep & signBit;
+ const bool subtraction = (aRep ^ bRep) & signBit;
+
+ // Shift the significands to give us round, guard and sticky, and set the
+ // implicit significand bit. If we fell through from the denormal path it
+ // was already set by normalize( ), but setting it twice won't hurt
+ // anything.
+ aSignificand = (aSignificand | implicitBit) << 3;
+ bSignificand = (bSignificand | implicitBit) << 3;
+
+ // Shift the significand of b by the difference in exponents, with a sticky
+ // bottom bit to get rounding correct.
+ const unsigned int align = aExponent - bExponent;
+ if (align) {
+ if (align < typeWidth) {
+ const bool sticky = (bSignificand << (typeWidth - align)) != 0;
+ bSignificand = bSignificand >> align | sticky;
+ } else {
+ bSignificand = 1; // Set the sticky bit. b is known to be non-zero.
}
- else /* addition */ {
- aSignificand += bSignificand;
-
- // If the addition carried up, we need to right-shift the result and
- // adjust the exponent:
- if (aSignificand & implicitBit << 4) {
- const bool sticky = aSignificand & 1;
- aSignificand = aSignificand >> 1 | sticky;
- aExponent += 1;
- }
+ }
+ if (subtraction) {
+ aSignificand -= bSignificand;
+ // If a == -b, return +zero.
+ if (aSignificand == 0)
+ return fromRep(0);
+
+ // If partial cancellation occured, we need to left-shift the result
+ // and adjust the exponent.
+ if (aSignificand < implicitBit << 3) {
+ const int shift = rep_clz(aSignificand) - rep_clz(implicitBit << 3);
+ aSignificand <<= shift;
+ aExponent -= shift;
}
-
- // If we have overflowed the type, return +/- infinity:
- if (aExponent >= maxExponent) return fromRep(infRep | resultSign);
-
- if (aExponent <= 0) {
- // Result is denormal before rounding; the exponent is zero and we
- // need to shift the significand.
- const int shift = 1 - aExponent;
- const bool sticky = aSignificand << (typeWidth - shift);
- aSignificand = aSignificand >> shift | sticky;
- aExponent = 0;
+ } else /* addition */ {
+ aSignificand += bSignificand;
+
+ // If the addition carried up, we need to right-shift the result and
+ // adjust the exponent.
+ if (aSignificand & implicitBit << 4) {
+ const bool sticky = aSignificand & 1;
+ aSignificand = aSignificand >> 1 | sticky;
+ aExponent += 1;
}
-
- // Low three bits are round, guard, and sticky.
- const int roundGuardSticky = aSignificand & 0x7;
-
- // Shift the significand into place, and mask off the implicit bit.
- rep_t result = aSignificand >> 3 & significandMask;
-
- // Insert the exponent and sign.
- result |= (rep_t)aExponent << significandBits;
- result |= resultSign;
-
- // Final rounding. The result may overflow to infinity, but that is the
- // correct result in that case.
- if (roundGuardSticky > 0x4) result++;
- if (roundGuardSticky == 0x4) result += result & 1;
- return fromRep(result);
+ }
+
+ // If we have overflowed the type, return +/- infinity.
+ if (aExponent >= maxExponent)
+ return fromRep(infRep | resultSign);
+
+ if (aExponent <= 0) {
+ // The result is denormal before rounding. The exponent is zero and we
+ // need to shift the significand.
+ const int shift = 1 - aExponent;
+ const bool sticky = (aSignificand << (typeWidth - shift)) != 0;
+ aSignificand = aSignificand >> shift | sticky;
+ aExponent = 0;
+ }
+
+ // Low three bits are round, guard, and sticky.
+ const int roundGuardSticky = aSignificand & 0x7;
+
+ // Shift the significand into place, and mask off the implicit bit.
+ rep_t result = aSignificand >> 3 & significandMask;
+
+ // Insert the exponent and sign.
+ result |= (rep_t)aExponent << significandBits;
+ result |= resultSign;
+
+ // Perform the final rounding. The result may overflow to infinity, but
+ // that is the correct result in that case.
+ switch (__fe_getround()) {
+ case CRT_FE_TONEAREST:
+ if (roundGuardSticky > 0x4)
+ result++;
+ if (roundGuardSticky == 0x4)
+ result += result & 1;
+ break;
+ case CRT_FE_DOWNWARD:
+ if (resultSign && roundGuardSticky) result++;
+ break;
+ case CRT_FE_UPWARD:
+ if (!resultSign && roundGuardSticky) result++;
+ break;
+ case CRT_FE_TOWARDZERO:
+ break;
+ }
+ if (roundGuardSticky)
+ __fe_raise_inexact();
+ return fromRep(result);
}
diff --git a/contrib/libs/cxxsupp/builtins/fp_compare_impl.inc b/contrib/libs/cxxsupp/builtins/fp_compare_impl.inc
new file mode 100644
index 0000000000..a9a4f6fbf5
--- /dev/null
+++ b/contrib/libs/cxxsupp/builtins/fp_compare_impl.inc
@@ -0,0 +1,119 @@
+//===-- lib/fp_compare_impl.inc - Floating-point comparison -------*- C -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "fp_lib.h"
+
+// GCC uses long (at least for x86_64) as the return type of the comparison
+// functions. We need to ensure that the return value is sign-extended in the
+// same way as GCC expects (since otherwise GCC-generated __builtin_isinf
+// returns true for finite 128-bit floating-point numbers).
+#ifdef __aarch64__
+// AArch64 GCC overrides libgcc_cmp_return to use int instead of long.
+typedef int CMP_RESULT;
+#elif __SIZEOF_POINTER__ == 8 && __SIZEOF_LONG__ == 4
+// LLP64 ABIs use long long instead of long.
+typedef long long CMP_RESULT;
+#elif __AVR__
+// AVR uses a single byte for the return value.
+typedef char CMP_RESULT;
+#else
+// Otherwise the comparison functions return long.
+typedef long CMP_RESULT;
+#endif
+
+#if !defined(__clang__) && defined(__GNUC__)
+// GCC uses a special __libgcc_cmp_return__ mode to define the return type, so
+// check that we are ABI-compatible when compiling the builtins with GCC.
+typedef int GCC_CMP_RESULT __attribute__((__mode__(__libgcc_cmp_return__)));
+_Static_assert(sizeof(GCC_CMP_RESULT) == sizeof(CMP_RESULT),
+ "SOFTFP ABI not compatible with GCC");
+#endif
+
+enum {
+ LE_LESS = -1,
+ LE_EQUAL = 0,
+ LE_GREATER = 1,
+ LE_UNORDERED = 1,
+};
+
+static inline CMP_RESULT __leXf2__(fp_t a, fp_t b) {
+ const srep_t aInt = toRep(a);
+ const srep_t bInt = toRep(b);
+ const rep_t aAbs = aInt & absMask;
+ const rep_t bAbs = bInt & absMask;
+
+ // If either a or b is NaN, they are unordered.
+ if (aAbs > infRep || bAbs > infRep)
+ return LE_UNORDERED;
+
+ // If a and b are both zeros, they are equal.
+ if ((aAbs | bAbs) == 0)
+ return LE_EQUAL;
+
+ // If at least one of a and b is positive, we get the same result comparing
+ // a and b as signed integers as we would with a floating-point compare.
+ if ((aInt & bInt) >= 0) {
+ if (aInt < bInt)
+ return LE_LESS;
+ else if (aInt == bInt)
+ return LE_EQUAL;
+ else
+ return LE_GREATER;
+ } else {
+ // Otherwise, both are negative, so we need to flip the sense of the
+ // comparison to get the correct result. (This assumes a twos- or ones-
+ // complement integer representation; if integers are represented in a
+ // sign-magnitude representation, then this flip is incorrect).
+ if (aInt > bInt)
+ return LE_LESS;
+ else if (aInt == bInt)
+ return LE_EQUAL;
+ else
+ return LE_GREATER;
+ }
+}
+
+enum {
+ GE_LESS = -1,
+ GE_EQUAL = 0,
+ GE_GREATER = 1,
+ GE_UNORDERED = -1 // Note: different from LE_UNORDERED
+};
+
+static inline CMP_RESULT __geXf2__(fp_t a, fp_t b) {
+ const srep_t aInt = toRep(a);
+ const srep_t bInt = toRep(b);
+ const rep_t aAbs = aInt & absMask;
+ const rep_t bAbs = bInt & absMask;
+
+ if (aAbs > infRep || bAbs > infRep)
+ return GE_UNORDERED;
+ if ((aAbs | bAbs) == 0)
+ return GE_EQUAL;
+ if ((aInt & bInt) >= 0) {
+ if (aInt < bInt)
+ return GE_LESS;
+ else if (aInt == bInt)
+ return GE_EQUAL;
+ else
+ return GE_GREATER;
+ } else {
+ if (aInt > bInt)
+ return GE_LESS;
+ else if (aInt == bInt)
+ return GE_EQUAL;
+ else
+ return GE_GREATER;
+ }
+}
+
+static inline CMP_RESULT __unordXf2__(fp_t a, fp_t b) {
+ const rep_t aAbs = toRep(a) & absMask;
+ const rep_t bAbs = toRep(b) & absMask;
+ return aAbs > infRep || bAbs > infRep;
+}
diff --git a/contrib/libs/cxxsupp/builtins/fp_div_impl.inc b/contrib/libs/cxxsupp/builtins/fp_div_impl.inc
new file mode 100644
index 0000000000..29bcd1920e
--- /dev/null
+++ b/contrib/libs/cxxsupp/builtins/fp_div_impl.inc
@@ -0,0 +1,419 @@
+//===-- fp_div_impl.inc - Floating point division -----------------*- C -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements soft-float division with the IEEE-754 default
+// rounding (to nearest, ties to even).
+//
+//===----------------------------------------------------------------------===//
+
+#include "fp_lib.h"
+
+// The __divXf3__ function implements Newton-Raphson floating point division.
+// It uses 3 iterations for float32, 4 for float64 and 5 for float128,
+// respectively. Due to number of significant bits being roughly doubled
+// every iteration, the two modes are supported: N full-width iterations (as
+// it is done for float32 by default) and (N-1) half-width iteration plus one
+// final full-width iteration. It is expected that half-width integer
+// operations (w.r.t rep_t size) can be performed faster for some hardware but
+// they require error estimations to be computed separately due to larger
+// computational errors caused by truncating intermediate results.
+
+// Half the bit-size of rep_t
+#define HW (typeWidth / 2)
+// rep_t-sized bitmask with lower half of bits set to ones
+#define loMask (REP_C(-1) >> HW)
+
+#if NUMBER_OF_FULL_ITERATIONS < 1
+#error At least one full iteration is required
+#endif
+
+static __inline fp_t __divXf3__(fp_t a, fp_t b) {
+
+ const unsigned int aExponent = toRep(a) >> significandBits & maxExponent;
+ const unsigned int bExponent = toRep(b) >> significandBits & maxExponent;
+ const rep_t quotientSign = (toRep(a) ^ toRep(b)) & signBit;
+
+ rep_t aSignificand = toRep(a) & significandMask;
+ rep_t bSignificand = toRep(b) & significandMask;
+ int scale = 0;
+
+ // Detect if a or b is zero, denormal, infinity, or NaN.
+ if (aExponent - 1U >= maxExponent - 1U ||
+ bExponent - 1U >= maxExponent - 1U) {
+
+ const rep_t aAbs = toRep(a) & absMask;
+ const rep_t bAbs = toRep(b) & absMask;
+
+ // NaN / anything = qNaN
+ if (aAbs > infRep)
+ return fromRep(toRep(a) | quietBit);
+ // anything / NaN = qNaN
+ if (bAbs > infRep)
+ return fromRep(toRep(b) | quietBit);
+
+ if (aAbs == infRep) {
+ // infinity / infinity = NaN
+ if (bAbs == infRep)
+ return fromRep(qnanRep);
+ // infinity / anything else = +/- infinity
+ else
+ return fromRep(aAbs | quotientSign);
+ }
+
+ // anything else / infinity = +/- 0
+ if (bAbs == infRep)
+ return fromRep(quotientSign);
+
+ if (!aAbs) {
+ // zero / zero = NaN
+ if (!bAbs)
+ return fromRep(qnanRep);
+ // zero / anything else = +/- zero
+ else
+ return fromRep(quotientSign);
+ }
+ // anything else / zero = +/- infinity
+ if (!bAbs)
+ return fromRep(infRep | quotientSign);
+
+ // One or both of a or b is denormal. The other (if applicable) is a
+ // normal number. Renormalize one or both of a and b, and set scale to
+ // include the necessary exponent adjustment.
+ if (aAbs < implicitBit)
+ scale += normalize(&aSignificand);
+ if (bAbs < implicitBit)
+ scale -= normalize(&bSignificand);
+ }
+
+ // Set the implicit significand bit. If we fell through from the
+ // denormal path it was already set by normalize( ), but setting it twice
+ // won't hurt anything.
+ aSignificand |= implicitBit;
+ bSignificand |= implicitBit;
+
+ int writtenExponent = (aExponent - bExponent + scale) + exponentBias;
+
+ const rep_t b_UQ1 = bSignificand << (typeWidth - significandBits - 1);
+
+ // Align the significand of b as a UQ1.(n-1) fixed-point number in the range
+ // [1.0, 2.0) and get a UQ0.n approximate reciprocal using a small minimax
+ // polynomial approximation: x0 = 3/4 + 1/sqrt(2) - b/2.
+ // The max error for this approximation is achieved at endpoints, so
+ // abs(x0(b) - 1/b) <= abs(x0(1) - 1/1) = 3/4 - 1/sqrt(2) = 0.04289...,
+ // which is about 4.5 bits.
+ // The initial approximation is between x0(1.0) = 0.9571... and x0(2.0) = 0.4571...
+
+ // Then, refine the reciprocal estimate using a quadratically converging
+ // Newton-Raphson iteration:
+ // x_{n+1} = x_n * (2 - x_n * b)
+ //
+ // Let b be the original divisor considered "in infinite precision" and
+ // obtained from IEEE754 representation of function argument (with the
+ // implicit bit set). Corresponds to rep_t-sized b_UQ1 represented in
+ // UQ1.(W-1).
+ //
+ // Let b_hw be an infinitely precise number obtained from the highest (HW-1)
+ // bits of divisor significand (with the implicit bit set). Corresponds to
+ // half_rep_t-sized b_UQ1_hw represented in UQ1.(HW-1) that is a **truncated**
+ // version of b_UQ1.
+ //
+ // Let e_n := x_n - 1/b_hw
+ // E_n := x_n - 1/b
+ // abs(E_n) <= abs(e_n) + (1/b_hw - 1/b)
+ // = abs(e_n) + (b - b_hw) / (b*b_hw)
+ // <= abs(e_n) + 2 * 2^-HW
+
+ // rep_t-sized iterations may be slower than the corresponding half-width
+ // variant depending on the handware and whether single/double/quad precision
+ // is selected.
+ // NB: Using half-width iterations increases computation errors due to
+ // rounding, so error estimations have to be computed taking the selected
+ // mode into account!
+#if NUMBER_OF_HALF_ITERATIONS > 0
+ // Starting with (n-1) half-width iterations
+ const half_rep_t b_UQ1_hw = bSignificand >> (significandBits + 1 - HW);
+
+ // C is (3/4 + 1/sqrt(2)) - 1 truncated to W0 fractional bits as UQ0.HW
+ // with W0 being either 16 or 32 and W0 <= HW.
+ // That is, C is the aforementioned 3/4 + 1/sqrt(2) constant (from which
+ // b/2 is subtracted to obtain x0) wrapped to [0, 1) range.
+#if defined(SINGLE_PRECISION)
+ // Use 16-bit initial estimation in case we are using half-width iterations
+ // for float32 division. This is expected to be useful for some 16-bit
+ // targets. Not used by default as it requires performing more work during
+ // rounding and would hardly help on regular 32- or 64-bit targets.
+ const half_rep_t C_hw = HALF_REP_C(0x7504);
+#else
+ // HW is at least 32. Shifting into the highest bits if needed.
+ const half_rep_t C_hw = HALF_REP_C(0x7504F333) << (HW - 32);
+#endif
+
+ // b >= 1, thus an upper bound for 3/4 + 1/sqrt(2) - b/2 is about 0.9572,
+ // so x0 fits to UQ0.HW without wrapping.
+ half_rep_t x_UQ0_hw = C_hw - (b_UQ1_hw /* exact b_hw/2 as UQ0.HW */);
+ // An e_0 error is comprised of errors due to
+ // * x0 being an inherently imprecise first approximation of 1/b_hw
+ // * C_hw being some (irrational) number **truncated** to W0 bits
+ // Please note that e_0 is calculated against the infinitely precise
+ // reciprocal of b_hw (that is, **truncated** version of b).
+ //
+ // e_0 <= 3/4 - 1/sqrt(2) + 2^-W0
+
+ // By construction, 1 <= b < 2
+ // f(x) = x * (2 - b*x) = 2*x - b*x^2
+ // f'(x) = 2 * (1 - b*x)
+ //
+ // On the [0, 1] interval, f(0) = 0,
+ // then it increses until f(1/b) = 1 / b, maximum on (0, 1),
+ // then it decreses to f(1) = 2 - b
+ //
+ // Let g(x) = x - f(x) = b*x^2 - x.
+ // On (0, 1/b), g(x) < 0 <=> f(x) > x
+ // On (1/b, 1], g(x) > 0 <=> f(x) < x
+ //
+ // For half-width iterations, b_hw is used instead of b.
+ REPEAT_N_TIMES(NUMBER_OF_HALF_ITERATIONS, {
+ // corr_UQ1_hw can be **larger** than 2 - b_hw*x by at most 1*Ulp
+ // of corr_UQ1_hw.
+ // "0.0 - (...)" is equivalent to "2.0 - (...)" in UQ1.(HW-1).
+ // On the other hand, corr_UQ1_hw should not overflow from 2.0 to 0.0 provided
+ // no overflow occurred earlier: ((rep_t)x_UQ0_hw * b_UQ1_hw >> HW) is
+ // expected to be strictly positive because b_UQ1_hw has its highest bit set
+ // and x_UQ0_hw should be rather large (it converges to 1/2 < 1/b_hw <= 1).
+ half_rep_t corr_UQ1_hw = 0 - ((rep_t)x_UQ0_hw * b_UQ1_hw >> HW);
+
+ // Now, we should multiply UQ0.HW and UQ1.(HW-1) numbers, naturally
+ // obtaining an UQ1.(HW-1) number and proving its highest bit could be
+ // considered to be 0 to be able to represent it in UQ0.HW.
+ // From the above analysis of f(x), if corr_UQ1_hw would be represented
+ // without any intermediate loss of precision (that is, in twice_rep_t)
+ // x_UQ0_hw could be at most [1.]000... if b_hw is exactly 1.0 and strictly
+ // less otherwise. On the other hand, to obtain [1.]000..., one have to pass
+ // 1/b_hw == 1.0 to f(x), so this cannot occur at all without overflow (due
+ // to 1.0 being not representable as UQ0.HW).
+ // The fact corr_UQ1_hw was virtually round up (due to result of
+ // multiplication being **first** truncated, then negated - to improve
+ // error estimations) can increase x_UQ0_hw by up to 2*Ulp of x_UQ0_hw.
+ x_UQ0_hw = (rep_t)x_UQ0_hw * corr_UQ1_hw >> (HW - 1);
+ // Now, either no overflow occurred or x_UQ0_hw is 0 or 1 in its half_rep_t
+ // representation. In the latter case, x_UQ0_hw will be either 0 or 1 after
+ // any number of iterations, so just subtract 2 from the reciprocal
+ // approximation after last iteration.
+
+ // In infinite precision, with 0 <= eps1, eps2 <= U = 2^-HW:
+ // corr_UQ1_hw = 2 - (1/b_hw + e_n) * b_hw + 2*eps1
+ // = 1 - e_n * b_hw + 2*eps1
+ // x_UQ0_hw = (1/b_hw + e_n) * (1 - e_n*b_hw + 2*eps1) - eps2
+ // = 1/b_hw - e_n + 2*eps1/b_hw + e_n - e_n^2*b_hw + 2*e_n*eps1 - eps2
+ // = 1/b_hw + 2*eps1/b_hw - e_n^2*b_hw + 2*e_n*eps1 - eps2
+ // e_{n+1} = -e_n^2*b_hw + 2*eps1/b_hw + 2*e_n*eps1 - eps2
+ // = 2*e_n*eps1 - (e_n^2*b_hw + eps2) + 2*eps1/b_hw
+ // \------ >0 -------/ \-- >0 ---/
+ // abs(e_{n+1}) <= 2*abs(e_n)*U + max(2*e_n^2 + U, 2 * U)
+ })
+ // For initial half-width iterations, U = 2^-HW
+ // Let abs(e_n) <= u_n * U,
+ // then abs(e_{n+1}) <= 2 * u_n * U^2 + max(2 * u_n^2 * U^2 + U, 2 * U)
+ // u_{n+1} <= 2 * u_n * U + max(2 * u_n^2 * U + 1, 2)
+
+ // Account for possible overflow (see above). For an overflow to occur for the
+ // first time, for "ideal" corr_UQ1_hw (that is, without intermediate
+ // truncation), the result of x_UQ0_hw * corr_UQ1_hw should be either maximum
+ // value representable in UQ0.HW or less by 1. This means that 1/b_hw have to
+ // be not below that value (see g(x) above), so it is safe to decrement just
+ // once after the final iteration. On the other hand, an effective value of
+ // divisor changes after this point (from b_hw to b), so adjust here.
+ x_UQ0_hw -= 1U;
+ rep_t x_UQ0 = (rep_t)x_UQ0_hw << HW;
+ x_UQ0 -= 1U;
+
+#else
+ // C is (3/4 + 1/sqrt(2)) - 1 truncated to 32 fractional bits as UQ0.n
+ const rep_t C = REP_C(0x7504F333) << (typeWidth - 32);
+ rep_t x_UQ0 = C - b_UQ1;
+ // E_0 <= 3/4 - 1/sqrt(2) + 2 * 2^-32
+#endif
+
+ // Error estimations for full-precision iterations are calculated just
+ // as above, but with U := 2^-W and taking extra decrementing into account.
+ // We need at least one such iteration.
+
+#ifdef USE_NATIVE_FULL_ITERATIONS
+ REPEAT_N_TIMES(NUMBER_OF_FULL_ITERATIONS, {
+ rep_t corr_UQ1 = 0 - ((twice_rep_t)x_UQ0 * b_UQ1 >> typeWidth);
+ x_UQ0 = (twice_rep_t)x_UQ0 * corr_UQ1 >> (typeWidth - 1);
+ })
+#else
+#if NUMBER_OF_FULL_ITERATIONS != 1
+#error Only a single emulated full iteration is supported
+#endif
+#if !(NUMBER_OF_HALF_ITERATIONS > 0)
+ // Cannot normally reach here: only one full-width iteration is requested and
+ // the total number of iterations should be at least 3 even for float32.
+#error Check NUMBER_OF_HALF_ITERATIONS, NUMBER_OF_FULL_ITERATIONS and USE_NATIVE_FULL_ITERATIONS.
+#endif
+ // Simulating operations on a twice_rep_t to perform a single final full-width
+ // iteration. Using ad-hoc multiplication implementations to take advantage
+ // of particular structure of operands.
+ rep_t blo = b_UQ1 & loMask;
+ // x_UQ0 = x_UQ0_hw * 2^HW - 1
+ // x_UQ0 * b_UQ1 = (x_UQ0_hw * 2^HW) * (b_UQ1_hw * 2^HW + blo) - b_UQ1
+ //
+ // <--- higher half ---><--- lower half --->
+ // [x_UQ0_hw * b_UQ1_hw]
+ // + [ x_UQ0_hw * blo ]
+ // - [ b_UQ1 ]
+ // = [ result ][.... discarded ...]
+ rep_t corr_UQ1 = 0U - ( (rep_t)x_UQ0_hw * b_UQ1_hw
+ + ((rep_t)x_UQ0_hw * blo >> HW)
+ - REP_C(1)); // account for *possible* carry
+ rep_t lo_corr = corr_UQ1 & loMask;
+ rep_t hi_corr = corr_UQ1 >> HW;
+ // x_UQ0 * corr_UQ1 = (x_UQ0_hw * 2^HW) * (hi_corr * 2^HW + lo_corr) - corr_UQ1
+ x_UQ0 = ((rep_t)x_UQ0_hw * hi_corr << 1)
+ + ((rep_t)x_UQ0_hw * lo_corr >> (HW - 1))
+ - REP_C(2); // 1 to account for the highest bit of corr_UQ1 can be 1
+ // 1 to account for possible carry
+ // Just like the case of half-width iterations but with possibility
+ // of overflowing by one extra Ulp of x_UQ0.
+ x_UQ0 -= 1U;
+ // ... and then traditional fixup by 2 should work
+
+ // On error estimation:
+ // abs(E_{N-1}) <= (u_{N-1} + 2 /* due to conversion e_n -> E_n */) * 2^-HW
+ // + (2^-HW + 2^-W))
+ // abs(E_{N-1}) <= (u_{N-1} + 3.01) * 2^-HW
+
+ // Then like for the half-width iterations:
+ // With 0 <= eps1, eps2 < 2^-W
+ // E_N = 4 * E_{N-1} * eps1 - (E_{N-1}^2 * b + 4 * eps2) + 4 * eps1 / b
+ // abs(E_N) <= 2^-W * [ 4 * abs(E_{N-1}) + max(2 * abs(E_{N-1})^2 * 2^W + 4, 8)) ]
+ // abs(E_N) <= 2^-W * [ 4 * (u_{N-1} + 3.01) * 2^-HW + max(4 + 2 * (u_{N-1} + 3.01)^2, 8) ]
+#endif
+
+ // Finally, account for possible overflow, as explained above.
+ x_UQ0 -= 2U;
+
+ // u_n for different precisions (with N-1 half-width iterations):
+ // W0 is the precision of C
+ // u_0 = (3/4 - 1/sqrt(2) + 2^-W0) * 2^HW
+
+ // Estimated with bc:
+ // define half1(un) { return 2.0 * (un + un^2) / 2.0^hw + 1.0; }
+ // define half2(un) { return 2.0 * un / 2.0^hw + 2.0; }
+ // define full1(un) { return 4.0 * (un + 3.01) / 2.0^hw + 2.0 * (un + 3.01)^2 + 4.0; }
+ // define full2(un) { return 4.0 * (un + 3.01) / 2.0^hw + 8.0; }
+
+ // | f32 (0 + 3) | f32 (2 + 1) | f64 (3 + 1) | f128 (4 + 1)
+ // u_0 | < 184224974 | < 2812.1 | < 184224974 | < 791240234244348797
+ // u_1 | < 15804007 | < 242.7 | < 15804007 | < 67877681371350440
+ // u_2 | < 116308 | < 2.81 | < 116308 | < 499533100252317
+ // u_3 | < 7.31 | | < 7.31 | < 27054456580
+ // u_4 | | | | < 80.4
+ // Final (U_N) | same as u_3 | < 72 | < 218 | < 13920
+
+ // Add 2 to U_N due to final decrement.
+
+#if defined(SINGLE_PRECISION) && NUMBER_OF_HALF_ITERATIONS == 2 && NUMBER_OF_FULL_ITERATIONS == 1
+#define RECIPROCAL_PRECISION REP_C(74)
+#elif defined(SINGLE_PRECISION) && NUMBER_OF_HALF_ITERATIONS == 0 && NUMBER_OF_FULL_ITERATIONS == 3
+#define RECIPROCAL_PRECISION REP_C(10)
+#elif defined(DOUBLE_PRECISION) && NUMBER_OF_HALF_ITERATIONS == 3 && NUMBER_OF_FULL_ITERATIONS == 1
+#define RECIPROCAL_PRECISION REP_C(220)
+#elif defined(QUAD_PRECISION) && NUMBER_OF_HALF_ITERATIONS == 4 && NUMBER_OF_FULL_ITERATIONS == 1
+#define RECIPROCAL_PRECISION REP_C(13922)
+#else
+#error Invalid number of iterations
+#endif
+
+ // Suppose 1/b - P * 2^-W < x < 1/b + P * 2^-W
+ x_UQ0 -= RECIPROCAL_PRECISION;
+ // Now 1/b - (2*P) * 2^-W < x < 1/b
+ // FIXME Is x_UQ0 still >= 0.5?
+
+ rep_t quotient_UQ1, dummy;
+ wideMultiply(x_UQ0, aSignificand << 1, &quotient_UQ1, &dummy);
+ // Now, a/b - 4*P * 2^-W < q < a/b for q=<quotient_UQ1:dummy> in UQ1.(SB+1+W).
+
+ // quotient_UQ1 is in [0.5, 2.0) as UQ1.(SB+1),
+ // adjust it to be in [1.0, 2.0) as UQ1.SB.
+ rep_t residualLo;
+ if (quotient_UQ1 < (implicitBit << 1)) {
+ // Highest bit is 0, so just reinterpret quotient_UQ1 as UQ1.SB,
+ // effectively doubling its value as well as its error estimation.
+ residualLo = (aSignificand << (significandBits + 1)) - quotient_UQ1 * bSignificand;
+ writtenExponent -= 1;
+ aSignificand <<= 1;
+ } else {
+ // Highest bit is 1 (the UQ1.(SB+1) value is in [1, 2)), convert it
+ // to UQ1.SB by right shifting by 1. Least significant bit is omitted.
+ quotient_UQ1 >>= 1;
+ residualLo = (aSignificand << significandBits) - quotient_UQ1 * bSignificand;
+ }
+ // NB: residualLo is calculated above for the normal result case.
+ // It is re-computed on denormal path that is expected to be not so
+ // performance-sensitive.
+
+ // Now, q cannot be greater than a/b and can differ by at most 8*P * 2^-W + 2^-SB
+ // Each NextAfter() increments the floating point value by at least 2^-SB
+ // (more, if exponent was incremented).
+ // Different cases (<---> is of 2^-SB length, * = a/b that is shown as a midpoint):
+ // q
+ // | | * | | | | |
+ // <---> 2^t
+ // | | | | | * | |
+ // q
+ // To require at most one NextAfter(), an error should be less than 1.5 * 2^-SB.
+ // (8*P) * 2^-W + 2^-SB < 1.5 * 2^-SB
+ // (8*P) * 2^-W < 0.5 * 2^-SB
+ // P < 2^(W-4-SB)
+ // Generally, for at most R NextAfter() to be enough,
+ // P < (2*R - 1) * 2^(W-4-SB)
+ // For f32 (0+3): 10 < 32 (OK)
+ // For f32 (2+1): 32 < 74 < 32 * 3, so two NextAfter() are required
+ // For f64: 220 < 256 (OK)
+ // For f128: 4096 * 3 < 13922 < 4096 * 5 (three NextAfter() are required)
+
+ // If we have overflowed the exponent, return infinity
+ if (writtenExponent >= maxExponent)
+ return fromRep(infRep | quotientSign);
+
+ // Now, quotient_UQ1_SB <= the correctly-rounded result
+ // and may need taking NextAfter() up to 3 times (see error estimates above)
+ // r = a - b * q
+ rep_t absResult;
+ if (writtenExponent > 0) {
+ // Clear the implicit bit
+ absResult = quotient_UQ1 & significandMask;
+ // Insert the exponent
+ absResult |= (rep_t)writtenExponent << significandBits;
+ residualLo <<= 1;
+ } else {
+ // Prevent shift amount from being negative
+ if (significandBits + writtenExponent < 0)
+ return fromRep(quotientSign);
+
+ absResult = quotient_UQ1 >> (-writtenExponent + 1);
+
+ // multiplied by two to prevent shift amount to be negative
+ residualLo = (aSignificand << (significandBits + writtenExponent)) - (absResult * bSignificand << 1);
+ }
+
+ // Round
+ residualLo += absResult & 1; // tie to even
+ // The above line conditionally turns the below LT comparison into LTE
+ absResult += residualLo > bSignificand;
+#if defined(QUAD_PRECISION) || (defined(SINGLE_PRECISION) && NUMBER_OF_HALF_ITERATIONS > 0)
+ // Do not round Infinity to NaN
+ absResult += absResult < infRep && residualLo > (2 + 1) * bSignificand;
+#endif
+#if defined(QUAD_PRECISION)
+ absResult += absResult < infRep && residualLo > (4 + 1) * bSignificand;
+#endif
+ return fromRep(absResult | quotientSign);
+}
diff --git a/contrib/libs/cxxsupp/builtins/fp_extend.h b/contrib/libs/cxxsupp/builtins/fp_extend.h
index 6d95a06807..eee4722bf9 100644
--- a/contrib/libs/cxxsupp/builtins/fp_extend.h
+++ b/contrib/libs/cxxsupp/builtins/fp_extend.h
@@ -1,9 +1,9 @@
-//===-lib/fp_extend.h - low precision -> high precision conversion -*- C -*-===//
+//===-lib/fp_extend.h - low precision -> high precision conversion -*- C
+//-*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -21,7 +21,7 @@ typedef float src_t;
typedef uint32_t src_rep_t;
#define SRC_REP_C UINT32_C
static const int srcSigBits = 23;
-#define src_rep_t_clz __builtin_clz
+#define src_rep_t_clz clzsi
#elif defined SRC_DOUBLE
typedef double src_t;
@@ -30,17 +30,21 @@ typedef uint64_t src_rep_t;
static const int srcSigBits = 52;
static __inline int src_rep_t_clz(src_rep_t a) {
#if defined __LP64__
- return __builtin_clzl(a);
+ return __builtin_clzl(a);
#else
- if (a & REP_C(0xffffffff00000000))
- return __builtin_clz(a >> 32);
- else
- return 32 + __builtin_clz(a & REP_C(0xffffffff));
+ if (a & REP_C(0xffffffff00000000))
+ return clzsi(a >> 32);
+ else
+ return 32 + clzsi(a & REP_C(0xffffffff));
#endif
}
#elif defined SRC_HALF
+#ifdef COMPILER_RT_HAS_FLOAT16
+typedef _Float16 src_t;
+#else
typedef uint16_t src_t;
+#endif
typedef uint16_t src_rep_t;
#define SRC_REP_C UINT16_C
static const int srcSigBits = 10;
@@ -48,7 +52,7 @@ static const int srcSigBits = 10;
#else
#error Source should be half, single, or double precision!
-#endif //end source precision
+#endif // end source precision
#if defined DST_SINGLE
typedef float dst_t;
@@ -70,20 +74,26 @@ static const int dstSigBits = 112;
#else
#error Destination should be single, double, or quad precision!
-#endif //end destination precision
+#endif // end destination precision
// End of specialization parameters. Two helper routines for conversion to and
// from the representation of floating-point data as integer values follow.
static __inline src_rep_t srcToRep(src_t x) {
- const union { src_t f; src_rep_t i; } rep = {.f = x};
- return rep.i;
+ const union {
+ src_t f;
+ src_rep_t i;
+ } rep = {.f = x};
+ return rep.i;
}
static __inline dst_t dstFromRep(dst_rep_t x) {
- const union { dst_t f; dst_rep_t i; } rep = {.i = x};
- return rep.f;
+ const union {
+ dst_t f;
+ dst_rep_t i;
+ } rep = {.i = x};
+ return rep.f;
}
// End helper routines. Conversion implementation follows.
-#endif //FP_EXTEND_HEADER
+#endif // FP_EXTEND_HEADER
diff --git a/contrib/libs/cxxsupp/builtins/fp_extend_impl.inc b/contrib/libs/cxxsupp/builtins/fp_extend_impl.inc
index b785cc7687..d1c9c02a00 100644
--- a/contrib/libs/cxxsupp/builtins/fp_extend_impl.inc
+++ b/contrib/libs/cxxsupp/builtins/fp_extend_impl.inc
@@ -1,9 +1,8 @@
//=-lib/fp_extend_impl.inc - low precision -> high precision conversion -*-- -//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -28,81 +27,81 @@
//
// Finally, the following assumptions are made:
//
-// 1. floating-point types and integer types have the same endianness on the
-// target platform
+// 1. Floating-point types and integer types have the same endianness on the
+// target platform.
//
-// 2. quiet NaNs, if supported, are indicated by the leading bit of the
-// significand field being set
+// 2. Quiet NaNs, if supported, are indicated by the leading bit of the
+// significand field being set.
//
//===----------------------------------------------------------------------===//
#include "fp_extend.h"
static __inline dst_t __extendXfYf2__(src_t a) {
- // Various constants whose values follow from the type parameters.
- // Any reasonable optimizer will fold and propagate all of these.
- const int srcBits = sizeof(src_t)*CHAR_BIT;
- const int srcExpBits = srcBits - srcSigBits - 1;
- const int srcInfExp = (1 << srcExpBits) - 1;
- const int srcExpBias = srcInfExp >> 1;
+ // Various constants whose values follow from the type parameters.
+ // Any reasonable optimizer will fold and propagate all of these.
+ const int srcBits = sizeof(src_t) * CHAR_BIT;
+ const int srcExpBits = srcBits - srcSigBits - 1;
+ const int srcInfExp = (1 << srcExpBits) - 1;
+ const int srcExpBias = srcInfExp >> 1;
- const src_rep_t srcMinNormal = SRC_REP_C(1) << srcSigBits;
- const src_rep_t srcInfinity = (src_rep_t)srcInfExp << srcSigBits;
- const src_rep_t srcSignMask = SRC_REP_C(1) << (srcSigBits + srcExpBits);
- const src_rep_t srcAbsMask = srcSignMask - 1;
- const src_rep_t srcQNaN = SRC_REP_C(1) << (srcSigBits - 1);
- const src_rep_t srcNaNCode = srcQNaN - 1;
+ const src_rep_t srcMinNormal = SRC_REP_C(1) << srcSigBits;
+ const src_rep_t srcInfinity = (src_rep_t)srcInfExp << srcSigBits;
+ const src_rep_t srcSignMask = SRC_REP_C(1) << (srcSigBits + srcExpBits);
+ const src_rep_t srcAbsMask = srcSignMask - 1;
+ const src_rep_t srcQNaN = SRC_REP_C(1) << (srcSigBits - 1);
+ const src_rep_t srcNaNCode = srcQNaN - 1;
- const int dstBits = sizeof(dst_t)*CHAR_BIT;
- const int dstExpBits = dstBits - dstSigBits - 1;
- const int dstInfExp = (1 << dstExpBits) - 1;
- const int dstExpBias = dstInfExp >> 1;
+ const int dstBits = sizeof(dst_t) * CHAR_BIT;
+ const int dstExpBits = dstBits - dstSigBits - 1;
+ const int dstInfExp = (1 << dstExpBits) - 1;
+ const int dstExpBias = dstInfExp >> 1;
- const dst_rep_t dstMinNormal = DST_REP_C(1) << dstSigBits;
+ const dst_rep_t dstMinNormal = DST_REP_C(1) << dstSigBits;
- // Break a into a sign and representation of the absolute value
- const src_rep_t aRep = srcToRep(a);
- const src_rep_t aAbs = aRep & srcAbsMask;
- const src_rep_t sign = aRep & srcSignMask;
- dst_rep_t absResult;
+ // Break a into a sign and representation of the absolute value.
+ const src_rep_t aRep = srcToRep(a);
+ const src_rep_t aAbs = aRep & srcAbsMask;
+ const src_rep_t sign = aRep & srcSignMask;
+ dst_rep_t absResult;
- // If sizeof(src_rep_t) < sizeof(int), the subtraction result is promoted
- // to (signed) int. To avoid that, explicitly cast to src_rep_t.
- if ((src_rep_t)(aAbs - srcMinNormal) < srcInfinity - srcMinNormal) {
- // a is a normal number.
- // Extend to the destination type by shifting the significand and
- // exponent into the proper position and rebiasing the exponent.
- absResult = (dst_rep_t)aAbs << (dstSigBits - srcSigBits);
- absResult += (dst_rep_t)(dstExpBias - srcExpBias) << dstSigBits;
- }
+ // If sizeof(src_rep_t) < sizeof(int), the subtraction result is promoted
+ // to (signed) int. To avoid that, explicitly cast to src_rep_t.
+ if ((src_rep_t)(aAbs - srcMinNormal) < srcInfinity - srcMinNormal) {
+ // a is a normal number.
+ // Extend to the destination type by shifting the significand and
+ // exponent into the proper position and rebiasing the exponent.
+ absResult = (dst_rep_t)aAbs << (dstSigBits - srcSigBits);
+ absResult += (dst_rep_t)(dstExpBias - srcExpBias) << dstSigBits;
+ }
- else if (aAbs >= srcInfinity) {
- // a is NaN or infinity.
- // Conjure the result by beginning with infinity, then setting the qNaN
- // bit (if needed) and right-aligning the rest of the trailing NaN
- // payload field.
- absResult = (dst_rep_t)dstInfExp << dstSigBits;
- absResult |= (dst_rep_t)(aAbs & srcQNaN) << (dstSigBits - srcSigBits);
- absResult |= (dst_rep_t)(aAbs & srcNaNCode) << (dstSigBits - srcSigBits);
- }
+ else if (aAbs >= srcInfinity) {
+ // a is NaN or infinity.
+ // Conjure the result by beginning with infinity, then setting the qNaN
+ // bit (if needed) and right-aligning the rest of the trailing NaN
+ // payload field.
+ absResult = (dst_rep_t)dstInfExp << dstSigBits;
+ absResult |= (dst_rep_t)(aAbs & srcQNaN) << (dstSigBits - srcSigBits);
+ absResult |= (dst_rep_t)(aAbs & srcNaNCode) << (dstSigBits - srcSigBits);
+ }
- else if (aAbs) {
- // a is denormal.
- // renormalize the significand and clear the leading bit, then insert
- // the correct adjusted exponent in the destination type.
- const int scale = src_rep_t_clz(aAbs) - src_rep_t_clz(srcMinNormal);
- absResult = (dst_rep_t)aAbs << (dstSigBits - srcSigBits + scale);
- absResult ^= dstMinNormal;
- const int resultExponent = dstExpBias - srcExpBias - scale + 1;
- absResult |= (dst_rep_t)resultExponent << dstSigBits;
- }
+ else if (aAbs) {
+ // a is denormal.
+ // renormalize the significand and clear the leading bit, then insert
+ // the correct adjusted exponent in the destination type.
+ const int scale = src_rep_t_clz(aAbs) - src_rep_t_clz(srcMinNormal);
+ absResult = (dst_rep_t)aAbs << (dstSigBits - srcSigBits + scale);
+ absResult ^= dstMinNormal;
+ const int resultExponent = dstExpBias - srcExpBias - scale + 1;
+ absResult |= (dst_rep_t)resultExponent << dstSigBits;
+ }
- else {
- // a is zero.
- absResult = 0;
- }
+ else {
+ // a is zero.
+ absResult = 0;
+ }
- // Apply the signbit to (dst_t)abs(a).
- const dst_rep_t result = absResult | (dst_rep_t)sign << (dstBits - srcBits);
- return dstFromRep(result);
+ // Apply the signbit to the absolute value.
+ const dst_rep_t result = absResult | (dst_rep_t)sign << (dstBits - srcBits);
+ return dstFromRep(result);
}
diff --git a/contrib/libs/cxxsupp/builtins/fp_fixint_impl.inc b/contrib/libs/cxxsupp/builtins/fp_fixint_impl.inc
index da70d4d393..2196d712f0 100644
--- a/contrib/libs/cxxsupp/builtins/fp_fixint_impl.inc
+++ b/contrib/libs/cxxsupp/builtins/fp_fixint_impl.inc
@@ -1,9 +1,8 @@
//===-- lib/fixdfsi.c - Double-precision -> integer conversion ----*- C -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -15,27 +14,27 @@
#include "fp_lib.h"
static __inline fixint_t __fixint(fp_t a) {
- const fixint_t fixint_max = (fixint_t)((~(fixuint_t)0) / 2);
- const fixint_t fixint_min = -fixint_max - 1;
- // Break a into sign, exponent, significand
- const rep_t aRep = toRep(a);
- const rep_t aAbs = aRep & absMask;
- const fixint_t sign = aRep & signBit ? -1 : 1;
- const int exponent = (aAbs >> significandBits) - exponentBias;
- const rep_t significand = (aAbs & significandMask) | implicitBit;
+ const fixint_t fixint_max = (fixint_t)((~(fixuint_t)0) / 2);
+ const fixint_t fixint_min = -fixint_max - 1;
+ // Break a into sign, exponent, significand parts.
+ const rep_t aRep = toRep(a);
+ const rep_t aAbs = aRep & absMask;
+ const fixint_t sign = aRep & signBit ? -1 : 1;
+ const int exponent = (aAbs >> significandBits) - exponentBias;
+ const rep_t significand = (aAbs & significandMask) | implicitBit;
- // If exponent is negative, the result is zero.
- if (exponent < 0)
- return 0;
+ // If exponent is negative, the result is zero.
+ if (exponent < 0)
+ return 0;
- // If the value is too large for the integer type, saturate.
- if ((unsigned)exponent >= sizeof(fixint_t) * CHAR_BIT)
- return sign == 1 ? fixint_max : fixint_min;
+ // If the value is too large for the integer type, saturate.
+ if ((unsigned)exponent >= sizeof(fixint_t) * CHAR_BIT)
+ return sign == 1 ? fixint_max : fixint_min;
- // If 0 <= exponent < significandBits, right shift to get the result.
- // Otherwise, shift left.
- if (exponent < significandBits)
- return sign * (significand >> (significandBits - exponent));
- else
- return sign * ((fixint_t)significand << (exponent - significandBits));
+ // If 0 <= exponent < significandBits, right shift to get the result.
+ // Otherwise, shift left.
+ if (exponent < significandBits)
+ return sign * (significand >> (significandBits - exponent));
+ else
+ return sign * ((fixint_t)significand << (exponent - significandBits));
}
diff --git a/contrib/libs/cxxsupp/builtins/fp_fixuint_impl.inc b/contrib/libs/cxxsupp/builtins/fp_fixuint_impl.inc
index d68ccf27a7..cb2bf54ffa 100644
--- a/contrib/libs/cxxsupp/builtins/fp_fixuint_impl.inc
+++ b/contrib/libs/cxxsupp/builtins/fp_fixuint_impl.inc
@@ -1,9 +1,8 @@
//===-- lib/fixdfsi.c - Double-precision -> integer conversion ----*- C -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -15,25 +14,25 @@
#include "fp_lib.h"
static __inline fixuint_t __fixuint(fp_t a) {
- // Break a into sign, exponent, significand
- const rep_t aRep = toRep(a);
- const rep_t aAbs = aRep & absMask;
- const int sign = aRep & signBit ? -1 : 1;
- const int exponent = (aAbs >> significandBits) - exponentBias;
- const rep_t significand = (aAbs & significandMask) | implicitBit;
+ // Break a into sign, exponent, significand parts.
+ const rep_t aRep = toRep(a);
+ const rep_t aAbs = aRep & absMask;
+ const int sign = aRep & signBit ? -1 : 1;
+ const int exponent = (aAbs >> significandBits) - exponentBias;
+ const rep_t significand = (aAbs & significandMask) | implicitBit;
- // If either the value or the exponent is negative, the result is zero.
- if (sign == -1 || exponent < 0)
- return 0;
+ // If either the value or the exponent is negative, the result is zero.
+ if (sign == -1 || exponent < 0)
+ return 0;
- // If the value is too large for the integer type, saturate.
- if ((unsigned)exponent >= sizeof(fixuint_t) * CHAR_BIT)
- return ~(fixuint_t)0;
+ // If the value is too large for the integer type, saturate.
+ if ((unsigned)exponent >= sizeof(fixuint_t) * CHAR_BIT)
+ return ~(fixuint_t)0;
- // If 0 <= exponent < significandBits, right shift to get the result.
- // Otherwise, shift left.
- if (exponent < significandBits)
- return significand >> (significandBits - exponent);
- else
- return (fixuint_t)significand << (exponent - significandBits);
+ // If 0 <= exponent < significandBits, right shift to get the result.
+ // Otherwise, shift left.
+ if (exponent < significandBits)
+ return significand >> (significandBits - exponent);
+ else
+ return (fixuint_t)significand << (exponent - significandBits);
}
diff --git a/contrib/libs/cxxsupp/builtins/fp_lib.h b/contrib/libs/cxxsupp/builtins/fp_lib.h
index 223fb980aa..3fb13a033a 100644
--- a/contrib/libs/cxxsupp/builtins/fp_lib.h
+++ b/contrib/libs/cxxsupp/builtins/fp_lib.h
@@ -1,9 +1,8 @@
//===-- lib/fp_lib.h - Floating-point utilities -------------------*- C -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -21,59 +20,63 @@
#ifndef FP_LIB_HEADER
#define FP_LIB_HEADER
-#include <stdint.h>
-#include <stdbool.h>
-#include <limits.h>
#include "int_lib.h"
+#include "int_math.h"
+#include <limits.h>
+#include <stdbool.h>
+#include <stdint.h>
// x86_64 FreeBSD prior v9.3 define fixed-width types incorrectly in
// 32-bit mode.
#if defined(__FreeBSD__) && defined(__i386__)
-# include <sys/param.h>
-# if __FreeBSD_version < 903000 // v9.3
-# define uint64_t unsigned long long
-# define int64_t long long
-# undef UINT64_C
-# define UINT64_C(c) (c ## ULL)
-# endif
+#include <sys/param.h>
+#if __FreeBSD_version < 903000 // v9.3
+#define uint64_t unsigned long long
+#define int64_t long long
+#undef UINT64_C
+#define UINT64_C(c) (c##ULL)
+#endif
#endif
#if defined SINGLE_PRECISION
+typedef uint16_t half_rep_t;
typedef uint32_t rep_t;
+typedef uint64_t twice_rep_t;
typedef int32_t srep_t;
typedef float fp_t;
+#define HALF_REP_C UINT16_C
#define REP_C UINT32_C
#define significandBits 23
-static __inline int rep_clz(rep_t a) {
- return __builtin_clz(a);
-}
+static __inline int rep_clz(rep_t a) { return clzsi(a); }
// 32x32 --> 64 bit multiply
static __inline void wideMultiply(rep_t a, rep_t b, rep_t *hi, rep_t *lo) {
- const uint64_t product = (uint64_t)a*b;
- *hi = product >> 32;
- *lo = product;
+ const uint64_t product = (uint64_t)a * b;
+ *hi = product >> 32;
+ *lo = product;
}
COMPILER_RT_ABI fp_t __addsf3(fp_t a, fp_t b);
#elif defined DOUBLE_PRECISION
+typedef uint32_t half_rep_t;
typedef uint64_t rep_t;
typedef int64_t srep_t;
typedef double fp_t;
+#define HALF_REP_C UINT32_C
#define REP_C UINT64_C
#define significandBits 52
static __inline int rep_clz(rep_t a) {
#if defined __LP64__
- return __builtin_clzl(a);
+ return __builtin_clzl(a);
#else
- if (a & REP_C(0xffffffff00000000))
- return __builtin_clz(a >> 32);
- else
- return 32 + __builtin_clz(a & REP_C(0xffffffff));
+ if (a & REP_C(0xffffffff00000000))
+ return clzsi(a >> 32);
+ else
+ return 32 + clzsi(a & REP_C(0xffffffff));
#endif
}
@@ -84,17 +87,17 @@ static __inline int rep_clz(rep_t a) {
// many 64-bit platforms have this operation, but they tend to have hardware
// floating-point, so we don't bother with a special case for them here.
static __inline void wideMultiply(rep_t a, rep_t b, rep_t *hi, rep_t *lo) {
- // Each of the component 32x32 -> 64 products
- const uint64_t plolo = loWord(a) * loWord(b);
- const uint64_t plohi = loWord(a) * hiWord(b);
- const uint64_t philo = hiWord(a) * loWord(b);
- const uint64_t phihi = hiWord(a) * hiWord(b);
- // Sum terms that contribute to lo in a way that allows us to get the carry
- const uint64_t r0 = loWord(plolo);
- const uint64_t r1 = hiWord(plolo) + loWord(plohi) + loWord(philo);
- *lo = r0 + (r1 << 32);
- // Sum terms contributing to hi with the carry from lo
- *hi = hiWord(plohi) + hiWord(philo) + hiWord(r1) + phihi;
+ // Each of the component 32x32 -> 64 products
+ const uint64_t plolo = loWord(a) * loWord(b);
+ const uint64_t plohi = loWord(a) * hiWord(b);
+ const uint64_t philo = hiWord(a) * loWord(b);
+ const uint64_t phihi = hiWord(a) * hiWord(b);
+ // Sum terms that contribute to lo in a way that allows us to get the carry
+ const uint64_t r0 = loWord(plolo);
+ const uint64_t r1 = hiWord(plolo) + loWord(plohi) + loWord(philo);
+ *lo = r0 + (r1 << 32);
+ // Sum terms contributing to hi with the carry from lo
+ *hi = hiWord(plohi) + hiWord(philo) + hiWord(r1) + phihi;
}
#undef loWord
#undef hiWord
@@ -102,43 +105,47 @@ static __inline void wideMultiply(rep_t a, rep_t b, rep_t *hi, rep_t *lo) {
COMPILER_RT_ABI fp_t __adddf3(fp_t a, fp_t b);
#elif defined QUAD_PRECISION
-#if __LDBL_MANT_DIG__ == 113
+#if __LDBL_MANT_DIG__ == 113 && defined(__SIZEOF_INT128__)
#define CRT_LDBL_128BIT
+typedef uint64_t half_rep_t;
typedef __uint128_t rep_t;
typedef __int128_t srep_t;
typedef long double fp_t;
+#define HALF_REP_C UINT64_C
#define REP_C (__uint128_t)
// Note: Since there is no explicit way to tell compiler the constant is a
// 128-bit integer, we let the constant be casted to 128-bit integer
#define significandBits 112
static __inline int rep_clz(rep_t a) {
- const union
- {
- __uint128_t ll;
+ const union {
+ __uint128_t ll;
#if _YUGA_BIG_ENDIAN
- struct { uint64_t high, low; } s;
+ struct {
+ uint64_t high, low;
+ } s;
#else
- struct { uint64_t low, high; } s;
+ struct {
+ uint64_t low, high;
+ } s;
#endif
- } uu = { .ll = a };
+ } uu = {.ll = a};
- uint64_t word;
- uint64_t add;
+ uint64_t word;
+ uint64_t add;
- if (uu.s.high){
- word = uu.s.high;
- add = 0;
- }
- else{
- word = uu.s.low;
- add = 64;
- }
- return __builtin_clzll(word) + add;
+ if (uu.s.high) {
+ word = uu.s.high;
+ add = 0;
+ } else {
+ word = uu.s.low;
+ add = 64;
+ }
+ return __builtin_clzll(word) + add;
}
-#define Word_LoMask UINT64_C(0x00000000ffffffff)
-#define Word_HiMask UINT64_C(0xffffffff00000000)
+#define Word_LoMask UINT64_C(0x00000000ffffffff)
+#define Word_HiMask UINT64_C(0xffffffff00000000)
#define Word_FullMask UINT64_C(0xffffffffffffffff)
#define Word_1(a) (uint64_t)((a >> 96) & Word_LoMask)
#define Word_2(a) (uint64_t)((a >> 64) & Word_LoMask)
@@ -150,55 +157,41 @@ static __inline int rep_clz(rep_t a) {
// floating-point, so we don't bother with a special case for them here.
static __inline void wideMultiply(rep_t a, rep_t b, rep_t *hi, rep_t *lo) {
- const uint64_t product11 = Word_1(a) * Word_1(b);
- const uint64_t product12 = Word_1(a) * Word_2(b);
- const uint64_t product13 = Word_1(a) * Word_3(b);
- const uint64_t product14 = Word_1(a) * Word_4(b);
- const uint64_t product21 = Word_2(a) * Word_1(b);
- const uint64_t product22 = Word_2(a) * Word_2(b);
- const uint64_t product23 = Word_2(a) * Word_3(b);
- const uint64_t product24 = Word_2(a) * Word_4(b);
- const uint64_t product31 = Word_3(a) * Word_1(b);
- const uint64_t product32 = Word_3(a) * Word_2(b);
- const uint64_t product33 = Word_3(a) * Word_3(b);
- const uint64_t product34 = Word_3(a) * Word_4(b);
- const uint64_t product41 = Word_4(a) * Word_1(b);
- const uint64_t product42 = Word_4(a) * Word_2(b);
- const uint64_t product43 = Word_4(a) * Word_3(b);
- const uint64_t product44 = Word_4(a) * Word_4(b);
-
- const __uint128_t sum0 = (__uint128_t)product44;
- const __uint128_t sum1 = (__uint128_t)product34 +
- (__uint128_t)product43;
- const __uint128_t sum2 = (__uint128_t)product24 +
- (__uint128_t)product33 +
- (__uint128_t)product42;
- const __uint128_t sum3 = (__uint128_t)product14 +
- (__uint128_t)product23 +
- (__uint128_t)product32 +
- (__uint128_t)product41;
- const __uint128_t sum4 = (__uint128_t)product13 +
- (__uint128_t)product22 +
- (__uint128_t)product31;
- const __uint128_t sum5 = (__uint128_t)product12 +
- (__uint128_t)product21;
- const __uint128_t sum6 = (__uint128_t)product11;
-
- const __uint128_t r0 = (sum0 & Word_FullMask) +
- ((sum1 & Word_LoMask) << 32);
- const __uint128_t r1 = (sum0 >> 64) +
- ((sum1 >> 32) & Word_FullMask) +
- (sum2 & Word_FullMask) +
- ((sum3 << 32) & Word_HiMask);
-
- *lo = r0 + (r1 << 64);
- *hi = (r1 >> 64) +
- (sum1 >> 96) +
- (sum2 >> 64) +
- (sum3 >> 32) +
- sum4 +
- (sum5 << 32) +
- (sum6 << 64);
+ const uint64_t product11 = Word_1(a) * Word_1(b);
+ const uint64_t product12 = Word_1(a) * Word_2(b);
+ const uint64_t product13 = Word_1(a) * Word_3(b);
+ const uint64_t product14 = Word_1(a) * Word_4(b);
+ const uint64_t product21 = Word_2(a) * Word_1(b);
+ const uint64_t product22 = Word_2(a) * Word_2(b);
+ const uint64_t product23 = Word_2(a) * Word_3(b);
+ const uint64_t product24 = Word_2(a) * Word_4(b);
+ const uint64_t product31 = Word_3(a) * Word_1(b);
+ const uint64_t product32 = Word_3(a) * Word_2(b);
+ const uint64_t product33 = Word_3(a) * Word_3(b);
+ const uint64_t product34 = Word_3(a) * Word_4(b);
+ const uint64_t product41 = Word_4(a) * Word_1(b);
+ const uint64_t product42 = Word_4(a) * Word_2(b);
+ const uint64_t product43 = Word_4(a) * Word_3(b);
+ const uint64_t product44 = Word_4(a) * Word_4(b);
+
+ const __uint128_t sum0 = (__uint128_t)product44;
+ const __uint128_t sum1 = (__uint128_t)product34 + (__uint128_t)product43;
+ const __uint128_t sum2 =
+ (__uint128_t)product24 + (__uint128_t)product33 + (__uint128_t)product42;
+ const __uint128_t sum3 = (__uint128_t)product14 + (__uint128_t)product23 +
+ (__uint128_t)product32 + (__uint128_t)product41;
+ const __uint128_t sum4 =
+ (__uint128_t)product13 + (__uint128_t)product22 + (__uint128_t)product31;
+ const __uint128_t sum5 = (__uint128_t)product12 + (__uint128_t)product21;
+ const __uint128_t sum6 = (__uint128_t)product11;
+
+ const __uint128_t r0 = (sum0 & Word_FullMask) + ((sum1 & Word_LoMask) << 32);
+ const __uint128_t r1 = (sum0 >> 64) + ((sum1 >> 32) & Word_FullMask) +
+ (sum2 & Word_FullMask) + ((sum3 << 32) & Word_HiMask);
+
+ *lo = r0 + (r1 << 64);
+ *hi = (r1 >> 64) + (sum1 >> 96) + (sum2 >> 64) + (sum3 >> 32) + sum4 +
+ (sum5 << 32) + (sum6 << 64);
}
#undef Word_1
#undef Word_2
@@ -207,64 +200,218 @@ static __inline void wideMultiply(rep_t a, rep_t b, rep_t *hi, rep_t *lo) {
#undef Word_HiMask
#undef Word_LoMask
#undef Word_FullMask
-#endif // __LDBL_MANT_DIG__ == 113
+#endif // __LDBL_MANT_DIG__ == 113 && __SIZEOF_INT128__
#else
#error SINGLE_PRECISION, DOUBLE_PRECISION or QUAD_PRECISION must be defined.
#endif
-#if defined(SINGLE_PRECISION) || defined(DOUBLE_PRECISION) || defined(CRT_LDBL_128BIT)
-#define typeWidth (sizeof(rep_t)*CHAR_BIT)
-#define exponentBits (typeWidth - significandBits - 1)
-#define maxExponent ((1 << exponentBits) - 1)
-#define exponentBias (maxExponent >> 1)
+#if defined(SINGLE_PRECISION) || defined(DOUBLE_PRECISION) || \
+ defined(CRT_LDBL_128BIT)
+#define typeWidth (sizeof(rep_t) * CHAR_BIT)
+#define exponentBits (typeWidth - significandBits - 1)
+#define maxExponent ((1 << exponentBits) - 1)
+#define exponentBias (maxExponent >> 1)
-#define implicitBit (REP_C(1) << significandBits)
+#define implicitBit (REP_C(1) << significandBits)
#define significandMask (implicitBit - 1U)
-#define signBit (REP_C(1) << (significandBits + exponentBits))
-#define absMask (signBit - 1U)
-#define exponentMask (absMask ^ significandMask)
-#define oneRep ((rep_t)exponentBias << significandBits)
-#define infRep exponentMask
-#define quietBit (implicitBit >> 1)
-#define qnanRep (exponentMask | quietBit)
+#define signBit (REP_C(1) << (significandBits + exponentBits))
+#define absMask (signBit - 1U)
+#define exponentMask (absMask ^ significandMask)
+#define oneRep ((rep_t)exponentBias << significandBits)
+#define infRep exponentMask
+#define quietBit (implicitBit >> 1)
+#define qnanRep (exponentMask | quietBit)
static __inline rep_t toRep(fp_t x) {
- const union { fp_t f; rep_t i; } rep = {.f = x};
- return rep.i;
+ const union {
+ fp_t f;
+ rep_t i;
+ } rep = {.f = x};
+ return rep.i;
}
static __inline fp_t fromRep(rep_t x) {
- const union { fp_t f; rep_t i; } rep = {.i = x};
- return rep.f;
+ const union {
+ fp_t f;
+ rep_t i;
+ } rep = {.i = x};
+ return rep.f;
}
static __inline int normalize(rep_t *significand) {
- const int shift = rep_clz(*significand) - rep_clz(implicitBit);
- *significand <<= shift;
- return 1 - shift;
+ const int shift = rep_clz(*significand) - rep_clz(implicitBit);
+ *significand <<= shift;
+ return 1 - shift;
}
static __inline void wideLeftShift(rep_t *hi, rep_t *lo, int count) {
- *hi = *hi << count | *lo >> (typeWidth - count);
- *lo = *lo << count;
+ *hi = *hi << count | *lo >> (typeWidth - count);
+ *lo = *lo << count;
}
-static __inline void wideRightShiftWithSticky(rep_t *hi, rep_t *lo, unsigned int count) {
- if (count < typeWidth) {
- const bool sticky = *lo << (typeWidth - count);
- *lo = *hi << (typeWidth - count) | *lo >> count | sticky;
- *hi = *hi >> count;
- }
- else if (count < 2*typeWidth) {
- const bool sticky = *hi << (2*typeWidth - count) | *lo;
- *lo = *hi >> (count - typeWidth) | sticky;
- *hi = 0;
+static __inline void wideRightShiftWithSticky(rep_t *hi, rep_t *lo,
+ unsigned int count) {
+ if (count < typeWidth) {
+ const bool sticky = (*lo << (typeWidth - count)) != 0;
+ *lo = *hi << (typeWidth - count) | *lo >> count | sticky;
+ *hi = *hi >> count;
+ } else if (count < 2 * typeWidth) {
+ const bool sticky = *hi << (2 * typeWidth - count) | *lo;
+ *lo = *hi >> (count - typeWidth) | sticky;
+ *hi = 0;
+ } else {
+ const bool sticky = *hi | *lo;
+ *lo = sticky;
+ *hi = 0;
+ }
+}
+
+// Implements logb methods (logb, logbf, logbl) for IEEE-754. This avoids
+// pulling in a libm dependency from compiler-rt, but is not meant to replace
+// it (i.e. code calling logb() should get the one from libm, not this), hence
+// the __compiler_rt prefix.
+static __inline fp_t __compiler_rt_logbX(fp_t x) {
+ rep_t rep = toRep(x);
+ int exp = (rep & exponentMask) >> significandBits;
+
+ // Abnormal cases:
+ // 1) +/- inf returns +inf; NaN returns NaN
+ // 2) 0.0 returns -inf
+ if (exp == maxExponent) {
+ if (((rep & signBit) == 0) || (x != x)) {
+ return x; // NaN or +inf: return x
} else {
- const bool sticky = *hi | *lo;
- *lo = sticky;
- *hi = 0;
+ return -x; // -inf: return -x
}
+ } else if (x == 0.0) {
+ // 0.0: return -inf
+ return fromRep(infRep | signBit);
+ }
+
+ if (exp != 0) {
+ // Normal number
+ return exp - exponentBias; // Unbias exponent
+ } else {
+ // Subnormal number; normalize and repeat
+ rep &= absMask;
+ const int shift = 1 - normalize(&rep);
+ exp = (rep & exponentMask) >> significandBits;
+ return exp - exponentBias - shift; // Unbias exponent
+ }
}
+
+// Avoid using scalbn from libm. Unlike libc/libm scalbn, this function never
+// sets errno on underflow/overflow.
+static __inline fp_t __compiler_rt_scalbnX(fp_t x, int y) {
+ const rep_t rep = toRep(x);
+ int exp = (rep & exponentMask) >> significandBits;
+
+ if (x == 0.0 || exp == maxExponent)
+ return x; // +/- 0.0, NaN, or inf: return x
+
+ // Normalize subnormal input.
+ rep_t sig = rep & significandMask;
+ if (exp == 0) {
+ exp += normalize(&sig);
+ sig &= ~implicitBit; // clear the implicit bit again
+ }
+
+ if (__builtin_sadd_overflow(exp, y, &exp)) {
+ // Saturate the exponent, which will guarantee an underflow/overflow below.
+ exp = (y >= 0) ? INT_MAX : INT_MIN;
+ }
+
+ // Return this value: [+/-] 1.sig * 2 ** (exp - exponentBias).
+ const rep_t sign = rep & signBit;
+ if (exp >= maxExponent) {
+ // Overflow, which could produce infinity or the largest-magnitude value,
+ // depending on the rounding mode.
+ return fromRep(sign | ((rep_t)(maxExponent - 1) << significandBits)) * 2.0f;
+ } else if (exp <= 0) {
+ // Subnormal or underflow. Use floating-point multiply to handle truncation
+ // correctly.
+ fp_t tmp = fromRep(sign | (REP_C(1) << significandBits) | sig);
+ exp += exponentBias - 1;
+ if (exp < 1)
+ exp = 1;
+ tmp *= fromRep((rep_t)exp << significandBits);
+ return tmp;
+ } else
+ return fromRep(sign | ((rep_t)exp << significandBits) | sig);
+}
+
+// Avoid using fmax from libm.
+static __inline fp_t __compiler_rt_fmaxX(fp_t x, fp_t y) {
+ // If either argument is NaN, return the other argument. If both are NaN,
+ // arbitrarily return the second one. Otherwise, if both arguments are +/-0,
+ // arbitrarily return the first one.
+ return (crt_isnan(x) || x < y) ? y : x;
+}
+
+#endif
+
+#if defined(SINGLE_PRECISION)
+
+static __inline fp_t __compiler_rt_logbf(fp_t x) {
+ return __compiler_rt_logbX(x);
+}
+static __inline fp_t __compiler_rt_scalbnf(fp_t x, int y) {
+ return __compiler_rt_scalbnX(x, y);
+}
+static __inline fp_t __compiler_rt_fmaxf(fp_t x, fp_t y) {
+#if defined(__aarch64__)
+ // Use __builtin_fmaxf which turns into an fmaxnm instruction on AArch64.
+ return __builtin_fmaxf(x, y);
+#else
+ // __builtin_fmaxf frequently turns into a libm call, so inline the function.
+ return __compiler_rt_fmaxX(x, y);
+#endif
+}
+
+#elif defined(DOUBLE_PRECISION)
+
+static __inline fp_t __compiler_rt_logb(fp_t x) {
+ return __compiler_rt_logbX(x);
+}
+static __inline fp_t __compiler_rt_scalbn(fp_t x, int y) {
+ return __compiler_rt_scalbnX(x, y);
+}
+static __inline fp_t __compiler_rt_fmax(fp_t x, fp_t y) {
+#if defined(__aarch64__)
+ // Use __builtin_fmax which turns into an fmaxnm instruction on AArch64.
+ return __builtin_fmax(x, y);
+#else
+ // __builtin_fmax frequently turns into a libm call, so inline the function.
+ return __compiler_rt_fmaxX(x, y);
#endif
+}
+
+#elif defined(QUAD_PRECISION)
+
+#if defined(CRT_LDBL_128BIT)
+static __inline fp_t __compiler_rt_logbl(fp_t x) {
+ return __compiler_rt_logbX(x);
+}
+static __inline fp_t __compiler_rt_scalbnl(fp_t x, int y) {
+ return __compiler_rt_scalbnX(x, y);
+}
+static __inline fp_t __compiler_rt_fmaxl(fp_t x, fp_t y) {
+ return __compiler_rt_fmaxX(x, y);
+}
+#else
+// The generic implementation only works for ieee754 floating point. For other
+// floating point types, continue to rely on the libm implementation for now.
+static __inline long double __compiler_rt_logbl(long double x) {
+ return crt_logbl(x);
+}
+static __inline long double __compiler_rt_scalbnl(long double x, int y) {
+ return crt_scalbnl(x, y);
+}
+static __inline long double __compiler_rt_fmaxl(long double x, long double y) {
+ return crt_fmaxl(x, y);
+}
+#endif // CRT_LDBL_128BIT
+
+#endif // *_PRECISION
#endif // FP_LIB_HEADER
diff --git a/contrib/libs/cxxsupp/builtins/fp_mode.c b/contrib/libs/cxxsupp/builtins/fp_mode.c
new file mode 100644
index 0000000000..51865473cd
--- /dev/null
+++ b/contrib/libs/cxxsupp/builtins/fp_mode.c
@@ -0,0 +1,22 @@
+//===----- lib/fp_mode.c - Floaing-point environment mode utilities --C -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file provides a default implementation of fp_mode.h for architectures
+// that does not support or does not have an implementation of floating point
+// environment mode.
+//
+//===----------------------------------------------------------------------===//
+
+#include "fp_mode.h"
+
+// IEEE-754 default rounding (to nearest, ties to even).
+CRT_FE_ROUND_MODE __fe_getround(void) { return CRT_FE_TONEAREST; }
+
+int __fe_raise_inexact(void) {
+ return 0;
+}
diff --git a/contrib/libs/cxxsupp/builtins/fp_mode.h b/contrib/libs/cxxsupp/builtins/fp_mode.h
new file mode 100644
index 0000000000..5b4969a441
--- /dev/null
+++ b/contrib/libs/cxxsupp/builtins/fp_mode.h
@@ -0,0 +1,29 @@
+//===----- lib/fp_mode.h - Floaing-point environment mode utilities --C -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is not part of the interface of this library.
+//
+// This file defines an interface for accessing hardware floating point
+// environment mode.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef FP_MODE_H
+#define FP_MODE_H
+
+typedef enum {
+ CRT_FE_TONEAREST,
+ CRT_FE_DOWNWARD,
+ CRT_FE_UPWARD,
+ CRT_FE_TOWARDZERO
+} CRT_FE_ROUND_MODE;
+
+CRT_FE_ROUND_MODE __fe_getround(void);
+int __fe_raise_inexact(void);
+
+#endif // FP_MODE_H
diff --git a/contrib/libs/cxxsupp/builtins/fp_mul_impl.inc b/contrib/libs/cxxsupp/builtins/fp_mul_impl.inc
index b34aa1b8f5..a93f2d78ad 100644
--- a/contrib/libs/cxxsupp/builtins/fp_mul_impl.inc
+++ b/contrib/libs/cxxsupp/builtins/fp_mul_impl.inc
@@ -1,9 +1,8 @@
//===---- lib/fp_mul_impl.inc - floating point multiplication -----*- C -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -15,102 +14,115 @@
#include "fp_lib.h"
static __inline fp_t __mulXf3__(fp_t a, fp_t b) {
- const unsigned int aExponent = toRep(a) >> significandBits & maxExponent;
- const unsigned int bExponent = toRep(b) >> significandBits & maxExponent;
- const rep_t productSign = (toRep(a) ^ toRep(b)) & signBit;
-
- rep_t aSignificand = toRep(a) & significandMask;
- rep_t bSignificand = toRep(b) & significandMask;
- int scale = 0;
-
- // Detect if a or b is zero, denormal, infinity, or NaN.
- if (aExponent-1U >= maxExponent-1U || bExponent-1U >= maxExponent-1U) {
-
- const rep_t aAbs = toRep(a) & absMask;
- const rep_t bAbs = toRep(b) & absMask;
-
- // NaN * anything = qNaN
- if (aAbs > infRep) return fromRep(toRep(a) | quietBit);
- // anything * NaN = qNaN
- if (bAbs > infRep) return fromRep(toRep(b) | quietBit);
-
- if (aAbs == infRep) {
- // infinity * non-zero = +/- infinity
- if (bAbs) return fromRep(aAbs | productSign);
- // infinity * zero = NaN
- else return fromRep(qnanRep);
- }
-
- if (bAbs == infRep) {
- //? non-zero * infinity = +/- infinity
- if (aAbs) return fromRep(bAbs | productSign);
- // zero * infinity = NaN
- else return fromRep(qnanRep);
- }
-
- // zero * anything = +/- zero
- if (!aAbs) return fromRep(productSign);
- // anything * zero = +/- zero
- if (!bAbs) return fromRep(productSign);
-
- // one or both of a or b is denormal, the other (if applicable) is a
- // normal number. Renormalize one or both of a and b, and set scale to
- // include the necessary exponent adjustment.
- if (aAbs < implicitBit) scale += normalize(&aSignificand);
- if (bAbs < implicitBit) scale += normalize(&bSignificand);
+ const unsigned int aExponent = toRep(a) >> significandBits & maxExponent;
+ const unsigned int bExponent = toRep(b) >> significandBits & maxExponent;
+ const rep_t productSign = (toRep(a) ^ toRep(b)) & signBit;
+
+ rep_t aSignificand = toRep(a) & significandMask;
+ rep_t bSignificand = toRep(b) & significandMask;
+ int scale = 0;
+
+ // Detect if a or b is zero, denormal, infinity, or NaN.
+ if (aExponent - 1U >= maxExponent - 1U ||
+ bExponent - 1U >= maxExponent - 1U) {
+
+ const rep_t aAbs = toRep(a) & absMask;
+ const rep_t bAbs = toRep(b) & absMask;
+
+ // NaN * anything = qNaN
+ if (aAbs > infRep)
+ return fromRep(toRep(a) | quietBit);
+ // anything * NaN = qNaN
+ if (bAbs > infRep)
+ return fromRep(toRep(b) | quietBit);
+
+ if (aAbs == infRep) {
+ // infinity * non-zero = +/- infinity
+ if (bAbs)
+ return fromRep(aAbs | productSign);
+ // infinity * zero = NaN
+ else
+ return fromRep(qnanRep);
}
- // Or in the implicit significand bit. (If we fell through from the
- // denormal path it was already set by normalize( ), but setting it twice
- // won't hurt anything.)
- aSignificand |= implicitBit;
- bSignificand |= implicitBit;
-
- // Get the significand of a*b. Before multiplying the significands, shift
- // one of them left to left-align it in the field. Thus, the product will
- // have (exponentBits + 2) integral digits, all but two of which must be
- // zero. Normalizing this result is just a conditional left-shift by one
- // and bumping the exponent accordingly.
- rep_t productHi, productLo;
- wideMultiply(aSignificand, bSignificand << exponentBits,
- &productHi, &productLo);
-
- int productExponent = aExponent + bExponent - exponentBias + scale;
-
- // Normalize the significand, adjust exponent if needed.
- if (productHi & implicitBit) productExponent++;
- else wideLeftShift(&productHi, &productLo, 1);
-
- // If we have overflowed the type, return +/- infinity.
- if (productExponent >= maxExponent) return fromRep(infRep | productSign);
-
- if (productExponent <= 0) {
- // Result is denormal before rounding
- //
- // If the result is so small that it just underflows to zero, return
- // a zero of the appropriate sign. Mathematically there is no need to
- // handle this case separately, but we make it a special case to
- // simplify the shift logic.
- const unsigned int shift = REP_C(1) - (unsigned int)productExponent;
- if (shift >= typeWidth) return fromRep(productSign);
-
- // Otherwise, shift the significand of the result so that the round
- // bit is the high bit of productLo.
- wideRightShiftWithSticky(&productHi, &productLo, shift);
- }
- else {
- // Result is normal before rounding; insert the exponent.
- productHi &= significandMask;
- productHi |= (rep_t)productExponent << significandBits;
+ if (bAbs == infRep) {
+ // non-zero * infinity = +/- infinity
+ if (aAbs)
+ return fromRep(bAbs | productSign);
+ // zero * infinity = NaN
+ else
+ return fromRep(qnanRep);
}
- // Insert the sign of the result:
- productHi |= productSign;
-
- // Final rounding. The final result may overflow to infinity, or underflow
- // to zero, but those are the correct results in those cases. We use the
- // default IEEE-754 round-to-nearest, ties-to-even rounding mode.
- if (productLo > signBit) productHi++;
- if (productLo == signBit) productHi += productHi & 1;
- return fromRep(productHi);
+ // zero * anything = +/- zero
+ if (!aAbs)
+ return fromRep(productSign);
+ // anything * zero = +/- zero
+ if (!bAbs)
+ return fromRep(productSign);
+
+ // One or both of a or b is denormal. The other (if applicable) is a
+ // normal number. Renormalize one or both of a and b, and set scale to
+ // include the necessary exponent adjustment.
+ if (aAbs < implicitBit)
+ scale += normalize(&aSignificand);
+ if (bAbs < implicitBit)
+ scale += normalize(&bSignificand);
+ }
+
+ // Set the implicit significand bit. If we fell through from the
+ // denormal path it was already set by normalize( ), but setting it twice
+ // won't hurt anything.
+ aSignificand |= implicitBit;
+ bSignificand |= implicitBit;
+
+ // Perform a basic multiplication on the significands. One of them must be
+ // shifted beforehand to be aligned with the exponent.
+ rep_t productHi, productLo;
+ wideMultiply(aSignificand, bSignificand << exponentBits, &productHi,
+ &productLo);
+
+ int productExponent = aExponent + bExponent - exponentBias + scale;
+
+ // Normalize the significand and adjust the exponent if needed.
+ if (productHi & implicitBit)
+ productExponent++;
+ else
+ wideLeftShift(&productHi, &productLo, 1);
+
+ // If we have overflowed the type, return +/- infinity.
+ if (productExponent >= maxExponent)
+ return fromRep(infRep | productSign);
+
+ if (productExponent <= 0) {
+ // The result is denormal before rounding.
+ //
+ // If the result is so small that it just underflows to zero, return
+ // zero with the appropriate sign. Mathematically, there is no need to
+ // handle this case separately, but we make it a special case to
+ // simplify the shift logic.
+ const unsigned int shift = REP_C(1) - (unsigned int)productExponent;
+ if (shift >= typeWidth)
+ return fromRep(productSign);
+
+ // Otherwise, shift the significand of the result so that the round
+ // bit is the high bit of productLo.
+ wideRightShiftWithSticky(&productHi, &productLo, shift);
+ } else {
+ // The result is normal before rounding. Insert the exponent.
+ productHi &= significandMask;
+ productHi |= (rep_t)productExponent << significandBits;
+ }
+
+ // Insert the sign of the result.
+ productHi |= productSign;
+
+ // Perform the final rounding. The final result may overflow to infinity,
+ // or underflow to zero, but those are the correct results in those cases.
+ // We use the default IEEE-754 round-to-nearest, ties-to-even rounding mode.
+ if (productLo > signBit)
+ productHi++;
+ if (productLo == signBit)
+ productHi += productHi & 1;
+ return fromRep(productHi);
}
diff --git a/contrib/libs/cxxsupp/builtins/fp_trunc.h b/contrib/libs/cxxsupp/builtins/fp_trunc.h
index d5e79bb5b8..91f614528a 100644
--- a/contrib/libs/cxxsupp/builtins/fp_trunc.h
+++ b/contrib/libs/cxxsupp/builtins/fp_trunc.h
@@ -1,9 +1,8 @@
//=== lib/fp_trunc.h - high precision -> low precision conversion *- C -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -36,7 +35,7 @@ static const int srcSigBits = 112;
#else
#error Source should be double precision or quad precision!
-#endif //end source precision
+#endif // end source precision
#if defined DST_DOUBLE
typedef double dst_t;
@@ -51,26 +50,42 @@ typedef uint32_t dst_rep_t;
static const int dstSigBits = 23;
#elif defined DST_HALF
+#ifdef COMPILER_RT_HAS_FLOAT16
+typedef _Float16 dst_t;
+#else
typedef uint16_t dst_t;
+#endif
typedef uint16_t dst_rep_t;
#define DST_REP_C UINT16_C
static const int dstSigBits = 10;
+#elif defined DST_BFLOAT
+typedef __bf16 dst_t;
+typedef uint16_t dst_rep_t;
+#define DST_REP_C UINT16_C
+static const int dstSigBits = 7;
+
#else
#error Destination should be single precision or double precision!
-#endif //end destination precision
+#endif // end destination precision
// End of specialization parameters. Two helper routines for conversion to and
// from the representation of floating-point data as integer values follow.
static __inline src_rep_t srcToRep(src_t x) {
- const union { src_t f; src_rep_t i; } rep = {.f = x};
- return rep.i;
+ const union {
+ src_t f;
+ src_rep_t i;
+ } rep = {.f = x};
+ return rep.i;
}
static __inline dst_t dstFromRep(dst_rep_t x) {
- const union { dst_t f; dst_rep_t i; } rep = {.i = x};
- return rep.f;
+ const union {
+ dst_t f;
+ dst_rep_t i;
+ } rep = {.i = x};
+ return rep.f;
}
#endif // FP_TRUNC_HEADER
diff --git a/contrib/libs/cxxsupp/builtins/fp_trunc_impl.inc b/contrib/libs/cxxsupp/builtins/fp_trunc_impl.inc
index d88ae06091..6662be7607 100644
--- a/contrib/libs/cxxsupp/builtins/fp_trunc_impl.inc
+++ b/contrib/libs/cxxsupp/builtins/fp_trunc_impl.inc
@@ -1,9 +1,8 @@
//= lib/fp_trunc_impl.inc - high precision -> low precision conversion *-*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -29,107 +28,105 @@
//
// Finally, the following assumptions are made:
//
-// 1. floating-point types and integer types have the same endianness on the
-// target platform
+// 1. Floating-point types and integer types have the same endianness on the
+// target platform.
//
-// 2. quiet NaNs, if supported, are indicated by the leading bit of the
-// significand field being set
+// 2. Quiet NaNs, if supported, are indicated by the leading bit of the
+// significand field being set.
//
//===----------------------------------------------------------------------===//
#include "fp_trunc.h"
static __inline dst_t __truncXfYf2__(src_t a) {
- // Various constants whose values follow from the type parameters.
- // Any reasonable optimizer will fold and propagate all of these.
- const int srcBits = sizeof(src_t)*CHAR_BIT;
- const int srcExpBits = srcBits - srcSigBits - 1;
- const int srcInfExp = (1 << srcExpBits) - 1;
- const int srcExpBias = srcInfExp >> 1;
+ // Various constants whose values follow from the type parameters.
+ // Any reasonable optimizer will fold and propagate all of these.
+ const int srcBits = sizeof(src_t) * CHAR_BIT;
+ const int srcExpBits = srcBits - srcSigBits - 1;
+ const int srcInfExp = (1 << srcExpBits) - 1;
+ const int srcExpBias = srcInfExp >> 1;
- const src_rep_t srcMinNormal = SRC_REP_C(1) << srcSigBits;
- const src_rep_t srcSignificandMask = srcMinNormal - 1;
- const src_rep_t srcInfinity = (src_rep_t)srcInfExp << srcSigBits;
- const src_rep_t srcSignMask = SRC_REP_C(1) << (srcSigBits + srcExpBits);
- const src_rep_t srcAbsMask = srcSignMask - 1;
- const src_rep_t roundMask = (SRC_REP_C(1) << (srcSigBits - dstSigBits)) - 1;
- const src_rep_t halfway = SRC_REP_C(1) << (srcSigBits - dstSigBits - 1);
- const src_rep_t srcQNaN = SRC_REP_C(1) << (srcSigBits - 1);
- const src_rep_t srcNaNCode = srcQNaN - 1;
+ const src_rep_t srcMinNormal = SRC_REP_C(1) << srcSigBits;
+ const src_rep_t srcSignificandMask = srcMinNormal - 1;
+ const src_rep_t srcInfinity = (src_rep_t)srcInfExp << srcSigBits;
+ const src_rep_t srcSignMask = SRC_REP_C(1) << (srcSigBits + srcExpBits);
+ const src_rep_t srcAbsMask = srcSignMask - 1;
+ const src_rep_t roundMask = (SRC_REP_C(1) << (srcSigBits - dstSigBits)) - 1;
+ const src_rep_t halfway = SRC_REP_C(1) << (srcSigBits - dstSigBits - 1);
+ const src_rep_t srcQNaN = SRC_REP_C(1) << (srcSigBits - 1);
+ const src_rep_t srcNaNCode = srcQNaN - 1;
- const int dstBits = sizeof(dst_t)*CHAR_BIT;
- const int dstExpBits = dstBits - dstSigBits - 1;
- const int dstInfExp = (1 << dstExpBits) - 1;
- const int dstExpBias = dstInfExp >> 1;
+ const int dstBits = sizeof(dst_t) * CHAR_BIT;
+ const int dstExpBits = dstBits - dstSigBits - 1;
+ const int dstInfExp = (1 << dstExpBits) - 1;
+ const int dstExpBias = dstInfExp >> 1;
- const int underflowExponent = srcExpBias + 1 - dstExpBias;
- const int overflowExponent = srcExpBias + dstInfExp - dstExpBias;
- const src_rep_t underflow = (src_rep_t)underflowExponent << srcSigBits;
- const src_rep_t overflow = (src_rep_t)overflowExponent << srcSigBits;
+ const int underflowExponent = srcExpBias + 1 - dstExpBias;
+ const int overflowExponent = srcExpBias + dstInfExp - dstExpBias;
+ const src_rep_t underflow = (src_rep_t)underflowExponent << srcSigBits;
+ const src_rep_t overflow = (src_rep_t)overflowExponent << srcSigBits;
- const dst_rep_t dstQNaN = DST_REP_C(1) << (dstSigBits - 1);
- const dst_rep_t dstNaNCode = dstQNaN - 1;
+ const dst_rep_t dstQNaN = DST_REP_C(1) << (dstSigBits - 1);
+ const dst_rep_t dstNaNCode = dstQNaN - 1;
- // Break a into a sign and representation of the absolute value
- const src_rep_t aRep = srcToRep(a);
- const src_rep_t aAbs = aRep & srcAbsMask;
- const src_rep_t sign = aRep & srcSignMask;
- dst_rep_t absResult;
+ // Break a into a sign and representation of the absolute value.
+ const src_rep_t aRep = srcToRep(a);
+ const src_rep_t aAbs = aRep & srcAbsMask;
+ const src_rep_t sign = aRep & srcSignMask;
+ dst_rep_t absResult;
- if (aAbs - underflow < aAbs - overflow) {
- // The exponent of a is within the range of normal numbers in the
- // destination format. We can convert by simply right-shifting with
- // rounding and adjusting the exponent.
- absResult = aAbs >> (srcSigBits - dstSigBits);
- absResult -= (dst_rep_t)(srcExpBias - dstExpBias) << dstSigBits;
+ if (aAbs - underflow < aAbs - overflow) {
+ // The exponent of a is within the range of normal numbers in the
+ // destination format. We can convert by simply right-shifting with
+ // rounding and adjusting the exponent.
+ absResult = aAbs >> (srcSigBits - dstSigBits);
+ absResult -= (dst_rep_t)(srcExpBias - dstExpBias) << dstSigBits;
- const src_rep_t roundBits = aAbs & roundMask;
- // Round to nearest
- if (roundBits > halfway)
- absResult++;
- // Ties to even
- else if (roundBits == halfway)
- absResult += absResult & 1;
- }
- else if (aAbs > srcInfinity) {
- // a is NaN.
- // Conjure the result by beginning with infinity, setting the qNaN
- // bit and inserting the (truncated) trailing NaN field.
- absResult = (dst_rep_t)dstInfExp << dstSigBits;
- absResult |= dstQNaN;
- absResult |= ((aAbs & srcNaNCode) >> (srcSigBits - dstSigBits)) & dstNaNCode;
- }
- else if (aAbs >= overflow) {
- // a overflows to infinity.
- absResult = (dst_rep_t)dstInfExp << dstSigBits;
- }
- else {
- // a underflows on conversion to the destination type or is an exact
- // zero. The result may be a denormal or zero. Extract the exponent
- // to get the shift amount for the denormalization.
- const int aExp = aAbs >> srcSigBits;
- const int shift = srcExpBias - dstExpBias - aExp + 1;
+ const src_rep_t roundBits = aAbs & roundMask;
+ // Round to nearest.
+ if (roundBits > halfway)
+ absResult++;
+ // Tie to even.
+ else if (roundBits == halfway)
+ absResult += absResult & 1;
+ } else if (aAbs > srcInfinity) {
+ // a is NaN.
+ // Conjure the result by beginning with infinity, setting the qNaN
+ // bit and inserting the (truncated) trailing NaN field.
+ absResult = (dst_rep_t)dstInfExp << dstSigBits;
+ absResult |= dstQNaN;
+ absResult |=
+ ((aAbs & srcNaNCode) >> (srcSigBits - dstSigBits)) & dstNaNCode;
+ } else if (aAbs >= overflow) {
+ // a overflows to infinity.
+ absResult = (dst_rep_t)dstInfExp << dstSigBits;
+ } else {
+ // a underflows on conversion to the destination type or is an exact
+ // zero. The result may be a denormal or zero. Extract the exponent
+ // to get the shift amount for the denormalization.
+ const int aExp = aAbs >> srcSigBits;
+ const int shift = srcExpBias - dstExpBias - aExp + 1;
- const src_rep_t significand = (aRep & srcSignificandMask) | srcMinNormal;
+ const src_rep_t significand = (aRep & srcSignificandMask) | srcMinNormal;
- // Right shift by the denormalization amount with sticky.
- if (shift > srcSigBits) {
- absResult = 0;
- } else {
- const bool sticky = significand << (srcBits - shift);
- src_rep_t denormalizedSignificand = significand >> shift | sticky;
- absResult = denormalizedSignificand >> (srcSigBits - dstSigBits);
- const src_rep_t roundBits = denormalizedSignificand & roundMask;
- // Round to nearest
- if (roundBits > halfway)
- absResult++;
- // Ties to even
- else if (roundBits == halfway)
- absResult += absResult & 1;
- }
+ // Right shift by the denormalization amount with sticky.
+ if (shift > srcSigBits) {
+ absResult = 0;
+ } else {
+ const bool sticky = (significand << (srcBits - shift)) != 0;
+ src_rep_t denormalizedSignificand = significand >> shift | sticky;
+ absResult = denormalizedSignificand >> (srcSigBits - dstSigBits);
+ const src_rep_t roundBits = denormalizedSignificand & roundMask;
+ // Round to nearest
+ if (roundBits > halfway)
+ absResult++;
+ // Ties to even
+ else if (roundBits == halfway)
+ absResult += absResult & 1;
}
+ }
- // Apply the signbit to (dst_t)abs(a).
- const dst_rep_t result = absResult | sign >> (srcBits - dstBits);
- return dstFromRep(result);
+ // Apply the signbit to the absolute value.
+ const dst_rep_t result = absResult | sign >> (srcBits - dstBits);
+ return dstFromRep(result);
}
diff --git a/contrib/libs/cxxsupp/builtins/gcc_personality_v0.c b/contrib/libs/cxxsupp/builtins/gcc_personality_v0.c
index 331dc2bea2..58fd7ceb58 100644
--- a/contrib/libs/cxxsupp/builtins/gcc_personality_v0.c
+++ b/contrib/libs/cxxsupp/builtins/gcc_personality_v0.c
@@ -1,209 +1,257 @@
-/* ===-- gcc_personality_v0.c - Implement __gcc_personality_v0 -------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- */
+//===-- gcc_personality_v0.c - Implement __gcc_personality_v0 -------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
+#include <stddef.h>
#include <unwind.h>
+#if defined(__arm__) && !defined(__ARM_DWARF_EH__) && \
+ !defined(__USING_SJLJ_EXCEPTIONS__)
+// When building with older compilers (e.g. clang <3.9), it is possible that we
+// have a version of unwind.h which does not provide the EHABI declarations
+// which are quired for the C personality to conform to the specification. In
+// order to provide forward compatibility for such compilers, we re-declare the
+// necessary interfaces in the helper to permit a standalone compilation of the
+// builtins (which contains the C unwinding personality for historical reasons).
+#include "unwind-ehabi-helpers.h"
+#endif
-/*
- * Pointer encodings documented at:
- * http://refspecs.freestandards.org/LSB_1.3.0/gLSB/gLSB/ehframehdr.html
- */
+#if defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__)
+#include <windows.h>
+#include <winnt.h>
-#define DW_EH_PE_omit 0xff /* no data follows */
+EXCEPTION_DISPOSITION _GCC_specific_handler(PEXCEPTION_RECORD, void *, PCONTEXT,
+ PDISPATCHER_CONTEXT,
+ _Unwind_Personality_Fn);
+#endif
-#define DW_EH_PE_absptr 0x00
-#define DW_EH_PE_uleb128 0x01
-#define DW_EH_PE_udata2 0x02
-#define DW_EH_PE_udata4 0x03
-#define DW_EH_PE_udata8 0x04
-#define DW_EH_PE_sleb128 0x09
-#define DW_EH_PE_sdata2 0x0A
-#define DW_EH_PE_sdata4 0x0B
-#define DW_EH_PE_sdata8 0x0C
+// Pointer encodings documented at:
+// http://refspecs.freestandards.org/LSB_1.3.0/gLSB/gLSB/ehframehdr.html
-#define DW_EH_PE_pcrel 0x10
-#define DW_EH_PE_textrel 0x20
-#define DW_EH_PE_datarel 0x30
-#define DW_EH_PE_funcrel 0x40
-#define DW_EH_PE_aligned 0x50
-#define DW_EH_PE_indirect 0x80 /* gcc extension */
+#define DW_EH_PE_omit 0xff // no data follows
+#define DW_EH_PE_absptr 0x00
+#define DW_EH_PE_uleb128 0x01
+#define DW_EH_PE_udata2 0x02
+#define DW_EH_PE_udata4 0x03
+#define DW_EH_PE_udata8 0x04
+#define DW_EH_PE_sleb128 0x09
+#define DW_EH_PE_sdata2 0x0A
+#define DW_EH_PE_sdata4 0x0B
+#define DW_EH_PE_sdata8 0x0C
+#define DW_EH_PE_pcrel 0x10
+#define DW_EH_PE_textrel 0x20
+#define DW_EH_PE_datarel 0x30
+#define DW_EH_PE_funcrel 0x40
+#define DW_EH_PE_aligned 0x50
+#define DW_EH_PE_indirect 0x80 // gcc extension
-/* read a uleb128 encoded value and advance pointer */
-static uintptr_t readULEB128(const uint8_t** data)
-{
- uintptr_t result = 0;
- uintptr_t shift = 0;
- unsigned char byte;
- const uint8_t* p = *data;
- do {
- byte = *p++;
- result |= (byte & 0x7f) << shift;
- shift += 7;
- } while (byte & 0x80);
- *data = p;
- return result;
+// read a uleb128 encoded value and advance pointer
+static size_t readULEB128(const uint8_t **data) {
+ size_t result = 0;
+ size_t shift = 0;
+ unsigned char byte;
+ const uint8_t *p = *data;
+ do {
+ byte = *p++;
+ result |= (byte & 0x7f) << shift;
+ shift += 7;
+ } while (byte & 0x80);
+ *data = p;
+ return result;
}
-/* read a pointer encoded value and advance pointer */
-static uintptr_t readEncodedPointer(const uint8_t** data, uint8_t encoding)
-{
- const uint8_t* p = *data;
- uintptr_t result = 0;
-
- if ( encoding == DW_EH_PE_omit )
- return 0;
-
- /* first get value */
- switch (encoding & 0x0F) {
- case DW_EH_PE_absptr:
- result = *((const uintptr_t*)p);
- p += sizeof(uintptr_t);
- break;
- case DW_EH_PE_uleb128:
- result = readULEB128(&p);
- break;
- case DW_EH_PE_udata2:
- result = *((const uint16_t*)p);
- p += sizeof(uint16_t);
- break;
- case DW_EH_PE_udata4:
- result = *((const uint32_t*)p);
- p += sizeof(uint32_t);
- break;
- case DW_EH_PE_udata8:
- result = *((const uint64_t*)p);
- p += sizeof(uint64_t);
- break;
- case DW_EH_PE_sdata2:
- result = *((const int16_t*)p);
- p += sizeof(int16_t);
- break;
- case DW_EH_PE_sdata4:
- result = *((const int32_t*)p);
- p += sizeof(int32_t);
- break;
- case DW_EH_PE_sdata8:
- result = *((const int64_t*)p);
- p += sizeof(int64_t);
- break;
- case DW_EH_PE_sleb128:
- default:
- /* not supported */
- compilerrt_abort();
- break;
- }
+// read a pointer encoded value and advance pointer
+static uintptr_t readEncodedPointer(const uint8_t **data, uint8_t encoding) {
+ const uint8_t *p = *data;
+ uintptr_t result = 0;
- /* then add relative offset */
- switch ( encoding & 0x70 ) {
- case DW_EH_PE_absptr:
- /* do nothing */
- break;
- case DW_EH_PE_pcrel:
- result += (uintptr_t)(*data);
- break;
- case DW_EH_PE_textrel:
- case DW_EH_PE_datarel:
- case DW_EH_PE_funcrel:
- case DW_EH_PE_aligned:
- default:
- /* not supported */
- compilerrt_abort();
- break;
- }
+ if (encoding == DW_EH_PE_omit)
+ return 0;
- /* then apply indirection */
- if (encoding & DW_EH_PE_indirect) {
- result = *((const uintptr_t*)result);
- }
+ // first get value
+ switch (encoding & 0x0F) {
+ case DW_EH_PE_absptr:
+ result = *((const uintptr_t *)p);
+ p += sizeof(uintptr_t);
+ break;
+ case DW_EH_PE_uleb128:
+ result = readULEB128(&p);
+ break;
+ case DW_EH_PE_udata2:
+ result = *((const uint16_t *)p);
+ p += sizeof(uint16_t);
+ break;
+ case DW_EH_PE_udata4:
+ result = *((const uint32_t *)p);
+ p += sizeof(uint32_t);
+ break;
+ case DW_EH_PE_udata8:
+ result = *((const uint64_t *)p);
+ p += sizeof(uint64_t);
+ break;
+ case DW_EH_PE_sdata2:
+ result = *((const int16_t *)p);
+ p += sizeof(int16_t);
+ break;
+ case DW_EH_PE_sdata4:
+ result = *((const int32_t *)p);
+ p += sizeof(int32_t);
+ break;
+ case DW_EH_PE_sdata8:
+ result = *((const int64_t *)p);
+ p += sizeof(int64_t);
+ break;
+ case DW_EH_PE_sleb128:
+ default:
+ // not supported
+ compilerrt_abort();
+ break;
+ }
+
+ // then add relative offset
+ switch (encoding & 0x70) {
+ case DW_EH_PE_absptr:
+ // do nothing
+ break;
+ case DW_EH_PE_pcrel:
+ result += (uintptr_t)(*data);
+ break;
+ case DW_EH_PE_textrel:
+ case DW_EH_PE_datarel:
+ case DW_EH_PE_funcrel:
+ case DW_EH_PE_aligned:
+ default:
+ // not supported
+ compilerrt_abort();
+ break;
+ }
+
+ // then apply indirection
+ if (encoding & DW_EH_PE_indirect) {
+ result = *((const uintptr_t *)result);
+ }
- *data = p;
- return result;
+ *data = p;
+ return result;
}
+#if defined(__arm__) && !defined(__USING_SJLJ_EXCEPTIONS__) && \
+ !defined(__ARM_DWARF_EH__) && !defined(__SEH__)
+#define USING_ARM_EHABI 1
+_Unwind_Reason_Code __gnu_unwind_frame(struct _Unwind_Exception *,
+ struct _Unwind_Context *);
+#endif
+
+static inline _Unwind_Reason_Code
+continueUnwind(struct _Unwind_Exception *exceptionObject,
+ struct _Unwind_Context *context) {
+#if USING_ARM_EHABI
+ // On ARM EHABI the personality routine is responsible for actually
+ // unwinding a single stack frame before returning (ARM EHABI Sec. 6.1).
+ if (__gnu_unwind_frame(exceptionObject, context) != _URC_OK)
+ return _URC_FAILURE;
+#endif
+ return _URC_CONTINUE_UNWIND;
+}
-/*
- * The C compiler makes references to __gcc_personality_v0 in
- * the dwarf unwind information for translation units that use
- * __attribute__((cleanup(xx))) on local variables.
- * This personality routine is called by the system unwinder
- * on each frame as the stack is unwound during a C++ exception
- * throw through a C function compiled with -fexceptions.
- */
+// The C compiler makes references to __gcc_personality_v0 in
+// the dwarf unwind information for translation units that use
+// __attribute__((cleanup(xx))) on local variables.
+// This personality routine is called by the system unwinder
+// on each frame as the stack is unwound during a C++ exception
+// throw through a C function compiled with -fexceptions.
#if __USING_SJLJ_EXCEPTIONS__
-// the setjump-longjump based exceptions personality routine has a different name
-COMPILER_RT_ABI _Unwind_Reason_Code
-__gcc_personality_sj0(int version, _Unwind_Action actions,
- uint64_t exceptionClass, struct _Unwind_Exception* exceptionObject,
- struct _Unwind_Context *context)
+// the setjump-longjump based exceptions personality routine has a
+// different name
+COMPILER_RT_ABI _Unwind_Reason_Code __gcc_personality_sj0(
+ int version, _Unwind_Action actions, uint64_t exceptionClass,
+ struct _Unwind_Exception *exceptionObject, struct _Unwind_Context *context)
+#elif USING_ARM_EHABI
+// The ARM EHABI personality routine has a different signature.
+COMPILER_RT_ABI _Unwind_Reason_Code __gcc_personality_v0(
+ _Unwind_State state, struct _Unwind_Exception *exceptionObject,
+ struct _Unwind_Context *context)
+#elif defined(__SEH__)
+static _Unwind_Reason_Code __gcc_personality_imp(
+ int version, _Unwind_Action actions, uint64_t exceptionClass,
+ struct _Unwind_Exception *exceptionObject, struct _Unwind_Context *context)
#else
-COMPILER_RT_ABI _Unwind_Reason_Code
-__gcc_personality_v0(int version, _Unwind_Action actions,
- uint64_t exceptionClass, struct _Unwind_Exception* exceptionObject,
- struct _Unwind_Context *context)
+COMPILER_RT_ABI _Unwind_Reason_Code __gcc_personality_v0(
+ int version, _Unwind_Action actions, uint64_t exceptionClass,
+ struct _Unwind_Exception *exceptionObject, struct _Unwind_Context *context)
#endif
{
- /* Since C does not have catch clauses, there is nothing to do during */
- /* phase 1 (the search phase). */
- if ( actions & _UA_SEARCH_PHASE )
- return _URC_CONTINUE_UNWIND;
-
- /* There is nothing to do if there is no LSDA for this frame. */
- const uint8_t* lsda = (uint8_t*)_Unwind_GetLanguageSpecificData(context);
- if ( lsda == (uint8_t*) 0 )
- return _URC_CONTINUE_UNWIND;
-
- uintptr_t pc = _Unwind_GetIP(context)-1;
- uintptr_t funcStart = _Unwind_GetRegionStart(context);
- uintptr_t pcOffset = pc - funcStart;
-
- /* Parse LSDA header. */
- uint8_t lpStartEncoding = *lsda++;
- if (lpStartEncoding != DW_EH_PE_omit) {
- readEncodedPointer(&lsda, lpStartEncoding);
- }
- uint8_t ttypeEncoding = *lsda++;
- if (ttypeEncoding != DW_EH_PE_omit) {
- readULEB128(&lsda);
- }
- /* Walk call-site table looking for range that includes current PC. */
- uint8_t callSiteEncoding = *lsda++;
- uint32_t callSiteTableLength = readULEB128(&lsda);
- const uint8_t* callSiteTableStart = lsda;
- const uint8_t* callSiteTableEnd = callSiteTableStart + callSiteTableLength;
- const uint8_t* p=callSiteTableStart;
- while (p < callSiteTableEnd) {
- uintptr_t start = readEncodedPointer(&p, callSiteEncoding);
- uintptr_t length = readEncodedPointer(&p, callSiteEncoding);
- uintptr_t landingPad = readEncodedPointer(&p, callSiteEncoding);
- readULEB128(&p); /* action value not used for C code */
- if ( landingPad == 0 )
- continue; /* no landing pad for this entry */
- if ( (start <= pcOffset) && (pcOffset < (start+length)) ) {
- /* Found landing pad for the PC.
- * Set Instruction Pointer to so we re-enter function
- * at landing pad. The landing pad is created by the compiler
- * to take two parameters in registers.
- */
- _Unwind_SetGR(context, __builtin_eh_return_data_regno(0),
- (uintptr_t)exceptionObject);
- _Unwind_SetGR(context, __builtin_eh_return_data_regno(1), 0);
- _Unwind_SetIP(context, (funcStart + landingPad));
- return _URC_INSTALL_CONTEXT;
- }
+ // Since C does not have catch clauses, there is nothing to do during
+ // phase 1 (the search phase).
+#if USING_ARM_EHABI
+ // After resuming from a cleanup we should also continue on to the next
+ // frame straight away.
+ if ((state & _US_ACTION_MASK) != _US_UNWIND_FRAME_STARTING)
+#else
+ if (actions & _UA_SEARCH_PHASE)
+#endif
+ return continueUnwind(exceptionObject, context);
+
+ // There is nothing to do if there is no LSDA for this frame.
+ const uint8_t *lsda = (uint8_t *)_Unwind_GetLanguageSpecificData(context);
+ if (lsda == (uint8_t *)0)
+ return continueUnwind(exceptionObject, context);
+
+ uintptr_t pc = (uintptr_t)_Unwind_GetIP(context) - 1;
+ uintptr_t funcStart = (uintptr_t)_Unwind_GetRegionStart(context);
+ uintptr_t pcOffset = pc - funcStart;
+
+ // Parse LSDA header.
+ uint8_t lpStartEncoding = *lsda++;
+ if (lpStartEncoding != DW_EH_PE_omit) {
+ readEncodedPointer(&lsda, lpStartEncoding);
+ }
+ uint8_t ttypeEncoding = *lsda++;
+ if (ttypeEncoding != DW_EH_PE_omit) {
+ readULEB128(&lsda);
+ }
+ // Walk call-site table looking for range that includes current PC.
+ uint8_t callSiteEncoding = *lsda++;
+ uint32_t callSiteTableLength = readULEB128(&lsda);
+ const uint8_t *callSiteTableStart = lsda;
+ const uint8_t *callSiteTableEnd = callSiteTableStart + callSiteTableLength;
+ const uint8_t *p = callSiteTableStart;
+ while (p < callSiteTableEnd) {
+ uintptr_t start = readEncodedPointer(&p, callSiteEncoding);
+ size_t length = readEncodedPointer(&p, callSiteEncoding);
+ size_t landingPad = readEncodedPointer(&p, callSiteEncoding);
+ readULEB128(&p); // action value not used for C code
+ if (landingPad == 0)
+ continue; // no landing pad for this entry
+ if ((start <= pcOffset) && (pcOffset < (start + length))) {
+ // Found landing pad for the PC.
+ // Set Instruction Pointer to so we re-enter function
+ // at landing pad. The landing pad is created by the compiler
+ // to take two parameters in registers.
+ _Unwind_SetGR(context, __builtin_eh_return_data_regno(0),
+ (uintptr_t)exceptionObject);
+ _Unwind_SetGR(context, __builtin_eh_return_data_regno(1), 0);
+ _Unwind_SetIP(context, (funcStart + landingPad));
+ return _URC_INSTALL_CONTEXT;
}
+ }
- /* No landing pad found, continue unwinding. */
- return _URC_CONTINUE_UNWIND;
+ // No landing pad found, continue unwinding.
+ return continueUnwind(exceptionObject, context);
}
+#if defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__)
+COMPILER_RT_ABI EXCEPTION_DISPOSITION
+__gcc_personality_seh0(PEXCEPTION_RECORD ms_exc, void *this_frame,
+ PCONTEXT ms_orig_context, PDISPATCHER_CONTEXT ms_disp) {
+ return _GCC_specific_handler(ms_exc, this_frame, ms_orig_context, ms_disp,
+ __gcc_personality_imp);
+}
+#endif
diff --git a/contrib/libs/cxxsupp/builtins/hexagon/common_entry_exit_abi1.S b/contrib/libs/cxxsupp/builtins/hexagon/common_entry_exit_abi1.S
new file mode 100644
index 0000000000..23fed01c6e
--- /dev/null
+++ b/contrib/libs/cxxsupp/builtins/hexagon/common_entry_exit_abi1.S
@@ -0,0 +1,102 @@
+//===----------------------Hexagon builtin routine ------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// Functions that implement common sequences in function prologues and epilogues
+// used to save code size
+
+ .macro FUNCTION_BEGIN name
+ .text
+ .globl \name
+ .type \name, @function
+ .falign
+\name:
+ .endm
+
+ .macro FUNCTION_END name
+ .size \name, . - \name
+ .endm
+
+ .macro FALLTHROUGH_TAIL_CALL name0 name1
+ .size \name0, . - \name0
+ .globl \name1
+ .type \name1, @function
+ .falign
+\name1:
+ .endm
+
+
+
+
+// Save r25:24 at fp+#-8 and r27:26 at fp+#-16.
+
+
+
+
+// The compiler knows that the __save_* functions clobber LR. No other
+// registers should be used without informing the compiler.
+
+// Since we can only issue one store per packet, we don't hurt performance by
+// simply jumping to the right point in this sequence of stores.
+
+FUNCTION_BEGIN __save_r24_through_r27
+ memd(fp+#-16) = r27:26
+FALLTHROUGH_TAIL_CALL __save_r24_through_r27 __save_r24_through_r25
+ {
+ memd(fp+#-8) = r25:24
+ jumpr lr
+ }
+FUNCTION_END __save_r24_through_r25
+
+
+
+
+// For each of the *_before_tailcall functions, jumpr lr is executed in parallel
+// with deallocframe. That way, the return gets the old value of lr, which is
+// where these functions need to return, and at the same time, lr gets the value
+// it needs going into the tail call.
+
+FUNCTION_BEGIN __restore_r24_through_r27_and_deallocframe_before_tailcall
+ r27:26 = memd(fp+#-16)
+FALLTHROUGH_TAIL_CALL __restore_r24_through_r27_and_deallocframe_before_tailcall __restore_r24_through_r25_and_deallocframe_before_tailcall
+ {
+ r25:24 = memd(fp+#-8)
+ deallocframe
+ jumpr lr
+ }
+FUNCTION_END __restore_r24_through_r25_and_deallocframe_before_tailcall
+
+
+
+
+// Here we use the extra load bandwidth to restore LR early, allowing the return
+// to occur in parallel with the deallocframe.
+
+FUNCTION_BEGIN __restore_r24_through_r27_and_deallocframe
+ {
+ lr = memw(fp+#4)
+ r27:26 = memd(fp+#-16)
+ }
+ {
+ r25:24 = memd(fp+#-8)
+ deallocframe
+ jumpr lr
+ }
+FUNCTION_END __restore_r24_through_r27_and_deallocframe
+
+
+
+
+// Here the load bandwidth is maximized.
+
+FUNCTION_BEGIN __restore_r24_through_r25_and_deallocframe
+ {
+ r25:24 = memd(fp+#-8)
+ deallocframe
+ }
+ jumpr lr
+FUNCTION_END __restore_r24_through_r25_and_deallocframe
diff --git a/contrib/libs/cxxsupp/builtins/hexagon/common_entry_exit_abi2.S b/contrib/libs/cxxsupp/builtins/hexagon/common_entry_exit_abi2.S
new file mode 100644
index 0000000000..3b85aea2f6
--- /dev/null
+++ b/contrib/libs/cxxsupp/builtins/hexagon/common_entry_exit_abi2.S
@@ -0,0 +1,267 @@
+//===----------------------Hexagon builtin routine ------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// Functions that implement common sequences in function prologues and epilogues
+// used to save code size
+
+ .macro FUNCTION_BEGIN name
+ .p2align 2
+ .section .text.\name,"ax",@progbits
+ .globl \name
+ .type \name, @function
+\name:
+ .endm
+
+ .macro FUNCTION_END name
+ .size \name, . - \name
+ .endm
+
+ .macro FALLTHROUGH_TAIL_CALL name0 name1
+ .p2align 2
+ .size \name0, . - \name0
+ .globl \name1
+ .type \name1, @function
+\name1:
+ .endm
+
+
+
+
+// Save r17:16 at fp+#-8, r19:18 at fp+#-16, r21:20 at fp+#-24, r23:22 at
+// fp+#-32, r25:24 at fp+#-40, and r27:26 at fp+#-48.
+// The compiler knows that the __save_* functions clobber LR. No other
+// registers should be used without informing the compiler.
+
+FUNCTION_BEGIN __save_r16_through_r27
+ {
+ memd(fp+#-48) = r27:26
+ memd(fp+#-40) = r25:24
+ }
+ {
+ memd(fp+#-32) = r23:22
+ memd(fp+#-24) = r21:20
+ }
+ {
+ memd(fp+#-16) = r19:18
+ memd(fp+#-8) = r17:16
+ jumpr lr
+ }
+FUNCTION_END __save_r16_through_r27
+
+FUNCTION_BEGIN __save_r16_through_r25
+ {
+ memd(fp+#-40) = r25:24
+ memd(fp+#-32) = r23:22
+ }
+ {
+ memd(fp+#-24) = r21:20
+ memd(fp+#-16) = r19:18
+ }
+ {
+ memd(fp+#-8) = r17:16
+ jumpr lr
+ }
+FUNCTION_END __save_r16_through_r25
+
+FUNCTION_BEGIN __save_r16_through_r23
+ {
+ memd(fp+#-32) = r23:22
+ memd(fp+#-24) = r21:20
+ }
+ {
+ memd(fp+#-16) = r19:18
+ memd(fp+#-8) = r17:16
+ jumpr lr
+ }
+FUNCTION_END __save_r16_through_r23
+
+FUNCTION_BEGIN __save_r16_through_r21
+ {
+ memd(fp+#-24) = r21:20
+ memd(fp+#-16) = r19:18
+ }
+ {
+ memd(fp+#-8) = r17:16
+ jumpr lr
+ }
+FUNCTION_END __save_r16_through_r21
+
+FUNCTION_BEGIN __save_r16_through_r19
+ {
+ memd(fp+#-16) = r19:18
+ memd(fp+#-8) = r17:16
+ jumpr lr
+ }
+FUNCTION_END __save_r16_through_r19
+
+FUNCTION_BEGIN __save_r16_through_r17
+ {
+ memd(fp+#-8) = r17:16
+ jumpr lr
+ }
+FUNCTION_END __save_r16_through_r17
+
+// For each of the *_before_tailcall functions, jumpr lr is executed in parallel
+// with deallocframe. That way, the return gets the old value of lr, which is
+// where these functions need to return, and at the same time, lr gets the value
+// it needs going into the tail call.
+
+
+FUNCTION_BEGIN __restore_r16_through_r27_and_deallocframe_before_tailcall
+ r27:26 = memd(fp+#-48)
+ {
+ r25:24 = memd(fp+#-40)
+ r23:22 = memd(fp+#-32)
+ }
+ {
+ r21:20 = memd(fp+#-24)
+ r19:18 = memd(fp+#-16)
+ }
+ {
+ r17:16 = memd(fp+#-8)
+ deallocframe
+ jumpr lr
+ }
+FUNCTION_END __restore_r16_through_r27_and_deallocframe_before_tailcall
+
+FUNCTION_BEGIN __restore_r16_through_r25_and_deallocframe_before_tailcall
+ {
+ r25:24 = memd(fp+#-40)
+ r23:22 = memd(fp+#-32)
+ }
+ {
+ r21:20 = memd(fp+#-24)
+ r19:18 = memd(fp+#-16)
+ }
+ {
+ r17:16 = memd(fp+#-8)
+ deallocframe
+ jumpr lr
+ }
+FUNCTION_END __restore_r16_through_r25_and_deallocframe_before_tailcall
+
+FUNCTION_BEGIN __restore_r16_through_r23_and_deallocframe_before_tailcall
+ {
+ r23:22 = memd(fp+#-32)
+ r21:20 = memd(fp+#-24)
+ }
+ r19:18 = memd(fp+#-16)
+ {
+ r17:16 = memd(fp+#-8)
+ deallocframe
+ jumpr lr
+ }
+FUNCTION_END __restore_r16_through_r23_and_deallocframe_before_tailcall
+
+
+FUNCTION_BEGIN __restore_r16_through_r21_and_deallocframe_before_tailcall
+ {
+ r21:20 = memd(fp+#-24)
+ r19:18 = memd(fp+#-16)
+ }
+ {
+ r17:16 = memd(fp+#-8)
+ deallocframe
+ jumpr lr
+ }
+FUNCTION_END __restore_r16_through_r19_and_deallocframe_before_tailcall
+
+FUNCTION_BEGIN __restore_r16_through_r19_and_deallocframe_before_tailcall
+ r19:18 = memd(fp+#-16)
+ {
+ r17:16 = memd(fp+#-8)
+ deallocframe
+ jumpr lr
+ }
+FUNCTION_END __restore_r16_through_r19_and_deallocframe_before_tailcall
+
+FUNCTION_BEGIN __restore_r16_through_r17_and_deallocframe_before_tailcall
+ {
+ r17:16 = memd(fp+#-8)
+ deallocframe
+ jumpr lr
+ }
+FUNCTION_END __restore_r16_through_r17_and_deallocframe_before_tailcall
+
+
+FUNCTION_BEGIN __restore_r16_through_r27_and_deallocframe
+ r27:26 = memd(fp+#-48)
+ {
+ r25:24 = memd(fp+#-40)
+ r23:22 = memd(fp+#-32)
+ }
+ {
+ r21:20 = memd(fp+#-24)
+ r19:18 = memd(fp+#-16)
+ }
+ {
+ r17:16 = memd(fp+#-8)
+ dealloc_return
+ }
+FUNCTION_END __restore_r16_through_r27_and_deallocframe
+
+FUNCTION_BEGIN __restore_r16_through_r25_and_deallocframe
+ {
+ r25:24 = memd(fp+#-40)
+ r23:22 = memd(fp+#-32)
+ }
+ {
+ r21:20 = memd(fp+#-24)
+ r19:18 = memd(fp+#-16)
+ }
+ {
+ r17:16 = memd(fp+#-8)
+ dealloc_return
+ }
+FUNCTION_END __restore_r16_through_r25_and_deallocframe
+
+FUNCTION_BEGIN __restore_r16_through_r23_and_deallocframe
+ {
+ r23:22 = memd(fp+#-32)
+ }
+ {
+ r21:20 = memd(fp+#-24)
+ r19:18 = memd(fp+#-16)
+ }
+ {
+ r17:16 = memd(fp+#-8)
+ dealloc_return
+ }
+FUNCTION_END __restore_r16_through_r23_and_deallocframe
+
+FUNCTION_BEGIN __restore_r16_through_r21_and_deallocframe
+ {
+ r21:20 = memd(fp+#-24)
+ r19:18 = memd(fp+#-16)
+ }
+ {
+ r17:16 = memd(fp+#-8)
+ dealloc_return
+ }
+FUNCTION_END __restore_r16_through_r21_and_deallocframe
+
+FUNCTION_BEGIN __restore_r16_through_r19_and_deallocframe
+ {
+ r19:18 = memd(fp+#-16)
+ r17:16 = memd(fp+#-8)
+ }
+ {
+ dealloc_return
+ }
+FUNCTION_END __restore_r16_through_r19_and_deallocframe
+
+FUNCTION_BEGIN __restore_r16_through_r17_and_deallocframe
+ {
+ r17:16 = memd(fp+#-8)
+ dealloc_return
+ }
+FUNCTION_END __restore_r16_through_r17_and_deallocframe
+
+FUNCTION_BEGIN __deallocframe
+ dealloc_return
+FUNCTION_END __deallocframe
diff --git a/contrib/libs/cxxsupp/builtins/hexagon/common_entry_exit_legacy.S b/contrib/libs/cxxsupp/builtins/hexagon/common_entry_exit_legacy.S
new file mode 100644
index 0000000000..8a60445732
--- /dev/null
+++ b/contrib/libs/cxxsupp/builtins/hexagon/common_entry_exit_legacy.S
@@ -0,0 +1,156 @@
+//===----------------------Hexagon builtin routine ------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+
+// Functions that implement common sequences in function prologues and epilogues
+// used to save code size
+
+ .macro FUNCTION_BEGIN name
+ .text
+ .globl \name
+ .type \name, @function
+ .falign
+\name:
+ .endm
+
+ .macro FUNCTION_END name
+ .size \name, . - \name
+ .endm
+
+ .macro FALLTHROUGH_TAIL_CALL name0 name1
+ .size \name0, . - \name0
+ .globl \name1
+ .type \name1, @function
+ .falign
+\name1:
+ .endm
+
+
+
+
+// Save r27:26 at fp+#-8, r25:24 at fp+#-16, r23:22 at fp+#-24, r21:20 at
+// fp+#-32, r19:18 at fp+#-40, and r17:16 at fp+#-48.
+
+
+
+
+// The compiler knows that the __save_* functions clobber LR. No other
+// registers should be used without informing the compiler.
+
+// Since we can only issue one store per packet, we don't hurt performance by
+// simply jumping to the right point in this sequence of stores.
+
+FUNCTION_BEGIN __save_r27_through_r16
+ memd(fp+#-48) = r17:16
+FALLTHROUGH_TAIL_CALL __save_r27_through_r16 __save_r27_through_r18
+ memd(fp+#-40) = r19:18
+FALLTHROUGH_TAIL_CALL __save_r27_through_r18 __save_r27_through_r20
+ memd(fp+#-32) = r21:20
+FALLTHROUGH_TAIL_CALL __save_r27_through_r20 __save_r27_through_r22
+ memd(fp+#-24) = r23:22
+FALLTHROUGH_TAIL_CALL __save_r27_through_r22 __save_r27_through_r24
+ memd(fp+#-16) = r25:24
+ {
+ memd(fp+#-8) = r27:26
+ jumpr lr
+ }
+FUNCTION_END __save_r27_through_r24
+
+
+
+
+// For each of the *_before_sibcall functions, jumpr lr is executed in parallel
+// with deallocframe. That way, the return gets the old value of lr, which is
+// where these functions need to return, and at the same time, lr gets the value
+// it needs going into the sibcall.
+
+FUNCTION_BEGIN __restore_r27_through_r20_and_deallocframe_before_sibcall
+ {
+ r21:20 = memd(fp+#-32)
+ r23:22 = memd(fp+#-24)
+ }
+FALLTHROUGH_TAIL_CALL __restore_r27_through_r20_and_deallocframe_before_sibcall __restore_r27_through_r24_and_deallocframe_before_sibcall
+ {
+ r25:24 = memd(fp+#-16)
+ jump __restore_r27_through_r26_and_deallocframe_before_sibcall
+ }
+FUNCTION_END __restore_r27_through_r24_and_deallocframe_before_sibcall
+
+
+
+
+FUNCTION_BEGIN __restore_r27_through_r16_and_deallocframe_before_sibcall
+ r17:16 = memd(fp+#-48)
+FALLTHROUGH_TAIL_CALL __restore_r27_through_r16_and_deallocframe_before_sibcall __restore_r27_through_r18_and_deallocframe_before_sibcall
+ {
+ r19:18 = memd(fp+#-40)
+ r21:20 = memd(fp+#-32)
+ }
+FALLTHROUGH_TAIL_CALL __restore_r27_through_r18_and_deallocframe_before_sibcall __restore_r27_through_r22_and_deallocframe_before_sibcall
+ {
+ r23:22 = memd(fp+#-24)
+ r25:24 = memd(fp+#-16)
+ }
+FALLTHROUGH_TAIL_CALL __restore_r27_through_r22_and_deallocframe_before_sibcall __restore_r27_through_r26_and_deallocframe_before_sibcall
+ {
+ r27:26 = memd(fp+#-8)
+ deallocframe
+ jumpr lr
+ }
+FUNCTION_END __restore_r27_through_r26_and_deallocframe_before_sibcall
+
+
+
+
+// Here we use the extra load bandwidth to restore LR early, allowing the return
+// to occur in parallel with the deallocframe.
+
+FUNCTION_BEGIN __restore_r27_through_r16_and_deallocframe
+ {
+ r17:16 = memd(fp+#-48)
+ r19:18 = memd(fp+#-40)
+ }
+FALLTHROUGH_TAIL_CALL __restore_r27_through_r16_and_deallocframe __restore_r27_through_r20_and_deallocframe
+ {
+ r21:20 = memd(fp+#-32)
+ r23:22 = memd(fp+#-24)
+ }
+FALLTHROUGH_TAIL_CALL __restore_r27_through_r20_and_deallocframe __restore_r27_through_r24_and_deallocframe
+ {
+ lr = memw(fp+#4)
+ r25:24 = memd(fp+#-16)
+ }
+ {
+ r27:26 = memd(fp+#-8)
+ deallocframe
+ jumpr lr
+ }
+FUNCTION_END __restore_r27_through_r24_and_deallocframe
+
+
+
+
+// Here the load bandwidth is maximized for all three functions.
+
+FUNCTION_BEGIN __restore_r27_through_r18_and_deallocframe
+ {
+ r19:18 = memd(fp+#-40)
+ r21:20 = memd(fp+#-32)
+ }
+FALLTHROUGH_TAIL_CALL __restore_r27_through_r18_and_deallocframe __restore_r27_through_r22_and_deallocframe
+ {
+ r23:22 = memd(fp+#-24)
+ r25:24 = memd(fp+#-16)
+ }
+FALLTHROUGH_TAIL_CALL __restore_r27_through_r22_and_deallocframe __restore_r27_through_r26_and_deallocframe
+ {
+ r27:26 = memd(fp+#-8)
+ deallocframe
+ }
+ jumpr lr
+FUNCTION_END __restore_r27_through_r26_and_deallocframe
diff --git a/contrib/libs/cxxsupp/builtins/hexagon/dfaddsub.S b/contrib/libs/cxxsupp/builtins/hexagon/dfaddsub.S
new file mode 100644
index 0000000000..1b0d34550f
--- /dev/null
+++ b/contrib/libs/cxxsupp/builtins/hexagon/dfaddsub.S
@@ -0,0 +1,396 @@
+//===----------------------Hexagon builtin routine ------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// Double Precision Multiply
+
+#define A r1:0
+#define AH r1
+#define AL r0
+#define B r3:2
+#define BH r3
+#define BL r2
+
+#define EXPA r4
+#define EXPB r5
+#define EXPB_A r5:4
+
+#define ZTMP r7:6
+#define ZTMPH r7
+#define ZTMPL r6
+
+#define ATMP r13:12
+#define ATMPH r13
+#define ATMPL r12
+
+#define BTMP r9:8
+#define BTMPH r9
+#define BTMPL r8
+
+#define ATMP2 r11:10
+#define ATMP2H r11
+#define ATMP2L r10
+
+#define EXPDIFF r15
+#define EXTRACTOFF r14
+#define EXTRACTAMT r15:14
+
+#define TMP r28
+
+#define MANTBITS 52
+#define HI_MANTBITS 20
+#define EXPBITS 11
+#define BIAS 1024
+#define MANTISSA_TO_INT_BIAS 52
+#define SR_BIT_INEXACT 5
+
+#ifndef SR_ROUND_OFF
+#define SR_ROUND_OFF 22
+#endif
+
+#define NORMAL p3
+#define BIGB p2
+
+#define Q6_ALIAS(TAG) .global __qdsp_##TAG ; .set __qdsp_##TAG, __hexagon_##TAG
+#define FAST_ALIAS(TAG) .global __hexagon_fast_##TAG ; .set __hexagon_fast_##TAG, __hexagon_##TAG
+#define FAST2_ALIAS(TAG) .global __hexagon_fast2_##TAG ; .set __hexagon_fast2_##TAG, __hexagon_##TAG
+#define END(TAG) .size TAG,.-TAG
+
+ .text
+ .global __hexagon_adddf3
+ .global __hexagon_subdf3
+ .type __hexagon_adddf3, @function
+ .type __hexagon_subdf3, @function
+
+Q6_ALIAS(adddf3)
+FAST_ALIAS(adddf3)
+FAST2_ALIAS(adddf3)
+Q6_ALIAS(subdf3)
+FAST_ALIAS(subdf3)
+FAST2_ALIAS(subdf3)
+
+ .p2align 5
+__hexagon_adddf3:
+ {
+ EXPA = extractu(AH,#EXPBITS,#HI_MANTBITS)
+ EXPB = extractu(BH,#EXPBITS,#HI_MANTBITS)
+ ATMP = combine(##0x20000000,#0)
+ }
+ {
+ NORMAL = dfclass(A,#2)
+ NORMAL = dfclass(B,#2)
+ BTMP = ATMP
+ BIGB = cmp.gtu(EXPB,EXPA) // Is B substantially greater than A?
+ }
+ {
+ if (!NORMAL) jump .Ladd_abnormal // If abnormal, go to special code
+ if (BIGB) A = B // if B >> A, swap A and B
+ if (BIGB) B = A // If B >> A, swap A and B
+ if (BIGB) EXPB_A = combine(EXPA,EXPB) // swap exponents
+ }
+ {
+ ATMP = insert(A,#MANTBITS,#EXPBITS-2) // Q1.62
+ BTMP = insert(B,#MANTBITS,#EXPBITS-2) // Q1.62
+ EXPDIFF = sub(EXPA,EXPB)
+ ZTMP = combine(#62,#1)
+ }
+#undef BIGB
+#undef NORMAL
+#define B_POS p3
+#define A_POS p2
+#define NO_STICKIES p1
+.Ladd_continue:
+ {
+ EXPDIFF = min(EXPDIFF,ZTMPH) // If exponent difference >= ~60,
+ // will collapse to sticky bit
+ ATMP2 = neg(ATMP)
+ A_POS = cmp.gt(AH,#-1)
+ EXTRACTOFF = #0
+ }
+ {
+ if (!A_POS) ATMP = ATMP2
+ ATMP2 = extractu(BTMP,EXTRACTAMT)
+ BTMP = ASR(BTMP,EXPDIFF)
+#undef EXTRACTAMT
+#undef EXPDIFF
+#undef EXTRACTOFF
+#define ZERO r15:14
+ ZERO = #0
+ }
+ {
+ NO_STICKIES = cmp.eq(ATMP2,ZERO)
+ if (!NO_STICKIES.new) BTMPL = or(BTMPL,ZTMPL)
+ EXPB = add(EXPA,#-BIAS-60)
+ B_POS = cmp.gt(BH,#-1)
+ }
+ {
+ ATMP = add(ATMP,BTMP) // ADD!!!
+ ATMP2 = sub(ATMP,BTMP) // Negate and ADD --> SUB!!!
+ ZTMP = combine(#54,##2045)
+ }
+ {
+ p0 = cmp.gtu(EXPA,ZTMPH) // must be pretty high in case of large cancellation
+ p0 = !cmp.gtu(EXPA,ZTMPL)
+ if (!p0.new) jump:nt .Ladd_ovf_unf
+ if (!B_POS) ATMP = ATMP2 // if B neg, pick difference
+ }
+ {
+ A = convert_d2df(ATMP) // Convert to Double Precision, taking care of flags, etc. So nice!
+ p0 = cmp.eq(ATMPH,#0)
+ p0 = cmp.eq(ATMPL,#0)
+ if (p0.new) jump:nt .Ladd_zero // or maybe conversion handles zero case correctly?
+ }
+ {
+ AH += asl(EXPB,#HI_MANTBITS)
+ jumpr r31
+ }
+ .falign
+__hexagon_subdf3:
+ {
+ BH = togglebit(BH,#31)
+ jump __qdsp_adddf3
+ }
+
+
+ .falign
+.Ladd_zero:
+ // True zero, full cancellation
+ // +0 unless round towards negative infinity
+ {
+ TMP = USR
+ A = #0
+ BH = #1
+ }
+ {
+ TMP = extractu(TMP,#2,#22)
+ BH = asl(BH,#31)
+ }
+ {
+ p0 = cmp.eq(TMP,#2)
+ if (p0.new) AH = xor(AH,BH)
+ jumpr r31
+ }
+ .falign
+.Ladd_ovf_unf:
+ // Overflow or Denormal is possible
+ // Good news: Underflow flag is not possible!
+
+ // ATMP has 2's complement value
+ //
+ // EXPA has A's exponent, EXPB has EXPA-BIAS-60
+ //
+ // Convert, extract exponent, add adjustment.
+ // If > 2046, overflow
+ // If <= 0, denormal
+ //
+ // Note that we've not done our zero check yet, so do that too
+
+ {
+ A = convert_d2df(ATMP)
+ p0 = cmp.eq(ATMPH,#0)
+ p0 = cmp.eq(ATMPL,#0)
+ if (p0.new) jump:nt .Ladd_zero
+ }
+ {
+ TMP = extractu(AH,#EXPBITS,#HI_MANTBITS)
+ AH += asl(EXPB,#HI_MANTBITS)
+ }
+ {
+ EXPB = add(EXPB,TMP)
+ B = combine(##0x00100000,#0)
+ }
+ {
+ p0 = cmp.gt(EXPB,##BIAS+BIAS-2)
+ if (p0.new) jump:nt .Ladd_ovf
+ }
+ {
+ p0 = cmp.gt(EXPB,#0)
+ if (p0.new) jumpr:t r31
+ TMP = sub(#1,EXPB)
+ }
+ {
+ B = insert(A,#MANTBITS,#0)
+ A = ATMP
+ }
+ {
+ B = lsr(B,TMP)
+ }
+ {
+ A = insert(B,#63,#0)
+ jumpr r31
+ }
+ .falign
+.Ladd_ovf:
+ // We get either max finite value or infinity. Either way, overflow+inexact
+ {
+ A = ATMP // 2's complement value
+ TMP = USR
+ ATMP = combine(##0x7fefffff,#-1) // positive max finite
+ }
+ {
+ EXPB = extractu(TMP,#2,#SR_ROUND_OFF) // rounding bits
+ TMP = or(TMP,#0x28) // inexact + overflow
+ BTMP = combine(##0x7ff00000,#0) // positive infinity
+ }
+ {
+ USR = TMP
+ EXPB ^= lsr(AH,#31) // Does sign match rounding?
+ TMP = EXPB // unmodified rounding mode
+ }
+ {
+ p0 = !cmp.eq(TMP,#1) // If not round-to-zero and
+ p0 = !cmp.eq(EXPB,#2) // Not rounding the other way,
+ if (p0.new) ATMP = BTMP // we should get infinity
+ }
+ {
+ A = insert(ATMP,#63,#0) // insert inf/maxfinite, leave sign
+ }
+ {
+ p0 = dfcmp.eq(A,A)
+ jumpr r31
+ }
+
+.Ladd_abnormal:
+ {
+ ATMP = extractu(A,#63,#0) // strip off sign
+ BTMP = extractu(B,#63,#0) // strip off sign
+ }
+ {
+ p3 = cmp.gtu(ATMP,BTMP)
+ if (!p3.new) A = B // sort values
+ if (!p3.new) B = A // sort values
+ }
+ {
+ // Any NaN --> NaN, possibly raise invalid if sNaN
+ p0 = dfclass(A,#0x0f) // A not NaN?
+ if (!p0.new) jump:nt .Linvalid_nan_add
+ if (!p3) ATMP = BTMP
+ if (!p3) BTMP = ATMP
+ }
+ {
+ // Infinity + non-infinity number is infinity
+ // Infinity + infinity --> inf or nan
+ p1 = dfclass(A,#0x08) // A is infinity
+ if (p1.new) jump:nt .Linf_add
+ }
+ {
+ p2 = dfclass(B,#0x01) // B is zero
+ if (p2.new) jump:nt .LB_zero // so return A or special 0+0
+ ATMP = #0
+ }
+ // We are left with adding one or more subnormals
+ {
+ p0 = dfclass(A,#4)
+ if (p0.new) jump:nt .Ladd_two_subnormal
+ ATMP = combine(##0x20000000,#0)
+ }
+ {
+ EXPA = extractu(AH,#EXPBITS,#HI_MANTBITS)
+ EXPB = #1
+ // BTMP already ABS(B)
+ BTMP = asl(BTMP,#EXPBITS-2)
+ }
+#undef ZERO
+#define EXTRACTOFF r14
+#define EXPDIFF r15
+ {
+ ATMP = insert(A,#MANTBITS,#EXPBITS-2)
+ EXPDIFF = sub(EXPA,EXPB)
+ ZTMP = combine(#62,#1)
+ jump .Ladd_continue
+ }
+
+.Ladd_two_subnormal:
+ {
+ ATMP = extractu(A,#63,#0)
+ BTMP = extractu(B,#63,#0)
+ }
+ {
+ ATMP = neg(ATMP)
+ BTMP = neg(BTMP)
+ p0 = cmp.gt(AH,#-1)
+ p1 = cmp.gt(BH,#-1)
+ }
+ {
+ if (p0) ATMP = A
+ if (p1) BTMP = B
+ }
+ {
+ ATMP = add(ATMP,BTMP)
+ }
+ {
+ BTMP = neg(ATMP)
+ p0 = cmp.gt(ATMPH,#-1)
+ B = #0
+ }
+ {
+ if (!p0) A = BTMP
+ if (p0) A = ATMP
+ BH = ##0x80000000
+ }
+ {
+ if (!p0) AH = or(AH,BH)
+ p0 = dfcmp.eq(A,B)
+ if (p0.new) jump:nt .Lzero_plus_zero
+ }
+ {
+ jumpr r31
+ }
+
+.Linvalid_nan_add:
+ {
+ TMP = convert_df2sf(A) // will generate invalid if sNaN
+ p0 = dfclass(B,#0x0f) // if B is not NaN
+ if (p0.new) B = A // make it whatever A is
+ }
+ {
+ BL = convert_df2sf(B) // will generate invalid if sNaN
+ A = #-1
+ jumpr r31
+ }
+ .falign
+.LB_zero:
+ {
+ p0 = dfcmp.eq(ATMP,A) // is A also zero?
+ if (!p0.new) jumpr:t r31 // If not, just return A
+ }
+ // 0 + 0 is special
+ // if equal integral values, they have the same sign, which is fine for all rounding
+ // modes.
+ // If unequal in sign, we get +0 for all rounding modes except round down
+.Lzero_plus_zero:
+ {
+ p0 = cmp.eq(A,B)
+ if (p0.new) jumpr:t r31
+ }
+ {
+ TMP = USR
+ }
+ {
+ TMP = extractu(TMP,#2,#SR_ROUND_OFF)
+ A = #0
+ }
+ {
+ p0 = cmp.eq(TMP,#2)
+ if (p0.new) AH = ##0x80000000
+ jumpr r31
+ }
+.Linf_add:
+ // adding infinities is only OK if they are equal
+ {
+ p0 = !cmp.eq(AH,BH) // Do they have different signs
+ p0 = dfclass(B,#8) // And is B also infinite?
+ if (!p0.new) jumpr:t r31 // If not, just a normal inf
+ }
+ {
+ BL = ##0x7f800001 // sNAN
+ }
+ {
+ A = convert_sf2df(BL) // trigger invalid, set NaN
+ jumpr r31
+ }
+END(__hexagon_adddf3)
diff --git a/contrib/libs/cxxsupp/builtins/hexagon/dfdiv.S b/contrib/libs/cxxsupp/builtins/hexagon/dfdiv.S
new file mode 100644
index 0000000000..202965ec47
--- /dev/null
+++ b/contrib/libs/cxxsupp/builtins/hexagon/dfdiv.S
@@ -0,0 +1,491 @@
+//===----------------------Hexagon builtin routine ------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// Double Precision Divide
+
+#define A r1:0
+#define AH r1
+#define AL r0
+
+#define B r3:2
+#define BH r3
+#define BL r2
+
+#define Q r5:4
+#define QH r5
+#define QL r4
+
+#define PROD r7:6
+#define PRODHI r7
+#define PRODLO r6
+
+#define SFONE r8
+#define SFDEN r9
+#define SFERROR r10
+#define SFRECIP r11
+
+#define EXPBA r13:12
+#define EXPB r13
+#define EXPA r12
+
+#define REMSUB2 r15:14
+
+
+
+#define SIGN r28
+
+#define Q_POSITIVE p3
+#define NORMAL p2
+#define NO_OVF_UNF p1
+#define P_TMP p0
+
+#define RECIPEST_SHIFT 3
+#define QADJ 61
+
+#define DFCLASS_NORMAL 0x02
+#define DFCLASS_NUMBER 0x0F
+#define DFCLASS_INFINITE 0x08
+#define DFCLASS_ZERO 0x01
+#define DFCLASS_NONZERO (DFCLASS_NUMBER ^ DFCLASS_ZERO)
+#define DFCLASS_NONINFINITE (DFCLASS_NUMBER ^ DFCLASS_INFINITE)
+
+#define DF_MANTBITS 52
+#define DF_EXPBITS 11
+#define SF_MANTBITS 23
+#define SF_EXPBITS 8
+#define DF_BIAS 0x3ff
+
+#define SR_ROUND_OFF 22
+
+#define Q6_ALIAS(TAG) .global __qdsp_##TAG ; .set __qdsp_##TAG, __hexagon_##TAG
+#define FAST_ALIAS(TAG) .global __hexagon_fast_##TAG ; .set __hexagon_fast_##TAG, __hexagon_##TAG
+#define FAST2_ALIAS(TAG) .global __hexagon_fast2_##TAG ; .set __hexagon_fast2_##TAG, __hexagon_##TAG
+#define END(TAG) .size TAG,.-TAG
+
+ .text
+ .global __hexagon_divdf3
+ .type __hexagon_divdf3,@function
+ Q6_ALIAS(divdf3)
+ FAST_ALIAS(divdf3)
+ FAST2_ALIAS(divdf3)
+ .p2align 5
+__hexagon_divdf3:
+ {
+ NORMAL = dfclass(A,#DFCLASS_NORMAL)
+ NORMAL = dfclass(B,#DFCLASS_NORMAL)
+ EXPBA = combine(BH,AH)
+ SIGN = xor(AH,BH)
+ }
+#undef A
+#undef AH
+#undef AL
+#undef B
+#undef BH
+#undef BL
+#define REM r1:0
+#define REMHI r1
+#define REMLO r0
+#define DENOM r3:2
+#define DENOMHI r3
+#define DENOMLO r2
+ {
+ if (!NORMAL) jump .Ldiv_abnormal
+ PROD = extractu(DENOM,#SF_MANTBITS,#DF_MANTBITS-SF_MANTBITS)
+ SFONE = ##0x3f800001
+ }
+ {
+ SFDEN = or(SFONE,PRODLO)
+ EXPB = extractu(EXPB,#DF_EXPBITS,#DF_MANTBITS-32)
+ EXPA = extractu(EXPA,#DF_EXPBITS,#DF_MANTBITS-32)
+ Q_POSITIVE = cmp.gt(SIGN,#-1)
+ }
+#undef SIGN
+#define ONE r28
+.Ldenorm_continue:
+ {
+ SFRECIP,P_TMP = sfrecipa(SFONE,SFDEN)
+ SFERROR = and(SFONE,#-2)
+ ONE = #1
+ EXPA = sub(EXPA,EXPB)
+ }
+#undef EXPB
+#define RECIPEST r13
+ {
+ SFERROR -= sfmpy(SFRECIP,SFDEN):lib
+ REMHI = insert(ONE,#DF_EXPBITS+1,#DF_MANTBITS-32)
+ RECIPEST = ##0x00800000 << RECIPEST_SHIFT
+ }
+ {
+ SFRECIP += sfmpy(SFRECIP,SFERROR):lib
+ DENOMHI = insert(ONE,#DF_EXPBITS+1,#DF_MANTBITS-32)
+ SFERROR = and(SFONE,#-2)
+ }
+ {
+ SFERROR -= sfmpy(SFRECIP,SFDEN):lib
+ QH = #-DF_BIAS+1
+ QL = #DF_BIAS-1
+ }
+ {
+ SFRECIP += sfmpy(SFRECIP,SFERROR):lib
+ NO_OVF_UNF = cmp.gt(EXPA,QH)
+ NO_OVF_UNF = !cmp.gt(EXPA,QL)
+ }
+ {
+ RECIPEST = insert(SFRECIP,#SF_MANTBITS,#RECIPEST_SHIFT)
+ Q = #0
+ EXPA = add(EXPA,#-QADJ)
+ }
+#undef SFERROR
+#undef SFRECIP
+#define TMP r10
+#define TMP1 r11
+ {
+ RECIPEST = add(RECIPEST,#((-3) << RECIPEST_SHIFT))
+ }
+
+#define DIV_ITER1B(QSHIFTINSN,QSHIFT,REMSHIFT,EXTRA) \
+ { \
+ PROD = mpyu(RECIPEST,REMHI); \
+ REM = asl(REM,# ## ( REMSHIFT )); \
+ }; \
+ { \
+ PRODLO = # ## 0; \
+ REM -= mpyu(PRODHI,DENOMLO); \
+ REMSUB2 = mpyu(PRODHI,DENOMHI); \
+ }; \
+ { \
+ Q += QSHIFTINSN(PROD, # ## ( QSHIFT )); \
+ REM -= asl(REMSUB2, # ## 32); \
+ EXTRA \
+ }
+
+
+ DIV_ITER1B(ASL,14,15,)
+ DIV_ITER1B(ASR,1,15,)
+ DIV_ITER1B(ASR,16,15,)
+ DIV_ITER1B(ASR,31,15,PROD=# ( 0 );)
+
+#undef REMSUB2
+#define TMPPAIR r15:14
+#define TMPPAIRHI r15
+#define TMPPAIRLO r14
+#undef RECIPEST
+#define EXPB r13
+ {
+ // compare or sub with carry
+ TMPPAIR = sub(REM,DENOM)
+ P_TMP = cmp.gtu(DENOM,REM)
+ // set up amt to add to q
+ if (!P_TMP.new) PRODLO = #2
+ }
+ {
+ Q = add(Q,PROD)
+ if (!P_TMP) REM = TMPPAIR
+ TMPPAIR = #0
+ }
+ {
+ P_TMP = cmp.eq(REM,TMPPAIR)
+ if (!P_TMP.new) QL = or(QL,ONE)
+ }
+ {
+ PROD = neg(Q)
+ }
+ {
+ if (!Q_POSITIVE) Q = PROD
+ }
+#undef REM
+#undef REMHI
+#undef REMLO
+#undef DENOM
+#undef DENOMLO
+#undef DENOMHI
+#define A r1:0
+#define AH r1
+#define AL r0
+#define B r3:2
+#define BH r3
+#define BL r2
+ {
+ A = convert_d2df(Q)
+ if (!NO_OVF_UNF) jump .Ldiv_ovf_unf
+ }
+ {
+ AH += asl(EXPA,#DF_MANTBITS-32)
+ jumpr r31
+ }
+
+.Ldiv_ovf_unf:
+ {
+ AH += asl(EXPA,#DF_MANTBITS-32)
+ EXPB = extractu(AH,#DF_EXPBITS,#DF_MANTBITS-32)
+ }
+ {
+ PROD = abs(Q)
+ EXPA = add(EXPA,EXPB)
+ }
+ {
+ P_TMP = cmp.gt(EXPA,##DF_BIAS+DF_BIAS) // overflow
+ if (P_TMP.new) jump:nt .Ldiv_ovf
+ }
+ {
+ P_TMP = cmp.gt(EXPA,#0)
+ if (P_TMP.new) jump:nt .Lpossible_unf // round up to normal possible...
+ }
+ // Underflow
+ // We know what the infinite range exponent should be (EXPA)
+ // Q is 2's complement, PROD is abs(Q)
+ // Normalize Q, shift right, add a high bit, convert, change exponent
+
+#define FUDGE1 7 // how much to shift right
+#define FUDGE2 4 // how many guard/round to keep at lsbs
+
+ {
+ EXPB = add(clb(PROD),#-1) // doesn't need to be added in since
+ EXPA = sub(#FUDGE1,EXPA) // we extract post-converted exponent
+ TMP = USR
+ TMP1 = #63
+ }
+ {
+ EXPB = min(EXPA,TMP1)
+ TMP1 = or(TMP,#0x030)
+ PROD = asl(PROD,EXPB)
+ EXPA = #0
+ }
+ {
+ TMPPAIR = extractu(PROD,EXPBA) // bits that will get shifted out
+ PROD = lsr(PROD,EXPB) // shift out bits
+ B = #1
+ }
+ {
+ P_TMP = cmp.gtu(B,TMPPAIR)
+ if (!P_TMP.new) PRODLO = or(BL,PRODLO)
+ PRODHI = setbit(PRODHI,#DF_MANTBITS-32+FUDGE2)
+ }
+ {
+ Q = neg(PROD)
+ P_TMP = bitsclr(PRODLO,#(1<<FUDGE2)-1)
+ if (!P_TMP.new) TMP = TMP1
+ }
+ {
+ USR = TMP
+ if (Q_POSITIVE) Q = PROD
+ TMP = #-DF_BIAS-(DF_MANTBITS+FUDGE2)
+ }
+ {
+ A = convert_d2df(Q)
+ }
+ {
+ AH += asl(TMP,#DF_MANTBITS-32)
+ jumpr r31
+ }
+
+
+.Lpossible_unf:
+ // If upper parts of Q were all F's, but abs(A) == 0x00100000_00000000, we rounded up to min_normal
+ // The answer is correct, but we need to raise Underflow
+ {
+ B = extractu(A,#63,#0)
+ TMPPAIR = combine(##0x00100000,#0) // min normal
+ TMP = #0x7FFF
+ }
+ {
+ P_TMP = dfcmp.eq(TMPPAIR,B) // Is everything zero in the rounded value...
+ P_TMP = bitsset(PRODHI,TMP) // but a bunch of bits set in the unrounded abs(quotient)?
+ }
+
+#if (__HEXAGON_ARCH__ == 60)
+ TMP = USR // If not, just return
+ if (!P_TMP) jumpr r31 // Else, we want to set Unf+Inexact
+ // Note that inexact is already set...
+#else
+ {
+ if (!P_TMP) jumpr r31 // If not, just return
+ TMP = USR // Else, we want to set Unf+Inexact
+ } // Note that inexact is already set...
+#endif
+ {
+ TMP = or(TMP,#0x30)
+ }
+ {
+ USR = TMP
+ }
+ {
+ p0 = dfcmp.eq(A,A)
+ jumpr r31
+ }
+
+.Ldiv_ovf:
+
+ // Raise Overflow, and choose the correct overflow value (saturated normal or infinity)
+
+ {
+ TMP = USR
+ B = combine(##0x7fefffff,#-1)
+ AH = mux(Q_POSITIVE,#0,#-1)
+ }
+ {
+ PROD = combine(##0x7ff00000,#0)
+ QH = extractu(TMP,#2,#SR_ROUND_OFF)
+ TMP = or(TMP,#0x28)
+ }
+ {
+ USR = TMP
+ QH ^= lsr(AH,#31)
+ QL = QH
+ }
+ {
+ p0 = !cmp.eq(QL,#1) // if not round-to-zero
+ p0 = !cmp.eq(QH,#2) // and not rounding the other way
+ if (p0.new) B = PROD // go to inf
+ p0 = dfcmp.eq(B,B) // get exceptions
+ }
+ {
+ A = insert(B,#63,#0)
+ jumpr r31
+ }
+
+#undef ONE
+#define SIGN r28
+#undef NORMAL
+#undef NO_OVF_UNF
+#define P_INF p1
+#define P_ZERO p2
+.Ldiv_abnormal:
+ {
+ P_TMP = dfclass(A,#DFCLASS_NUMBER)
+ P_TMP = dfclass(B,#DFCLASS_NUMBER)
+ Q_POSITIVE = cmp.gt(SIGN,#-1)
+ }
+ {
+ P_INF = dfclass(A,#DFCLASS_INFINITE)
+ P_INF = dfclass(B,#DFCLASS_INFINITE)
+ }
+ {
+ P_ZERO = dfclass(A,#DFCLASS_ZERO)
+ P_ZERO = dfclass(B,#DFCLASS_ZERO)
+ }
+ {
+ if (!P_TMP) jump .Ldiv_nan
+ if (P_INF) jump .Ldiv_invalid
+ }
+ {
+ if (P_ZERO) jump .Ldiv_invalid
+ }
+ {
+ P_ZERO = dfclass(A,#DFCLASS_NONZERO) // nonzero
+ P_ZERO = dfclass(B,#DFCLASS_NONINFINITE) // non-infinite
+ }
+ {
+ P_INF = dfclass(A,#DFCLASS_NONINFINITE) // non-infinite
+ P_INF = dfclass(B,#DFCLASS_NONZERO) // nonzero
+ }
+ {
+ if (!P_ZERO) jump .Ldiv_zero_result
+ if (!P_INF) jump .Ldiv_inf_result
+ }
+ // Now we've narrowed it down to (de)normal / (de)normal
+ // Set up A/EXPA B/EXPB and go back
+#undef P_ZERO
+#undef P_INF
+#define P_TMP2 p1
+ {
+ P_TMP = dfclass(A,#DFCLASS_NORMAL)
+ P_TMP2 = dfclass(B,#DFCLASS_NORMAL)
+ TMP = ##0x00100000
+ }
+ {
+ EXPBA = combine(BH,AH)
+ AH = insert(TMP,#DF_EXPBITS+1,#DF_MANTBITS-32) // clear out hidden bit, sign bit
+ BH = insert(TMP,#DF_EXPBITS+1,#DF_MANTBITS-32) // clear out hidden bit, sign bit
+ }
+ {
+ if (P_TMP) AH = or(AH,TMP) // if normal, add back in hidden bit
+ if (P_TMP2) BH = or(BH,TMP) // if normal, add back in hidden bit
+ }
+ {
+ QH = add(clb(A),#-DF_EXPBITS)
+ QL = add(clb(B),#-DF_EXPBITS)
+ TMP = #1
+ }
+ {
+ EXPA = extractu(EXPA,#DF_EXPBITS,#DF_MANTBITS-32)
+ EXPB = extractu(EXPB,#DF_EXPBITS,#DF_MANTBITS-32)
+ }
+ {
+ A = asl(A,QH)
+ B = asl(B,QL)
+ if (!P_TMP) EXPA = sub(TMP,QH)
+ if (!P_TMP2) EXPB = sub(TMP,QL)
+ } // recreate values needed by resume coke
+ {
+ PROD = extractu(B,#SF_MANTBITS,#DF_MANTBITS-SF_MANTBITS)
+ }
+ {
+ SFDEN = or(SFONE,PRODLO)
+ jump .Ldenorm_continue
+ }
+
+.Ldiv_zero_result:
+ {
+ AH = xor(AH,BH)
+ B = #0
+ }
+ {
+ A = insert(B,#63,#0)
+ jumpr r31
+ }
+.Ldiv_inf_result:
+ {
+ p2 = dfclass(B,#DFCLASS_ZERO)
+ p2 = dfclass(A,#DFCLASS_NONINFINITE)
+ }
+ {
+ TMP = USR
+ if (!p2) jump 1f
+ AH = xor(AH,BH)
+ }
+ {
+ TMP = or(TMP,#0x04) // DBZ
+ }
+ {
+ USR = TMP
+ }
+1:
+ {
+ B = combine(##0x7ff00000,#0)
+ p0 = dfcmp.uo(B,B) // take possible exception
+ }
+ {
+ A = insert(B,#63,#0)
+ jumpr r31
+ }
+.Ldiv_nan:
+ {
+ p0 = dfclass(A,#0x10)
+ p1 = dfclass(B,#0x10)
+ if (!p0.new) A = B
+ if (!p1.new) B = A
+ }
+ {
+ QH = convert_df2sf(A) // get possible invalid exceptions
+ QL = convert_df2sf(B)
+ }
+ {
+ A = #-1
+ jumpr r31
+ }
+
+.Ldiv_invalid:
+ {
+ TMP = ##0x7f800001
+ }
+ {
+ A = convert_sf2df(TMP) // get invalid, get DF qNaN
+ jumpr r31
+ }
+END(__hexagon_divdf3)
diff --git a/contrib/libs/cxxsupp/builtins/hexagon/dffma.S b/contrib/libs/cxxsupp/builtins/hexagon/dffma.S
new file mode 100644
index 0000000000..843e88b3ca
--- /dev/null
+++ b/contrib/libs/cxxsupp/builtins/hexagon/dffma.S
@@ -0,0 +1,694 @@
+//===----------------------Hexagon builtin routine ------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#define Q6_ALIAS(TAG) .global __qdsp_##TAG ; .set __qdsp_##TAG, __hexagon_##TAG
+#define END(TAG) .size TAG,.-TAG
+
+// Double Precision Multiply
+
+
+#define A r1:0
+#define AH r1
+#define AL r0
+#define B r3:2
+#define BH r3
+#define BL r2
+#define C r5:4
+#define CH r5
+#define CL r4
+
+
+
+#define BTMP r15:14
+#define BTMPH r15
+#define BTMPL r14
+
+#define ATMP r13:12
+#define ATMPH r13
+#define ATMPL r12
+
+#define CTMP r11:10
+#define CTMPH r11
+#define CTMPL r10
+
+#define PP_LL r9:8
+#define PP_LL_H r9
+#define PP_LL_L r8
+
+#define PP_ODD r7:6
+#define PP_ODD_H r7
+#define PP_ODD_L r6
+
+
+#define PP_HH r17:16
+#define PP_HH_H r17
+#define PP_HH_L r16
+
+#define EXPA r18
+#define EXPB r19
+#define EXPBA r19:18
+
+#define TMP r28
+
+#define P_TMP p0
+#define PROD_NEG p3
+#define EXACT p2
+#define SWAP p1
+
+#define MANTBITS 52
+#define HI_MANTBITS 20
+#define EXPBITS 11
+#define BIAS 1023
+#define STACKSPACE 32
+
+#define ADJUST 4
+
+#define FUDGE 7
+#define FUDGE2 3
+
+#ifndef SR_ROUND_OFF
+#define SR_ROUND_OFF 22
+#endif
+
+ // First, classify for normal values, and abort if abnormal
+ //
+ // Next, unpack mantissa into 0x1000_0000_0000_0000 + mant<<8
+ //
+ // Since we know that the 2 MSBs of the H registers is zero, we should never carry
+ // the partial products that involve the H registers
+ //
+ // Try to buy X slots, at the expense of latency if needed
+ //
+ // We will have PP_HH with the upper bits of the product, PP_LL with the lower
+ // PP_HH can have a maximum of 0x03FF_FFFF_FFFF_FFFF or thereabouts
+ // PP_HH can have a minimum of 0x0100_0000_0000_0000
+ //
+ // 0x0100_0000_0000_0000 has EXP of EXPA+EXPB-BIAS
+ //
+ // We need to align CTMP.
+ // If CTMP >> PP, convert PP to 64 bit with sticky, align CTMP, and follow normal add
+ // If CTMP << PP align CTMP and add 128 bits. Then compute sticky
+ // If CTMP ~= PP, align CTMP and add 128 bits. May have massive cancellation.
+ //
+ // Convert partial product and CTMP to 2's complement prior to addition
+ //
+ // After we add, we need to normalize into upper 64 bits, then compute sticky.
+
+ .text
+ .global __hexagon_fmadf4
+ .type __hexagon_fmadf4,@function
+ .global __hexagon_fmadf5
+ .type __hexagon_fmadf5,@function
+ Q6_ALIAS(fmadf5)
+ .p2align 5
+__hexagon_fmadf4:
+__hexagon_fmadf5:
+.Lfma_begin:
+ {
+ P_TMP = dfclass(A,#2)
+ P_TMP = dfclass(B,#2)
+ ATMP = #0
+ BTMP = #0
+ }
+ {
+ ATMP = insert(A,#MANTBITS,#EXPBITS-3)
+ BTMP = insert(B,#MANTBITS,#EXPBITS-3)
+ PP_ODD_H = ##0x10000000
+ allocframe(#STACKSPACE)
+ }
+ {
+ PP_LL = mpyu(ATMPL,BTMPL)
+ if (!P_TMP) jump .Lfma_abnormal_ab
+ ATMPH = or(ATMPH,PP_ODD_H)
+ BTMPH = or(BTMPH,PP_ODD_H)
+ }
+ {
+ P_TMP = dfclass(C,#2)
+ if (!P_TMP.new) jump:nt .Lfma_abnormal_c
+ CTMP = combine(PP_ODD_H,#0)
+ PP_ODD = combine(#0,PP_LL_H)
+ }
+.Lfma_abnormal_c_restart:
+ {
+ PP_ODD += mpyu(BTMPL,ATMPH)
+ CTMP = insert(C,#MANTBITS,#EXPBITS-3)
+ memd(r29+#0) = PP_HH
+ memd(r29+#8) = EXPBA
+ }
+ {
+ PP_ODD += mpyu(ATMPL,BTMPH)
+ EXPBA = neg(CTMP)
+ P_TMP = cmp.gt(CH,#-1)
+ TMP = xor(AH,BH)
+ }
+ {
+ EXPA = extractu(AH,#EXPBITS,#HI_MANTBITS)
+ EXPB = extractu(BH,#EXPBITS,#HI_MANTBITS)
+ PP_HH = combine(#0,PP_ODD_H)
+ if (!P_TMP) CTMP = EXPBA
+ }
+ {
+ PP_HH += mpyu(ATMPH,BTMPH)
+ PP_LL = combine(PP_ODD_L,PP_LL_L)
+#undef PP_ODD
+#undef PP_ODD_H
+#undef PP_ODD_L
+#undef ATMP
+#undef ATMPL
+#undef ATMPH
+#undef BTMP
+#undef BTMPL
+#undef BTMPH
+#define RIGHTLEFTSHIFT r13:12
+#define RIGHTSHIFT r13
+#define LEFTSHIFT r12
+
+ EXPA = add(EXPA,EXPB)
+#undef EXPB
+#undef EXPBA
+#define EXPC r19
+#define EXPCA r19:18
+ EXPC = extractu(CH,#EXPBITS,#HI_MANTBITS)
+ }
+ // PP_HH:PP_LL now has product
+ // CTMP is negated
+ // EXPA,B,C are extracted
+ // We need to negate PP
+ // Since we will be adding with carry later, if we need to negate,
+ // just invert all bits now, which we can do conditionally and in parallel
+#define PP_HH_TMP r15:14
+#define PP_LL_TMP r7:6
+ {
+ EXPA = add(EXPA,#-BIAS+(ADJUST))
+ PROD_NEG = !cmp.gt(TMP,#-1)
+ PP_LL_TMP = #0
+ PP_HH_TMP = #0
+ }
+ {
+ PP_LL_TMP = sub(PP_LL_TMP,PP_LL,PROD_NEG):carry
+ P_TMP = !cmp.gt(TMP,#-1)
+ SWAP = cmp.gt(EXPC,EXPA) // If C >> PP
+ if (SWAP.new) EXPCA = combine(EXPA,EXPC)
+ }
+ {
+ PP_HH_TMP = sub(PP_HH_TMP,PP_HH,PROD_NEG):carry
+ if (P_TMP) PP_LL = PP_LL_TMP
+#undef PP_LL_TMP
+#define CTMP2 r7:6
+#define CTMP2H r7
+#define CTMP2L r6
+ CTMP2 = #0
+ EXPC = sub(EXPA,EXPC)
+ }
+ {
+ if (P_TMP) PP_HH = PP_HH_TMP
+ P_TMP = cmp.gt(EXPC,#63)
+ if (SWAP) PP_LL = CTMP2
+ if (SWAP) CTMP2 = PP_LL
+ }
+#undef PP_HH_TMP
+//#define ONE r15:14
+//#define S_ONE r14
+#define ZERO r15:14
+#define S_ZERO r15
+#undef PROD_NEG
+#define P_CARRY p3
+ {
+ if (SWAP) PP_HH = CTMP // Swap C and PP
+ if (SWAP) CTMP = PP_HH
+ if (P_TMP) EXPC = add(EXPC,#-64)
+ TMP = #63
+ }
+ {
+ // If diff > 63, pre-shift-right by 64...
+ if (P_TMP) CTMP2 = CTMP
+ TMP = asr(CTMPH,#31)
+ RIGHTSHIFT = min(EXPC,TMP)
+ LEFTSHIFT = #0
+ }
+#undef C
+#undef CH
+#undef CL
+#define STICKIES r5:4
+#define STICKIESH r5
+#define STICKIESL r4
+ {
+ if (P_TMP) CTMP = combine(TMP,TMP) // sign extension of pre-shift-right-64
+ STICKIES = extract(CTMP2,RIGHTLEFTSHIFT)
+ CTMP2 = lsr(CTMP2,RIGHTSHIFT)
+ LEFTSHIFT = sub(#64,RIGHTSHIFT)
+ }
+ {
+ ZERO = #0
+ TMP = #-2
+ CTMP2 |= lsl(CTMP,LEFTSHIFT)
+ CTMP = asr(CTMP,RIGHTSHIFT)
+ }
+ {
+ P_CARRY = cmp.gtu(STICKIES,ZERO) // If we have sticky bits from C shift
+ if (P_CARRY.new) CTMP2L = and(CTMP2L,TMP) // make sure adding 1 == OR
+#undef ZERO
+#define ONE r15:14
+#define S_ONE r14
+ ONE = #1
+ STICKIES = #0
+ }
+ {
+ PP_LL = add(CTMP2,PP_LL,P_CARRY):carry // use the carry to add the sticky
+ }
+ {
+ PP_HH = add(CTMP,PP_HH,P_CARRY):carry
+ TMP = #62
+ }
+ // PP_HH:PP_LL now holds the sum
+ // We may need to normalize left, up to ??? bits.
+ //
+ // I think that if we have massive cancellation, the range we normalize by
+ // is still limited
+ {
+ LEFTSHIFT = add(clb(PP_HH),#-2)
+ if (!cmp.eq(LEFTSHIFT.new,TMP)) jump:t 1f // all sign bits?
+ }
+ // We had all sign bits, shift left by 62.
+ {
+ CTMP = extractu(PP_LL,#62,#2)
+ PP_LL = asl(PP_LL,#62)
+ EXPA = add(EXPA,#-62) // And adjust exponent of result
+ }
+ {
+ PP_HH = insert(CTMP,#62,#0) // Then shift 63
+ }
+ {
+ LEFTSHIFT = add(clb(PP_HH),#-2)
+ }
+ .falign
+1:
+ {
+ CTMP = asl(PP_HH,LEFTSHIFT)
+ STICKIES |= asl(PP_LL,LEFTSHIFT)
+ RIGHTSHIFT = sub(#64,LEFTSHIFT)
+ EXPA = sub(EXPA,LEFTSHIFT)
+ }
+ {
+ CTMP |= lsr(PP_LL,RIGHTSHIFT)
+ EXACT = cmp.gtu(ONE,STICKIES)
+ TMP = #BIAS+BIAS-2
+ }
+ {
+ if (!EXACT) CTMPL = or(CTMPL,S_ONE)
+ // If EXPA is overflow/underflow, jump to ovf_unf
+ P_TMP = !cmp.gt(EXPA,TMP)
+ P_TMP = cmp.gt(EXPA,#1)
+ if (!P_TMP.new) jump:nt .Lfma_ovf_unf
+ }
+ {
+ // XXX: FIXME: should PP_HH for check of zero be CTMP?
+ P_TMP = cmp.gtu(ONE,CTMP) // is result true zero?
+ A = convert_d2df(CTMP)
+ EXPA = add(EXPA,#-BIAS-60)
+ PP_HH = memd(r29+#0)
+ }
+ {
+ AH += asl(EXPA,#HI_MANTBITS)
+ EXPCA = memd(r29+#8)
+ if (!P_TMP) dealloc_return // not zero, return
+ }
+.Ladd_yields_zero:
+ // We had full cancellation. Return +/- zero (-0 when round-down)
+ {
+ TMP = USR
+ A = #0
+ }
+ {
+ TMP = extractu(TMP,#2,#SR_ROUND_OFF)
+ PP_HH = memd(r29+#0)
+ EXPCA = memd(r29+#8)
+ }
+ {
+ p0 = cmp.eq(TMP,#2)
+ if (p0.new) AH = ##0x80000000
+ dealloc_return
+ }
+
+#undef RIGHTLEFTSHIFT
+#undef RIGHTSHIFT
+#undef LEFTSHIFT
+#undef CTMP2
+#undef CTMP2H
+#undef CTMP2L
+
+.Lfma_ovf_unf:
+ {
+ p0 = cmp.gtu(ONE,CTMP)
+ if (p0.new) jump:nt .Ladd_yields_zero
+ }
+ {
+ A = convert_d2df(CTMP)
+ EXPA = add(EXPA,#-BIAS-60)
+ TMP = EXPA
+ }
+#define NEW_EXPB r7
+#define NEW_EXPA r6
+ {
+ AH += asl(EXPA,#HI_MANTBITS)
+ NEW_EXPB = extractu(AH,#EXPBITS,#HI_MANTBITS)
+ }
+ {
+ NEW_EXPA = add(EXPA,NEW_EXPB)
+ PP_HH = memd(r29+#0)
+ EXPCA = memd(r29+#8)
+#undef PP_HH
+#undef PP_HH_H
+#undef PP_HH_L
+#undef EXPCA
+#undef EXPC
+#undef EXPA
+#undef PP_LL
+#undef PP_LL_H
+#undef PP_LL_L
+#define EXPA r6
+#define EXPB r7
+#define EXPBA r7:6
+#define ATMP r9:8
+#define ATMPH r9
+#define ATMPL r8
+#undef NEW_EXPB
+#undef NEW_EXPA
+ ATMP = abs(CTMP)
+ }
+ {
+ p0 = cmp.gt(EXPA,##BIAS+BIAS)
+ if (p0.new) jump:nt .Lfma_ovf
+ }
+ {
+ p0 = cmp.gt(EXPA,#0)
+ if (p0.new) jump:nt .Lpossible_unf
+ }
+ {
+ // TMP has original EXPA.
+ // ATMP is corresponding value
+ // Normalize ATMP and shift right to correct location
+ EXPB = add(clb(ATMP),#-2) // Amount to left shift to normalize
+ EXPA = sub(#1+5,TMP) // Amount to right shift to denormalize
+ p3 = cmp.gt(CTMPH,#-1)
+ }
+ // Underflow
+ // We know that the infinte range exponent should be EXPA
+ // CTMP is 2's complement, ATMP is abs(CTMP)
+ {
+ EXPA = add(EXPA,EXPB) // how much to shift back right
+ ATMP = asl(ATMP,EXPB) // shift left
+ AH = USR
+ TMP = #63
+ }
+ {
+ EXPB = min(EXPA,TMP)
+ EXPA = #0
+ AL = #0x0030
+ }
+ {
+ B = extractu(ATMP,EXPBA)
+ ATMP = asr(ATMP,EXPB)
+ }
+ {
+ p0 = cmp.gtu(ONE,B)
+ if (!p0.new) ATMPL = or(ATMPL,S_ONE)
+ ATMPH = setbit(ATMPH,#HI_MANTBITS+FUDGE2)
+ }
+ {
+ CTMP = neg(ATMP)
+ p1 = bitsclr(ATMPL,#(1<<FUDGE2)-1)
+ if (!p1.new) AH = or(AH,AL)
+ B = #0
+ }
+ {
+ if (p3) CTMP = ATMP
+ USR = AH
+ TMP = #-BIAS-(MANTBITS+FUDGE2)
+ }
+ {
+ A = convert_d2df(CTMP)
+ }
+ {
+ AH += asl(TMP,#HI_MANTBITS)
+ dealloc_return
+ }
+.Lpossible_unf:
+ {
+ TMP = ##0x7fefffff
+ ATMP = abs(CTMP)
+ }
+ {
+ p0 = cmp.eq(AL,#0)
+ p0 = bitsclr(AH,TMP)
+ if (!p0.new) dealloc_return:t
+ TMP = #0x7fff
+ }
+ {
+ p0 = bitsset(ATMPH,TMP)
+ BH = USR
+ BL = #0x0030
+ }
+ {
+ if (p0) BH = or(BH,BL)
+ }
+ {
+ USR = BH
+ }
+ {
+ p0 = dfcmp.eq(A,A)
+ dealloc_return
+ }
+.Lfma_ovf:
+ {
+ TMP = USR
+ CTMP = combine(##0x7fefffff,#-1)
+ A = CTMP
+ }
+ {
+ ATMP = combine(##0x7ff00000,#0)
+ BH = extractu(TMP,#2,#SR_ROUND_OFF)
+ TMP = or(TMP,#0x28)
+ }
+ {
+ USR = TMP
+ BH ^= lsr(AH,#31)
+ BL = BH
+ }
+ {
+ p0 = !cmp.eq(BL,#1)
+ p0 = !cmp.eq(BH,#2)
+ }
+ {
+ p0 = dfcmp.eq(ATMP,ATMP)
+ if (p0.new) CTMP = ATMP
+ }
+ {
+ A = insert(CTMP,#63,#0)
+ dealloc_return
+ }
+#undef CTMP
+#undef CTMPH
+#undef CTMPL
+#define BTMP r11:10
+#define BTMPH r11
+#define BTMPL r10
+
+#undef STICKIES
+#undef STICKIESH
+#undef STICKIESL
+#define C r5:4
+#define CH r5
+#define CL r4
+
+.Lfma_abnormal_ab:
+ {
+ ATMP = extractu(A,#63,#0)
+ BTMP = extractu(B,#63,#0)
+ deallocframe
+ }
+ {
+ p3 = cmp.gtu(ATMP,BTMP)
+ if (!p3.new) A = B // sort values
+ if (!p3.new) B = A
+ }
+ {
+ p0 = dfclass(A,#0x0f) // A NaN?
+ if (!p0.new) jump:nt .Lnan
+ if (!p3) ATMP = BTMP
+ if (!p3) BTMP = ATMP
+ }
+ {
+ p1 = dfclass(A,#0x08) // A is infinity
+ p1 = dfclass(B,#0x0e) // B is nonzero
+ }
+ {
+ p0 = dfclass(A,#0x08) // a is inf
+ p0 = dfclass(B,#0x01) // b is zero
+ }
+ {
+ if (p1) jump .Lab_inf
+ p2 = dfclass(B,#0x01)
+ }
+ {
+ if (p0) jump .Linvalid
+ if (p2) jump .Lab_true_zero
+ TMP = ##0x7c000000
+ }
+ // We are left with a normal or subnormal times a subnormal, A > B
+ // If A and B are both very small, we will go to a single sticky bit; replace
+ // A and B lower 63 bits with 0x0010_0000_0000_0000, which yields equivalent results
+ // if A and B might multiply to something bigger, decrease A exp and increase B exp
+ // and start over
+ {
+ p0 = bitsclr(AH,TMP)
+ if (p0.new) jump:nt .Lfma_ab_tiny
+ }
+ {
+ TMP = add(clb(BTMP),#-EXPBITS)
+ }
+ {
+ BTMP = asl(BTMP,TMP)
+ }
+ {
+ B = insert(BTMP,#63,#0)
+ AH -= asl(TMP,#HI_MANTBITS)
+ }
+ jump .Lfma_begin
+
+.Lfma_ab_tiny:
+ ATMP = combine(##0x00100000,#0)
+ {
+ A = insert(ATMP,#63,#0)
+ B = insert(ATMP,#63,#0)
+ }
+ jump .Lfma_begin
+
+.Lab_inf:
+ {
+ B = lsr(B,#63)
+ p0 = dfclass(C,#0x10)
+ }
+ {
+ A ^= asl(B,#63)
+ if (p0) jump .Lnan
+ }
+ {
+ p1 = dfclass(C,#0x08)
+ if (p1.new) jump:nt .Lfma_inf_plus_inf
+ }
+ // A*B is +/- inf, C is finite. Return A
+ {
+ jumpr r31
+ }
+ .falign
+.Lfma_inf_plus_inf:
+ { // adding infinities of different signs is invalid
+ p0 = dfcmp.eq(A,C)
+ if (!p0.new) jump:nt .Linvalid
+ }
+ {
+ jumpr r31
+ }
+
+.Lnan:
+ {
+ p0 = dfclass(B,#0x10)
+ p1 = dfclass(C,#0x10)
+ if (!p0.new) B = A
+ if (!p1.new) C = A
+ }
+ { // find sNaNs
+ BH = convert_df2sf(B)
+ BL = convert_df2sf(C)
+ }
+ {
+ BH = convert_df2sf(A)
+ A = #-1
+ jumpr r31
+ }
+
+.Linvalid:
+ {
+ TMP = ##0x7f800001 // sp snan
+ }
+ {
+ A = convert_sf2df(TMP)
+ jumpr r31
+ }
+
+.Lab_true_zero:
+ // B is zero, A is finite number
+ {
+ p0 = dfclass(C,#0x10)
+ if (p0.new) jump:nt .Lnan
+ if (p0.new) A = C
+ }
+ {
+ p0 = dfcmp.eq(B,C) // is C also zero?
+ AH = lsr(AH,#31) // get sign
+ }
+ {
+ BH ^= asl(AH,#31) // form correctly signed zero in B
+ if (!p0) A = C // If C is not zero, return C
+ if (!p0) jumpr r31
+ }
+ // B has correctly signed zero, C is also zero
+.Lzero_plus_zero:
+ {
+ p0 = cmp.eq(B,C) // yes, scalar equals. +0++0 or -0+-0
+ if (p0.new) jumpr:t r31
+ A = B
+ }
+ {
+ TMP = USR
+ }
+ {
+ TMP = extractu(TMP,#2,#SR_ROUND_OFF)
+ A = #0
+ }
+ {
+ p0 = cmp.eq(TMP,#2)
+ if (p0.new) AH = ##0x80000000
+ jumpr r31
+ }
+#undef BTMP
+#undef BTMPH
+#undef BTMPL
+#define CTMP r11:10
+ .falign
+.Lfma_abnormal_c:
+ // We know that AB is normal * normal
+ // C is not normal: zero, subnormal, inf, or NaN.
+ {
+ p0 = dfclass(C,#0x10) // is C NaN?
+ if (p0.new) jump:nt .Lnan
+ if (p0.new) A = C // move NaN to A
+ deallocframe
+ }
+ {
+ p0 = dfclass(C,#0x08) // is C inf?
+ if (p0.new) A = C // return C
+ if (p0.new) jumpr:nt r31
+ }
+ // zero or subnormal
+ // If we have a zero, and we know AB is normal*normal, we can just call normal multiply
+ {
+ p0 = dfclass(C,#0x01) // is C zero?
+ if (p0.new) jump:nt __hexagon_muldf3
+ TMP = #1
+ }
+ // Left with: subnormal
+ // Adjust C and jump back to restart
+ {
+ allocframe(#STACKSPACE) // oops, deallocated above, re-allocate frame
+ CTMP = #0
+ CH = insert(TMP,#EXPBITS,#HI_MANTBITS)
+ jump .Lfma_abnormal_c_restart
+ }
+END(fma)
diff --git a/contrib/libs/cxxsupp/builtins/hexagon/dfminmax.S b/contrib/libs/cxxsupp/builtins/hexagon/dfminmax.S
new file mode 100644
index 0000000000..44f031ba11
--- /dev/null
+++ b/contrib/libs/cxxsupp/builtins/hexagon/dfminmax.S
@@ -0,0 +1,75 @@
+//===----------------------Hexagon builtin routine ------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#define A r1:0
+#define B r3:2
+#define ATMP r5:4
+
+
+#define Q6_ALIAS(TAG) .global __qdsp_##TAG ; .set __qdsp_##TAG, __hexagon_##TAG
+#define END(TAG) .size TAG,.-TAG
+
+// Min and Max return A if B is NaN, or B if A is NaN
+// Otherwise, they return the smaller or bigger value
+//
+// If values are equal, we want to favor -0.0 for min and +0.0 for max.
+
+// Compares always return false for NaN
+// if (isnan(A)) A = B; if (A > B) A = B will only trigger at most one of those options.
+
+ .text
+ .global __hexagon_mindf3
+ .global __hexagon_maxdf3
+ .global fmin
+ .type fmin,@function
+ .global fmax
+ .type fmax,@function
+ .type __hexagon_mindf3,@function
+ .type __hexagon_maxdf3,@function
+ Q6_ALIAS(mindf3)
+ Q6_ALIAS(maxdf3)
+ .p2align 5
+__hexagon_mindf3:
+fmin:
+ {
+ p0 = dfclass(A,#0x10) // If A is a number
+ p1 = dfcmp.gt(A,B) // AND B > A, don't swap
+ ATMP = A
+ }
+ {
+ if (p0) A = B // if A is NaN use B
+ if (p1) A = B // gt is always false if either is NaN
+ p2 = dfcmp.eq(A,B) // if A == B
+ if (!p2.new) jumpr:t r31
+ }
+ // A == B, return A|B to select -0.0 over 0.0
+ {
+ A = or(ATMP,B)
+ jumpr r31
+ }
+END(__hexagon_mindf3)
+ .falign
+__hexagon_maxdf3:
+fmax:
+ {
+ p0 = dfclass(A,#0x10)
+ p1 = dfcmp.gt(B,A)
+ ATMP = A
+ }
+ {
+ if (p0) A = B
+ if (p1) A = B
+ p2 = dfcmp.eq(A,B)
+ if (!p2.new) jumpr:t r31
+ }
+ // A == B, return A&B to select 0.0 over -0.0
+ {
+ A = and(ATMP,B)
+ jumpr r31
+ }
+END(__hexagon_maxdf3)
diff --git a/contrib/libs/cxxsupp/builtins/hexagon/dfmul.S b/contrib/libs/cxxsupp/builtins/hexagon/dfmul.S
new file mode 100644
index 0000000000..e6f62c3515
--- /dev/null
+++ b/contrib/libs/cxxsupp/builtins/hexagon/dfmul.S
@@ -0,0 +1,413 @@
+//===----------------------Hexagon builtin routine ------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// Double Precision Multiply
+#define A r1:0
+#define AH r1
+#define AL r0
+#define B r3:2
+#define BH r3
+#define BL r2
+
+#define BTMP r5:4
+#define BTMPH r5
+#define BTMPL r4
+
+#define PP_ODD r7:6
+#define PP_ODD_H r7
+#define PP_ODD_L r6
+
+#define ONE r9:8
+#define S_ONE r8
+#define S_ZERO r9
+
+#define PP_HH r11:10
+#define PP_HH_H r11
+#define PP_HH_L r10
+
+#define ATMP r13:12
+#define ATMPH r13
+#define ATMPL r12
+
+#define PP_LL r15:14
+#define PP_LL_H r15
+#define PP_LL_L r14
+
+#define TMP r28
+
+#define MANTBITS 52
+#define HI_MANTBITS 20
+#define EXPBITS 11
+#define BIAS 1024
+#define MANTISSA_TO_INT_BIAS 52
+
+// Some constant to adjust normalization amount in error code
+// Amount to right shift the partial product to get to a denorm
+#define FUDGE 5
+
+#define Q6_ALIAS(TAG) .global __qdsp_##TAG ; .set __qdsp_##TAG, __hexagon_##TAG
+#define FAST_ALIAS(TAG) .global __hexagon_fast_##TAG ; .set __hexagon_fast_##TAG, __hexagon_##TAG
+#define FAST2_ALIAS(TAG) .global __hexagon_fast2_##TAG ; .set __hexagon_fast2_##TAG, __hexagon_##TAG
+#define END(TAG) .size TAG,.-TAG
+
+#define SR_ROUND_OFF 22
+ .text
+ .global __hexagon_muldf3
+ .type __hexagon_muldf3,@function
+ Q6_ALIAS(muldf3)
+ FAST_ALIAS(muldf3)
+ FAST2_ALIAS(muldf3)
+ .p2align 5
+__hexagon_muldf3:
+ {
+ p0 = dfclass(A,#2)
+ p0 = dfclass(B,#2)
+ ATMP = combine(##0x40000000,#0)
+ }
+ {
+ ATMP = insert(A,#MANTBITS,#EXPBITS-1)
+ BTMP = asl(B,#EXPBITS-1)
+ TMP = #-BIAS
+ ONE = #1
+ }
+ {
+ PP_ODD = mpyu(BTMPL,ATMPH)
+ BTMP = insert(ONE,#2,#62)
+ }
+ // since we know that the MSB of the H registers is zero, we should never carry
+ // H <= 2^31-1. L <= 2^32-1. Therefore, HL <= 2^63-2^32-2^31+1
+ // Adding 2 HLs, we get 2^64-3*2^32+2 maximum.
+ // Therefore, we can add 3 2^32-1 values safely without carry. We only need one.
+ {
+ PP_LL = mpyu(ATMPL,BTMPL)
+ PP_ODD += mpyu(ATMPL,BTMPH)
+ }
+ {
+ PP_ODD += lsr(PP_LL,#32)
+ PP_HH = mpyu(ATMPH,BTMPH)
+ BTMP = combine(##BIAS+BIAS-4,#0)
+ }
+ {
+ PP_HH += lsr(PP_ODD,#32)
+ if (!p0) jump .Lmul_abnormal
+ p1 = cmp.eq(PP_LL_L,#0) // 64 lsb's 0?
+ p1 = cmp.eq(PP_ODD_L,#0) // 64 lsb's 0?
+ }
+
+ // PP_HH can have a maximum of 0x3FFF_FFFF_FFFF_FFFF or thereabouts
+ // PP_HH can have a minimum of 0x1000_0000_0000_0000 or so
+
+#undef PP_ODD
+#undef PP_ODD_H
+#undef PP_ODD_L
+#define EXP10 r7:6
+#define EXP1 r7
+#define EXP0 r6
+ {
+ if (!p1) PP_HH_L = or(PP_HH_L,S_ONE)
+ EXP0 = extractu(AH,#EXPBITS,#HI_MANTBITS)
+ EXP1 = extractu(BH,#EXPBITS,#HI_MANTBITS)
+ }
+ {
+ PP_LL = neg(PP_HH)
+ EXP0 += add(TMP,EXP1)
+ TMP = xor(AH,BH)
+ }
+ {
+ if (!p2.new) PP_HH = PP_LL
+ p2 = cmp.gt(TMP,#-1)
+ p0 = !cmp.gt(EXP0,BTMPH)
+ p0 = cmp.gt(EXP0,BTMPL)
+ if (!p0.new) jump:nt .Lmul_ovf_unf
+ }
+ {
+ A = convert_d2df(PP_HH)
+ EXP0 = add(EXP0,#-BIAS-58)
+ }
+ {
+ AH += asl(EXP0,#HI_MANTBITS)
+ jumpr r31
+ }
+
+ .falign
+.Lpossible_unf:
+ // We end up with a positive exponent
+ // But we may have rounded up to an exponent of 1.
+ // If the exponent is 1, if we rounded up to it
+ // we need to also raise underflow
+ // Fortunately, this is pretty easy to detect, we must have +/- 0x0010_0000_0000_0000
+ // And the PP should also have more than one bit set
+ //
+ // Note: ATMP should have abs(PP_HH)
+ // Note: BTMPL should have 0x7FEFFFFF
+ {
+ p0 = cmp.eq(AL,#0)
+ p0 = bitsclr(AH,BTMPL)
+ if (!p0.new) jumpr:t r31
+ BTMPH = #0x7fff
+ }
+ {
+ p0 = bitsset(ATMPH,BTMPH)
+ BTMPL = USR
+ BTMPH = #0x030
+ }
+ {
+ if (p0) BTMPL = or(BTMPL,BTMPH)
+ }
+ {
+ USR = BTMPL
+ }
+ {
+ p0 = dfcmp.eq(A,A)
+ jumpr r31
+ }
+ .falign
+.Lmul_ovf_unf:
+ {
+ A = convert_d2df(PP_HH)
+ ATMP = abs(PP_HH) // take absolute value
+ EXP1 = add(EXP0,#-BIAS-58)
+ }
+ {
+ AH += asl(EXP1,#HI_MANTBITS)
+ EXP1 = extractu(AH,#EXPBITS,#HI_MANTBITS)
+ BTMPL = ##0x7FEFFFFF
+ }
+ {
+ EXP1 += add(EXP0,##-BIAS-58)
+ //BTMPH = add(clb(ATMP),#-2)
+ BTMPH = #0
+ }
+ {
+ p0 = cmp.gt(EXP1,##BIAS+BIAS-2) // overflow
+ if (p0.new) jump:nt .Lmul_ovf
+ }
+ {
+ p0 = cmp.gt(EXP1,#0)
+ if (p0.new) jump:nt .Lpossible_unf
+ BTMPH = sub(EXP0,BTMPH)
+ TMP = #63 // max amount to shift
+ }
+ // Underflow
+ //
+ // PP_HH has the partial product with sticky LSB.
+ // PP_HH can have a maximum of 0x3FFF_FFFF_FFFF_FFFF or thereabouts
+ // PP_HH can have a minimum of 0x1000_0000_0000_0000 or so
+ // The exponent of PP_HH is in EXP1, which is non-positive (0 or negative)
+ // That's the exponent that happens after the normalization
+ //
+ // EXP0 has the exponent that, when added to the normalized value, is out of range.
+ //
+ // Strategy:
+ //
+ // * Shift down bits, with sticky bit, such that the bits are aligned according
+ // to the LZ count and appropriate exponent, but not all the way to mantissa
+ // field, keep around the last few bits.
+ // * Put a 1 near the MSB
+ // * Check the LSBs for inexact; if inexact also set underflow
+ // * Convert [u]d2df -- will correctly round according to rounding mode
+ // * Replace exponent field with zero
+
+ {
+ BTMPL = #0 // offset for extract
+ BTMPH = sub(#FUDGE,BTMPH) // amount to right shift
+ }
+ {
+ p3 = cmp.gt(PP_HH_H,#-1) // is it positive?
+ BTMPH = min(BTMPH,TMP) // Don't shift more than 63
+ PP_HH = ATMP
+ }
+ {
+ TMP = USR
+ PP_LL = extractu(PP_HH,BTMP)
+ }
+ {
+ PP_HH = asr(PP_HH,BTMPH)
+ BTMPL = #0x0030 // underflow flag
+ AH = insert(S_ZERO,#EXPBITS,#HI_MANTBITS)
+ }
+ {
+ p0 = cmp.gtu(ONE,PP_LL) // Did we extract all zeros?
+ if (!p0.new) PP_HH_L = or(PP_HH_L,S_ONE) // add sticky bit
+ PP_HH_H = setbit(PP_HH_H,#HI_MANTBITS+3) // Add back in a bit so we can use convert instruction
+ }
+ {
+ PP_LL = neg(PP_HH)
+ p1 = bitsclr(PP_HH_L,#0x7) // Are the LSB's clear?
+ if (!p1.new) TMP = or(BTMPL,TMP) // If not, Inexact+Underflow
+ }
+ {
+ if (!p3) PP_HH = PP_LL
+ USR = TMP
+ }
+ {
+ A = convert_d2df(PP_HH) // Do rounding
+ p0 = dfcmp.eq(A,A) // realize exception
+ }
+ {
+ AH = insert(S_ZERO,#EXPBITS-1,#HI_MANTBITS+1) // Insert correct exponent
+ jumpr r31
+ }
+ .falign
+.Lmul_ovf:
+ // We get either max finite value or infinity. Either way, overflow+inexact
+ {
+ TMP = USR
+ ATMP = combine(##0x7fefffff,#-1) // positive max finite
+ A = PP_HH
+ }
+ {
+ PP_LL_L = extractu(TMP,#2,#SR_ROUND_OFF) // rounding bits
+ TMP = or(TMP,#0x28) // inexact + overflow
+ BTMP = combine(##0x7ff00000,#0) // positive infinity
+ }
+ {
+ USR = TMP
+ PP_LL_L ^= lsr(AH,#31) // Does sign match rounding?
+ TMP = PP_LL_L // unmodified rounding mode
+ }
+ {
+ p0 = !cmp.eq(TMP,#1) // If not round-to-zero and
+ p0 = !cmp.eq(PP_LL_L,#2) // Not rounding the other way,
+ if (p0.new) ATMP = BTMP // we should get infinity
+ p0 = dfcmp.eq(A,A) // Realize FP exception if enabled
+ }
+ {
+ A = insert(ATMP,#63,#0) // insert inf/maxfinite, leave sign
+ jumpr r31
+ }
+
+.Lmul_abnormal:
+ {
+ ATMP = extractu(A,#63,#0) // strip off sign
+ BTMP = extractu(B,#63,#0) // strip off sign
+ }
+ {
+ p3 = cmp.gtu(ATMP,BTMP)
+ if (!p3.new) A = B // sort values
+ if (!p3.new) B = A // sort values
+ }
+ {
+ // Any NaN --> NaN, possibly raise invalid if sNaN
+ p0 = dfclass(A,#0x0f) // A not NaN?
+ if (!p0.new) jump:nt .Linvalid_nan
+ if (!p3) ATMP = BTMP
+ if (!p3) BTMP = ATMP
+ }
+ {
+ // Infinity * nonzero number is infinity
+ p1 = dfclass(A,#0x08) // A is infinity
+ p1 = dfclass(B,#0x0e) // B is nonzero
+ }
+ {
+ // Infinity * zero --> NaN, raise invalid
+ // Other zeros return zero
+ p0 = dfclass(A,#0x08) // A is infinity
+ p0 = dfclass(B,#0x01) // B is zero
+ }
+ {
+ if (p1) jump .Ltrue_inf
+ p2 = dfclass(B,#0x01)
+ }
+ {
+ if (p0) jump .Linvalid_zeroinf
+ if (p2) jump .Ltrue_zero // so return zero
+ TMP = ##0x7c000000
+ }
+ // We are left with a normal or subnormal times a subnormal. A > B
+ // If A and B are both very small (exp(a) < BIAS-MANTBITS),
+ // we go to a single sticky bit, which we can round easily.
+ // If A and B might multiply to something bigger, decrease A exponent and increase
+ // B exponent and try again
+ {
+ p0 = bitsclr(AH,TMP)
+ if (p0.new) jump:nt .Lmul_tiny
+ }
+ {
+ TMP = cl0(BTMP)
+ }
+ {
+ TMP = add(TMP,#-EXPBITS)
+ }
+ {
+ BTMP = asl(BTMP,TMP)
+ }
+ {
+ B = insert(BTMP,#63,#0)
+ AH -= asl(TMP,#HI_MANTBITS)
+ }
+ jump __hexagon_muldf3
+.Lmul_tiny:
+ {
+ TMP = USR
+ A = xor(A,B) // get sign bit
+ }
+ {
+ TMP = or(TMP,#0x30) // Inexact + Underflow
+ A = insert(ONE,#63,#0) // put in rounded up value
+ BTMPH = extractu(TMP,#2,#SR_ROUND_OFF) // get rounding mode
+ }
+ {
+ USR = TMP
+ p0 = cmp.gt(BTMPH,#1) // Round towards pos/neg inf?
+ if (!p0.new) AL = #0 // If not, zero
+ BTMPH ^= lsr(AH,#31) // rounding my way --> set LSB
+ }
+ {
+ p0 = cmp.eq(BTMPH,#3) // if rounding towards right inf
+ if (!p0.new) AL = #0 // don't go to zero
+ jumpr r31
+ }
+.Linvalid_zeroinf:
+ {
+ TMP = USR
+ }
+ {
+ A = #-1
+ TMP = or(TMP,#2)
+ }
+ {
+ USR = TMP
+ }
+ {
+ p0 = dfcmp.uo(A,A) // force exception if enabled
+ jumpr r31
+ }
+.Linvalid_nan:
+ {
+ p0 = dfclass(B,#0x0f) // if B is not NaN
+ TMP = convert_df2sf(A) // will generate invalid if sNaN
+ if (p0.new) B = A // make it whatever A is
+ }
+ {
+ BL = convert_df2sf(B) // will generate invalid if sNaN
+ A = #-1
+ jumpr r31
+ }
+ .falign
+.Ltrue_zero:
+ {
+ A = B
+ B = A
+ }
+.Ltrue_inf:
+ {
+ BH = extract(BH,#1,#31)
+ }
+ {
+ AH ^= asl(BH,#31)
+ jumpr r31
+ }
+END(__hexagon_muldf3)
+
+#undef ATMP
+#undef ATMPL
+#undef ATMPH
+#undef BTMP
+#undef BTMPL
+#undef BTMPH
diff --git a/contrib/libs/cxxsupp/builtins/hexagon/dfsqrt.S b/contrib/libs/cxxsupp/builtins/hexagon/dfsqrt.S
new file mode 100644
index 0000000000..f1435e8683
--- /dev/null
+++ b/contrib/libs/cxxsupp/builtins/hexagon/dfsqrt.S
@@ -0,0 +1,405 @@
+//===----------------------Hexagon builtin routine ------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// Double Precision square root
+
+#define EXP r28
+
+#define A r1:0
+#define AH r1
+#define AL r0
+
+#define SFSH r3:2
+#define SF_S r3
+#define SF_H r2
+
+#define SFHALF_SONE r5:4
+#define S_ONE r4
+#define SFHALF r5
+#define SF_D r6
+#define SF_E r7
+#define RECIPEST r8
+#define SFRAD r9
+
+#define FRACRAD r11:10
+#define FRACRADH r11
+#define FRACRADL r10
+
+#define ROOT r13:12
+#define ROOTHI r13
+#define ROOTLO r12
+
+#define PROD r15:14
+#define PRODHI r15
+#define PRODLO r14
+
+#define P_TMP p0
+#define P_EXP1 p1
+#define NORMAL p2
+
+#define SF_EXPBITS 8
+#define SF_MANTBITS 23
+
+#define DF_EXPBITS 11
+#define DF_MANTBITS 52
+
+#define DF_BIAS 0x3ff
+
+#define DFCLASS_ZERO 0x01
+#define DFCLASS_NORMAL 0x02
+#define DFCLASS_DENORMAL 0x02
+#define DFCLASS_INFINITE 0x08
+#define DFCLASS_NAN 0x10
+
+#define Q6_ALIAS(TAG) .global __qdsp_##TAG ; .set __qdsp_##TAG, __hexagon_##TAG; .type __qdsp_##TAG,@function
+#define FAST_ALIAS(TAG) .global __hexagon_fast_##TAG ; .set __hexagon_fast_##TAG, __hexagon_##TAG; .type __hexagon_fast_##TAG,@function
+#define FAST2_ALIAS(TAG) .global __hexagon_fast2_##TAG ; .set __hexagon_fast2_##TAG, __hexagon_##TAG; .type __hexagon_fast2_##TAG,@function
+#define END(TAG) .size TAG,.-TAG
+
+ .text
+ .global __hexagon_sqrtdf2
+ .type __hexagon_sqrtdf2,@function
+ .global __hexagon_sqrt
+ .type __hexagon_sqrt,@function
+ Q6_ALIAS(sqrtdf2)
+ Q6_ALIAS(sqrt)
+ FAST_ALIAS(sqrtdf2)
+ FAST_ALIAS(sqrt)
+ FAST2_ALIAS(sqrtdf2)
+ FAST2_ALIAS(sqrt)
+ .type sqrt,@function
+ .p2align 5
+__hexagon_sqrtdf2:
+__hexagon_sqrt:
+ {
+ PROD = extractu(A,#SF_MANTBITS+1,#DF_MANTBITS-SF_MANTBITS)
+ EXP = extractu(AH,#DF_EXPBITS,#DF_MANTBITS-32)
+ SFHALF_SONE = combine(##0x3f000004,#1)
+ }
+ {
+ NORMAL = dfclass(A,#DFCLASS_NORMAL) // Is it normal
+ NORMAL = cmp.gt(AH,#-1) // and positive?
+ if (!NORMAL.new) jump:nt .Lsqrt_abnormal
+ SFRAD = or(SFHALF,PRODLO)
+ }
+#undef NORMAL
+.Ldenormal_restart:
+ {
+ FRACRAD = A
+ SF_E,P_TMP = sfinvsqrta(SFRAD)
+ SFHALF = and(SFHALF,#-16)
+ SFSH = #0
+ }
+#undef A
+#undef AH
+#undef AL
+#define ERROR r1:0
+#define ERRORHI r1
+#define ERRORLO r0
+ // SF_E : reciprocal square root
+ // SF_H : half rsqrt
+ // sf_S : square root
+ // SF_D : error term
+ // SFHALF: 0.5
+ {
+ SF_S += sfmpy(SF_E,SFRAD):lib // s0: root
+ SF_H += sfmpy(SF_E,SFHALF):lib // h0: 0.5*y0. Could also decrement exponent...
+ SF_D = SFHALF
+#undef SFRAD
+#define SHIFTAMT r9
+ SHIFTAMT = and(EXP,#1)
+ }
+ {
+ SF_D -= sfmpy(SF_S,SF_H):lib // d0: 0.5-H*S = 0.5-0.5*~1
+ FRACRADH = insert(S_ONE,#DF_EXPBITS+1,#DF_MANTBITS-32) // replace upper bits with hidden
+ P_EXP1 = cmp.gtu(SHIFTAMT,#0)
+ }
+ {
+ SF_S += sfmpy(SF_S,SF_D):lib // s1: refine sqrt
+ SF_H += sfmpy(SF_H,SF_D):lib // h1: refine half-recip
+ SF_D = SFHALF
+ SHIFTAMT = mux(P_EXP1,#8,#9)
+ }
+ {
+ SF_D -= sfmpy(SF_S,SF_H):lib // d1: error term
+ FRACRAD = asl(FRACRAD,SHIFTAMT) // Move fracrad bits to right place
+ SHIFTAMT = mux(P_EXP1,#3,#2)
+ }
+ {
+ SF_H += sfmpy(SF_H,SF_D):lib // d2: rsqrt
+ // cool trick: half of 1/sqrt(x) has same mantissa as 1/sqrt(x).
+ PROD = asl(FRACRAD,SHIFTAMT) // fracrad<<(2+exp1)
+ }
+ {
+ SF_H = and(SF_H,##0x007fffff)
+ }
+ {
+ SF_H = add(SF_H,##0x00800000 - 3)
+ SHIFTAMT = mux(P_EXP1,#7,#8)
+ }
+ {
+ RECIPEST = asl(SF_H,SHIFTAMT)
+ SHIFTAMT = mux(P_EXP1,#15-(1+1),#15-(1+0))
+ }
+ {
+ ROOT = mpyu(RECIPEST,PRODHI) // root = mpyu_full(recipest,hi(fracrad<<(2+exp1)))
+ }
+
+#undef SFSH // r3:2
+#undef SF_H // r2
+#undef SF_S // r3
+#undef S_ONE // r4
+#undef SFHALF // r5
+#undef SFHALF_SONE // r5:4
+#undef SF_D // r6
+#undef SF_E // r7
+
+#define HL r3:2
+#define LL r5:4
+#define HH r7:6
+
+#undef P_EXP1
+#define P_CARRY0 p1
+#define P_CARRY1 p2
+#define P_CARRY2 p3
+
+ // Iteration 0
+ // Maybe we can save a cycle by starting with ERROR=asl(fracrad), then as we multiply
+ // We can shift and subtract instead of shift and add?
+ {
+ ERROR = asl(FRACRAD,#15)
+ PROD = mpyu(ROOTHI,ROOTHI)
+ P_CARRY0 = cmp.eq(r0,r0)
+ }
+ {
+ ERROR -= asl(PROD,#15)
+ PROD = mpyu(ROOTHI,ROOTLO)
+ P_CARRY1 = cmp.eq(r0,r0)
+ }
+ {
+ ERROR -= lsr(PROD,#16)
+ P_CARRY2 = cmp.eq(r0,r0)
+ }
+ {
+ ERROR = mpyu(ERRORHI,RECIPEST)
+ }
+ {
+ ROOT += lsr(ERROR,SHIFTAMT)
+ SHIFTAMT = add(SHIFTAMT,#16)
+ ERROR = asl(FRACRAD,#31) // for next iter
+ }
+ // Iteration 1
+ {
+ PROD = mpyu(ROOTHI,ROOTHI)
+ ERROR -= mpyu(ROOTHI,ROOTLO) // amount is 31, no shift needed
+ }
+ {
+ ERROR -= asl(PROD,#31)
+ PROD = mpyu(ROOTLO,ROOTLO)
+ }
+ {
+ ERROR -= lsr(PROD,#33)
+ }
+ {
+ ERROR = mpyu(ERRORHI,RECIPEST)
+ }
+ {
+ ROOT += lsr(ERROR,SHIFTAMT)
+ SHIFTAMT = add(SHIFTAMT,#16)
+ ERROR = asl(FRACRAD,#47) // for next iter
+ }
+ // Iteration 2
+ {
+ PROD = mpyu(ROOTHI,ROOTHI)
+ }
+ {
+ ERROR -= asl(PROD,#47)
+ PROD = mpyu(ROOTHI,ROOTLO)
+ }
+ {
+ ERROR -= asl(PROD,#16) // bidir shr 31-47
+ PROD = mpyu(ROOTLO,ROOTLO)
+ }
+ {
+ ERROR -= lsr(PROD,#17) // 64-47
+ }
+ {
+ ERROR = mpyu(ERRORHI,RECIPEST)
+ }
+ {
+ ROOT += lsr(ERROR,SHIFTAMT)
+ }
+#undef ERROR
+#undef PROD
+#undef PRODHI
+#undef PRODLO
+#define REM_HI r15:14
+#define REM_HI_HI r15
+#define REM_LO r1:0
+#undef RECIPEST
+#undef SHIFTAMT
+#define TWOROOT_LO r9:8
+ // Adjust Root
+ {
+ HL = mpyu(ROOTHI,ROOTLO)
+ LL = mpyu(ROOTLO,ROOTLO)
+ REM_HI = #0
+ REM_LO = #0
+ }
+ {
+ HL += lsr(LL,#33)
+ LL += asl(HL,#33)
+ P_CARRY0 = cmp.eq(r0,r0)
+ }
+ {
+ HH = mpyu(ROOTHI,ROOTHI)
+ REM_LO = sub(REM_LO,LL,P_CARRY0):carry
+ TWOROOT_LO = #1
+ }
+ {
+ HH += lsr(HL,#31)
+ TWOROOT_LO += asl(ROOT,#1)
+ }
+#undef HL
+#undef LL
+#define REM_HI_TMP r3:2
+#define REM_HI_TMP_HI r3
+#define REM_LO_TMP r5:4
+ {
+ REM_HI = sub(FRACRAD,HH,P_CARRY0):carry
+ REM_LO_TMP = sub(REM_LO,TWOROOT_LO,P_CARRY1):carry
+#undef FRACRAD
+#undef HH
+#define ZERO r11:10
+#define ONE r7:6
+ ONE = #1
+ ZERO = #0
+ }
+ {
+ REM_HI_TMP = sub(REM_HI,ZERO,P_CARRY1):carry
+ ONE = add(ROOT,ONE)
+ EXP = add(EXP,#-DF_BIAS) // subtract bias --> signed exp
+ }
+ {
+ // If carry set, no borrow: result was still positive
+ if (P_CARRY1) ROOT = ONE
+ if (P_CARRY1) REM_LO = REM_LO_TMP
+ if (P_CARRY1) REM_HI = REM_HI_TMP
+ }
+ {
+ REM_LO_TMP = sub(REM_LO,TWOROOT_LO,P_CARRY2):carry
+ ONE = #1
+ EXP = asr(EXP,#1) // divide signed exp by 2
+ }
+ {
+ REM_HI_TMP = sub(REM_HI,ZERO,P_CARRY2):carry
+ ONE = add(ROOT,ONE)
+ }
+ {
+ if (P_CARRY2) ROOT = ONE
+ if (P_CARRY2) REM_LO = REM_LO_TMP
+ // since tworoot <= 2^32, remhi must be zero
+#undef REM_HI_TMP
+#undef REM_HI_TMP_HI
+#define S_ONE r2
+#define ADJ r3
+ S_ONE = #1
+ }
+ {
+ P_TMP = cmp.eq(REM_LO,ZERO) // is the low part zero
+ if (!P_TMP.new) ROOTLO = or(ROOTLO,S_ONE) // if so, it's exact... hopefully
+ ADJ = cl0(ROOT)
+ EXP = add(EXP,#-63)
+ }
+#undef REM_LO
+#define RET r1:0
+#define RETHI r1
+ {
+ RET = convert_ud2df(ROOT) // set up mantissa, maybe set inexact flag
+ EXP = add(EXP,ADJ) // add back bias
+ }
+ {
+ RETHI += asl(EXP,#DF_MANTBITS-32) // add exponent adjust
+ jumpr r31
+ }
+#undef REM_LO_TMP
+#undef REM_HI_TMP
+#undef REM_HI_TMP_HI
+#undef REM_LO
+#undef REM_HI
+#undef TWOROOT_LO
+
+#undef RET
+#define A r1:0
+#define AH r1
+#define AL r1
+#undef S_ONE
+#define TMP r3:2
+#define TMPHI r3
+#define TMPLO r2
+#undef P_CARRY0
+#define P_NEG p1
+
+
+#define SFHALF r5
+#define SFRAD r9
+.Lsqrt_abnormal:
+ {
+ P_TMP = dfclass(A,#DFCLASS_ZERO) // zero?
+ if (P_TMP.new) jumpr:t r31
+ }
+ {
+ P_TMP = dfclass(A,#DFCLASS_NAN)
+ if (P_TMP.new) jump:nt .Lsqrt_nan
+ }
+ {
+ P_TMP = cmp.gt(AH,#-1)
+ if (!P_TMP.new) jump:nt .Lsqrt_invalid_neg
+ if (!P_TMP.new) EXP = ##0x7F800001 // sNaN
+ }
+ {
+ P_TMP = dfclass(A,#DFCLASS_INFINITE)
+ if (P_TMP.new) jumpr:nt r31
+ }
+ // If we got here, we're denormal
+ // prepare to restart
+ {
+ A = extractu(A,#DF_MANTBITS,#0) // Extract mantissa
+ }
+ {
+ EXP = add(clb(A),#-DF_EXPBITS) // how much to normalize?
+ }
+ {
+ A = asl(A,EXP) // Shift mantissa
+ EXP = sub(#1,EXP) // Form exponent
+ }
+ {
+ AH = insert(EXP,#1,#DF_MANTBITS-32) // insert lsb of exponent
+ }
+ {
+ TMP = extractu(A,#SF_MANTBITS+1,#DF_MANTBITS-SF_MANTBITS) // get sf value (mant+exp1)
+ SFHALF = ##0x3f000004 // form half constant
+ }
+ {
+ SFRAD = or(SFHALF,TMPLO) // form sf value
+ SFHALF = and(SFHALF,#-16)
+ jump .Ldenormal_restart // restart
+ }
+.Lsqrt_nan:
+ {
+ EXP = convert_df2sf(A) // if sNaN, get invalid
+ A = #-1 // qNaN
+ jumpr r31
+ }
+.Lsqrt_invalid_neg:
+ {
+ A = convert_sf2df(EXP) // Invalid,NaNval
+ jumpr r31
+ }
+END(__hexagon_sqrt)
+END(__hexagon_sqrtdf2)
diff --git a/contrib/libs/cxxsupp/builtins/hexagon/divdi3.S b/contrib/libs/cxxsupp/builtins/hexagon/divdi3.S
new file mode 100644
index 0000000000..770601a470
--- /dev/null
+++ b/contrib/libs/cxxsupp/builtins/hexagon/divdi3.S
@@ -0,0 +1,84 @@
+//===----------------------Hexagon builtin routine ------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+ .macro FUNCTION_BEGIN name
+ .text
+ .p2align 5
+ .globl \name
+ .type \name, @function
+\name:
+ .endm
+
+ .macro FUNCTION_END name
+ .size \name, . - \name
+ .endm
+
+
+FUNCTION_BEGIN __hexagon_divdi3
+ {
+ p2 = tstbit(r1,#31)
+ p3 = tstbit(r3,#31)
+ }
+ {
+ r1:0 = abs(r1:0)
+ r3:2 = abs(r3:2)
+ }
+ {
+ r6 = cl0(r1:0) // count leading 0's of dividend (numerator)
+ r7 = cl0(r3:2) // count leading 0's of divisor (denominator)
+ r5:4 = r3:2 // divisor moved into working registers
+ r3:2 = r1:0 // dividend is the initial remainder, r3:2 contains remainder
+ }
+ {
+ p3 = xor(p2,p3)
+ r10 = sub(r7,r6) // left shift count for bit & divisor
+ r1:0 = #0 // initialize quotient to 0
+ r15:14 = #1 // initialize bit to 1
+ }
+ {
+ r11 = add(r10,#1) // loop count is 1 more than shift count
+ r13:12 = lsl(r5:4,r10) // shift divisor msb into same bit position as dividend msb
+ r15:14 = lsl(r15:14,r10) // shift the bit left by same amount as divisor
+ }
+ {
+ p0 = cmp.gtu(r5:4,r3:2) // check if divisor > dividend
+ loop0(1f,r11) // register loop
+ }
+ {
+ if (p0) jump .hexagon_divdi3_return // if divisor > dividend, we're done, so return
+ }
+ .falign
+1:
+ {
+ p0 = cmp.gtu(r13:12,r3:2) // set predicate reg if shifted divisor > current remainder
+ }
+ {
+ r7:6 = sub(r3:2, r13:12) // subtract shifted divisor from current remainder
+ r9:8 = add(r1:0, r15:14) // save current quotient to temp (r9:8)
+ }
+ {
+ r1:0 = vmux(p0, r1:0, r9:8) // choose either current quotient or new quotient (r9:8)
+ r3:2 = vmux(p0, r3:2, r7:6) // choose either current remainder or new remainder (r7:6)
+ }
+ {
+ r15:14 = lsr(r15:14, #1) // shift bit right by 1 for next iteration
+ r13:12 = lsr(r13:12, #1) // shift "shifted divisor" right by 1 for next iteration
+ }:endloop0
+
+.hexagon_divdi3_return:
+ {
+ r3:2 = neg(r1:0)
+ }
+ {
+ r1:0 = vmux(p3,r3:2,r1:0)
+ jumpr r31
+ }
+FUNCTION_END __hexagon_divdi3
+
+ .globl __qdsp_divdi3
+ .set __qdsp_divdi3, __hexagon_divdi3
diff --git a/contrib/libs/cxxsupp/builtins/hexagon/divsi3.S b/contrib/libs/cxxsupp/builtins/hexagon/divsi3.S
new file mode 100644
index 0000000000..5f406524e8
--- /dev/null
+++ b/contrib/libs/cxxsupp/builtins/hexagon/divsi3.S
@@ -0,0 +1,83 @@
+//===----------------------Hexagon builtin routine ------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+
+
+ .macro FUNCTION_BEGIN name
+ .text
+ .p2align 5
+ .globl \name
+ .type \name, @function
+\name:
+ .endm
+
+ .macro FUNCTION_END name
+ .size \name, . - \name
+ .endm
+
+
+FUNCTION_BEGIN __hexagon_divsi3
+ {
+ p0 = cmp.ge(r0,#0)
+ p1 = cmp.ge(r1,#0)
+ r1 = abs(r0)
+ r2 = abs(r1)
+ }
+ {
+ r3 = cl0(r1)
+ r4 = cl0(r2)
+ r5 = sub(r1,r2)
+ p2 = cmp.gtu(r2,r1)
+ }
+#if (__HEXAGON_ARCH__ == 60)
+ {
+ r0 = #0
+ p1 = xor(p0,p1)
+ p0 = cmp.gtu(r2,r5)
+ }
+ if (p2) jumpr r31
+#else
+ {
+ r0 = #0
+ p1 = xor(p0,p1)
+ p0 = cmp.gtu(r2,r5)
+ if (p2) jumpr r31
+ }
+#endif
+ {
+ r0 = mux(p1,#-1,#1)
+ if (p0) jumpr r31
+ r4 = sub(r4,r3)
+ r3 = #1
+ }
+ {
+ r0 = #0
+ r3:2 = vlslw(r3:2,r4)
+ loop0(1f,r4)
+ }
+ .falign
+1:
+ {
+ p0 = cmp.gtu(r2,r1)
+ if (!p0.new) r1 = sub(r1,r2)
+ if (!p0.new) r0 = add(r0,r3)
+ r3:2 = vlsrw(r3:2,#1)
+ }:endloop0
+ {
+ p0 = cmp.gtu(r2,r1)
+ if (!p0.new) r0 = add(r0,r3)
+ if (!p1) jumpr r31
+ }
+ {
+ r0 = neg(r0)
+ jumpr r31
+ }
+FUNCTION_END __hexagon_divsi3
+
+ .globl __qdsp_divsi3
+ .set __qdsp_divsi3, __hexagon_divsi3
diff --git a/contrib/libs/cxxsupp/builtins/hexagon/fastmath2_dlib_asm.S b/contrib/libs/cxxsupp/builtins/hexagon/fastmath2_dlib_asm.S
new file mode 100644
index 0000000000..574a04432f
--- /dev/null
+++ b/contrib/libs/cxxsupp/builtins/hexagon/fastmath2_dlib_asm.S
@@ -0,0 +1,490 @@
+//===----------------------Hexagon builtin routine ------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+/* ==================================================================== */
+/* FUNCTIONS Optimized double floating point operators */
+/* ==================================================================== */
+/* c = dadd_asm(a, b) */
+/* ==================================================================== *
+fast2_QDOUBLE fast2_dadd(fast2_QDOUBLE a,fast2_QDOUBLE b) {
+ fast2_QDOUBLE c;
+ lint manta = a & MANTMASK;
+ int expa = Q6_R_sxth_R(a) ;
+ lint mantb = b & MANTMASK;
+ int expb = Q6_R_sxth_R(b) ;
+ int exp, expdiff, j, k, hi, lo, cn;
+ lint mant;
+
+ expdiff = (int) Q6_P_vabsdiffh_PP(a, b);
+ expdiff = Q6_R_sxth_R(expdiff) ;
+ if (expdiff > 63) { expdiff = 62;}
+ if (expa > expb) {
+ exp = expa + 1;
+ expa = 1;
+ expb = expdiff + 1;
+ } else {
+ exp = expb + 1;
+ expb = 1;
+ expa = expdiff + 1;
+ }
+ mant = (manta>>expa) + (mantb>>expb);
+
+ hi = (int) (mant>>32);
+ lo = (int) (mant);
+
+ k = Q6_R_normamt_R(hi);
+ if(hi == 0 || hi == -1) k = 31+Q6_R_normamt_R(lo);
+
+ mant = (mant << k);
+ cn = (mant == 0x8000000000000000LL);
+ exp = exp - k + cn;
+
+ if (mant == 0 || mant == -1) exp = 0x8001;
+ c = (mant & MANTMASK) | (((lint) exp) & EXP_MASK);
+ return(c);
+ }
+ * ==================================================================== */
+ .text
+ .global fast2_dadd_asm
+ .type fast2_dadd_asm, @function
+fast2_dadd_asm:
+#define manta R0
+#define mantexpa R1:0
+#define lmanta R1:0
+#define mantb R2
+#define mantexpb R3:2
+#define lmantb R3:2
+#define expa R4
+#define expb R5
+#define mantexpd R7:6
+#define expd R6
+#define exp R8
+#define c63 R9
+#define lmant R1:0
+#define manth R1
+#define mantl R0
+#define minmin R11:10 // exactly 0x000000000000008001LL
+#define minminl R10
+#define k R4
+#define ce P0
+ .falign
+ {
+ mantexpd = VABSDIFFH(mantexpa, mantexpb) //represented as 0x08001LL
+ c63 = #62
+ expa = SXTH(manta)
+ expb = SXTH(mantb)
+ } {
+ expd = SXTH(expd)
+ ce = CMP.GT(expa, expb);
+ if ( ce.new) exp = add(expa, #1)
+ if (!ce.new) exp = add(expb, #1)
+ } {
+ if ( ce) expa = #1
+ if (!ce) expb = #1
+ manta.L = #0
+ expd = MIN(expd, c63)
+ } {
+ if (!ce) expa = add(expd, #1)
+ if ( ce) expb = add(expd, #1)
+ mantb.L = #0
+ minmin = #0
+ } {
+ lmanta = ASR(lmanta, expa)
+ lmantb = ASR(lmantb, expb)
+ } {
+ lmant = add(lmanta, lmantb)
+ minminl.L = #0x8001
+ } {
+ k = clb(lmant)
+ c63 = #58
+ } {
+ k = add(k, #-1)
+ p0 = cmp.gt(k, c63)
+ } {
+ mantexpa = ASL(lmant, k)
+ exp = SUB(exp, k)
+ if(p0) jump .Ldenorma
+ } {
+ manta = insert(exp, #16, #0)
+ jumpr r31
+ }
+.Ldenorma:
+ {
+ mantexpa = minmin
+ jumpr r31
+ }
+/* =================================================================== *
+ fast2_QDOUBLE fast2_dsub(fast2_QDOUBLE a,fast2_QDOUBLE b) {
+ fast2_QDOUBLE c;
+ lint manta = a & MANTMASK;
+ int expa = Q6_R_sxth_R(a) ;
+ lint mantb = b & MANTMASK;
+ int expb = Q6_R_sxth_R(b) ;
+ int exp, expdiff, j, k;
+ lint mant;
+
+ expdiff = (int) Q6_P_vabsdiffh_PP(a, b);
+ expdiff = Q6_R_sxth_R(expdiff) ;
+ if (expdiff > 63) { expdiff = 62;}
+ if (expa > expb) {
+ exp = expa + 1;
+ expa = 1;
+ expb = expdiff + 1;
+ } else {
+ exp = expb + 1;
+ expb = 1;
+ expa = expdiff + 1;
+ }
+ mant = (manta>>expa) - (mantb>>expb);
+ k = Q6_R_clb_P(mant)-1;
+ mant = (mant << k);
+ exp = exp - k;
+ if (mant == 0 || mant == -1) exp = 0x8001;
+ c = (mant & MANTMASK) | (((lint) exp) & EXP_MASK);
+ return(c);
+ }
+ * ==================================================================== */
+ .text
+ .global fast2_dsub_asm
+ .type fast2_dsub_asm, @function
+fast2_dsub_asm:
+
+#define manta R0
+#define mantexpa R1:0
+#define lmanta R1:0
+#define mantb R2
+#define mantexpb R3:2
+#define lmantb R3:2
+#define expa R4
+#define expb R5
+#define mantexpd R7:6
+#define expd R6
+#define exp R8
+#define c63 R9
+#define lmant R1:0
+#define manth R1
+#define mantl R0
+#define minmin R11:10 // exactly 0x000000000000008001LL
+#define minminl R10
+#define k R4
+#define ce P0
+ .falign
+ {
+ mantexpd = VABSDIFFH(mantexpa, mantexpb) //represented as 0x08001LL
+ c63 = #62
+ expa = SXTH(manta)
+ expb = SXTH(mantb)
+ } {
+ expd = SXTH(expd)
+ ce = CMP.GT(expa, expb);
+ if ( ce.new) exp = add(expa, #1)
+ if (!ce.new) exp = add(expb, #1)
+ } {
+ if ( ce) expa = #1
+ if (!ce) expb = #1
+ manta.L = #0
+ expd = MIN(expd, c63)
+ } {
+ if (!ce) expa = add(expd, #1)
+ if ( ce) expb = add(expd, #1)
+ mantb.L = #0
+ minmin = #0
+ } {
+ lmanta = ASR(lmanta, expa)
+ lmantb = ASR(lmantb, expb)
+ } {
+ lmant = sub(lmanta, lmantb)
+ minminl.L = #0x8001
+ } {
+ k = clb(lmant)
+ c63 = #58
+ } {
+ k = add(k, #-1)
+ p0 = cmp.gt(k, c63)
+ } {
+ mantexpa = ASL(lmant, k)
+ exp = SUB(exp, k)
+ if(p0) jump .Ldenorm
+ } {
+ manta = insert(exp, #16, #0)
+ jumpr r31
+ }
+.Ldenorm:
+ {
+ mantexpa = minmin
+ jumpr r31
+ }
+/* ==================================================================== *
+ fast2_QDOUBLE fast2_dmpy(fast2_QDOUBLE a,fast2_QDOUBLE b) {
+ fast2_QDOUBLE c;
+ lint manta = a & MANTMASK;
+ int expa = Q6_R_sxth_R(a) ;
+ lint mantb = b & MANTMASK;
+ int expb = Q6_R_sxth_R(b) ;
+ int exp, k;
+ lint mant;
+ int hia, hib, hi, lo;
+ unsigned int loa, lob;
+
+ hia = (int)(a >> 32);
+ loa = Q6_R_extractu_RII((int)manta, 31, 1);
+ hib = (int)(b >> 32);
+ lob = Q6_R_extractu_RII((int)mantb, 31, 1);
+
+ mant = Q6_P_mpy_RR(hia, lob);
+ mant = Q6_P_mpyacc_RR(mant,hib, loa);
+ mant = (mant >> 30) + (Q6_P_mpy_RR(hia, hib)<<1);
+
+ hi = (int) (mant>>32);
+
+ k = Q6_R_normamt_R(hi);
+ mant = mant << k;
+ exp = expa + expb - k;
+ if (mant == 0 || mant == -1) exp = 0x8001;
+ c = (mant & MANTMASK) | (((lint) exp) & EXP_MASK);
+ return(c);
+ }
+ * ==================================================================== */
+ .text
+ .global fast2_dmpy_asm
+ .type fast2_dmpy_asm, @function
+fast2_dmpy_asm:
+
+#define mantal R0
+#define mantah R1
+#define mantexpa R1:0
+#define mantbl R2
+#define mantbh R3
+#define mantexpb R3:2
+#define expa R4
+#define expb R5
+#define c8001 R12
+#define mantexpd R7:6
+#define mantdh R7
+#define exp R8
+#define lmantc R11:10
+#define kb R9
+#define guard R11
+#define mantal_ R12
+#define mantbl_ R13
+#define min R15:14
+#define minh R15
+
+ .falign
+ {
+ mantbl_= lsr(mantbl, #16)
+ expb = sxth(mantbl)
+ expa = sxth(mantal)
+ mantal_= lsr(mantal, #16)
+ }
+ {
+ lmantc = mpy(mantah, mantbh)
+ mantexpd = mpy(mantah, mantbl_)
+ mantal.L = #0x0
+ min = #0
+ }
+ {
+ lmantc = add(lmantc, lmantc)
+ mantexpd+= mpy(mantbh, mantal_)
+ mantbl.L = #0x0
+ minh.H = #0x8000
+ }
+ {
+ mantexpd = asr(mantexpd, #15)
+ c8001.L = #0x8001
+ p1 = cmp.eq(mantexpa, mantexpb)
+ }
+ {
+ mantexpd = add(mantexpd, lmantc)
+ exp = add(expa, expb)
+ p2 = cmp.eq(mantexpa, min)
+ }
+ {
+ kb = clb(mantexpd)
+ mantexpb = abs(mantexpd)
+ guard = #58
+ }
+ {
+ p1 = and(p1, p2)
+ exp = sub(exp, kb)
+ kb = add(kb, #-1)
+ p0 = cmp.gt(kb, guard)
+ }
+ {
+ exp = add(exp, #1)
+ mantexpa = asl(mantexpd, kb)
+ if(p1) jump .Lsat //rarely happens
+ }
+ {
+ mantal = insert(exp,#16, #0)
+ if(!p0) jumpr r31
+ }
+ {
+ mantal = insert(c8001,#16, #0)
+ jumpr r31
+ }
+.Lsat:
+ {
+ mantexpa = #-1
+ }
+ {
+ mantexpa = lsr(mantexpa, #1)
+ }
+ {
+ mantal = insert(exp,#16, #0)
+ jumpr r31
+ }
+
+/* ==================================================================== *
+ int fast2_qd2f(fast2_QDOUBLE a) {
+ int exp;
+ long long int manta;
+ int ic, rnd, mantb;
+
+ manta = a>>32;
+ exp = Q6_R_sxth_R(a) ;
+ ic = 0x80000000 & manta;
+ manta = Q6_R_abs_R_sat(manta);
+ mantb = (manta + rnd)>>7;
+ rnd = 0x40
+ exp = (exp + 126);
+ if((manta & 0xff) == rnd) rnd = 0x00;
+ if((manta & 0x7fffffc0) == 0x7fffffc0) {
+ manta = 0x0; exp++;
+ } else {
+ manta= mantb & 0x007fffff;
+ }
+ exp = (exp << 23) & 0x7fffffc0;
+ ic = Q6_R_addacc_RR(ic, exp, manta);
+ return (ic);
+ }
+ * ==================================================================== */
+
+ .text
+ .global fast2_qd2f_asm
+ .type fast2_qd2f_asm, @function
+fast2_qd2f_asm:
+#define mantah R1
+#define mantal R0
+#define cff R0
+#define mant R3
+#define expo R4
+#define rnd R5
+#define mask R6
+#define c07f R7
+#define c80 R0
+#define mantb R2
+#define ic R0
+
+ .falign
+ {
+ mant = abs(mantah):sat
+ expo = sxth(mantal)
+ rnd = #0x40
+ mask.L = #0xffc0
+ }
+ {
+ cff = extractu(mant, #8, #0)
+ p2 = cmp.gt(expo, #126)
+ p3 = cmp.ge(expo, #-126)
+ mask.H = #0x7fff
+ }
+ {
+ p1 = cmp.eq(cff,#0x40)
+ if(p1.new) rnd = #0
+ expo = add(expo, #126)
+ if(!p3) jump .Lmin
+ }
+ {
+ p0 = bitsset(mant, mask)
+ c80.L = #0x0000
+ mantb = add(mant, rnd)
+ c07f = lsr(mask, #8)
+ }
+ {
+ if(p0) expo = add(expo, #1)
+ if(p0) mant = #0
+ mantb = lsr(mantb, #7)
+ c80.H = #0x8000
+ }
+ {
+ ic = and(c80, mantah)
+ mask &= asl(expo, #23)
+ if(!p0) mant = and(mantb, c07f)
+ if(p2) jump .Lmax
+ }
+ {
+ ic += add(mask, mant)
+ jumpr r31
+ }
+.Lmax:
+ {
+ ic.L = #0xffff;
+ }
+ {
+ ic.H = #0x7f7f;
+ jumpr r31
+ }
+.Lmin:
+ {
+ ic = #0x0
+ jumpr r31
+ }
+
+/* ==================================================================== *
+fast2_QDOUBLE fast2_f2qd(int ia) {
+ lint exp;
+ lint mant;
+ fast2_QDOUBLE c;
+
+ mant = ((ia << 7) | 0x40000000)&0x7fffff80 ;
+ if (ia & 0x80000000) mant = -mant;
+ exp = ((ia >> 23) & 0xFFLL) - 126;
+ c = (mant<<32) | Q6_R_zxth_R(exp);;
+ return(c);
+}
+ * ==================================================================== */
+ .text
+ .global fast2_f2qd_asm
+ .type fast2_f2qd_asm, @function
+fast2_f2qd_asm:
+#define ia R0
+#define mag R3
+#define mantr R1
+#define expr R0
+#define zero R2
+#define maxneg R5:4
+#define maxnegl R4
+ .falign
+ {
+ mantr = asl(ia, #7)
+ p0 = tstbit(ia, #31)
+ maxneg = #0
+ mag = add(ia,ia)
+ }
+ {
+ mantr = setbit(mantr, #30)
+ expr= extractu(ia,#8,#23)
+ maxnegl.L = #0x8001
+ p1 = cmp.eq(mag, #0)
+ }
+ {
+ mantr= extractu(mantr, #31, #0)
+ expr= add(expr, #-126)
+ zero = #0
+ if(p1) jump .Lminqd
+ }
+ {
+ expr = zxth(expr)
+ if(p0) mantr= sub(zero, mantr)
+ jumpr r31
+ }
+.Lminqd:
+ {
+ R1:0 = maxneg
+ jumpr r31
+ }
diff --git a/contrib/libs/cxxsupp/builtins/hexagon/fastmath2_ldlib_asm.S b/contrib/libs/cxxsupp/builtins/hexagon/fastmath2_ldlib_asm.S
new file mode 100644
index 0000000000..cf623f94c8
--- /dev/null
+++ b/contrib/libs/cxxsupp/builtins/hexagon/fastmath2_ldlib_asm.S
@@ -0,0 +1,344 @@
+//===----------------------Hexagon builtin routine ------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+/* ==================================================================== *
+
+fast2_QLDOUBLE fast2_ldadd(fast2_QLDOUBLE a,fast2_QLDOUBLE b) {
+ fast2_QLDOUBLE c;
+ lint manta = a & MANTMASK;
+ int expa = Q6_R_sxth_R(a) ;
+ lint mantb = b & MANTMASK;
+ int expb = Q6_R_sxth_R(b) ;
+ int exp, expdiff, j, k, hi, lo, cn;
+ lint mant;
+
+ expdiff = (int) Q6_P_vabsdiffh_PP(a, b);
+ expdiff = Q6_R_sxth_R(expdiff) ;
+ if (expdiff > 63) { expdiff = 62;}
+ if (expa > expb) {
+ exp = expa + 1;
+ expa = 1;
+ expb = expdiff + 1;
+ } else {
+ exp = expb + 1;
+ expb = 1;
+ expa = expdiff + 1;
+ }
+ mant = (manta>>expa) + (mantb>>expb);
+
+ hi = (int) (mant>>32);
+ lo = (int) (mant);
+
+ k = Q6_R_normamt_R(hi);
+ if(hi == 0 || hi == -1) k = 31+Q6_R_normamt_R(lo);
+
+ mant = (mant << k);
+ cn = (mant == 0x8000000000000000LL);
+ exp = exp - k + cn;
+
+ if (mant == 0 || mant == -1) exp = 0x8001;
+ c = (mant & MANTMASK) | (((lint) exp) & EXP_MASK);
+ return(c);
+ }
+ * ==================================================================== */
+ .text
+ .global fast2_ldadd_asm
+ .type fast2_ldadd_asm, @function
+fast2_ldadd_asm:
+#define manta R1:0
+#define lmanta R1:0
+#define mantb R3:2
+#define lmantb R3:2
+#define expa R4
+#define expb R5
+#define expd R6
+#define exp R8
+#define c63 R9
+#define lmant R1:0
+#define k R4
+#define ce P0
+#define zero R3:2
+ .falign
+ {
+ expa = memw(r29+#8)
+ expb = memw(r29+#24)
+ r7 = r0
+ }
+ {
+ expd = sub(expa, expb):sat
+ ce = CMP.GT(expa, expb);
+ if ( ce.new) exp = add(expa, #1)
+ if (!ce.new) exp = add(expb, #1)
+ } {
+ expd = abs(expd):sat
+ if ( ce) expa = #1
+ if (!ce) expb = #1
+ c63 = #62
+ } {
+ expd = MIN(expd, c63)
+ manta = memd(r29+#0)
+ mantb = memd(r29+#16)
+ } {
+ if (!ce) expa = add(expd, #1)
+ if ( ce) expb = add(expd, #1)
+ } {
+ lmanta = ASR(lmanta, expa)
+ lmantb = ASR(lmantb, expb)
+ } {
+ lmant = add(lmanta, lmantb)
+ zero = #0
+ } {
+ k = clb(lmant)
+ c63.L =#0x0001
+ } {
+ exp -= add(k, #-1) //exp = exp - (k-1)
+ k = add(k, #-1)
+ p0 = cmp.gt(k, #58)
+ c63.H =#0x8000
+ } {
+ if(!p0)memw(r7+#8) = exp
+ lmant = ASL(lmant, k)
+ if(p0) jump .Ldenorma
+ } {
+ memd(r7+#0) = lmant
+ jumpr r31
+ }
+.Ldenorma:
+ memd(r7+#0) = zero
+ {
+ memw(r7+#8) = c63
+ jumpr r31
+ }
+/* =================================================================== *
+ fast2_QLDOUBLE fast2_ldsub(fast2_QLDOUBLE a,fast2_QLDOUBLE b) {
+ fast2_QLDOUBLE c;
+ lint manta = a & MANTMASK;
+ int expa = Q6_R_sxth_R(a) ;
+ lint mantb = b & MANTMASK;
+ int expb = Q6_R_sxth_R(b) ;
+ int exp, expdiff, j, k;
+ lint mant;
+
+ expdiff = (int) Q6_P_vabsdiffh_PP(a, b);
+ expdiff = Q6_R_sxth_R(expdiff) ;
+ if (expdiff > 63) { expdiff = 62;}
+ if (expa > expb) {
+ exp = expa + 1;
+ expa = 1;
+ expb = expdiff + 1;
+ } else {
+ exp = expb + 1;
+ expb = 1;
+ expa = expdiff + 1;
+ }
+ mant = (manta>>expa) - (mantb>>expb);
+ k = Q6_R_clb_P(mant)-1;
+ mant = (mant << k);
+ exp = exp - k;
+ if (mant == 0 || mant == -1) exp = 0x8001;
+ c = (mant & MANTMASK) | (((lint) exp) & EXP_MASK);
+ return(c);
+ }
+ * ==================================================================== */
+ .text
+ .global fast2_ldsub_asm
+ .type fast2_ldsub_asm, @function
+fast2_ldsub_asm:
+#define manta R1:0
+#define lmanta R1:0
+#define mantb R3:2
+#define lmantb R3:2
+#define expa R4
+#define expb R5
+#define expd R6
+#define exp R8
+#define c63 R9
+#define lmant R1:0
+#define k R4
+#define ce P0
+#define zero R3:2
+ .falign
+ {
+ expa = memw(r29+#8)
+ expb = memw(r29+#24)
+ r7 = r0
+ }
+ {
+ expd = sub(expa, expb):sat
+ ce = CMP.GT(expa, expb);
+ if ( ce.new) exp = add(expa, #1)
+ if (!ce.new) exp = add(expb, #1)
+ } {
+ expd = abs(expd):sat
+ if ( ce) expa = #1
+ if (!ce) expb = #1
+ c63 = #62
+ } {
+ expd = min(expd, c63)
+ manta = memd(r29+#0)
+ mantb = memd(r29+#16)
+ } {
+ if (!ce) expa = add(expd, #1)
+ if ( ce) expb = add(expd, #1)
+ } {
+ lmanta = ASR(lmanta, expa)
+ lmantb = ASR(lmantb, expb)
+ } {
+ lmant = sub(lmanta, lmantb)
+ zero = #0
+ } {
+ k = clb(lmant)
+ c63.L =#0x0001
+ } {
+ exp -= add(k, #-1) //exp = exp - (k+1)
+ k = add(k, #-1)
+ p0 = cmp.gt(k, #58)
+ c63.H =#0x8000
+ } {
+ if(!p0)memw(r7+#8) = exp
+ lmant = asl(lmant, k)
+ if(p0) jump .Ldenorma_s
+ } {
+ memd(r7+#0) = lmant
+ jumpr r31
+ }
+.Ldenorma_s:
+ memd(r7+#0) = zero
+ {
+ memw(r7+#8) = c63
+ jumpr r31
+ }
+
+/* ==================================================================== *
+ fast2_QLDOUBLE fast2_ldmpy(fast2_QLDOUBLE a,fast2_QLDOUBLE b) {
+ fast2_QLDOUBLE c;
+ lint manta = a & MANTMASK;
+ int expa = Q6_R_sxth_R(a) ;
+ lint mantb = b & MANTMASK;
+ int expb = Q6_R_sxth_R(b) ;
+ int exp, k;
+ lint mant;
+ int hia, hib, hi, lo;
+ unsigned int loa, lob;
+
+ hia = (int)(a >> 32);
+ loa = Q6_R_extractu_RII((int)manta, 31, 1);
+ hib = (int)(b >> 32);
+ lob = Q6_R_extractu_RII((int)mantb, 31, 1);
+
+ mant = Q6_P_mpy_RR(hia, lob);
+ mant = Q6_P_mpyacc_RR(mant,hib, loa);
+ mant = (mant >> 30) + (Q6_P_mpy_RR(hia, hib)<<1);
+
+ hi = (int) (mant>>32);
+
+ k = Q6_R_normamt_R(hi);
+ mant = mant << k;
+ exp = expa + expb - k;
+ if (mant == 0 || mant == -1) exp = 0x8001;
+ c = (mant & MANTMASK) | (((lint) exp) & EXP_MASK);
+ return(c);
+ }
+ * ==================================================================== */
+ .text
+ .global fast2_ldmpy_asm
+ .type fast2_ldmpy_asm, @function
+fast2_ldmpy_asm:
+
+#define mantxl_ R9
+#define mantxl R14
+#define mantxh R15
+#define mantx R15:14
+#define mantbl R2
+#define mantbl_ R8
+#define mantbh R3
+#define mantb R3:2
+#define expa R4
+#define expb R5
+#define c8001 R8
+#define mantd R7:6
+#define lmantc R11:10
+#define kp R9
+#define min R13:12
+#define minh R13
+#define max R13:12
+#define maxh R13
+#define ret R0
+
+ .falign
+ {
+ mantx = memd(r29+#0)
+ mantb = memd(r29+#16)
+ min = #0
+ }
+ {
+ mantbl_= extractu(mantbl, #31, #1)
+ mantxl_= extractu(mantxl, #31, #1)
+ minh.H = #0x8000
+ }
+ {
+ lmantc = mpy(mantxh, mantbh)
+ mantd = mpy(mantxh, mantbl_)
+ expa = memw(r29+#8)
+ expb = memw(r29+#24)
+ }
+ {
+ lmantc = add(lmantc, lmantc)
+ mantd += mpy(mantbh, mantxl_)
+ }
+ {
+ mantd = asr(mantd, #30)
+ c8001.L = #0x0001
+ p1 = cmp.eq(mantx, mantb)
+ }
+ {
+ mantd = add(mantd, lmantc)
+ expa= add(expa, expb)
+ p2 = cmp.eq(mantb, min)
+ }
+ {
+ kp = clb(mantd)
+ c8001.H = #0x8000
+ p1 = and(p1, p2)
+ }
+ {
+ expa-= add(kp, #-1)
+ kp = add(kp, #-1)
+ if(p1) jump .Lsat
+ }
+ {
+ mantd = asl(mantd, kp)
+ memw(ret+#8) = expa
+ p0 = cmp.gt(kp, #58)
+ if(p0.new) jump:NT .Ldenorm //rarely happens
+ }
+ {
+ memd(ret+#0) = mantd
+ jumpr r31
+ }
+.Lsat:
+ {
+ max = #0
+ expa+= add(kp, #1)
+ }
+ {
+ maxh.H = #0x4000
+ memw(ret+#8) = expa
+ }
+ {
+ memd(ret+#0) = max
+ jumpr r31
+ }
+.Ldenorm:
+ {
+ memw(ret+#8) = c8001
+ mantx = #0
+ }
+ {
+ memd(ret+#0) = mantx
+ jumpr r31
+ }
diff --git a/contrib/libs/cxxsupp/builtins/hexagon/fastmath_dlib_asm.S b/contrib/libs/cxxsupp/builtins/hexagon/fastmath_dlib_asm.S
new file mode 100644
index 0000000000..3e59526c1e
--- /dev/null
+++ b/contrib/libs/cxxsupp/builtins/hexagon/fastmath_dlib_asm.S
@@ -0,0 +1,399 @@
+//===----------------------Hexagon builtin routine ------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+/* ==================================================================== */
+/* FUNCTIONS Optimized double floating point operators */
+/* ==================================================================== */
+/* c = dadd_asm(a, b) */
+/* ====================================================================
+
+QDOUBLE dadd(QDOUBLE a,QDOUBLE b) {
+ QDOUBLE c;
+ lint manta = a & MANTMASK;
+ int expa = HEXAGON_R_sxth_R(a) ;
+ lint mantb = b & MANTMASK;
+ int expb = HEXAGON_R_sxth_R(b) ;
+ int exp, expdiff, j, k, hi, lo, cn;
+ lint mant;
+
+ expdiff = (int) HEXAGON_P_vabsdiffh_PP(a, b);
+ expdiff = HEXAGON_R_sxth_R(expdiff) ;
+ if (expdiff > 63) { expdiff = 62;}
+ if (expa > expb) {
+ exp = expa + 1;
+ expa = 1;
+ expb = expdiff + 1;
+ } else {
+ exp = expb + 1;
+ expb = 1;
+ expa = expdiff + 1;
+ }
+ mant = (manta>>expa) + (mantb>>expb);
+
+ hi = (int) (mant>>32);
+ lo = (int) (mant);
+
+ k = HEXAGON_R_normamt_R(hi);
+ if(hi == 0 || hi == -1) k = 31+HEXAGON_R_normamt_R(lo);
+
+ mant = (mant << k);
+ cn = (mant == 0x8000000000000000LL);
+ exp = exp - k + cn;
+
+ if (mant == 0 || mant == -1) exp = 0x8001;
+ c = (mant & MANTMASK) | (((lint) exp) & EXP_MASK);
+ return(c);
+ }
+ * ==================================================================== */
+ .text
+ .global dadd_asm
+ .type dadd_asm, @function
+dadd_asm:
+
+#define manta R0
+#define mantexpa R1:0
+#define lmanta R1:0
+#define mantb R2
+#define mantexpb R3:2
+#define lmantb R3:2
+#define expa R4
+#define expb R5
+#define mantexpd R7:6
+#define expd R6
+#define exp R8
+#define c63 R9
+#define lmant R1:0
+#define manth R1
+#define mantl R0
+#define zero R7:6
+#define zerol R6
+#define minus R3:2
+#define minusl R2
+#define maxneg R9
+#define minmin R11:10 // exactly 0x800000000000000000LL
+#define minminh R11
+#define k R4
+#define kl R5
+#define ce P0
+ .falign
+ {
+ mantexpd = VABSDIFFH(mantexpa, mantexpb) //represented as 0x08001LL
+ c63 = #62
+ expa = SXTH(manta)
+ expb = SXTH(mantb)
+ } {
+ expd = SXTH(expd)
+ ce = CMP.GT(expa, expb);
+ if ( ce.new) exp = add(expa, #1)
+ if (!ce.new) exp = add(expb, #1)
+ } {
+ if ( ce) expa = #1
+ if (!ce) expb = #1
+ manta.L = #0
+ expd = MIN(expd, c63)
+ } {
+ if (!ce) expa = add(expd, #1)
+ if ( ce) expb = add(expd, #1)
+ mantb.L = #0
+ zero = #0
+ } {
+ lmanta = ASR(lmanta, expa)
+ lmantb = ASR(lmantb, expb)
+ minmin = #0
+ } {
+ lmant = add(lmanta, lmantb)
+ minus = #-1
+ minminh.H = #0x8000
+ } {
+ k = NORMAMT(manth)
+ kl = NORMAMT(mantl)
+ p0 = cmp.eq(manth, zerol)
+ p1 = cmp.eq(manth, minusl)
+ } {
+ p0 = OR(p0, p1)
+ if(p0.new) k = add(kl, #31)
+ maxneg.H = #0
+ } {
+ mantexpa = ASL(lmant, k)
+ exp = SUB(exp, k)
+ maxneg.L = #0x8001
+ } {
+ p0 = cmp.eq(mantexpa, zero)
+ p1 = cmp.eq(mantexpa, minus)
+ manta.L = #0
+ exp = ZXTH(exp)
+ } {
+ p2 = cmp.eq(mantexpa, minmin) //is result 0x80....0
+ if(p2.new) exp = add(exp, #1)
+ }
+#if (__HEXAGON_ARCH__ == 60)
+ {
+ p0 = OR(p0, p1)
+ if( p0.new) manta = OR(manta,maxneg)
+ if(!p0.new) manta = OR(manta,exp)
+ }
+ jumpr r31
+#else
+ {
+ p0 = OR(p0, p1)
+ if( p0.new) manta = OR(manta,maxneg)
+ if(!p0.new) manta = OR(manta,exp)
+ jumpr r31
+ }
+#endif
+/* =================================================================== *
+ QDOUBLE dsub(QDOUBLE a,QDOUBLE b) {
+ QDOUBLE c;
+ lint manta = a & MANTMASK;
+ int expa = HEXAGON_R_sxth_R(a) ;
+ lint mantb = b & MANTMASK;
+ int expb = HEXAGON_R_sxth_R(b) ;
+ int exp, expdiff, j, k, hi, lo, cn;
+ lint mant;
+
+ expdiff = (int) HEXAGON_P_vabsdiffh_PP(a, b);
+ expdiff = HEXAGON_R_sxth_R(expdiff) ;
+ if (expdiff > 63) { expdiff = 62;}
+ if (expa > expb) {
+ exp = expa + 1;
+ expa = 1;
+ expb = expdiff + 1;
+ } else {
+ exp = expb + 1;
+ expb = 1;
+ expa = expdiff + 1;
+ }
+ mant = (manta>>expa) - (mantb>>expb);
+
+ hi = (int) (mant>>32);
+ lo = (int) (mant);
+
+ k = HEXAGON_R_normamt_R(hi);
+ if(hi == 0 || hi == -1) k = 31+HEXAGON_R_normamt_R(lo);
+
+ mant = (mant << k);
+ cn = (mant == 0x8000000000000000LL);
+ exp = exp - k + cn;
+
+ if (mant == 0 || mant == -1) exp = 0x8001;
+ c = (mant & MANTMASK) | (((lint) exp) & EXP_MASK);
+ return(c);
+ }
+ * ==================================================================== */
+ .text
+ .global dsub_asm
+ .type dsub_asm, @function
+dsub_asm:
+
+#define manta R0
+#define mantexpa R1:0
+#define lmanta R1:0
+#define mantb R2
+#define mantexpb R3:2
+#define lmantb R3:2
+#define expa R4
+#define expb R5
+#define mantexpd R7:6
+#define expd R6
+#define exp R8
+#define c63 R9
+#define lmant R1:0
+#define manth R1
+#define mantl R0
+#define zero R7:6
+#define zerol R6
+#define minus R3:2
+#define minusl R2
+#define maxneg R9
+#define minmin R11:10 // exactly 0x800000000000000000LL
+#define minminh R11
+#define k R4
+#define kl R5
+#define ce P0
+ .falign
+ {
+ mantexpd = VABSDIFFH(mantexpa, mantexpb) //represented as 0x08001LL
+ c63 = #62
+ expa = SXTH(manta)
+ expb = SXTH(mantb)
+ } {
+ expd = SXTH(expd)
+ ce = CMP.GT(expa, expb);
+ if ( ce.new) exp = add(expa, #1)
+ if (!ce.new) exp = add(expb, #1)
+ } {
+ if ( ce) expa = #1
+ if (!ce) expb = #1
+ manta.L = #0
+ expd = MIN(expd, c63)
+ } {
+ if (!ce) expa = add(expd, #1)
+ if ( ce) expb = add(expd, #1)
+ mantb.L = #0
+ zero = #0
+ } {
+ lmanta = ASR(lmanta, expa)
+ lmantb = ASR(lmantb, expb)
+ minmin = #0
+ } {
+ lmant = sub(lmanta, lmantb)
+ minus = #-1
+ minminh.H = #0x8000
+ } {
+ k = NORMAMT(manth)
+ kl = NORMAMT(mantl)
+ p0 = cmp.eq(manth, zerol)
+ p1 = cmp.eq(manth, minusl)
+ } {
+ p0 = OR(p0, p1)
+ if(p0.new) k = add(kl, #31)
+ maxneg.H = #0
+ } {
+ mantexpa = ASL(lmant, k)
+ exp = SUB(exp, k)
+ maxneg.L = #0x8001
+ } {
+ p0 = cmp.eq(mantexpa, zero)
+ p1 = cmp.eq(mantexpa, minus)
+ manta.L = #0
+ exp = ZXTH(exp)
+ } {
+ p2 = cmp.eq(mantexpa, minmin) //is result 0x80....0
+ if(p2.new) exp = add(exp, #1)
+ }
+#if (__HEXAGON_ARCH__ == 60)
+ {
+ p0 = OR(p0, p1)
+ if( p0.new) manta = OR(manta,maxneg)
+ if(!p0.new) manta = OR(manta,exp)
+ }
+ jumpr r31
+#else
+ {
+ p0 = OR(p0, p1)
+ if( p0.new) manta = OR(manta,maxneg)
+ if(!p0.new) manta = OR(manta,exp)
+ jumpr r31
+ }
+#endif
+/* ==================================================================== *
+ QDOUBLE dmpy(QDOUBLE a,QDOUBLE b) {
+ QDOUBLE c;
+ lint manta = a & MANTMASK;
+ int expa = HEXAGON_R_sxth_R(a) ;
+ lint mantb = b & MANTMASK;
+ int expb = HEXAGON_R_sxth_R(b) ;
+ int exp, k;
+ lint mant;
+ int hia, hib, hi, lo;
+ unsigned int loa, lob;
+
+ hia = (int)(a >> 32);
+ loa = HEXAGON_R_extractu_RII((int)manta, 31, 1);
+ hib = (int)(b >> 32);
+ lob = HEXAGON_R_extractu_RII((int)mantb, 31, 1);
+
+ mant = HEXAGON_P_mpy_RR(hia, lob);
+ mant = HEXAGON_P_mpyacc_RR(mant,hib, loa);
+ mant = (mant >> 30) + (HEXAGON_P_mpy_RR(hia, hib)<<1);
+
+ hi = (int) (mant>>32);
+ lo = (int) (mant);
+
+ k = HEXAGON_R_normamt_R(hi);
+ if(hi == 0 || hi == -1) k = 31+HEXAGON_R_normamt_R(lo);
+ mant = mant << k;
+ exp = expa + expb - k;
+ if (mant == 0 || mant == -1) exp = 0x8001;
+ c = (mant & MANTMASK) | (((lint) exp) & EXP_MASK);
+ return(c);
+ }
+ * ==================================================================== */
+ .text
+ .global dmpy_asm
+ .type dmpy_asm, @function
+dmpy_asm:
+
+#define mantal R0
+#define mantah R1
+#define mantexpa R1:0
+#define mantbl R2
+#define mantbh R3
+#define mantexpb R3:2
+#define expa R4
+#define expb R5
+#define mantexpd R7:6
+#define exp R8
+#define lmantc R11:10
+#define mantch R11
+#define mantcl R10
+#define zero0 R7:6
+#define zero0l R6
+#define minus1 R3:2
+#define minus1l R2
+#define maxneg R9
+#define k R4
+#define kl R5
+
+ .falign
+ {
+ mantbl = lsr(mantbl, #16)
+ mantal = lsr(mantal, #16)
+ expa = sxth(mantal)
+ expb = sxth(mantbl)
+ }
+ {
+ lmantc = mpy(mantah, mantbh)
+ mantexpd = mpy(mantah, mantbl)
+ }
+ {
+ lmantc = add(lmantc, lmantc) //<<1
+ mantexpd+= mpy(mantbh, mantal)
+ }
+ {
+ lmantc += asr(mantexpd, #15)
+ exp = add(expa, expb)
+ zero0 = #0
+ minus1 = #-1
+ }
+ {
+ k = normamt(mantch)
+ kl = normamt(mantcl)
+ p0 = cmp.eq(mantch, zero0l)
+ p1 = cmp.eq(mantch, minus1l)
+ }
+ {
+ p0 = or(p0, p1)
+ if(p0.new) k = add(kl, #31)
+ maxneg.H = #0
+ }
+ {
+ mantexpa = asl(lmantc, k)
+ exp = sub(exp, k)
+ maxneg.L = #0x8001
+ }
+ {
+ p0 = cmp.eq(mantexpa, zero0)
+ p1 = cmp.eq(mantexpa, minus1)
+ mantal.L = #0
+ exp = zxth(exp)
+ }
+#if (__HEXAGON_ARCH__ == 60)
+ {
+ p0 = or(p0, p1)
+ if( p0.new) mantal = or(mantal,maxneg)
+ if(!p0.new) mantal = or(mantal,exp)
+ }
+ jumpr r31
+#else
+ {
+ p0 = or(p0, p1)
+ if( p0.new) mantal = or(mantal,maxneg)
+ if(!p0.new) mantal = or(mantal,exp)
+ jumpr r31
+ }
+#endif
diff --git a/contrib/libs/cxxsupp/builtins/hexagon/memcpy_forward_vp4cp4n2.S b/contrib/libs/cxxsupp/builtins/hexagon/memcpy_forward_vp4cp4n2.S
new file mode 100644
index 0000000000..10b81f6533
--- /dev/null
+++ b/contrib/libs/cxxsupp/builtins/hexagon/memcpy_forward_vp4cp4n2.S
@@ -0,0 +1,124 @@
+//===----------------------Hexagon builtin routine ------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// An optimized version of a memcpy which is equivalent to the following loop:
+//
+// volatile unsigned *dest;
+// unsigned *src;
+//
+// for (i = 0; i < num_words; ++i)
+// *dest++ = *src++;
+//
+// The corresponding C prototype for this function would be
+// void hexagon_memcpy_forward_vp4cp4n2(volatile unsigned *dest,
+// const unsigned *src,
+// unsigned num_words);
+//
+// *** Both dest and src must be aligned to 32-bit boundaries. ***
+// The code does not perform any runtime checks for this, and will fail
+// in bad ways if this requirement is not met.
+//
+// The "forward" in the name refers to the fact that the function copies
+// the words going forward in memory. It is incorrect to use this function
+// for cases where the original code copied words in any other order.
+//
+// *** This function is only for the use by the compiler. ***
+// The only indended use is for the LLVM compiler to generate calls to
+// this function, when a mem-copy loop, like the one above, is detected.
+
+ .text
+
+// Inputs:
+// r0: dest
+// r1: src
+// r2: num_words
+
+ .globl hexagon_memcpy_forward_vp4cp4n2
+ .balign 32
+ .type hexagon_memcpy_forward_vp4cp4n2,@function
+hexagon_memcpy_forward_vp4cp4n2:
+
+ // Compute r3 to be the number of words remaining in the current page.
+ // At the same time, compute r4 to be the number of 32-byte blocks
+ // remaining in the page (for prefetch).
+ {
+ r3 = sub(##4096, r1)
+ r5 = lsr(r2, #3)
+ }
+ {
+ // The word count before end-of-page is in the 12 lowest bits of r3.
+ // (If the address in r1 was already page-aligned, the bits are 0.)
+ r3 = extractu(r3, #10, #2)
+ r4 = extractu(r3, #7, #5)
+ }
+ {
+ r3 = minu(r2, r3)
+ r4 = minu(r5, r4)
+ }
+ {
+ r4 = or(r4, ##2105344) // 2105344 = 0x202000
+ p0 = cmp.eq(r3, #0)
+ if (p0.new) jump:nt .Lskipprolog
+ }
+ l2fetch(r1, r4)
+ {
+ loop0(.Lprolog, r3)
+ r2 = sub(r2, r3) // r2 = number of words left after the prolog.
+ }
+ .falign
+.Lprolog:
+ {
+ r4 = memw(r1++#4)
+ memw(r0++#4) = r4.new
+ } :endloop0
+.Lskipprolog:
+ {
+ // Let r3 = number of whole pages left (page = 1024 words).
+ r3 = lsr(r2, #10)
+ if (cmp.eq(r3.new, #0)) jump:nt .Lskipmain
+ }
+ {
+ loop1(.Lout, r3)
+ r2 = extractu(r2, #10, #0) // r2 = r2 & 1023
+ r3 = ##2105472 // r3 = 0x202080 (prefetch info)
+ }
+ // Iterate over pages.
+ .falign
+.Lout:
+ // Prefetch each individual page.
+ l2fetch(r1, r3)
+ loop0(.Lpage, #512)
+ .falign
+.Lpage:
+ r5:4 = memd(r1++#8)
+ {
+ memw(r0++#8) = r4
+ memw(r0+#4) = r5
+ } :endloop0:endloop1
+.Lskipmain:
+ {
+ r3 = ##2105344 // r3 = 0x202000 (prefetch info)
+ r4 = lsr(r2, #3) // r4 = number of 32-byte blocks remaining.
+ p0 = cmp.eq(r2, #0)
+ if (p0.new) jumpr:nt r31
+ }
+ {
+ r3 = or(r3, r4)
+ loop0(.Lepilog, r2)
+ }
+ l2fetch(r1, r3)
+ .falign
+.Lepilog:
+ {
+ r4 = memw(r1++#4)
+ memw(r0++#4) = r4.new
+ } :endloop0
+
+ jumpr r31
+
+.size hexagon_memcpy_forward_vp4cp4n2, . - hexagon_memcpy_forward_vp4cp4n2
diff --git a/contrib/libs/cxxsupp/builtins/hexagon/memcpy_likely_aligned.S b/contrib/libs/cxxsupp/builtins/hexagon/memcpy_likely_aligned.S
new file mode 100644
index 0000000000..492298f103
--- /dev/null
+++ b/contrib/libs/cxxsupp/builtins/hexagon/memcpy_likely_aligned.S
@@ -0,0 +1,63 @@
+//===------------------------- memcopy routines ---------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+
+ .macro FUNCTION_BEGIN name
+ .text
+ .p2align 5
+ .globl \name
+ .type \name, @function
+\name:
+ .endm
+
+ .macro FUNCTION_END name
+ .size \name, . - \name
+ .endm
+
+FUNCTION_BEGIN __hexagon_memcpy_likely_aligned_min32bytes_mult8bytes
+ {
+ p0 = bitsclr(r1,#7)
+ p0 = bitsclr(r0,#7)
+ if (p0.new) r5:4 = memd(r1)
+ r3 = #-3
+ }
+ {
+ if (!p0) jump .Lmemcpy_call
+ if (p0) memd(r0++#8) = r5:4
+ if (p0) r5:4 = memd(r1+#8)
+ r3 += lsr(r2,#3)
+ }
+ {
+ memd(r0++#8) = r5:4
+ r5:4 = memd(r1+#16)
+ r1 = add(r1,#24)
+ loop0(1f,r3)
+ }
+ .falign
+1:
+ {
+ memd(r0++#8) = r5:4
+ r5:4 = memd(r1++#8)
+ }:endloop0
+ {
+ memd(r0) = r5:4
+ r0 -= add(r2,#-8)
+ jumpr r31
+ }
+FUNCTION_END __hexagon_memcpy_likely_aligned_min32bytes_mult8bytes
+
+.Lmemcpy_call:
+#ifdef __PIC__
+ jump memcpy@PLT
+#else
+ jump memcpy
+#endif
+
+ .globl __qdsp_memcpy_likely_aligned_min32bytes_mult8bytes
+ .set __qdsp_memcpy_likely_aligned_min32bytes_mult8bytes, \
+ __hexagon_memcpy_likely_aligned_min32bytes_mult8bytes
diff --git a/contrib/libs/cxxsupp/builtins/hexagon/moddi3.S b/contrib/libs/cxxsupp/builtins/hexagon/moddi3.S
new file mode 100644
index 0000000000..d4246b61bd
--- /dev/null
+++ b/contrib/libs/cxxsupp/builtins/hexagon/moddi3.S
@@ -0,0 +1,82 @@
+//===----------------------Hexagon builtin routine ------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+ .macro FUNCTION_BEGIN name
+ .text
+ .p2align 5
+ .globl \name
+ .type \name, @function
+\name:
+ .endm
+
+ .macro FUNCTION_END name
+ .size \name, . - \name
+ .endm
+
+
+FUNCTION_BEGIN __hexagon_moddi3
+ {
+ p3 = tstbit(r1,#31)
+ }
+ {
+ r1:0 = abs(r1:0)
+ r3:2 = abs(r3:2)
+ }
+ {
+ r6 = cl0(r1:0) // count leading 0's of dividend (numerator)
+ r7 = cl0(r3:2) // count leading 0's of divisor (denominator)
+ r5:4 = r3:2 // divisor moved into working registers
+ r3:2 = r1:0 // dividend is the initial remainder, r3:2 contains remainder
+ }
+ {
+ r10 = sub(r7,r6) // left shift count for bit & divisor
+ r1:0 = #0 // initialize quotient to 0
+ r15:14 = #1 // initialize bit to 1
+ }
+ {
+ r11 = add(r10,#1) // loop count is 1 more than shift count
+ r13:12 = lsl(r5:4,r10) // shift divisor msb into same bit position as dividend msb
+ r15:14 = lsl(r15:14,r10) // shift the bit left by same amount as divisor
+ }
+ {
+ p0 = cmp.gtu(r5:4,r3:2) // check if divisor > dividend
+ loop0(1f,r11) // register loop
+ }
+ {
+ if (p0) jump .hexagon_moddi3_return // if divisor > dividend, we're done, so return
+ }
+ .falign
+1:
+ {
+ p0 = cmp.gtu(r13:12,r3:2) // set predicate reg if shifted divisor > current remainder
+ }
+ {
+ r7:6 = sub(r3:2, r13:12) // subtract shifted divisor from current remainder
+ r9:8 = add(r1:0, r15:14) // save current quotient to temp (r9:8)
+ }
+ {
+ r1:0 = vmux(p0, r1:0, r9:8) // choose either current quotient or new quotient (r9:8)
+ r3:2 = vmux(p0, r3:2, r7:6) // choose either current remainder or new remainder (r7:6)
+ }
+ {
+ r15:14 = lsr(r15:14, #1) // shift bit right by 1 for next iteration
+ r13:12 = lsr(r13:12, #1) // shift "shifted divisor" right by 1 for next iteration
+ }:endloop0
+
+.hexagon_moddi3_return:
+ {
+ r1:0 = neg(r3:2)
+ }
+ {
+ r1:0 = vmux(p3,r1:0,r3:2)
+ jumpr r31
+ }
+FUNCTION_END __hexagon_moddi3
+
+ .globl __qdsp_moddi3
+ .set __qdsp_moddi3, __hexagon_moddi3
diff --git a/contrib/libs/cxxsupp/builtins/hexagon/modsi3.S b/contrib/libs/cxxsupp/builtins/hexagon/modsi3.S
new file mode 100644
index 0000000000..4015d5e068
--- /dev/null
+++ b/contrib/libs/cxxsupp/builtins/hexagon/modsi3.S
@@ -0,0 +1,65 @@
+//===----------------------Hexagon builtin routine ------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+
+
+ .macro FUNCTION_BEGIN name
+ .text
+ .p2align 5
+ .globl \name
+ .type \name, @function
+\name:
+ .endm
+
+ .macro FUNCTION_END name
+ .size \name, . - \name
+ .endm
+
+
+FUNCTION_BEGIN __hexagon_modsi3
+ {
+ p2 = cmp.ge(r0,#0)
+ r2 = abs(r0)
+ r1 = abs(r1)
+ }
+ {
+ r3 = cl0(r2)
+ r4 = cl0(r1)
+ p0 = cmp.gtu(r1,r2)
+ }
+ {
+ r3 = sub(r4,r3)
+ if (p0) jumpr r31
+ }
+ {
+ p1 = cmp.eq(r3,#0)
+ loop0(1f,r3)
+ r0 = r2
+ r2 = lsl(r1,r3)
+ }
+ .falign
+1:
+ {
+ p0 = cmp.gtu(r2,r0)
+ if (!p0.new) r0 = sub(r0,r2)
+ r2 = lsr(r2,#1)
+ if (p1) r1 = #0
+ }:endloop0
+ {
+ p0 = cmp.gtu(r2,r0)
+ if (!p0.new) r0 = sub(r0,r1)
+ if (p2) jumpr r31
+ }
+ {
+ r0 = neg(r0)
+ jumpr r31
+ }
+FUNCTION_END __hexagon_modsi3
+
+ .globl __qdsp_modsi3
+ .set __qdsp_modsi3, __hexagon_modsi3
diff --git a/contrib/libs/cxxsupp/builtins/hexagon/sfdiv_opt.S b/contrib/libs/cxxsupp/builtins/hexagon/sfdiv_opt.S
new file mode 100644
index 0000000000..7c9ae14b71
--- /dev/null
+++ b/contrib/libs/cxxsupp/builtins/hexagon/sfdiv_opt.S
@@ -0,0 +1,65 @@
+//===----------------------Hexagon builtin routine ------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+ .macro FUNCTION_BEGIN name
+ .text
+ .p2align 5
+ .globl \name
+ .type \name, @function
+\name:
+ .endm
+
+ .macro FUNCTION_END name
+ .size \name, . - \name
+ .endm
+
+#define Q6_ALIAS(TAG) .global __qdsp_##TAG ; .set __qdsp_##TAG, __hexagon_##TAG
+#define FAST_ALIAS(TAG) .global __hexagon_fast_##TAG ; .set __hexagon_fast_##TAG, __hexagon_##TAG
+#define FAST2_ALIAS(TAG) .global __hexagon_fast2_##TAG ; .set __hexagon_fast2_##TAG, __hexagon_##TAG
+
+FUNCTION_BEGIN __hexagon_divsf3
+ {
+ r2,p0 = sfrecipa(r0,r1)
+ r4 = sffixupd(r0,r1)
+ r3 = ##0x3f800000 // 1.0
+ }
+ {
+ r5 = sffixupn(r0,r1)
+ r3 -= sfmpy(r4,r2):lib // 1-(den/recip) yields error?
+ r6 = ##0x80000000
+ r7 = r3
+ }
+ {
+ r2 += sfmpy(r3,r2):lib
+ r3 = r7
+ r6 = r5
+ r0 = and(r6,r5)
+ }
+ {
+ r3 -= sfmpy(r4,r2):lib
+ r0 += sfmpy(r5,r2):lib
+ }
+ {
+ r2 += sfmpy(r3,r2):lib
+ r6 -= sfmpy(r0,r4):lib
+ }
+ {
+ r0 += sfmpy(r6,r2):lib
+ }
+ {
+ r5 -= sfmpy(r0,r4):lib
+ }
+ {
+ r0 += sfmpy(r5,r2,p0):scale
+ jumpr r31
+ }
+FUNCTION_END __hexagon_divsf3
+
+Q6_ALIAS(divsf3)
+FAST_ALIAS(divsf3)
+FAST2_ALIAS(divsf3)
diff --git a/contrib/libs/cxxsupp/builtins/hexagon/sfsqrt_opt.S b/contrib/libs/cxxsupp/builtins/hexagon/sfsqrt_opt.S
new file mode 100644
index 0000000000..532df9a06d
--- /dev/null
+++ b/contrib/libs/cxxsupp/builtins/hexagon/sfsqrt_opt.S
@@ -0,0 +1,81 @@
+//===----------------------Hexagon builtin routine ------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+ .macro FUNCTION_BEGIN name
+ .text
+ .p2align 5
+ .globl \name
+ .type \name, @function
+\name:
+ .endm
+
+ .macro FUNCTION_END name
+ .size \name, . - \name
+ .endm
+
+#define RIN r0
+#define S r0
+#define H r1
+#define D r2
+#define E r3
+#define HALF r4
+#define R r5
+
+#define Q6_ALIAS(TAG) .global __qdsp_##TAG ; .set __qdsp_##TAG, __hexagon_##TAG
+#define FAST_ALIAS(TAG) .global __hexagon_fast_##TAG ; .set __hexagon_fast_##TAG, __hexagon_##TAG
+#define FAST2_ALIAS(TAG) .global __hexagon_fast2_##TAG ; .set __hexagon_fast2_##TAG, __hexagon_##TAG
+
+FUNCTION_BEGIN __hexagon_sqrtf
+ {
+ E,p0 = sfinvsqrta(RIN)
+ R = sffixupr(RIN)
+ HALF = ##0x3f000000 // 0.5
+ r1:0 = combine(#0,#0) // clear S/H
+ }
+ {
+ S += sfmpy(E,R):lib // S0
+ H += sfmpy(E,HALF):lib // H0
+ D = HALF
+ E = R
+ }
+ {
+ D -= sfmpy(S,H):lib // d0
+ p1 = sfclass(R,#1) // is zero?
+ //E -= sfmpy(S,S):lib // e0
+ }
+ {
+ S += sfmpy(S,D):lib // S1
+ H += sfmpy(H,D):lib // H1
+ D = HALF
+ E = R
+ }
+ {
+ D -= sfmpy(S,H):lib // d0
+ E -= sfmpy(S,S):lib // e0
+ }
+ {
+ S += sfmpy(H,E):lib // S2
+ H += sfmpy(H,D):lib // H2
+ D = HALF
+ E = R
+ }
+ {
+ //D -= sfmpy(S,H):lib // d2
+ E -= sfmpy(S,S):lib // e2
+ if (p1) r0 = or(r0,R) // sqrt(-0.0) = -0.0
+ }
+ {
+ S += sfmpy(H,E,p0):scale // S3
+ jumpr r31
+ }
+
+FUNCTION_END __hexagon_sqrtf
+
+Q6_ALIAS(sqrtf)
+FAST_ALIAS(sqrtf)
+FAST2_ALIAS(sqrtf)
diff --git a/contrib/libs/cxxsupp/builtins/hexagon/udivdi3.S b/contrib/libs/cxxsupp/builtins/hexagon/udivdi3.S
new file mode 100644
index 0000000000..23f931d4f5
--- /dev/null
+++ b/contrib/libs/cxxsupp/builtins/hexagon/udivdi3.S
@@ -0,0 +1,70 @@
+//===----------------------Hexagon builtin routine ------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+
+ .macro FUNCTION_BEGIN name
+ .text
+ .p2align 5
+ .globl \name
+ .type \name, @function
+\name:
+ .endm
+
+ .macro FUNCTION_END name
+ .size \name, . - \name
+ .endm
+
+
+FUNCTION_BEGIN __hexagon_udivdi3
+ {
+ r6 = cl0(r1:0) // count leading 0's of dividend (numerator)
+ r7 = cl0(r3:2) // count leading 0's of divisor (denominator)
+ r5:4 = r3:2 // divisor moved into working registers
+ r3:2 = r1:0 // dividend is the initial remainder, r3:2 contains remainder
+ }
+ {
+ r10 = sub(r7,r6) // left shift count for bit & divisor
+ r1:0 = #0 // initialize quotient to 0
+ r15:14 = #1 // initialize bit to 1
+ }
+ {
+ r11 = add(r10,#1) // loop count is 1 more than shift count
+ r13:12 = lsl(r5:4,r10) // shift divisor msb into same bit position as dividend msb
+ r15:14 = lsl(r15:14,r10) // shift the bit left by same amount as divisor
+ }
+ {
+ p0 = cmp.gtu(r5:4,r3:2) // check if divisor > dividend
+ loop0(1f,r11) // register loop
+ }
+ {
+ if (p0) jumpr r31 // if divisor > dividend, we're done, so return
+ }
+ .falign
+1:
+ {
+ p0 = cmp.gtu(r13:12,r3:2) // set predicate reg if shifted divisor > current remainder
+ }
+ {
+ r7:6 = sub(r3:2, r13:12) // subtract shifted divisor from current remainder
+ r9:8 = add(r1:0, r15:14) // save current quotient to temp (r9:8)
+ }
+ {
+ r1:0 = vmux(p0, r1:0, r9:8) // choose either current quotient or new quotient (r9:8)
+ r3:2 = vmux(p0, r3:2, r7:6) // choose either current remainder or new remainder (r7:6)
+ }
+ {
+ r15:14 = lsr(r15:14, #1) // shift bit right by 1 for next iteration
+ r13:12 = lsr(r13:12, #1) // shift "shifted divisor" right by 1 for next iteration
+ }:endloop0
+ {
+ jumpr r31 // return
+ }
+FUNCTION_END __hexagon_udivdi3
+
+ .globl __qdsp_udivdi3
+ .set __qdsp_udivdi3, __hexagon_udivdi3
diff --git a/contrib/libs/cxxsupp/builtins/hexagon/udivmoddi4.S b/contrib/libs/cxxsupp/builtins/hexagon/udivmoddi4.S
new file mode 100644
index 0000000000..6dbfc59bd6
--- /dev/null
+++ b/contrib/libs/cxxsupp/builtins/hexagon/udivmoddi4.S
@@ -0,0 +1,70 @@
+//===----------------------Hexagon builtin routine ------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+
+ .macro FUNCTION_BEGIN name
+ .text
+ .p2align 5
+ .globl \name
+ .type \name, @function
+\name:
+ .endm
+
+ .macro FUNCTION_END name
+ .size \name, . - \name
+ .endm
+
+
+FUNCTION_BEGIN __hexagon_udivmoddi4
+ {
+ r6 = cl0(r1:0) // count leading 0's of dividend (numerator)
+ r7 = cl0(r3:2) // count leading 0's of divisor (denominator)
+ r5:4 = r3:2 // divisor moved into working registers
+ r3:2 = r1:0 // dividend is the initial remainder, r3:2 contains remainder
+ }
+ {
+ r10 = sub(r7,r6) // left shift count for bit & divisor
+ r1:0 = #0 // initialize quotient to 0
+ r15:14 = #1 // initialize bit to 1
+ }
+ {
+ r11 = add(r10,#1) // loop count is 1 more than shift count
+ r13:12 = lsl(r5:4,r10) // shift divisor msb into same bit position as dividend msb
+ r15:14 = lsl(r15:14,r10) // shift the bit left by same amount as divisor
+ }
+ {
+ p0 = cmp.gtu(r5:4,r3:2) // check if divisor > dividend
+ loop0(1f,r11) // register loop
+ }
+ {
+ if (p0) jumpr r31 // if divisor > dividend, we're done, so return
+ }
+ .falign
+1:
+ {
+ p0 = cmp.gtu(r13:12,r3:2) // set predicate reg if shifted divisor > current remainder
+ }
+ {
+ r7:6 = sub(r3:2, r13:12) // subtract shifted divisor from current remainder
+ r9:8 = add(r1:0, r15:14) // save current quotient to temp (r9:8)
+ }
+ {
+ r1:0 = vmux(p0, r1:0, r9:8) // choose either current quotient or new quotient (r9:8)
+ r3:2 = vmux(p0, r3:2, r7:6) // choose either current remainder or new remainder (r7:6)
+ }
+ {
+ r15:14 = lsr(r15:14, #1) // shift bit right by 1 for next iteration
+ r13:12 = lsr(r13:12, #1) // shift "shifted divisor" right by 1 for next iteration
+ }:endloop0
+ {
+ jumpr r31 // return
+ }
+FUNCTION_END __hexagon_udivmoddi4
+
+ .globl __qdsp_udivmoddi4
+ .set __qdsp_udivmoddi4, __hexagon_udivmoddi4
diff --git a/contrib/libs/cxxsupp/builtins/hexagon/udivmodsi4.S b/contrib/libs/cxxsupp/builtins/hexagon/udivmodsi4.S
new file mode 100644
index 0000000000..9e231212d6
--- /dev/null
+++ b/contrib/libs/cxxsupp/builtins/hexagon/udivmodsi4.S
@@ -0,0 +1,59 @@
+//===----------------------Hexagon builtin routine ------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+
+ .macro FUNCTION_BEGIN name
+ .text
+ .p2align 5
+ .globl \name
+ .type \name, @function
+\name:
+ .endm
+
+ .macro FUNCTION_END name
+ .size \name, . - \name
+ .endm
+
+
+FUNCTION_BEGIN __hexagon_udivmodsi4
+ {
+ r2 = cl0(r0)
+ r3 = cl0(r1)
+ r5:4 = combine(#1,#0)
+ p0 = cmp.gtu(r1,r0)
+ }
+ {
+ r6 = sub(r3,r2)
+ r4 = r1
+ r1:0 = combine(r0,r4)
+ if (p0) jumpr r31
+ }
+ {
+ r3:2 = vlslw(r5:4,r6)
+ loop0(1f,r6)
+ p0 = cmp.eq(r6,#0)
+ if (p0.new) r4 = #0
+ }
+ .falign
+1:
+ {
+ p0 = cmp.gtu(r2,r1)
+ if (!p0.new) r1 = sub(r1,r2)
+ if (!p0.new) r0 = add(r0,r3)
+ r3:2 = vlsrw(r3:2,#1)
+ }:endloop0
+ {
+ p0 = cmp.gtu(r2,r1)
+ if (!p0.new) r1 = sub(r1,r4)
+ if (!p0.new) r0 = add(r0,r3)
+ jumpr r31
+ }
+FUNCTION_END __hexagon_udivmodsi4
+
+ .globl __qdsp_udivmodsi4
+ .set __qdsp_udivmodsi4, __hexagon_udivmodsi4
diff --git a/contrib/libs/cxxsupp/builtins/hexagon/udivsi3.S b/contrib/libs/cxxsupp/builtins/hexagon/udivsi3.S
new file mode 100644
index 0000000000..d68599a8e0
--- /dev/null
+++ b/contrib/libs/cxxsupp/builtins/hexagon/udivsi3.S
@@ -0,0 +1,55 @@
+//===----------------------Hexagon builtin routine ------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+ .macro FUNCTION_BEGIN name
+ .text
+ .p2align 5
+ .globl \name
+ .type \name, @function
+\name:
+ .endm
+
+ .macro FUNCTION_END name
+ .size \name, . - \name
+ .endm
+
+
+FUNCTION_BEGIN __hexagon_udivsi3
+ {
+ r2 = cl0(r0)
+ r3 = cl0(r1)
+ r5:4 = combine(#1,#0)
+ p0 = cmp.gtu(r1,r0)
+ }
+ {
+ r6 = sub(r3,r2)
+ r4 = r1
+ r1:0 = combine(r0,r4)
+ if (p0) jumpr r31
+ }
+ {
+ r3:2 = vlslw(r5:4,r6)
+ loop0(1f,r6)
+ }
+ .falign
+1:
+ {
+ p0 = cmp.gtu(r2,r1)
+ if (!p0.new) r1 = sub(r1,r2)
+ if (!p0.new) r0 = add(r0,r3)
+ r3:2 = vlsrw(r3:2,#1)
+ }:endloop0
+ {
+ p0 = cmp.gtu(r2,r1)
+ if (!p0.new) r0 = add(r0,r3)
+ jumpr r31
+ }
+FUNCTION_END __hexagon_udivsi3
+
+ .globl __qdsp_udivsi3
+ .set __qdsp_udivsi3, __hexagon_udivsi3
diff --git a/contrib/libs/cxxsupp/builtins/hexagon/umoddi3.S b/contrib/libs/cxxsupp/builtins/hexagon/umoddi3.S
new file mode 100644
index 0000000000..646ca128dd
--- /dev/null
+++ b/contrib/libs/cxxsupp/builtins/hexagon/umoddi3.S
@@ -0,0 +1,73 @@
+//===----------------------Hexagon builtin routine ------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+
+ .macro FUNCTION_BEGIN name
+ .text
+ .p2align 5
+ .globl \name
+ .type \name, @function
+\name:
+ .endm
+
+ .macro FUNCTION_END name
+ .size \name, . - \name
+ .endm
+
+
+FUNCTION_BEGIN __hexagon_umoddi3
+ {
+ r6 = cl0(r1:0) // count leading 0's of dividend (numerator)
+ r7 = cl0(r3:2) // count leading 0's of divisor (denominator)
+ r5:4 = r3:2 // divisor moved into working registers
+ r3:2 = r1:0 // dividend is the initial remainder, r3:2 contains remainder
+ }
+ {
+ r10 = sub(r7,r6) // left shift count for bit & divisor
+ r1:0 = #0 // initialize quotient to 0
+ r15:14 = #1 // initialize bit to 1
+ }
+ {
+ r11 = add(r10,#1) // loop count is 1 more than shift count
+ r13:12 = lsl(r5:4,r10) // shift divisor msb into same bit position as dividend msb
+ r15:14 = lsl(r15:14,r10) // shift the bit left by same amount as divisor
+ }
+ {
+ p0 = cmp.gtu(r5:4,r3:2) // check if divisor > dividend
+ loop0(1f,r11) // register loop
+ }
+ {
+ if (p0) jump .hexagon_umoddi3_return // if divisor > dividend, we're done, so return
+ }
+ .falign
+1:
+ {
+ p0 = cmp.gtu(r13:12,r3:2) // set predicate reg if shifted divisor > current remainder
+ }
+ {
+ r7:6 = sub(r3:2, r13:12) // subtract shifted divisor from current remainder
+ r9:8 = add(r1:0, r15:14) // save current quotient to temp (r9:8)
+ }
+ {
+ r1:0 = vmux(p0, r1:0, r9:8) // choose either current quotient or new quotient (r9:8)
+ r3:2 = vmux(p0, r3:2, r7:6) // choose either current remainder or new remainder (r7:6)
+ }
+ {
+ r15:14 = lsr(r15:14, #1) // shift bit right by 1 for next iteration
+ r13:12 = lsr(r13:12, #1) // shift "shifted divisor" right by 1 for next iteration
+ }:endloop0
+
+.hexagon_umoddi3_return:
+ {
+ r1:0 = r3:2
+ jumpr r31
+ }
+FUNCTION_END __hexagon_umoddi3
+
+ .globl __qdsp_umoddi3
+ .set __qdsp_umoddi3, __hexagon_umoddi3
diff --git a/contrib/libs/cxxsupp/builtins/hexagon/umodsi3.S b/contrib/libs/cxxsupp/builtins/hexagon/umodsi3.S
new file mode 100644
index 0000000000..a923944862
--- /dev/null
+++ b/contrib/libs/cxxsupp/builtins/hexagon/umodsi3.S
@@ -0,0 +1,54 @@
+//===----------------------Hexagon builtin routine ------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+
+ .macro FUNCTION_BEGIN name
+ .text
+ .p2align 5
+ .globl \name
+ .type \name, @function
+\name:
+ .endm
+
+ .macro FUNCTION_END name
+ .size \name, . - \name
+ .endm
+
+
+FUNCTION_BEGIN __hexagon_umodsi3
+ {
+ r2 = cl0(r0)
+ r3 = cl0(r1)
+ p0 = cmp.gtu(r1,r0)
+ }
+ {
+ r2 = sub(r3,r2)
+ if (p0) jumpr r31
+ }
+ {
+ loop0(1f,r2)
+ p1 = cmp.eq(r2,#0)
+ r2 = lsl(r1,r2)
+ }
+ .falign
+1:
+ {
+ p0 = cmp.gtu(r2,r0)
+ if (!p0.new) r0 = sub(r0,r2)
+ r2 = lsr(r2,#1)
+ if (p1) r1 = #0
+ }:endloop0
+ {
+ p0 = cmp.gtu(r2,r0)
+ if (!p0.new) r0 = sub(r0,r1)
+ jumpr r31
+ }
+FUNCTION_END __hexagon_umodsi3
+
+ .globl __qdsp_umodsi3
+ .set __qdsp_umodsi3, __hexagon_umodsi3
diff --git a/contrib/libs/cxxsupp/builtins/i386/Makefile.mk b/contrib/libs/cxxsupp/builtins/i386/Makefile.mk
deleted file mode 100644
index f3776a02c0..0000000000
--- a/contrib/libs/cxxsupp/builtins/i386/Makefile.mk
+++ /dev/null
@@ -1,20 +0,0 @@
-#===- lib/builtins/i386/Makefile.mk ------------------------*- Makefile -*--===#
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-#===------------------------------------------------------------------------===#
-
-ModuleName := builtins
-SubDirs :=
-OnlyArchs := i386
-
-AsmSources := $(foreach file,$(wildcard $(Dir)/*.S),$(notdir $(file)))
-Sources := $(foreach file,$(wildcard $(Dir)/*.c),$(notdir $(file)))
-ObjNames := $(Sources:%.c=%.o) $(AsmSources:%.S=%.o)
-Implementation := Optimized
-
-# FIXME: use automatic dependencies?
-Dependencies := $(wildcard lib/*.h $(Dir)/*.h)
diff --git a/contrib/libs/cxxsupp/builtins/i386/ashldi3.S b/contrib/libs/cxxsupp/builtins/i386/ashldi3.S
index 3fbd739038..7ba912692f 100644
--- a/contrib/libs/cxxsupp/builtins/i386/ashldi3.S
+++ b/contrib/libs/cxxsupp/builtins/i386/ashldi3.S
@@ -1,5 +1,6 @@
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#include "../assembly.h"
@@ -56,3 +57,6 @@ END_COMPILERRT_FUNCTION(__ashldi3)
#endif // __SSE2__
#endif // __i386__
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/i386/ashrdi3.S b/contrib/libs/cxxsupp/builtins/i386/ashrdi3.S
index 8f4742481b..3cca4782ae 100644
--- a/contrib/libs/cxxsupp/builtins/i386/ashrdi3.S
+++ b/contrib/libs/cxxsupp/builtins/i386/ashrdi3.S
@@ -1,5 +1,6 @@
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#include "../assembly.h"
@@ -22,10 +23,10 @@ DEFINE_COMPILERRT_FUNCTION(__ashrdi3)
#endif
psrlq %xmm2, %xmm0 // unsigned shift input by count
-
+
testl %eax, %eax // check the sign-bit of the input
jns 1f // early out for positive inputs
-
+
// If the input is negative, we need to construct the shifted sign bit
// to or into the result, as xmm does not have a signed right shift.
pcmpeqb %xmm1, %xmm1 // -1ULL
@@ -35,7 +36,7 @@ DEFINE_COMPILERRT_FUNCTION(__ashrdi3)
psubq %xmm1, %xmm2 // 64 - count
psllq %xmm2, %xmm1 // -1 << (64 - count) = leading sign bits
por %xmm1, %xmm0
-
+
// Move the result back to the general purpose registers and return
1: movd %xmm0, %eax
psrlq $32, %xmm0
@@ -51,14 +52,14 @@ DEFINE_COMPILERRT_FUNCTION(__ashrdi3)
movl 12(%esp), %ecx // Load count
movl 8(%esp), %edx // Load high
movl 4(%esp), %eax // Load low
-
+
testl $0x20, %ecx // If count >= 32
jnz 1f // goto 1
shrdl %cl, %edx, %eax // right shift low by count
sarl %cl, %edx // right shift high by count
ret
-
+
1: movl %edx, %eax // Move high to low
sarl $31, %edx // clear high
sarl %cl, %eax // shift low by count - 32
@@ -67,3 +68,6 @@ END_COMPILERRT_FUNCTION(__ashrdi3)
#endif // __SSE2__
#endif // __i386__
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/i386/chkstk.S b/contrib/libs/cxxsupp/builtins/i386/chkstk.S
index b59974868f..f0bea21874 100644
--- a/contrib/libs/cxxsupp/builtins/i386/chkstk.S
+++ b/contrib/libs/cxxsupp/builtins/i386/chkstk.S
@@ -1,5 +1,6 @@
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#include "../assembly.h"
diff --git a/contrib/libs/cxxsupp/builtins/i386/chkstk2.S b/contrib/libs/cxxsupp/builtins/i386/chkstk2.S
index 7d65bb0889..5d6cbdfa5c 100644
--- a/contrib/libs/cxxsupp/builtins/i386/chkstk2.S
+++ b/contrib/libs/cxxsupp/builtins/i386/chkstk2.S
@@ -1,5 +1,6 @@
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#include "../assembly.h"
diff --git a/contrib/libs/cxxsupp/builtins/i386/divdi3.S b/contrib/libs/cxxsupp/builtins/i386/divdi3.S
index 2cb0ddd4c2..09e1e42eb7 100644
--- a/contrib/libs/cxxsupp/builtins/i386/divdi3.S
+++ b/contrib/libs/cxxsupp/builtins/i386/divdi3.S
@@ -1,5 +1,6 @@
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#include "../assembly.h"
@@ -22,9 +23,9 @@
.balign 4
DEFINE_COMPILERRT_FUNCTION(__divdi3)
-/* This is currently implemented by wrapping the unsigned divide up in an absolute
- value, then restoring the correct sign at the end of the computation. This could
- certainly be improved upon. */
+// This is currently implemented by wrapping the unsigned divide up in an absolute
+// value, then restoring the correct sign at the end of the computation. This could
+// certainly be improved upon.
pushl %esi
movl 20(%esp), %edx // high word of b
@@ -38,7 +39,7 @@ DEFINE_COMPILERRT_FUNCTION(__divdi3)
movl %edx, 20(%esp)
movl %eax, 16(%esp) // store abs(b) back to stack
movl %ecx, %esi // set aside sign of b
-
+
movl 12(%esp), %edx // high word of b
movl 8(%esp), %eax // low word of b
movl %edx, %ecx
@@ -55,11 +56,11 @@ DEFINE_COMPILERRT_FUNCTION(__divdi3)
movl 24(%esp), %ebx // Find the index i of the leading bit in b.
bsrl %ebx, %ecx // If the high word of b is zero, jump to
jz 9f // the code to handle that special case [9].
-
- /* High word of b is known to be non-zero on this branch */
-
+
+ // High word of b is known to be non-zero on this branch
+
movl 20(%esp), %eax // Construct bhi, containing bits [1+i:32+i] of b
-
+
shrl %cl, %eax // Practically, this means that bhi is given by:
shrl %eax //
notl %ecx // bhi = (high word of b) << (31 - i) |
@@ -68,10 +69,10 @@ DEFINE_COMPILERRT_FUNCTION(__divdi3)
movl 16(%esp), %edx // Load the high and low words of a, and jump
movl 12(%esp), %eax // to [1] if the high word is larger than bhi
cmpl %ebx, %edx // to avoid overflowing the upcoming divide.
- jae 1f
-
- /* High word of a is greater than or equal to (b >> (1 + i)) on this branch */
-
+ jae 1f
+
+ // High word of a is greater than or equal to (b >> (1 + i)) on this branch
+
divl %ebx // eax <-- qs, edx <-- r such that ahi:alo = bs*qs + r
pushl %edi
@@ -90,7 +91,7 @@ DEFINE_COMPILERRT_FUNCTION(__divdi3)
sbbl $0, %edi // decrement q if remainder is negative
xorl %edx, %edx
movl %edi, %eax
-
+
addl %esi, %eax // Restore correct sign to result
adcl %esi, %edx
xorl %esi, %eax
@@ -101,8 +102,8 @@ DEFINE_COMPILERRT_FUNCTION(__divdi3)
retl // Return
-1: /* High word of a is greater than or equal to (b >> (1 + i)) on this branch */
-
+1: // High word of a is greater than or equal to (b >> (1 + i)) on this branch
+
subl %ebx, %edx // subtract bhi from ahi so that divide will not
divl %ebx // overflow, and find q and r such that
//
@@ -128,7 +129,7 @@ DEFINE_COMPILERRT_FUNCTION(__divdi3)
sbbl $0, %edi // decrement q if remainder is negative
xorl %edx, %edx
movl %edi, %eax
-
+
addl %esi, %eax // Restore correct sign to result
adcl %esi, %edx
xorl %esi, %eax
@@ -138,8 +139,8 @@ DEFINE_COMPILERRT_FUNCTION(__divdi3)
popl %esi
retl // Return
-
-9: /* High word of b is zero on this branch */
+
+9: // High word of b is zero on this branch
movl 16(%esp), %eax // Find qhi and rhi such that
movl 20(%esp), %ecx //
@@ -149,7 +150,7 @@ DEFINE_COMPILERRT_FUNCTION(__divdi3)
movl 12(%esp), %eax // Find qlo such that
divl %ecx //
movl %ebx, %edx // rhi:alo = qlo*b + rlo with 0 ≤ rlo < b
-
+
addl %esi, %eax // Restore correct sign to result
adcl %esi, %edx
xorl %esi, %eax
@@ -160,3 +161,6 @@ DEFINE_COMPILERRT_FUNCTION(__divdi3)
END_COMPILERRT_FUNCTION(__divdi3)
#endif // __i386__
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/i386/floatdidf.S b/contrib/libs/cxxsupp/builtins/i386/floatdidf.S
index dcc32f8ed8..d588e77036 100644
--- a/contrib/libs/cxxsupp/builtins/i386/floatdidf.S
+++ b/contrib/libs/cxxsupp/builtins/i386/floatdidf.S
@@ -1,9 +1,10 @@
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#include "../assembly.h"
-// double __floatundidf(du_int a);
+// double __floatdidf(du_int a);
#ifdef __i386__
@@ -37,3 +38,6 @@ DEFINE_COMPILERRT_FUNCTION(__floatdidf)
END_COMPILERRT_FUNCTION(__floatdidf)
#endif // __i386__
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/i386/floatdisf.S b/contrib/libs/cxxsupp/builtins/i386/floatdisf.S
index f642767036..d91f14e9f3 100644
--- a/contrib/libs/cxxsupp/builtins/i386/floatdisf.S
+++ b/contrib/libs/cxxsupp/builtins/i386/floatdisf.S
@@ -1,5 +1,6 @@
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#include "../assembly.h"
@@ -30,3 +31,6 @@ DEFINE_COMPILERRT_FUNCTION(__floatdisf)
END_COMPILERRT_FUNCTION(__floatdisf)
#endif // __i386__
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/i386/floatdixf.S b/contrib/libs/cxxsupp/builtins/i386/floatdixf.S
index 839b0434c0..19dd0835a9 100644
--- a/contrib/libs/cxxsupp/builtins/i386/floatdixf.S
+++ b/contrib/libs/cxxsupp/builtins/i386/floatdixf.S
@@ -1,9 +1,10 @@
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#include "../assembly.h"
-// float __floatdixf(di_int a);
+// long double __floatdixf(di_int a);
#ifdef __i386__
@@ -28,3 +29,6 @@ DEFINE_COMPILERRT_FUNCTION(__floatdixf)
END_COMPILERRT_FUNCTION(__floatdixf)
#endif // __i386__
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/i386/floatundidf.S b/contrib/libs/cxxsupp/builtins/i386/floatundidf.S
index 8058c2ac0a..8b1b666ce1 100644
--- a/contrib/libs/cxxsupp/builtins/i386/floatundidf.S
+++ b/contrib/libs/cxxsupp/builtins/i386/floatundidf.S
@@ -1,9 +1,8 @@
//===-- floatundidf.S - Implement __floatundidf for i386 ------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -50,3 +49,6 @@ DEFINE_COMPILERRT_FUNCTION(__floatundidf)
END_COMPILERRT_FUNCTION(__floatundidf)
#endif // __i386__
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/i386/floatundisf.S b/contrib/libs/cxxsupp/builtins/i386/floatundisf.S
index 94c97e25aa..44301719ed 100644
--- a/contrib/libs/cxxsupp/builtins/i386/floatundisf.S
+++ b/contrib/libs/cxxsupp/builtins/i386/floatundisf.S
@@ -1,5 +1,6 @@
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#include "../assembly.h"
@@ -48,7 +49,7 @@ END_COMPILERRT_FUNCTION(__floatundisf)
*/
-/* branch-free, x87-free implementation - faster at the expense of code size */
+// branch-free, x87-free implementation - faster at the expense of code size
#ifdef __i386__
@@ -78,7 +79,7 @@ DEFINE_COMPILERRT_FUNCTION(__floatundisf)
movd 8(%esp), %xmm1
movd 4(%esp), %xmm0
punpckldq %xmm1, %xmm0
-
+
calll 0f
0: popl %ecx
shrl %eax // high 31 bits of input as sint32
@@ -103,3 +104,6 @@ DEFINE_COMPILERRT_FUNCTION(__floatundisf)
END_COMPILERRT_FUNCTION(__floatundisf)
#endif // __i386__
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/i386/floatundixf.S b/contrib/libs/cxxsupp/builtins/i386/floatundixf.S
index 814b52f941..30b4d9f4b9 100644
--- a/contrib/libs/cxxsupp/builtins/i386/floatundixf.S
+++ b/contrib/libs/cxxsupp/builtins/i386/floatundixf.S
@@ -1,5 +1,6 @@
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#include "../assembly.h"
@@ -41,3 +42,6 @@ DEFINE_COMPILERRT_FUNCTION(__floatundixf)
END_COMPILERRT_FUNCTION(__floatundixf)
#endif // __i386__
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/i386/fp_mode.c b/contrib/libs/cxxsupp/builtins/i386/fp_mode.c
new file mode 100644
index 0000000000..887ca9c34c
--- /dev/null
+++ b/contrib/libs/cxxsupp/builtins/i386/fp_mode.c
@@ -0,0 +1,39 @@
+//===----- lib/i386/fp_mode.c - Floaing-point mode utilities -----*- C -*-====//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "../fp_mode.h"
+
+#define X87_TONEAREST 0x0000
+#define X87_DOWNWARD 0x0400
+#define X87_UPWARD 0x0800
+#define X87_TOWARDZERO 0x0c00
+#define X87_RMODE_MASK (X87_TONEAREST | X87_UPWARD | X87_DOWNWARD | X87_TOWARDZERO)
+
+CRT_FE_ROUND_MODE __fe_getround(void) {
+ // Assume that the rounding mode state for the fpu agrees with the SSE unit.
+ unsigned short cw;
+ __asm__ __volatile__ ("fnstcw %0" : "=m" (cw));
+
+ switch (cw & X87_RMODE_MASK) {
+ case X87_TONEAREST:
+ return CRT_FE_TONEAREST;
+ case X87_DOWNWARD:
+ return CRT_FE_DOWNWARD;
+ case X87_UPWARD:
+ return CRT_FE_UPWARD;
+ case X87_TOWARDZERO:
+ return CRT_FE_TOWARDZERO;
+ }
+ return CRT_FE_TONEAREST;
+}
+
+int __fe_raise_inexact(void) {
+ float f = 1.0f, g = 3.0f;
+ __asm__ __volatile__ ("fdivs %1" : "+t" (f) : "m" (g));
+ return 0;
+}
diff --git a/contrib/libs/cxxsupp/builtins/i386/lshrdi3.S b/contrib/libs/cxxsupp/builtins/i386/lshrdi3.S
index b80f11a380..896633e85d 100644
--- a/contrib/libs/cxxsupp/builtins/i386/lshrdi3.S
+++ b/contrib/libs/cxxsupp/builtins/i386/lshrdi3.S
@@ -1,5 +1,6 @@
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#include "../assembly.h"
@@ -41,14 +42,14 @@ DEFINE_COMPILERRT_FUNCTION(__lshrdi3)
movl 12(%esp), %ecx // Load count
movl 8(%esp), %edx // Load high
movl 4(%esp), %eax // Load low
-
+
testl $0x20, %ecx // If count >= 32
jnz 1f // goto 1
shrdl %cl, %edx, %eax // right shift low by count
shrl %cl, %edx // right shift high by count
ret
-
+
1: movl %edx, %eax // Move high to low
xorl %edx, %edx // clear high
shrl %cl, %eax // shift low by count - 32
@@ -57,3 +58,6 @@ END_COMPILERRT_FUNCTION(__lshrdi3)
#endif // __SSE2__
#endif // __i386__
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/i386/moddi3.S b/contrib/libs/cxxsupp/builtins/i386/moddi3.S
index b9cee9d7aa..4580f20ead 100644
--- a/contrib/libs/cxxsupp/builtins/i386/moddi3.S
+++ b/contrib/libs/cxxsupp/builtins/i386/moddi3.S
@@ -1,5 +1,6 @@
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#include "../assembly.h"
@@ -23,8 +24,8 @@
.balign 4
DEFINE_COMPILERRT_FUNCTION(__moddi3)
-/* This is currently implemented by wrapping the unsigned modulus up in an absolute
- value. This could certainly be improved upon. */
+// This is currently implemented by wrapping the unsigned modulus up in an absolute
+// value. This could certainly be improved upon.
pushl %esi
movl 20(%esp), %edx // high word of b
@@ -37,7 +38,7 @@ DEFINE_COMPILERRT_FUNCTION(__moddi3)
sbbl %ecx, %edx // EDX:EAX = abs(b)
movl %edx, 20(%esp)
movl %eax, 16(%esp) // store abs(b) back to stack
-
+
movl 12(%esp), %edx // high word of b
movl 8(%esp), %eax // low word of b
movl %edx, %ecx
@@ -54,11 +55,11 @@ DEFINE_COMPILERRT_FUNCTION(__moddi3)
movl 24(%esp), %ebx // Find the index i of the leading bit in b.
bsrl %ebx, %ecx // If the high word of b is zero, jump to
jz 9f // the code to handle that special case [9].
-
- /* High word of b is known to be non-zero on this branch */
-
+
+ // High word of b is known to be non-zero on this branch
+
movl 20(%esp), %eax // Construct bhi, containing bits [1+i:32+i] of b
-
+
shrl %cl, %eax // Practically, this means that bhi is given by:
shrl %eax //
notl %ecx // bhi = (high word of b) << (31 - i) |
@@ -67,10 +68,10 @@ DEFINE_COMPILERRT_FUNCTION(__moddi3)
movl 16(%esp), %edx // Load the high and low words of a, and jump
movl 12(%esp), %eax // to [2] if the high word is larger than bhi
cmpl %ebx, %edx // to avoid overflowing the upcoming divide.
- jae 2f
-
- /* High word of a is greater than or equal to (b >> (1 + i)) on this branch */
-
+ jae 2f
+
+ // High word of a is greater than or equal to (b >> (1 + i)) on this branch
+
divl %ebx // eax <-- qs, edx <-- r such that ahi:alo = bs*qs + r
pushl %edi
@@ -86,13 +87,13 @@ DEFINE_COMPILERRT_FUNCTION(__moddi3)
movl 28(%esp), %eax
imull %edi, %eax // q*bhi
subl %eax, %ecx // ECX:EBX = a - q*b
-
+
jnc 1f // if positive, this is the result.
addl 24(%esp), %ebx // otherwise
adcl 28(%esp), %ecx // ECX:EBX = a - (q-1)*b = result
1: movl %ebx, %eax
movl %ecx, %edx
-
+
addl %esi, %eax // Restore correct sign to result
adcl %esi, %edx
xorl %esi, %eax
@@ -102,8 +103,8 @@ DEFINE_COMPILERRT_FUNCTION(__moddi3)
popl %esi
retl // Return
-2: /* High word of a is greater than or equal to (b >> (1 + i)) on this branch */
-
+2: // High word of a is greater than or equal to (b >> (1 + i)) on this branch
+
subl %ebx, %edx // subtract bhi from ahi so that divide will not
divl %ebx // overflow, and find q and r such that
//
@@ -132,7 +133,7 @@ DEFINE_COMPILERRT_FUNCTION(__moddi3)
adcl 28(%esp), %ecx // ECX:EBX = a - (q-1)*b = result
3: movl %ebx, %eax
movl %ecx, %edx
-
+
addl %esi, %eax // Restore correct sign to result
adcl %esi, %edx
xorl %esi, %eax
@@ -141,8 +142,8 @@ DEFINE_COMPILERRT_FUNCTION(__moddi3)
popl %ebx
popl %esi
retl // Return
-
-9: /* High word of b is zero on this branch */
+
+9: // High word of b is zero on this branch
movl 16(%esp), %eax // Find qhi and rhi such that
movl 20(%esp), %ecx //
@@ -164,3 +165,6 @@ DEFINE_COMPILERRT_FUNCTION(__moddi3)
END_COMPILERRT_FUNCTION(__moddi3)
#endif // __i386__
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/i386/muldi3.S b/contrib/libs/cxxsupp/builtins/i386/muldi3.S
index 15b6b49984..a898e24146 100644
--- a/contrib/libs/cxxsupp/builtins/i386/muldi3.S
+++ b/contrib/libs/cxxsupp/builtins/i386/muldi3.S
@@ -1,5 +1,6 @@
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#include "../assembly.h"
@@ -14,17 +15,20 @@ DEFINE_COMPILERRT_FUNCTION(__muldi3)
movl 16(%esp), %eax // b.lo
movl 12(%esp), %ecx // a.hi
imull %eax, %ecx // b.lo * a.hi
-
+
movl 8(%esp), %edx // a.lo
movl 20(%esp), %ebx // b.hi
imull %edx, %ebx // a.lo * b.hi
-
+
mull %edx // EDX:EAX = a.lo * b.lo
addl %ecx, %ebx // EBX = (a.lo*b.hi + a.hi*b.lo)
addl %ebx, %edx
-
+
popl %ebx
retl
END_COMPILERRT_FUNCTION(__muldi3)
#endif // __i386__
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/i386/udivdi3.S b/contrib/libs/cxxsupp/builtins/i386/udivdi3.S
index 41b2edf03e..ca390245ea 100644
--- a/contrib/libs/cxxsupp/builtins/i386/udivdi3.S
+++ b/contrib/libs/cxxsupp/builtins/i386/udivdi3.S
@@ -1,5 +1,6 @@
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#include "../assembly.h"
@@ -26,11 +27,11 @@ DEFINE_COMPILERRT_FUNCTION(__udivdi3)
movl 20(%esp), %ebx // Find the index i of the leading bit in b.
bsrl %ebx, %ecx // If the high word of b is zero, jump to
jz 9f // the code to handle that special case [9].
-
- /* High word of b is known to be non-zero on this branch */
-
+
+ // High word of b is known to be non-zero on this branch
+
movl 16(%esp), %eax // Construct bhi, containing bits [1+i:32+i] of b
-
+
shrl %cl, %eax // Practically, this means that bhi is given by:
shrl %eax //
notl %ecx // bhi = (high word of b) << (31 - i) |
@@ -39,10 +40,10 @@ DEFINE_COMPILERRT_FUNCTION(__udivdi3)
movl 12(%esp), %edx // Load the high and low words of a, and jump
movl 8(%esp), %eax // to [1] if the high word is larger than bhi
cmpl %ebx, %edx // to avoid overflowing the upcoming divide.
- jae 1f
-
- /* High word of a is greater than or equal to (b >> (1 + i)) on this branch */
-
+ jae 1f
+
+ // High word of a is greater than or equal to (b >> (1 + i)) on this branch
+
divl %ebx // eax <-- qs, edx <-- r such that ahi:alo = bs*qs + r
pushl %edi
@@ -66,8 +67,8 @@ DEFINE_COMPILERRT_FUNCTION(__udivdi3)
retl
-1: /* High word of a is greater than or equal to (b >> (1 + i)) on this branch */
-
+1: // High word of a is greater than or equal to (b >> (1 + i)) on this branch
+
subl %ebx, %edx // subtract bhi from ahi so that divide will not
divl %ebx // overflow, and find q and r such that
//
@@ -97,8 +98,8 @@ DEFINE_COMPILERRT_FUNCTION(__udivdi3)
popl %ebx
retl
-
-9: /* High word of b is zero on this branch */
+
+9: // High word of b is zero on this branch
movl 12(%esp), %eax // Find qhi and rhi such that
movl 16(%esp), %ecx //
@@ -113,3 +114,6 @@ DEFINE_COMPILERRT_FUNCTION(__udivdi3)
END_COMPILERRT_FUNCTION(__udivdi3)
#endif // __i386__
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/i386/umoddi3.S b/contrib/libs/cxxsupp/builtins/i386/umoddi3.S
index a190a7d397..2717e7e5da 100644
--- a/contrib/libs/cxxsupp/builtins/i386/umoddi3.S
+++ b/contrib/libs/cxxsupp/builtins/i386/umoddi3.S
@@ -1,5 +1,6 @@
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#include "../assembly.h"
@@ -27,11 +28,11 @@ DEFINE_COMPILERRT_FUNCTION(__umoddi3)
movl 20(%esp), %ebx // Find the index i of the leading bit in b.
bsrl %ebx, %ecx // If the high word of b is zero, jump to
jz 9f // the code to handle that special case [9].
-
- /* High word of b is known to be non-zero on this branch */
-
+
+ // High word of b is known to be non-zero on this branch
+
movl 16(%esp), %eax // Construct bhi, containing bits [1+i:32+i] of b
-
+
shrl %cl, %eax // Practically, this means that bhi is given by:
shrl %eax //
notl %ecx // bhi = (high word of b) << (31 - i) |
@@ -40,10 +41,10 @@ DEFINE_COMPILERRT_FUNCTION(__umoddi3)
movl 12(%esp), %edx // Load the high and low words of a, and jump
movl 8(%esp), %eax // to [2] if the high word is larger than bhi
cmpl %ebx, %edx // to avoid overflowing the upcoming divide.
- jae 2f
-
- /* High word of a is greater than or equal to (b >> (1 + i)) on this branch */
-
+ jae 2f
+
+ // High word of a is greater than or equal to (b >> (1 + i)) on this branch
+
divl %ebx // eax <-- qs, edx <-- r such that ahi:alo = bs*qs + r
pushl %edi
@@ -59,20 +60,20 @@ DEFINE_COMPILERRT_FUNCTION(__umoddi3)
movl 24(%esp), %eax
imull %edi, %eax // q*bhi
subl %eax, %ecx // ECX:EBX = a - q*b
-
+
jnc 1f // if positive, this is the result.
addl 20(%esp), %ebx // otherwise
adcl 24(%esp), %ecx // ECX:EBX = a - (q-1)*b = result
1: movl %ebx, %eax
movl %ecx, %edx
-
+
popl %edi
popl %ebx
retl
-2: /* High word of a is greater than or equal to (b >> (1 + i)) on this branch */
-
+2: // High word of a is greater than or equal to (b >> (1 + i)) on this branch
+
subl %ebx, %edx // subtract bhi from ahi so that divide will not
divl %ebx // overflow, and find q and r such that
//
@@ -101,14 +102,14 @@ DEFINE_COMPILERRT_FUNCTION(__umoddi3)
adcl 24(%esp), %ecx // ECX:EBX = a - (q-1)*b = result
3: movl %ebx, %eax
movl %ecx, %edx
-
+
popl %edi
popl %ebx
retl
-
-9: /* High word of b is zero on this branch */
+
+9: // High word of b is zero on this branch
movl 12(%esp), %eax // Find qhi and rhi such that
movl 16(%esp), %ecx //
@@ -120,7 +121,10 @@ DEFINE_COMPILERRT_FUNCTION(__umoddi3)
movl %edx, %eax // rhi:alo = qlo*b + rlo with 0 ≤ rlo < b
popl %ebx //
xorl %edx, %edx // and return 0:rlo
- retl //
+ retl //
END_COMPILERRT_FUNCTION(__umoddi3)
#endif // __i386__
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/int_div_impl.inc b/contrib/libs/cxxsupp/builtins/int_div_impl.inc
new file mode 100644
index 0000000000..dc1f97cbea
--- /dev/null
+++ b/contrib/libs/cxxsupp/builtins/int_div_impl.inc
@@ -0,0 +1,95 @@
+//===-- int_div_impl.inc - Integer division ---------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Helpers used by __udivsi3, __umodsi3, __udivdi3, and __umodsi3.
+//
+//===----------------------------------------------------------------------===//
+
+#define clz(a) (sizeof(a) == sizeof(unsigned long long) ? __builtin_clzll(a) : clzsi(a))
+
+// Adapted from Figure 3-40 of The PowerPC Compiler Writer's Guide
+static __inline fixuint_t __udivXi3(fixuint_t n, fixuint_t d) {
+ const unsigned N = sizeof(fixuint_t) * CHAR_BIT;
+ // d == 0 cases are unspecified.
+ unsigned sr = (d ? clz(d) : N) - (n ? clz(n) : N);
+ // 0 <= sr <= N - 1 or sr is very large.
+ if (sr > N - 1) // n < d
+ return 0;
+ if (sr == N - 1) // d == 1
+ return n;
+ ++sr;
+ // 1 <= sr <= N - 1. Shifts do not trigger UB.
+ fixuint_t r = n >> sr;
+ n <<= N - sr;
+ fixuint_t carry = 0;
+ for (; sr > 0; --sr) {
+ r = (r << 1) | (n >> (N - 1));
+ n = (n << 1) | carry;
+ // Branch-less version of:
+ // carry = 0;
+ // if (r >= d) r -= d, carry = 1;
+ const fixint_t s = (fixint_t)(d - r - 1) >> (N - 1);
+ carry = s & 1;
+ r -= d & s;
+ }
+ n = (n << 1) | carry;
+ return n;
+}
+
+// Mostly identical to __udivXi3 but the return values are different.
+static __inline fixuint_t __umodXi3(fixuint_t n, fixuint_t d) {
+ const unsigned N = sizeof(fixuint_t) * CHAR_BIT;
+ // d == 0 cases are unspecified.
+ unsigned sr = (d ? clz(d) : N) - (n ? clz(n) : N);
+ // 0 <= sr <= N - 1 or sr is very large.
+ if (sr > N - 1) // n < d
+ return n;
+ if (sr == N - 1) // d == 1
+ return 0;
+ ++sr;
+ // 1 <= sr <= N - 1. Shifts do not trigger UB.
+ fixuint_t r = n >> sr;
+ n <<= N - sr;
+ fixuint_t carry = 0;
+ for (; sr > 0; --sr) {
+ r = (r << 1) | (n >> (N - 1));
+ n = (n << 1) | carry;
+ // Branch-less version of:
+ // carry = 0;
+ // if (r >= d) r -= d, carry = 1;
+ const fixint_t s = (fixint_t)(d - r - 1) >> (N - 1);
+ carry = s & 1;
+ r -= d & s;
+ }
+ return r;
+}
+
+#ifdef COMPUTE_UDIV
+static __inline fixint_t __divXi3(fixint_t a, fixint_t b) {
+ const int N = (int)(sizeof(fixint_t) * CHAR_BIT) - 1;
+ fixint_t s_a = a >> N; // s_a = a < 0 ? -1 : 0
+ fixint_t s_b = b >> N; // s_b = b < 0 ? -1 : 0
+ fixuint_t a_u = (fixuint_t)(a ^ s_a) + (-s_a); // negate if s_a == -1
+ fixuint_t b_u = (fixuint_t)(b ^ s_b) + (-s_b); // negate if s_b == -1
+ s_a ^= s_b; // sign of quotient
+ return (COMPUTE_UDIV(a_u, b_u) ^ s_a) + (-s_a); // negate if s_a == -1
+}
+#endif // COMPUTE_UDIV
+
+#ifdef ASSIGN_UMOD
+static __inline fixint_t __modXi3(fixint_t a, fixint_t b) {
+ const int N = (int)(sizeof(fixint_t) * CHAR_BIT) - 1;
+ fixint_t s = b >> N; // s = b < 0 ? -1 : 0
+ fixuint_t b_u = (fixuint_t)(b ^ s) + (-s); // negate if s == -1
+ s = a >> N; // s = a < 0 ? -1 : 0
+ fixuint_t a_u = (fixuint_t)(a ^ s) + (-s); // negate if s == -1
+ fixuint_t res;
+ ASSIGN_UMOD(res, a_u, b_u);
+ return (res ^ s) + (-s); // negate if s == -1
+}
+#endif // ASSIGN_UMOD
diff --git a/contrib/libs/cxxsupp/builtins/int_endianness.h b/contrib/libs/cxxsupp/builtins/int_endianness.h
index 5aca6d29c1..4ef5e73df5 100644
--- a/contrib/libs/cxxsupp/builtins/int_endianness.h
+++ b/contrib/libs/cxxsupp/builtins/int_endianness.h
@@ -1,51 +1,49 @@
-/* ===-- int_endianness.h - configuration header for compiler-rt ------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file is a configuration header for compiler-rt.
- * This file is not part of the interface of this library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- int_endianness.h - configuration header for compiler-rt -----------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a configuration header for compiler-rt.
+// This file is not part of the interface of this library.
+//
+//===----------------------------------------------------------------------===//
#ifndef INT_ENDIANNESS_H
#define INT_ENDIANNESS_H
-#if defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && \
+#if defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && \
defined(__ORDER_LITTLE_ENDIAN__)
-/* Clang and GCC provide built-in endianness definitions. */
+// Clang and GCC provide built-in endianness definitions.
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
#define _YUGA_LITTLE_ENDIAN 0
-#define _YUGA_BIG_ENDIAN 1
+#define _YUGA_BIG_ENDIAN 1
#elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#define _YUGA_LITTLE_ENDIAN 1
-#define _YUGA_BIG_ENDIAN 0
-#endif /* __BYTE_ORDER__ */
+#define _YUGA_BIG_ENDIAN 0
+#endif // __BYTE_ORDER__
-#else /* Compilers other than Clang or GCC. */
+#else // Compilers other than Clang or GCC.
#if defined(__SVR4) && defined(__sun)
-#error #include <sys/byteorder.h>
+
#if defined(_BIG_ENDIAN)
#define _YUGA_LITTLE_ENDIAN 0
-#define _YUGA_BIG_ENDIAN 1
+#define _YUGA_BIG_ENDIAN 1
#elif defined(_LITTLE_ENDIAN)
#define _YUGA_LITTLE_ENDIAN 1
-#define _YUGA_BIG_ENDIAN 0
-#else /* !_LITTLE_ENDIAN */
+#define _YUGA_BIG_ENDIAN 0
+#else // !_LITTLE_ENDIAN
#error "unknown endianness"
-#endif /* !_LITTLE_ENDIAN */
+#endif // !_LITTLE_ENDIAN
-#endif /* Solaris and AuroraUX. */
+#endif // Solaris
-/* .. */
+// ..
#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || \
defined(__minix)
@@ -53,64 +51,64 @@
#if _BYTE_ORDER == _BIG_ENDIAN
#define _YUGA_LITTLE_ENDIAN 0
-#define _YUGA_BIG_ENDIAN 1
+#define _YUGA_BIG_ENDIAN 1
#elif _BYTE_ORDER == _LITTLE_ENDIAN
#define _YUGA_LITTLE_ENDIAN 1
-#define _YUGA_BIG_ENDIAN 0
-#endif /* _BYTE_ORDER */
+#define _YUGA_BIG_ENDIAN 0
+#endif // _BYTE_ORDER
-#endif /* *BSD */
+#endif // *BSD
-#if defined(__OpenBSD__) || defined(__Bitrig__)
+#if defined(__OpenBSD__)
#include <machine/endian.h>
#if _BYTE_ORDER == _BIG_ENDIAN
#define _YUGA_LITTLE_ENDIAN 0
-#define _YUGA_BIG_ENDIAN 1
+#define _YUGA_BIG_ENDIAN 1
#elif _BYTE_ORDER == _LITTLE_ENDIAN
#define _YUGA_LITTLE_ENDIAN 1
-#define _YUGA_BIG_ENDIAN 0
-#endif /* _BYTE_ORDER */
+#define _YUGA_BIG_ENDIAN 0
+#endif // _BYTE_ORDER
-#endif /* OpenBSD and Bitrig. */
+#endif // OpenBSD
-/* .. */
+// ..
-/* Mac OSX has __BIG_ENDIAN__ or __LITTLE_ENDIAN__ automatically set by the
- * compiler (at least with GCC) */
-#if defined(__APPLE__) || defined(__ellcc__ )
+// Mac OSX has __BIG_ENDIAN__ or __LITTLE_ENDIAN__ automatically set by the
+// compiler (at least with GCC)
+#if defined(__APPLE__) || defined(__ellcc__)
#ifdef __BIG_ENDIAN__
#if __BIG_ENDIAN__
#define _YUGA_LITTLE_ENDIAN 0
-#define _YUGA_BIG_ENDIAN 1
+#define _YUGA_BIG_ENDIAN 1
#endif
-#endif /* __BIG_ENDIAN__ */
+#endif // __BIG_ENDIAN__
#ifdef __LITTLE_ENDIAN__
#if __LITTLE_ENDIAN__
#define _YUGA_LITTLE_ENDIAN 1
-#define _YUGA_BIG_ENDIAN 0
+#define _YUGA_BIG_ENDIAN 0
#endif
-#endif /* __LITTLE_ENDIAN__ */
+#endif // __LITTLE_ENDIAN__
-#endif /* Mac OSX */
+#endif // Mac OSX
-/* .. */
+// ..
#if defined(_WIN32)
#define _YUGA_LITTLE_ENDIAN 1
-#define _YUGA_BIG_ENDIAN 0
+#define _YUGA_BIG_ENDIAN 0
-#endif /* Windows */
+#endif // Windows
-#endif /* Clang or GCC. */
+#endif // Clang or GCC.
-/* . */
+// .
#if !defined(_YUGA_LITTLE_ENDIAN) || !defined(_YUGA_BIG_ENDIAN)
#error Unable to determine endian
-#endif /* Check we found an endianness correctly. */
+#endif // Check we found an endianness correctly.
-#endif /* INT_ENDIANNESS_H */
+#endif // INT_ENDIANNESS_H
diff --git a/contrib/libs/cxxsupp/builtins/int_lib.h b/contrib/libs/cxxsupp/builtins/int_lib.h
index 272f9d9dad..fb791ebc42 100644
--- a/contrib/libs/cxxsupp/builtins/int_lib.h
+++ b/contrib/libs/cxxsupp/builtins/int_lib.h
@@ -1,48 +1,38 @@
-/* ===-- int_lib.h - configuration header for compiler-rt -----------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file is a configuration header for compiler-rt.
- * This file is not part of the interface of this library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- int_lib.h - configuration header for compiler-rt -----------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a configuration header for compiler-rt.
+// This file is not part of the interface of this library.
+//
+//===----------------------------------------------------------------------===//
#ifndef INT_LIB_H
#define INT_LIB_H
-/* Assumption: Signed integral is 2's complement. */
-/* Assumption: Right shift of signed negative is arithmetic shift. */
-/* Assumption: Endianness is little or big (not mixed). */
+// Assumption: Signed integral is 2's complement.
+// Assumption: Right shift of signed negative is arithmetic shift.
+// Assumption: Endianness is little or big (not mixed).
-#if defined(__ELF__)
-#define FNALIAS(alias_name, original_name) \
- void alias_name() __attribute__((alias(#original_name)))
-#else
-#define FNALIAS(alias, name) _Pragma("GCC error(\"alias unsupported on this file format\")")
-#endif
-
-/* ABI macro definitions */
+// ABI macro definitions
#if __ARM_EABI__
-# define ARM_EABI_FNALIAS(aeabi_name, name) \
- void __aeabi_##aeabi_name() __attribute__((alias("__" #name)));
-# define COMPILER_RT_ABI __attribute__((pcs("aapcs")))
+#ifdef COMPILER_RT_ARMHF_TARGET
+#define COMPILER_RT_ABI
+#else
+#define COMPILER_RT_ABI __attribute__((__pcs__("aapcs")))
+#endif
#else
-# define ARM_EABI_FNALIAS(aeabi_name, name)
-# if defined(__arm__) && defined(_WIN32) && (!defined(_MSC_VER) || defined(__clang__))
-# define COMPILER_RT_ABI __attribute__((pcs("aapcs")))
-# else
-# define COMPILER_RT_ABI
-# endif
+#define COMPILER_RT_ABI
#endif
-#ifdef _MSC_VER
+#define AEABI_RTABI __attribute__((__pcs__("aapcs")))
+
+#if defined(_MSC_VER) && !defined(__clang__)
#define ALWAYS_INLINE __forceinline
#define NOINLINE __declspec(noinline)
#define NORETURN __declspec(noreturn)
@@ -54,69 +44,104 @@
#define UNUSED __attribute__((unused))
#endif
-#if defined(__NetBSD__) && (defined(_KERNEL) || defined(_STANDALONE))
-/*
- * Kernel and boot environment can't use normal headers,
- * so use the equivalent system headers.
- */
-# include <machine/limits.h>
-# include <sys/stdint.h>
-# include <sys/types.h>
+#define STR(a) #a
+#define XSTR(a) STR(a)
+#define SYMBOL_NAME(name) XSTR(__USER_LABEL_PREFIX__) #name
+
+#if defined(__ELF__) || defined(__MINGW32__) || defined(__wasm__) || \
+ defined(_AIX)
+#define COMPILER_RT_ALIAS(name, aliasname) \
+ COMPILER_RT_ABI __typeof(name) aliasname __attribute__((__alias__(#name)));
+#elif defined(__APPLE__)
+#if defined(VISIBILITY_HIDDEN)
+#define COMPILER_RT_ALIAS_VISIBILITY(name) \
+ __asm__(".private_extern " SYMBOL_NAME(name));
+#else
+#define COMPILER_RT_ALIAS_VISIBILITY(name)
+#endif
+#define COMPILER_RT_ALIAS(name, aliasname) \
+ __asm__(".globl " SYMBOL_NAME(aliasname)); \
+ COMPILER_RT_ALIAS_VISIBILITY(aliasname) \
+ __asm__(SYMBOL_NAME(aliasname) " = " SYMBOL_NAME(name)); \
+ COMPILER_RT_ABI __typeof(name) aliasname;
+#elif defined(_WIN32)
+#define COMPILER_RT_ALIAS(name, aliasname)
#else
-/* Include the standard compiler builtin headers we use functionality from. */
-# include <limits.h>
-# include <stdint.h>
-# include <stdbool.h>
-# include <float.h>
+#error Unsupported target
#endif
-/* Include the commonly used internal type definitions. */
+#if (defined(__FreeBSD__) || defined(__NetBSD__)) && \
+ (defined(_KERNEL) || defined(_STANDALONE))
+//
+// Kernel and boot environment can't use normal headers,
+// so use the equivalent system headers.
+// NB: FreeBSD (and OpenBSD) deprecate machine/limits.h in
+// favour of sys/limits.h, so prefer the former, but fall
+// back on the latter if not available since NetBSD only has
+// the latter.
+//
+#if defined(__has_include) && __has_include(<sys/limits.h>)
+#include <sys/limits.h>
+#else
+#include <machine/limits.h>
+#endif
+#include <sys/stdint.h>
+#include <sys/types.h>
+#else
+// Include the standard compiler builtin headers we use functionality from.
+#include <float.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <stdint.h>
+#endif
+
+// Include the commonly used internal type definitions.
#include "int_types.h"
-/* Include internal utility function declarations. */
+// Include internal utility function declarations.
#include "int_util.h"
-COMPILER_RT_ABI si_int __paritysi2(si_int a);
-COMPILER_RT_ABI si_int __paritydi2(di_int a);
+COMPILER_RT_ABI int __paritysi2(si_int a);
+COMPILER_RT_ABI int __paritydi2(di_int a);
COMPILER_RT_ABI di_int __divdi3(di_int a, di_int b);
COMPILER_RT_ABI si_int __divsi3(si_int a, si_int b);
COMPILER_RT_ABI su_int __udivsi3(su_int n, su_int d);
-COMPILER_RT_ABI su_int __udivmodsi4(su_int a, su_int b, su_int* rem);
-COMPILER_RT_ABI du_int __udivmoddi4(du_int a, du_int b, du_int* rem);
+COMPILER_RT_ABI su_int __udivmodsi4(su_int a, su_int b, su_int *rem);
+COMPILER_RT_ABI du_int __udivmoddi4(du_int a, du_int b, du_int *rem);
#ifdef CRT_HAS_128BIT
-COMPILER_RT_ABI si_int __clzti2(ti_int a);
-COMPILER_RT_ABI tu_int __udivmodti4(tu_int a, tu_int b, tu_int* rem);
+COMPILER_RT_ABI int __clzti2(ti_int a);
+COMPILER_RT_ABI tu_int __udivmodti4(tu_int a, tu_int b, tu_int *rem);
#endif
-/* Definitions for builtins unavailable on MSVC */
+// Definitions for builtins unavailable on MSVC
#if defined(_MSC_VER) && !defined(__clang__)
#include <intrin.h>
-uint32_t __inline __builtin_ctz(uint32_t value) {
- uint32_t trailing_zero = 0;
+int __inline __builtin_ctz(uint32_t value) {
+ unsigned long trailing_zero = 0;
if (_BitScanForward(&trailing_zero, value))
return trailing_zero;
return 32;
}
-uint32_t __inline __builtin_clz(uint32_t value) {
- uint32_t leading_zero = 0;
+int __inline __builtin_clz(uint32_t value) {
+ unsigned long leading_zero = 0;
if (_BitScanReverse(&leading_zero, value))
return 31 - leading_zero;
return 32;
}
#if defined(_M_ARM) || defined(_M_X64)
-uint32_t __inline __builtin_clzll(uint64_t value) {
- uint32_t leading_zero = 0;
+int __inline __builtin_clzll(uint64_t value) {
+ unsigned long leading_zero = 0;
if (_BitScanReverse64(&leading_zero, value))
return 63 - leading_zero;
return 64;
}
#else
-uint32_t __inline __builtin_clzll(uint64_t value) {
+int __inline __builtin_clzll(uint64_t value) {
if (value == 0)
return 64;
uint32_t msh = (uint32_t)(value >> 32);
@@ -128,6 +153,19 @@ uint32_t __inline __builtin_clzll(uint64_t value) {
#endif
#define __builtin_clzl __builtin_clzll
+
+bool __inline __builtin_sadd_overflow(int x, int y, int *result) {
+ if ((x < 0) != (y < 0)) {
+ *result = x + y;
+ return false;
+ }
+ int tmp = (unsigned int)x + (unsigned int)y;
+ if ((tmp < 0) != (x < 0))
+ return true;
+ *result = tmp;
+ return false;
+}
+
#endif // defined(_MSC_VER) && !defined(__clang__)
-#endif /* INT_LIB_H */
+#endif // INT_LIB_H
diff --git a/contrib/libs/cxxsupp/builtins/int_math.h b/contrib/libs/cxxsupp/builtins/int_math.h
index 9151bc6ef9..48b9580f59 100644
--- a/contrib/libs/cxxsupp/builtins/int_math.h
+++ b/contrib/libs/cxxsupp/builtins/int_math.h
@@ -1,28 +1,26 @@
-/* ===-- int_math.h - internal math inlines ---------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===-----------------------------------------------------------------------===
- *
- * This file is not part of the interface of this library.
- *
- * This file defines substitutes for the libm functions used in some of the
- * compiler-rt implementations, defined in such a way that there is not a direct
- * dependency on libm or math.h. Instead, we use the compiler builtin versions
- * where available. This reduces our dependencies on the system SDK by foisting
- * the responsibility onto the compiler.
- *
- * ===-----------------------------------------------------------------------===
- */
+//===-- int_math.h - internal math inlines --------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is not part of the interface of this library.
+//
+// This file defines substitutes for the libm functions used in some of the
+// compiler-rt implementations, defined in such a way that there is not a direct
+// dependency on libm or math.h. Instead, we use the compiler builtin versions
+// where available. This reduces our dependencies on the system SDK by foisting
+// the responsibility onto the compiler.
+//
+//===----------------------------------------------------------------------===//
#ifndef INT_MATH_H
#define INT_MATH_H
#ifndef __has_builtin
-# define __has_builtin(x) 0
+#define __has_builtin(x) 0
#endif
#if defined(_MSC_VER) && !defined(__clang__)
@@ -41,24 +39,23 @@
#define crt_isinf(x) !_finite((x))
#define crt_isnan(x) _isnan((x))
#else
-/* Define crt_isfinite in terms of the builtin if available, otherwise provide
- * an alternate version in terms of our other functions. This supports some
- * versions of GCC which didn't have __builtin_isfinite.
- */
+// Define crt_isfinite in terms of the builtin if available, otherwise provide
+// an alternate version in terms of our other functions. This supports some
+// versions of GCC which didn't have __builtin_isfinite.
#if __has_builtin(__builtin_isfinite)
-# define crt_isfinite(x) __builtin_isfinite((x))
+#define crt_isfinite(x) __builtin_isfinite((x))
#elif defined(__GNUC__)
-# define crt_isfinite(x) \
- __extension__(({ \
- __typeof((x)) x_ = (x); \
- !crt_isinf(x_) && !crt_isnan(x_); \
- }))
+#define crt_isfinite(x) \
+ __extension__(({ \
+ __typeof((x)) x_ = (x); \
+ !crt_isinf(x_) && !crt_isnan(x_); \
+ }))
#else
-# error "Do not know how to check for infinity"
-#endif /* __has_builtin(__builtin_isfinite) */
+#error "Do not know how to check for infinity"
+#endif // __has_builtin(__builtin_isfinite)
#define crt_isinf(x) __builtin_isinf((x))
#define crt_isnan(x) __builtin_isnan((x))
-#endif /* _MSC_VER */
+#endif // _MSC_VER
#if defined(_MSC_VER) && !defined(__clang__)
#define crt_copysign(x, y) copysign((x), (y))
@@ -81,33 +78,21 @@
#endif
#if defined(_MSC_VER) && !defined(__clang__)
-#define crt_fmax(x, y) __max((x), (y))
-#define crt_fmaxf(x, y) __max((x), (y))
#define crt_fmaxl(x, y) __max((x), (y))
#else
-#define crt_fmax(x, y) __builtin_fmax((x), (y))
-#define crt_fmaxf(x, y) __builtin_fmaxf((x), (y))
#define crt_fmaxl(x, y) __builtin_fmaxl((x), (y))
#endif
#if defined(_MSC_VER) && !defined(__clang__)
-#define crt_logb(x) logb((x))
-#define crt_logbf(x) logbf((x))
#define crt_logbl(x) logbl((x))
#else
-#define crt_logb(x) __builtin_logb((x))
-#define crt_logbf(x) __builtin_logbf((x))
#define crt_logbl(x) __builtin_logbl((x))
#endif
#if defined(_MSC_VER) && !defined(__clang__)
-#define crt_scalbn(x, y) scalbn((x), (y))
-#define crt_scalbnf(x, y) scalbnf((x), (y))
#define crt_scalbnl(x, y) scalbnl((x), (y))
#else
-#define crt_scalbn(x, y) __builtin_scalbn((x), (y))
-#define crt_scalbnf(x, y) __builtin_scalbnf((x), (y))
#define crt_scalbnl(x, y) __builtin_scalbnl((x), (y))
#endif
-#endif /* INT_MATH_H */
+#endif // INT_MATH_H
diff --git a/contrib/libs/cxxsupp/builtins/int_mulo_impl.inc b/contrib/libs/cxxsupp/builtins/int_mulo_impl.inc
new file mode 100644
index 0000000000..567d8b9e6e
--- /dev/null
+++ b/contrib/libs/cxxsupp/builtins/int_mulo_impl.inc
@@ -0,0 +1,49 @@
+//===-- int_mulo_impl.inc - Implement __mulo[sdt]i4 ---------------*- C -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Helper used by __mulosi4, __mulodi4 and __muloti4.
+//
+//===----------------------------------------------------------------------===//
+
+#include "int_lib.h"
+
+// Returns: a * b
+
+// Effects: sets *overflow to 1 if a * b overflows
+
+static __inline fixint_t __muloXi4(fixint_t a, fixint_t b, int *overflow) {
+ const int N = (int)(sizeof(fixint_t) * CHAR_BIT);
+ const fixint_t MIN = (fixint_t)1 << (N - 1);
+ const fixint_t MAX = ~MIN;
+ *overflow = 0;
+ fixint_t result = a * b;
+ if (a == MIN) {
+ if (b != 0 && b != 1)
+ *overflow = 1;
+ return result;
+ }
+ if (b == MIN) {
+ if (a != 0 && a != 1)
+ *overflow = 1;
+ return result;
+ }
+ fixint_t sa = a >> (N - 1);
+ fixint_t abs_a = (a ^ sa) - sa;
+ fixint_t sb = b >> (N - 1);
+ fixint_t abs_b = (b ^ sb) - sb;
+ if (abs_a < 2 || abs_b < 2)
+ return result;
+ if (sa == sb) {
+ if (abs_a > MAX / abs_b)
+ *overflow = 1;
+ } else {
+ if (abs_a > MIN / -abs_b)
+ *overflow = 1;
+ }
+ return result;
+}
diff --git a/contrib/libs/cxxsupp/builtins/int_mulv_impl.inc b/contrib/libs/cxxsupp/builtins/int_mulv_impl.inc
new file mode 100644
index 0000000000..1e920716ec
--- /dev/null
+++ b/contrib/libs/cxxsupp/builtins/int_mulv_impl.inc
@@ -0,0 +1,47 @@
+//===-- int_mulv_impl.inc - Implement __mulv[sdt]i3 ---------------*- C -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Helper used by __mulvsi3, __mulvdi3 and __mulvti3.
+//
+//===----------------------------------------------------------------------===//
+
+#include "int_lib.h"
+
+// Returns: a * b
+
+// Effects: aborts if a * b overflows
+
+static __inline fixint_t __mulvXi3(fixint_t a, fixint_t b) {
+ const int N = (int)(sizeof(fixint_t) * CHAR_BIT);
+ const fixint_t MIN = (fixint_t)1 << (N - 1);
+ const fixint_t MAX = ~MIN;
+ if (a == MIN) {
+ if (b == 0 || b == 1)
+ return a * b;
+ compilerrt_abort();
+ }
+ if (b == MIN) {
+ if (a == 0 || a == 1)
+ return a * b;
+ compilerrt_abort();
+ }
+ fixint_t sa = a >> (N - 1);
+ fixint_t abs_a = (a ^ sa) - sa;
+ fixint_t sb = b >> (N - 1);
+ fixint_t abs_b = (b ^ sb) - sb;
+ if (abs_a < 2 || abs_b < 2)
+ return a * b;
+ if (sa == sb) {
+ if (abs_a > MAX / abs_b)
+ compilerrt_abort();
+ } else {
+ if (abs_a > MIN / -abs_b)
+ compilerrt_abort();
+ }
+ return a * b;
+}
diff --git a/contrib/libs/cxxsupp/builtins/int_types.h b/contrib/libs/cxxsupp/builtins/int_types.h
index 23065b89bd..e94d3154c6 100644
--- a/contrib/libs/cxxsupp/builtins/int_types.h
+++ b/contrib/libs/cxxsupp/builtins/int_types.h
@@ -1,147 +1,174 @@
-/* ===-- int_lib.h - configuration header for compiler-rt -----------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file is not part of the interface of this library.
- *
- * This file defines various standard types, most importantly a number of unions
- * used to access parts of larger types.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- int_lib.h - configuration header for compiler-rt -----------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is not part of the interface of this library.
+//
+// This file defines various standard types, most importantly a number of unions
+// used to access parts of larger types.
+//
+//===----------------------------------------------------------------------===//
#ifndef INT_TYPES_H
#define INT_TYPES_H
#include "int_endianness.h"
-/* si_int is defined in Linux sysroot's asm-generic/siginfo.h */
+// si_int is defined in Linux sysroot's asm-generic/siginfo.h
#ifdef si_int
#undef si_int
#endif
-typedef int si_int;
-typedef unsigned su_int;
+typedef int32_t si_int;
+typedef uint32_t su_int;
+#if UINT_MAX == 0xFFFFFFFF
+#define clzsi __builtin_clz
+#define ctzsi __builtin_ctz
+#elif ULONG_MAX == 0xFFFFFFFF
+#define clzsi __builtin_clzl
+#define ctzsi __builtin_ctzl
+#else
+#error could not determine appropriate clzsi macro for this system
+#endif
-typedef long long di_int;
-typedef unsigned long long du_int;
+typedef int64_t di_int;
+typedef uint64_t du_int;
-typedef union
-{
- di_int all;
- struct
- {
+typedef union {
+ di_int all;
+ struct {
#if _YUGA_LITTLE_ENDIAN
- su_int low;
- si_int high;
+ su_int low;
+ si_int high;
#else
- si_int high;
- su_int low;
-#endif /* _YUGA_LITTLE_ENDIAN */
- }s;
+ si_int high;
+ su_int low;
+#endif // _YUGA_LITTLE_ENDIAN
+ } s;
} dwords;
-typedef union
-{
- du_int all;
- struct
- {
+typedef union {
+ du_int all;
+ struct {
#if _YUGA_LITTLE_ENDIAN
- su_int low;
- su_int high;
+ su_int low;
+ su_int high;
#else
- su_int high;
- su_int low;
-#endif /* _YUGA_LITTLE_ENDIAN */
- }s;
+ su_int high;
+ su_int low;
+#endif // _YUGA_LITTLE_ENDIAN
+ } s;
} udwords;
-/* MIPS64 issue: PR 20098 */
-#if defined(__LP64__) && !(defined(__mips__) && defined(__clang__)) || (defined(_MSC_VER) && defined(__clang__))
+#if defined(__LP64__) || defined(__wasm__) || defined(__mips64) || \
+ defined(__SIZEOF_INT128__) || defined(_WIN64)
#define CRT_HAS_128BIT
#endif
+// MSVC doesn't have a working 128bit integer type. Users should really compile
+// compiler-rt with clang, but if they happen to be doing a standalone build for
+// asan or something else, disable the 128 bit parts so things sort of work.
+#if defined(_MSC_VER) && !defined(__clang__)
+#undef CRT_HAS_128BIT
+#endif
+
#ifdef CRT_HAS_128BIT
-typedef int ti_int __attribute__ ((mode (TI)));
-typedef unsigned tu_int __attribute__ ((mode (TI)));
-
-typedef union
-{
- ti_int all;
- struct
- {
+typedef int ti_int __attribute__((mode(TI)));
+typedef unsigned tu_int __attribute__((mode(TI)));
+
+typedef union {
+ ti_int all;
+ struct {
#if _YUGA_LITTLE_ENDIAN
- du_int low;
- di_int high;
+ du_int low;
+ di_int high;
#else
- di_int high;
- du_int low;
-#endif /* _YUGA_LITTLE_ENDIAN */
- }s;
+ di_int high;
+ du_int low;
+#endif // _YUGA_LITTLE_ENDIAN
+ } s;
} twords;
-typedef union
-{
- tu_int all;
- struct
- {
+typedef union {
+ tu_int all;
+ struct {
#if _YUGA_LITTLE_ENDIAN
- du_int low;
- du_int high;
+ du_int low;
+ du_int high;
#else
- du_int high;
- du_int low;
-#endif /* _YUGA_LITTLE_ENDIAN */
- }s;
+ du_int high;
+ du_int low;
+#endif // _YUGA_LITTLE_ENDIAN
+ } s;
} utwords;
static __inline ti_int make_ti(di_int h, di_int l) {
- twords r;
- r.s.high = h;
- r.s.low = l;
- return r.all;
+ twords r;
+ r.s.high = h;
+ r.s.low = l;
+ return r.all;
}
static __inline tu_int make_tu(du_int h, du_int l) {
- utwords r;
- r.s.high = h;
- r.s.low = l;
- return r.all;
+ utwords r;
+ r.s.high = h;
+ r.s.low = l;
+ return r.all;
}
-#endif /* CRT_HAS_128BIT */
+#endif // CRT_HAS_128BIT
+
+// FreeBSD's boot environment does not support using floating-point and poisons
+// the float and double keywords.
+#if defined(__FreeBSD__) && defined(_STANDALONE)
+#define CRT_HAS_FLOATING_POINT 0
+#else
+#define CRT_HAS_FLOATING_POINT 1
+#endif
-typedef union
-{
- su_int u;
- float f;
+#if CRT_HAS_FLOATING_POINT
+typedef union {
+ su_int u;
+ float f;
} float_bits;
-typedef union
-{
- udwords u;
- double f;
+typedef union {
+ udwords u;
+ double f;
} double_bits;
+#endif
-typedef struct
-{
+typedef struct {
#if _YUGA_LITTLE_ENDIAN
- udwords low;
- udwords high;
+ udwords low;
+ udwords high;
#else
- udwords high;
- udwords low;
-#endif /* _YUGA_LITTLE_ENDIAN */
+ udwords high;
+ udwords low;
+#endif // _YUGA_LITTLE_ENDIAN
} uqwords;
-typedef union
-{
- uqwords u;
- long double f;
+// Check if the target supports 80 bit extended precision long doubles.
+// Notably, on x86 Windows, MSVC only provides a 64-bit long double, but GCC
+// still makes it 80 bits. Clang will match whatever compiler it is trying to
+// be compatible with. On 32-bit x86 Android, long double is 64 bits, while on
+// x86_64 Android, long double is 128 bits.
+#if (defined(__i386__) || defined(__x86_64__)) && \
+ !(defined(_MSC_VER) || defined(__ANDROID__))
+#define HAS_80_BIT_LONG_DOUBLE 1
+#elif defined(__m68k__) || defined(__ia64__)
+#define HAS_80_BIT_LONG_DOUBLE 1
+#else
+#define HAS_80_BIT_LONG_DOUBLE 0
+#endif
+
+#if CRT_HAS_FLOATING_POINT
+typedef union {
+ uqwords u;
+ long double f;
} long_double_bits;
#if __STDC_VERSION__ >= 199901L
@@ -152,14 +179,20 @@ typedef long double _Complex Lcomplex;
#define COMPLEX_REAL(x) __real__(x)
#define COMPLEX_IMAGINARY(x) __imag__(x)
#else
-typedef struct { float real, imaginary; } Fcomplex;
+typedef struct {
+ float real, imaginary;
+} Fcomplex;
-typedef struct { double real, imaginary; } Dcomplex;
+typedef struct {
+ double real, imaginary;
+} Dcomplex;
-typedef struct { long double real, imaginary; } Lcomplex;
+typedef struct {
+ long double real, imaginary;
+} Lcomplex;
#define COMPLEX_REAL(x) (x).real
#define COMPLEX_IMAGINARY(x) (x).imaginary
#endif
-#endif /* INT_TYPES_H */
-
+#endif
+#endif // INT_TYPES_H
diff --git a/contrib/libs/cxxsupp/builtins/int_util.c b/contrib/libs/cxxsupp/builtins/int_util.c
index 420d1e237a..bbb735ccf2 100644
--- a/contrib/libs/cxxsupp/builtins/int_util.c
+++ b/contrib/libs/cxxsupp/builtins/int_util.c
@@ -1,25 +1,21 @@
-/* ===-- int_util.c - Implement internal utilities --------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- int_util.c - Implement internal utilities -------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
-#include "int_util.h"
-
-/* NOTE: The definitions in this file are declared weak because we clients to be
- * able to arbitrarily package individual functions into separate .a files. If
- * we did not declare these weak, some link situations might end up seeing
- * duplicate strong definitions of the same symbol.
- *
- * We can't use this solution for kernel use (which may not support weak), but
- * currently expect that when built for kernel use all the functionality is
- * packaged into a single library.
- */
+
+// NOTE: The definitions in this file are declared weak because we clients to be
+// able to arbitrarily package individual functions into separate .a files. If
+// we did not declare these weak, some link situations might end up seeing
+// duplicate strong definitions of the same symbol.
+//
+// We can't use this solution for kernel use (which may not support weak), but
+// currently expect that when built for kernel use all the functionality is
+// packaged into a single library.
#ifdef KERNEL_USE
@@ -27,35 +23,41 @@ NORETURN extern void panic(const char *, ...);
#ifndef _WIN32
__attribute__((visibility("hidden")))
#endif
-void compilerrt_abort_impl(const char *file, int line, const char *function) {
+void __compilerrt_abort_impl(const char *file, int line, const char *function) {
panic("%s:%d: abort in %s", file, line, function);
}
#elif __APPLE__
-/* from libSystem.dylib */
+// from libSystem.dylib
NORETURN extern void __assert_rtn(const char *func, const char *file, int line,
const char *message);
-#ifndef _WIN32
__attribute__((weak))
__attribute__((visibility("hidden")))
-#endif
-void compilerrt_abort_impl(const char *file, int line, const char *function) {
+void __compilerrt_abort_impl(const char *file, int line, const char *function) {
__assert_rtn(function, file, line, "libcompiler_rt abort");
}
#else
-/* Get the system definition of abort() */
+#ifdef _WIN32
#include <stdlib.h>
+#endif
#ifndef _WIN32
__attribute__((weak))
__attribute__((visibility("hidden")))
#endif
-void compilerrt_abort_impl(const char *file, int line, const char *function) {
+void __compilerrt_abort_impl(const char *file, int line, const char *function) {
+#if !__STDC_HOSTED__
+ // Avoid depending on libc when compiling with -ffreestanding.
+ __builtin_trap();
+#elif defined(_WIN32)
abort();
+#else
+ __builtin_abort();
+#endif
}
#endif
diff --git a/contrib/libs/cxxsupp/builtins/int_util.h b/contrib/libs/cxxsupp/builtins/int_util.h
index a7b20ed662..c372c2edc6 100644
--- a/contrib/libs/cxxsupp/builtins/int_util.h
+++ b/contrib/libs/cxxsupp/builtins/int_util.h
@@ -1,33 +1,47 @@
-/* ===-- int_util.h - internal utility functions ----------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===-----------------------------------------------------------------------===
- *
- * This file is not part of the interface of this library.
- *
- * This file defines non-inline utilities which are available for use in the
- * library. The function definitions themselves are all contained in int_util.c
- * which will always be compiled into any compiler-rt library.
- *
- * ===-----------------------------------------------------------------------===
- */
+//===-- int_util.h - internal utility functions ---------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is not part of the interface of this library.
+//
+// This file defines non-inline utilities which are available for use in the
+// library. The function definitions themselves are all contained in int_util.c
+// which will always be compiled into any compiler-rt library.
+//
+//===----------------------------------------------------------------------===//
#ifndef INT_UTIL_H
#define INT_UTIL_H
-/** \brief Trigger a program abort (or panic for kernel code). */
-#define compilerrt_abort() compilerrt_abort_impl(__FILE__, __LINE__, __func__)
+/// \brief Trigger a program abort (or panic for kernel code).
+#define compilerrt_abort() __compilerrt_abort_impl(__FILE__, __LINE__, __func__)
-NORETURN void compilerrt_abort_impl(const char *file, int line,
- const char *function);
+NORETURN void __compilerrt_abort_impl(const char *file, int line,
+ const char *function);
#define COMPILE_TIME_ASSERT(expr) COMPILE_TIME_ASSERT1(expr, __COUNTER__)
#define COMPILE_TIME_ASSERT1(expr, cnt) COMPILE_TIME_ASSERT2(expr, cnt)
#define COMPILE_TIME_ASSERT2(expr, cnt) \
typedef char ct_assert_##cnt[(expr) ? 1 : -1] UNUSED
-#endif /* INT_UTIL_H */
+// Force unrolling the code specified to be repeated N times.
+#define REPEAT_0_TIMES(code_to_repeat) /* do nothing */
+#define REPEAT_1_TIMES(code_to_repeat) code_to_repeat
+#define REPEAT_2_TIMES(code_to_repeat) \
+ REPEAT_1_TIMES(code_to_repeat) \
+ code_to_repeat
+#define REPEAT_3_TIMES(code_to_repeat) \
+ REPEAT_2_TIMES(code_to_repeat) \
+ code_to_repeat
+#define REPEAT_4_TIMES(code_to_repeat) \
+ REPEAT_3_TIMES(code_to_repeat) \
+ code_to_repeat
+
+#define REPEAT_N_TIMES_(N, code_to_repeat) REPEAT_##N##_TIMES(code_to_repeat)
+#define REPEAT_N_TIMES(N, code_to_repeat) REPEAT_N_TIMES_(N, code_to_repeat)
+
+#endif // INT_UTIL_H
diff --git a/contrib/libs/cxxsupp/builtins/loongarch/fp_mode.c b/contrib/libs/cxxsupp/builtins/loongarch/fp_mode.c
new file mode 100644
index 0000000000..31877fb02b
--- /dev/null
+++ b/contrib/libs/cxxsupp/builtins/loongarch/fp_mode.c
@@ -0,0 +1,59 @@
+//=== lib/builtins/loongarch/fp_mode.c - Floaing-point mode utilities -*- C -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+#include "../fp_mode.h"
+
+#define LOONGARCH_TONEAREST 0x0000
+#define LOONGARCH_TOWARDZERO 0x0100
+#define LOONGARCH_UPWARD 0x0200
+#define LOONGARCH_DOWNWARD 0x0300
+
+#define LOONGARCH_RMODE_MASK (LOONGARCH_TONEAREST | LOONGARCH_TOWARDZERO | \
+ LOONGARCH_UPWARD | LOONGARCH_DOWNWARD)
+
+#define LOONGARCH_INEXACT 0x10000
+
+CRT_FE_ROUND_MODE __fe_getround(void) {
+#if __loongarch_frlen != 0
+ int fcsr;
+# ifdef __clang__
+ __asm__ __volatile__("movfcsr2gr %0, $fcsr0" : "=r" (fcsr));
+# else
+ __asm__ __volatile__("movfcsr2gr %0, $r0" : "=r" (fcsr));
+# endif
+ fcsr &= LOONGARCH_RMODE_MASK;
+ switch (fcsr) {
+ case LOONGARCH_TOWARDZERO:
+ return CRT_FE_TOWARDZERO;
+ case LOONGARCH_DOWNWARD:
+ return CRT_FE_DOWNWARD;
+ case LOONGARCH_UPWARD:
+ return CRT_FE_UPWARD;
+ case LOONGARCH_TONEAREST:
+ default:
+ return CRT_FE_TONEAREST;
+ }
+#else
+ return CRT_FE_TONEAREST;
+#endif
+}
+
+int __fe_raise_inexact(void) {
+#if __loongarch_frlen != 0
+ int fcsr;
+# ifdef __clang__
+ __asm__ __volatile__("movfcsr2gr %0, $fcsr0" : "=r" (fcsr));
+ __asm__ __volatile__(
+ "movgr2fcsr $fcsr0, %0" :: "r" (fcsr | LOONGARCH_INEXACT));
+# else
+ __asm__ __volatile__("movfcsr2gr %0, $r0" : "=r" (fcsr));
+ __asm__ __volatile__(
+ "movgr2fcsr $r0, %0" :: "r" (fcsr | LOONGARCH_INEXACT));
+# endif
+#endif
+ return 0;
+}
diff --git a/contrib/libs/cxxsupp/builtins/lshrdi3.c b/contrib/libs/cxxsupp/builtins/lshrdi3.c
index 6b1ea923b7..6072152583 100644
--- a/contrib/libs/cxxsupp/builtins/lshrdi3.c
+++ b/contrib/libs/cxxsupp/builtins/lshrdi3.c
@@ -1,43 +1,38 @@
-/* ===-- lshrdi3.c - Implement __lshrdi3 -----------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __lshrdi3 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- lshrdi3.c - Implement __lshrdi3 -----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __lshrdi3 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
-/* Returns: logical a >> b */
+// Returns: logical a >> b
-/* Precondition: 0 <= b < bits_in_dword */
+// Precondition: 0 <= b < bits_in_dword
-ARM_EABI_FNALIAS(llsr, lshrdi3)
-
-COMPILER_RT_ABI di_int
-__lshrdi3(di_int a, si_int b)
-{
- const int bits_in_word = (int)(sizeof(si_int) * CHAR_BIT);
- udwords input;
- udwords result;
- input.all = a;
- if (b & bits_in_word) /* bits_in_word <= b < bits_in_dword */
- {
- result.s.high = 0;
- result.s.low = input.s.high >> (b - bits_in_word);
- }
- else /* 0 <= b < bits_in_word */
- {
- if (b == 0)
- return a;
- result.s.high = input.s.high >> b;
- result.s.low = (input.s.high << (bits_in_word - b)) | (input.s.low >> b);
- }
- return result.all;
+COMPILER_RT_ABI di_int __lshrdi3(di_int a, int b) {
+ const int bits_in_word = (int)(sizeof(si_int) * CHAR_BIT);
+ udwords input;
+ udwords result;
+ input.all = a;
+ if (b & bits_in_word) /* bits_in_word <= b < bits_in_dword */ {
+ result.s.high = 0;
+ result.s.low = input.s.high >> (b - bits_in_word);
+ } else /* 0 <= b < bits_in_word */ {
+ if (b == 0)
+ return a;
+ result.s.high = input.s.high >> b;
+ result.s.low = (input.s.high << (bits_in_word - b)) | (input.s.low >> b);
+ }
+ return result.all;
}
+
+#if defined(__ARM_EABI__)
+COMPILER_RT_ALIAS(__lshrdi3, __aeabi_llsr)
+#endif
diff --git a/contrib/libs/cxxsupp/builtins/lshrti3.c b/contrib/libs/cxxsupp/builtins/lshrti3.c
index e4170ff84a..d00a220959 100644
--- a/contrib/libs/cxxsupp/builtins/lshrti3.c
+++ b/contrib/libs/cxxsupp/builtins/lshrti3.c
@@ -1,45 +1,38 @@
-/* ===-- lshrti3.c - Implement __lshrti3 -----------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __lshrti3 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- lshrti3.c - Implement __lshrti3 -----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __lshrti3 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
#ifdef CRT_HAS_128BIT
-/* Returns: logical a >> b */
+// Returns: logical a >> b
-/* Precondition: 0 <= b < bits_in_tword */
+// Precondition: 0 <= b < bits_in_tword
-COMPILER_RT_ABI ti_int
-__lshrti3(ti_int a, si_int b)
-{
- const int bits_in_dword = (int)(sizeof(di_int) * CHAR_BIT);
- utwords input;
- utwords result;
- input.all = a;
- if (b & bits_in_dword) /* bits_in_dword <= b < bits_in_tword */
- {
- result.s.high = 0;
- result.s.low = input.s.high >> (b - bits_in_dword);
- }
- else /* 0 <= b < bits_in_dword */
- {
- if (b == 0)
- return a;
- result.s.high = input.s.high >> b;
- result.s.low = (input.s.high << (bits_in_dword - b)) | (input.s.low >> b);
- }
- return result.all;
+COMPILER_RT_ABI ti_int __lshrti3(ti_int a, si_int b) {
+ const int bits_in_dword = (int)(sizeof(di_int) * CHAR_BIT);
+ utwords input;
+ utwords result;
+ input.all = a;
+ if (b & bits_in_dword) /* bits_in_dword <= b < bits_in_tword */ {
+ result.s.high = 0;
+ result.s.low = input.s.high >> (b - bits_in_dword);
+ } else /* 0 <= b < bits_in_dword */ {
+ if (b == 0)
+ return a;
+ result.s.high = input.s.high >> b;
+ result.s.low = (input.s.high << (bits_in_dword - b)) | (input.s.low >> b);
+ }
+ return result.all;
}
-#endif /* CRT_HAS_128BIT */
+#endif // CRT_HAS_128BIT
diff --git a/contrib/libs/cxxsupp/builtins/macho_embedded/common.txt b/contrib/libs/cxxsupp/builtins/macho_embedded/common.txt
index 6ac85a771f..819109768f 100644
--- a/contrib/libs/cxxsupp/builtins/macho_embedded/common.txt
+++ b/contrib/libs/cxxsupp/builtins/macho_embedded/common.txt
@@ -90,3 +90,4 @@ atomic_flag_test_and_set_explicit
atomic_signal_fence
atomic_thread_fence
int_util
+fp_mode
diff --git a/contrib/libs/cxxsupp/builtins/moddi3.c b/contrib/libs/cxxsupp/builtins/moddi3.c
index a04279e387..15cf80b995 100644
--- a/contrib/libs/cxxsupp/builtins/moddi3.c
+++ b/contrib/libs/cxxsupp/builtins/moddi3.c
@@ -1,30 +1,22 @@
-/*===-- moddi3.c - Implement __moddi3 -------------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __moddi3 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- moddi3.c - Implement __moddi3 -------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __moddi3 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
-/* Returns: a % b */
+// Returns: a % b
-COMPILER_RT_ABI di_int
-__moddi3(di_int a, di_int b)
-{
- const int bits_in_dword_m1 = (int)(sizeof(di_int) * CHAR_BIT) - 1;
- di_int s = b >> bits_in_dword_m1; /* s = b < 0 ? -1 : 0 */
- b = (b ^ s) - s; /* negate if s == -1 */
- s = a >> bits_in_dword_m1; /* s = a < 0 ? -1 : 0 */
- a = (a ^ s) - s; /* negate if s == -1 */
- du_int r;
- __udivmoddi4(a, b, &r);
- return ((di_int)r ^ s) - s; /* negate if s == -1 */
-}
+#define fixint_t di_int
+#define fixuint_t du_int
+#define ASSIGN_UMOD(res, a, b) __udivmoddi4((a), (b), &(res))
+#include "int_div_impl.inc"
+
+COMPILER_RT_ABI di_int __moddi3(di_int a, di_int b) { return __modXi3(a, b); }
diff --git a/contrib/libs/cxxsupp/builtins/modsi3.c b/contrib/libs/cxxsupp/builtins/modsi3.c
index 86c73ce137..e443b8a590 100644
--- a/contrib/libs/cxxsupp/builtins/modsi3.c
+++ b/contrib/libs/cxxsupp/builtins/modsi3.c
@@ -1,23 +1,19 @@
-/* ===-- modsi3.c - Implement __modsi3 -------------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __modsi3 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- modsi3.c - Implement __modsi3 -------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __modsi3 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
-/* Returns: a % b */
+// Returns: a % b
-COMPILER_RT_ABI si_int
-__modsi3(si_int a, si_int b)
-{
- return a - __divsi3(a, b) * b;
+COMPILER_RT_ABI si_int __modsi3(si_int a, si_int b) {
+ return a - __divsi3(a, b) * b;
}
diff --git a/contrib/libs/cxxsupp/builtins/modti3.c b/contrib/libs/cxxsupp/builtins/modti3.c
index d505c07ac1..7c10cfd390 100644
--- a/contrib/libs/cxxsupp/builtins/modti3.c
+++ b/contrib/libs/cxxsupp/builtins/modti3.c
@@ -1,34 +1,26 @@
-/* ===-- modti3.c - Implement __modti3 -------------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __modti3 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- modti3.c - Implement __modti3 -------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __modti3 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
#ifdef CRT_HAS_128BIT
-/*Returns: a % b */
+// Returns: a % b
-COMPILER_RT_ABI ti_int
-__modti3(ti_int a, ti_int b)
-{
- const int bits_in_tword_m1 = (int)(sizeof(ti_int) * CHAR_BIT) - 1;
- ti_int s = b >> bits_in_tword_m1; /* s = b < 0 ? -1 : 0 */
- b = (b ^ s) - s; /* negate if s == -1 */
- s = a >> bits_in_tword_m1; /* s = a < 0 ? -1 : 0 */
- a = (a ^ s) - s; /* negate if s == -1 */
- tu_int r;
- __udivmodti4(a, b, &r);
- return ((ti_int)r ^ s) - s; /* negate if s == -1 */
-}
+#define fixint_t ti_int
+#define fixuint_t tu_int
+#define ASSIGN_UMOD(res, a, b) __udivmodti4((a), (b), &(res))
+#include "int_div_impl.inc"
-#endif /* CRT_HAS_128BIT */
+COMPILER_RT_ABI ti_int __modti3(ti_int a, ti_int b) { return __modXi3(a, b); }
+
+#endif // CRT_HAS_128BIT
diff --git a/contrib/libs/cxxsupp/builtins/muldc3.c b/contrib/libs/cxxsupp/builtins/muldc3.c
index 16d8e98390..0ea7041c37 100644
--- a/contrib/libs/cxxsupp/builtins/muldc3.c
+++ b/contrib/libs/cxxsupp/builtins/muldc3.c
@@ -1,73 +1,65 @@
-/* ===-- muldc3.c - Implement __muldc3 -------------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __muldc3 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- muldc3.c - Implement __muldc3 -------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __muldc3 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
#include "int_math.h"
-/* Returns: the product of a + ib and c + id */
+// Returns: the product of a + ib and c + id
-COMPILER_RT_ABI Dcomplex
-__muldc3(double __a, double __b, double __c, double __d)
-{
- double __ac = __a * __c;
- double __bd = __b * __d;
- double __ad = __a * __d;
- double __bc = __b * __c;
- Dcomplex z;
- COMPLEX_REAL(z) = __ac - __bd;
- COMPLEX_IMAGINARY(z) = __ad + __bc;
- if (crt_isnan(COMPLEX_REAL(z)) && crt_isnan(COMPLEX_IMAGINARY(z)))
- {
- int __recalc = 0;
- if (crt_isinf(__a) || crt_isinf(__b))
- {
- __a = crt_copysign(crt_isinf(__a) ? 1 : 0, __a);
- __b = crt_copysign(crt_isinf(__b) ? 1 : 0, __b);
- if (crt_isnan(__c))
- __c = crt_copysign(0, __c);
- if (crt_isnan(__d))
- __d = crt_copysign(0, __d);
- __recalc = 1;
- }
- if (crt_isinf(__c) || crt_isinf(__d))
- {
- __c = crt_copysign(crt_isinf(__c) ? 1 : 0, __c);
- __d = crt_copysign(crt_isinf(__d) ? 1 : 0, __d);
- if (crt_isnan(__a))
- __a = crt_copysign(0, __a);
- if (crt_isnan(__b))
- __b = crt_copysign(0, __b);
- __recalc = 1;
- }
- if (!__recalc && (crt_isinf(__ac) || crt_isinf(__bd) ||
- crt_isinf(__ad) || crt_isinf(__bc)))
- {
- if (crt_isnan(__a))
- __a = crt_copysign(0, __a);
- if (crt_isnan(__b))
- __b = crt_copysign(0, __b);
- if (crt_isnan(__c))
- __c = crt_copysign(0, __c);
- if (crt_isnan(__d))
- __d = crt_copysign(0, __d);
- __recalc = 1;
- }
- if (__recalc)
- {
- COMPLEX_REAL(z) = CRT_INFINITY * (__a * __c - __b * __d);
- COMPLEX_IMAGINARY(z) = CRT_INFINITY * (__a * __d + __b * __c);
- }
+COMPILER_RT_ABI Dcomplex __muldc3(double __a, double __b, double __c,
+ double __d) {
+ double __ac = __a * __c;
+ double __bd = __b * __d;
+ double __ad = __a * __d;
+ double __bc = __b * __c;
+ Dcomplex z;
+ COMPLEX_REAL(z) = __ac - __bd;
+ COMPLEX_IMAGINARY(z) = __ad + __bc;
+ if (crt_isnan(COMPLEX_REAL(z)) && crt_isnan(COMPLEX_IMAGINARY(z))) {
+ int __recalc = 0;
+ if (crt_isinf(__a) || crt_isinf(__b)) {
+ __a = crt_copysign(crt_isinf(__a) ? 1 : 0, __a);
+ __b = crt_copysign(crt_isinf(__b) ? 1 : 0, __b);
+ if (crt_isnan(__c))
+ __c = crt_copysign(0, __c);
+ if (crt_isnan(__d))
+ __d = crt_copysign(0, __d);
+ __recalc = 1;
}
- return z;
+ if (crt_isinf(__c) || crt_isinf(__d)) {
+ __c = crt_copysign(crt_isinf(__c) ? 1 : 0, __c);
+ __d = crt_copysign(crt_isinf(__d) ? 1 : 0, __d);
+ if (crt_isnan(__a))
+ __a = crt_copysign(0, __a);
+ if (crt_isnan(__b))
+ __b = crt_copysign(0, __b);
+ __recalc = 1;
+ }
+ if (!__recalc && (crt_isinf(__ac) || crt_isinf(__bd) || crt_isinf(__ad) ||
+ crt_isinf(__bc))) {
+ if (crt_isnan(__a))
+ __a = crt_copysign(0, __a);
+ if (crt_isnan(__b))
+ __b = crt_copysign(0, __b);
+ if (crt_isnan(__c))
+ __c = crt_copysign(0, __c);
+ if (crt_isnan(__d))
+ __d = crt_copysign(0, __d);
+ __recalc = 1;
+ }
+ if (__recalc) {
+ COMPLEX_REAL(z) = CRT_INFINITY * (__a * __c - __b * __d);
+ COMPLEX_IMAGINARY(z) = CRT_INFINITY * (__a * __d + __b * __c);
+ }
+ }
+ return z;
}
diff --git a/contrib/libs/cxxsupp/builtins/muldf3.c b/contrib/libs/cxxsupp/builtins/muldf3.c
index 1eb733849e..f64b5228d7 100644
--- a/contrib/libs/cxxsupp/builtins/muldf3.c
+++ b/contrib/libs/cxxsupp/builtins/muldf3.c
@@ -1,9 +1,8 @@
//===-- lib/muldf3.c - Double-precision multiplication ------------*- C -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -15,8 +14,12 @@
#define DOUBLE_PRECISION
#include "fp_mul_impl.inc"
-ARM_EABI_FNALIAS(dmul, muldf3)
+COMPILER_RT_ABI fp_t __muldf3(fp_t a, fp_t b) { return __mulXf3__(a, b); }
-COMPILER_RT_ABI fp_t __muldf3(fp_t a, fp_t b) {
- return __mulXf3__(a, b);
-}
+#if defined(__ARM_EABI__)
+#if defined(COMPILER_RT_ARMHF_TARGET)
+AEABI_RTABI fp_t __aeabi_dmul(fp_t a, fp_t b) { return __muldf3(a, b); }
+#else
+COMPILER_RT_ALIAS(__muldf3, __aeabi_dmul)
+#endif
+#endif
diff --git a/contrib/libs/cxxsupp/builtins/muldi3.c b/contrib/libs/cxxsupp/builtins/muldi3.c
index 2dae44c11b..013f669a18 100644
--- a/contrib/libs/cxxsupp/builtins/muldi3.c
+++ b/contrib/libs/cxxsupp/builtins/muldi3.c
@@ -1,56 +1,51 @@
-/* ===-- muldi3.c - Implement __muldi3 -------------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __muldi3 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- muldi3.c - Implement __muldi3 -------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __muldi3 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
-/* Returns: a * b */
+// Returns: a * b
-static
-di_int
-__muldsi3(su_int a, su_int b)
-{
- dwords r;
- const int bits_in_word_2 = (int)(sizeof(si_int) * CHAR_BIT) / 2;
- const su_int lower_mask = (su_int)~0 >> bits_in_word_2;
- r.s.low = (a & lower_mask) * (b & lower_mask);
- su_int t = r.s.low >> bits_in_word_2;
- r.s.low &= lower_mask;
- t += (a >> bits_in_word_2) * (b & lower_mask);
- r.s.low += (t & lower_mask) << bits_in_word_2;
- r.s.high = t >> bits_in_word_2;
- t = r.s.low >> bits_in_word_2;
- r.s.low &= lower_mask;
- t += (b >> bits_in_word_2) * (a & lower_mask);
- r.s.low += (t & lower_mask) << bits_in_word_2;
- r.s.high += t >> bits_in_word_2;
- r.s.high += (a >> bits_in_word_2) * (b >> bits_in_word_2);
- return r.all;
+static di_int __muldsi3(su_int a, su_int b) {
+ dwords r;
+ const int bits_in_word_2 = (int)(sizeof(si_int) * CHAR_BIT) / 2;
+ const su_int lower_mask = (su_int)~0 >> bits_in_word_2;
+ r.s.low = (a & lower_mask) * (b & lower_mask);
+ su_int t = r.s.low >> bits_in_word_2;
+ r.s.low &= lower_mask;
+ t += (a >> bits_in_word_2) * (b & lower_mask);
+ r.s.low += (t & lower_mask) << bits_in_word_2;
+ r.s.high = t >> bits_in_word_2;
+ t = r.s.low >> bits_in_word_2;
+ r.s.low &= lower_mask;
+ t += (b >> bits_in_word_2) * (a & lower_mask);
+ r.s.low += (t & lower_mask) << bits_in_word_2;
+ r.s.high += t >> bits_in_word_2;
+ r.s.high += (a >> bits_in_word_2) * (b >> bits_in_word_2);
+ return r.all;
}
-/* Returns: a * b */
+// Returns: a * b
-ARM_EABI_FNALIAS(lmul, muldi3)
-
-COMPILER_RT_ABI di_int
-__muldi3(di_int a, di_int b)
-{
- dwords x;
- x.all = a;
- dwords y;
- y.all = b;
- dwords r;
- r.all = __muldsi3(x.s.low, y.s.low);
- r.s.high += x.s.high * y.s.low + x.s.low * y.s.high;
- return r.all;
+COMPILER_RT_ABI di_int __muldi3(di_int a, di_int b) {
+ dwords x;
+ x.all = a;
+ dwords y;
+ y.all = b;
+ dwords r;
+ r.all = __muldsi3(x.s.low, y.s.low);
+ r.s.high += x.s.high * y.s.low + x.s.low * y.s.high;
+ return r.all;
}
+
+#if defined(__ARM_EABI__)
+COMPILER_RT_ALIAS(__muldi3, __aeabi_lmul)
+#endif
diff --git a/contrib/libs/cxxsupp/builtins/mulodi4.c b/contrib/libs/cxxsupp/builtins/mulodi4.c
index d2fd7db2bc..7209676a32 100644
--- a/contrib/libs/cxxsupp/builtins/mulodi4.c
+++ b/contrib/libs/cxxsupp/builtins/mulodi4.c
@@ -1,58 +1,22 @@
-/*===-- mulodi4.c - Implement __mulodi4 -----------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __mulodi4 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- mulodi4.c - Implement __mulodi4 -----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __mulodi4 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
-#include "int_lib.h"
+#define fixint_t di_int
+#include "int_mulo_impl.inc"
-/* Returns: a * b */
+// Returns: a * b
-/* Effects: sets *overflow to 1 if a * b overflows */
+// Effects: sets *overflow to 1 if a * b overflows
-COMPILER_RT_ABI di_int
-__mulodi4(di_int a, di_int b, int* overflow)
-{
- const int N = (int)(sizeof(di_int) * CHAR_BIT);
- const di_int MIN = (di_int)1 << (N-1);
- const di_int MAX = ~MIN;
- *overflow = 0;
- di_int result = a * b;
- if (a == MIN)
- {
- if (b != 0 && b != 1)
- *overflow = 1;
- return result;
- }
- if (b == MIN)
- {
- if (a != 0 && a != 1)
- *overflow = 1;
- return result;
- }
- di_int sa = a >> (N - 1);
- di_int abs_a = (a ^ sa) - sa;
- di_int sb = b >> (N - 1);
- di_int abs_b = (b ^ sb) - sb;
- if (abs_a < 2 || abs_b < 2)
- return result;
- if (sa == sb)
- {
- if (abs_a > MAX / abs_b)
- *overflow = 1;
- }
- else
- {
- if (abs_a > MIN / -abs_b)
- *overflow = 1;
- }
- return result;
+COMPILER_RT_ABI di_int __mulodi4(di_int a, di_int b, int *overflow) {
+ return __muloXi4(a, b, overflow);
}
diff --git a/contrib/libs/cxxsupp/builtins/mulosi4.c b/contrib/libs/cxxsupp/builtins/mulosi4.c
index 422528085c..4e03c24455 100644
--- a/contrib/libs/cxxsupp/builtins/mulosi4.c
+++ b/contrib/libs/cxxsupp/builtins/mulosi4.c
@@ -1,58 +1,22 @@
-/*===-- mulosi4.c - Implement __mulosi4 -----------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __mulosi4 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- mulosi4.c - Implement __mulosi4 -----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __mulosi4 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
-#include "int_lib.h"
+#define fixint_t si_int
+#include "int_mulo_impl.inc"
-/* Returns: a * b */
+// Returns: a * b
-/* Effects: sets *overflow to 1 if a * b overflows */
+// Effects: sets *overflow to 1 if a * b overflows
-COMPILER_RT_ABI si_int
-__mulosi4(si_int a, si_int b, int* overflow)
-{
- const int N = (int)(sizeof(si_int) * CHAR_BIT);
- const si_int MIN = (si_int)1 << (N-1);
- const si_int MAX = ~MIN;
- *overflow = 0;
- si_int result = a * b;
- if (a == MIN)
- {
- if (b != 0 && b != 1)
- *overflow = 1;
- return result;
- }
- if (b == MIN)
- {
- if (a != 0 && a != 1)
- *overflow = 1;
- return result;
- }
- si_int sa = a >> (N - 1);
- si_int abs_a = (a ^ sa) - sa;
- si_int sb = b >> (N - 1);
- si_int abs_b = (b ^ sb) - sb;
- if (abs_a < 2 || abs_b < 2)
- return result;
- if (sa == sb)
- {
- if (abs_a > MAX / abs_b)
- *overflow = 1;
- }
- else
- {
- if (abs_a > MIN / -abs_b)
- *overflow = 1;
- }
- return result;
+COMPILER_RT_ABI si_int __mulosi4(si_int a, si_int b, int *overflow) {
+ return __muloXi4(a, b, overflow);
}
diff --git a/contrib/libs/cxxsupp/builtins/muloti4.c b/contrib/libs/cxxsupp/builtins/muloti4.c
index aef8207aaa..9a7aa85b02 100644
--- a/contrib/libs/cxxsupp/builtins/muloti4.c
+++ b/contrib/libs/cxxsupp/builtins/muloti4.c
@@ -1,63 +1,28 @@
-/*===-- muloti4.c - Implement __muloti4 -----------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __muloti4 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- muloti4.c - Implement __muloti4 -----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __muloti4 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
#ifdef CRT_HAS_128BIT
-/* Returns: a * b */
+// Returns: a * b
-/* Effects: sets *overflow to 1 if a * b overflows */
+// Effects: sets *overflow to 1 if a * b overflows
-__attribute__((no_sanitize("undefined")))
-COMPILER_RT_ABI ti_int
-__muloti4(ti_int a, ti_int b, int* overflow)
-{
- const int N = (int)(sizeof(ti_int) * CHAR_BIT);
- const ti_int MIN = (ti_int)1 << (N-1);
- const ti_int MAX = ~MIN;
- *overflow = 0;
- ti_int result = a * b;
- if (a == MIN)
- {
- if (b != 0 && b != 1)
- *overflow = 1;
- return result;
- }
- if (b == MIN)
- {
- if (a != 0 && a != 1)
- *overflow = 1;
- return result;
- }
- ti_int sa = a >> (N - 1);
- ti_int abs_a = (a ^ sa) - sa;
- ti_int sb = b >> (N - 1);
- ti_int abs_b = (b ^ sb) - sb;
- if (abs_a < 2 || abs_b < 2)
- return result;
- if (sa == sb)
- {
- if (abs_a > MAX / abs_b)
- *overflow = 1;
- }
- else
- {
- if (abs_a > MIN / -abs_b)
- *overflow = 1;
- }
- return result;
+#define fixint_t ti_int
+#include "int_mulo_impl.inc"
+
+COMPILER_RT_ABI ti_int __muloti4(ti_int a, ti_int b, int *overflow) {
+ return __muloXi4(a, b, overflow);
}
-#endif /* CRT_HAS_128BIT */
+#endif // CRT_HAS_128BIT
diff --git a/contrib/libs/cxxsupp/builtins/mulsc3.c b/contrib/libs/cxxsupp/builtins/mulsc3.c
index c89cfd247a..60653174e4 100644
--- a/contrib/libs/cxxsupp/builtins/mulsc3.c
+++ b/contrib/libs/cxxsupp/builtins/mulsc3.c
@@ -1,73 +1,64 @@
-/* ===-- mulsc3.c - Implement __mulsc3 -------------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __mulsc3 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- mulsc3.c - Implement __mulsc3 -------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __mulsc3 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
#include "int_math.h"
-/* Returns: the product of a + ib and c + id */
+// Returns: the product of a + ib and c + id
-COMPILER_RT_ABI Fcomplex
-__mulsc3(float __a, float __b, float __c, float __d)
-{
- float __ac = __a * __c;
- float __bd = __b * __d;
- float __ad = __a * __d;
- float __bc = __b * __c;
- Fcomplex z;
- COMPLEX_REAL(z) = __ac - __bd;
- COMPLEX_IMAGINARY(z) = __ad + __bc;
- if (crt_isnan(COMPLEX_REAL(z)) && crt_isnan(COMPLEX_IMAGINARY(z)))
- {
- int __recalc = 0;
- if (crt_isinf(__a) || crt_isinf(__b))
- {
- __a = crt_copysignf(crt_isinf(__a) ? 1 : 0, __a);
- __b = crt_copysignf(crt_isinf(__b) ? 1 : 0, __b);
- if (crt_isnan(__c))
- __c = crt_copysignf(0, __c);
- if (crt_isnan(__d))
- __d = crt_copysignf(0, __d);
- __recalc = 1;
- }
- if (crt_isinf(__c) || crt_isinf(__d))
- {
- __c = crt_copysignf(crt_isinf(__c) ? 1 : 0, __c);
- __d = crt_copysignf(crt_isinf(__d) ? 1 : 0, __d);
- if (crt_isnan(__a))
- __a = crt_copysignf(0, __a);
- if (crt_isnan(__b))
- __b = crt_copysignf(0, __b);
- __recalc = 1;
- }
- if (!__recalc && (crt_isinf(__ac) || crt_isinf(__bd) ||
- crt_isinf(__ad) || crt_isinf(__bc)))
- {
- if (crt_isnan(__a))
- __a = crt_copysignf(0, __a);
- if (crt_isnan(__b))
- __b = crt_copysignf(0, __b);
- if (crt_isnan(__c))
- __c = crt_copysignf(0, __c);
- if (crt_isnan(__d))
- __d = crt_copysignf(0, __d);
- __recalc = 1;
- }
- if (__recalc)
- {
- COMPLEX_REAL(z) = CRT_INFINITY * (__a * __c - __b * __d);
- COMPLEX_IMAGINARY(z) = CRT_INFINITY * (__a * __d + __b * __c);
- }
+COMPILER_RT_ABI Fcomplex __mulsc3(float __a, float __b, float __c, float __d) {
+ float __ac = __a * __c;
+ float __bd = __b * __d;
+ float __ad = __a * __d;
+ float __bc = __b * __c;
+ Fcomplex z;
+ COMPLEX_REAL(z) = __ac - __bd;
+ COMPLEX_IMAGINARY(z) = __ad + __bc;
+ if (crt_isnan(COMPLEX_REAL(z)) && crt_isnan(COMPLEX_IMAGINARY(z))) {
+ int __recalc = 0;
+ if (crt_isinf(__a) || crt_isinf(__b)) {
+ __a = crt_copysignf(crt_isinf(__a) ? 1 : 0, __a);
+ __b = crt_copysignf(crt_isinf(__b) ? 1 : 0, __b);
+ if (crt_isnan(__c))
+ __c = crt_copysignf(0, __c);
+ if (crt_isnan(__d))
+ __d = crt_copysignf(0, __d);
+ __recalc = 1;
}
- return z;
+ if (crt_isinf(__c) || crt_isinf(__d)) {
+ __c = crt_copysignf(crt_isinf(__c) ? 1 : 0, __c);
+ __d = crt_copysignf(crt_isinf(__d) ? 1 : 0, __d);
+ if (crt_isnan(__a))
+ __a = crt_copysignf(0, __a);
+ if (crt_isnan(__b))
+ __b = crt_copysignf(0, __b);
+ __recalc = 1;
+ }
+ if (!__recalc && (crt_isinf(__ac) || crt_isinf(__bd) || crt_isinf(__ad) ||
+ crt_isinf(__bc))) {
+ if (crt_isnan(__a))
+ __a = crt_copysignf(0, __a);
+ if (crt_isnan(__b))
+ __b = crt_copysignf(0, __b);
+ if (crt_isnan(__c))
+ __c = crt_copysignf(0, __c);
+ if (crt_isnan(__d))
+ __d = crt_copysignf(0, __d);
+ __recalc = 1;
+ }
+ if (__recalc) {
+ COMPLEX_REAL(z) = CRT_INFINITY * (__a * __c - __b * __d);
+ COMPLEX_IMAGINARY(z) = CRT_INFINITY * (__a * __d + __b * __c);
+ }
+ }
+ return z;
}
diff --git a/contrib/libs/cxxsupp/builtins/mulsf3.c b/contrib/libs/cxxsupp/builtins/mulsf3.c
index 478b3bc0e0..b9cf39abc7 100644
--- a/contrib/libs/cxxsupp/builtins/mulsf3.c
+++ b/contrib/libs/cxxsupp/builtins/mulsf3.c
@@ -1,9 +1,8 @@
//===-- lib/mulsf3.c - Single-precision multiplication ------------*- C -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -15,8 +14,12 @@
#define SINGLE_PRECISION
#include "fp_mul_impl.inc"
-ARM_EABI_FNALIAS(fmul, mulsf3)
+COMPILER_RT_ABI fp_t __mulsf3(fp_t a, fp_t b) { return __mulXf3__(a, b); }
-COMPILER_RT_ABI fp_t __mulsf3(fp_t a, fp_t b) {
- return __mulXf3__(a, b);
-}
+#if defined(__ARM_EABI__)
+#if defined(COMPILER_RT_ARMHF_TARGET)
+AEABI_RTABI fp_t __aeabi_fmul(fp_t a, fp_t b) { return __mulsf3(a, b); }
+#else
+COMPILER_RT_ALIAS(__mulsf3, __aeabi_fmul)
+#endif
+#endif
diff --git a/contrib/libs/cxxsupp/builtins/multc3.c b/contrib/libs/cxxsupp/builtins/multc3.c
index 0518bc2569..bb7f6aabfe 100644
--- a/contrib/libs/cxxsupp/builtins/multc3.c
+++ b/contrib/libs/cxxsupp/builtins/multc3.c
@@ -1,68 +1,65 @@
-/* ===-- multc3.c - Implement __multc3 -------------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __multc3 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- multc3.c - Implement __multc3 -------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __multc3 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
#include "int_math.h"
-/* Returns: the product of a + ib and c + id */
+// Returns: the product of a + ib and c + id
-COMPILER_RT_ABI long double _Complex
-__multc3(long double a, long double b, long double c, long double d)
-{
- long double ac = a * c;
- long double bd = b * d;
- long double ad = a * d;
- long double bc = b * c;
- long double _Complex z;
- __real__ z = ac - bd;
- __imag__ z = ad + bc;
- if (crt_isnan(__real__ z) && crt_isnan(__imag__ z)) {
- int recalc = 0;
- if (crt_isinf(a) || crt_isinf(b)) {
- a = crt_copysignl(crt_isinf(a) ? 1 : 0, a);
- b = crt_copysignl(crt_isinf(b) ? 1 : 0, b);
- if (crt_isnan(c))
- c = crt_copysignl(0, c);
- if (crt_isnan(d))
- d = crt_copysignl(0, d);
- recalc = 1;
- }
- if (crt_isinf(c) || crt_isinf(d)) {
- c = crt_copysignl(crt_isinf(c) ? 1 : 0, c);
- d = crt_copysignl(crt_isinf(d) ? 1 : 0, d);
- if (crt_isnan(a))
- a = crt_copysignl(0, a);
- if (crt_isnan(b))
- b = crt_copysignl(0, b);
- recalc = 1;
- }
- if (!recalc && (crt_isinf(ac) || crt_isinf(bd) ||
- crt_isinf(ad) || crt_isinf(bc))) {
- if (crt_isnan(a))
- a = crt_copysignl(0, a);
- if (crt_isnan(b))
- b = crt_copysignl(0, b);
- if (crt_isnan(c))
- c = crt_copysignl(0, c);
- if (crt_isnan(d))
- d = crt_copysignl(0, d);
- recalc = 1;
- }
- if (recalc) {
- __real__ z = CRT_INFINITY * (a * c - b * d);
- __imag__ z = CRT_INFINITY * (a * d + b * c);
- }
+COMPILER_RT_ABI long double _Complex __multc3(long double a, long double b,
+ long double c, long double d) {
+ long double ac = a * c;
+ long double bd = b * d;
+ long double ad = a * d;
+ long double bc = b * c;
+ long double _Complex z;
+ __real__ z = ac - bd;
+ __imag__ z = ad + bc;
+ if (crt_isnan(__real__ z) && crt_isnan(__imag__ z)) {
+ int recalc = 0;
+ if (crt_isinf(a) || crt_isinf(b)) {
+ a = crt_copysignl(crt_isinf(a) ? 1 : 0, a);
+ b = crt_copysignl(crt_isinf(b) ? 1 : 0, b);
+ if (crt_isnan(c))
+ c = crt_copysignl(0, c);
+ if (crt_isnan(d))
+ d = crt_copysignl(0, d);
+ recalc = 1;
}
- return z;
+ if (crt_isinf(c) || crt_isinf(d)) {
+ c = crt_copysignl(crt_isinf(c) ? 1 : 0, c);
+ d = crt_copysignl(crt_isinf(d) ? 1 : 0, d);
+ if (crt_isnan(a))
+ a = crt_copysignl(0, a);
+ if (crt_isnan(b))
+ b = crt_copysignl(0, b);
+ recalc = 1;
+ }
+ if (!recalc &&
+ (crt_isinf(ac) || crt_isinf(bd) || crt_isinf(ad) || crt_isinf(bc))) {
+ if (crt_isnan(a))
+ a = crt_copysignl(0, a);
+ if (crt_isnan(b))
+ b = crt_copysignl(0, b);
+ if (crt_isnan(c))
+ c = crt_copysignl(0, c);
+ if (crt_isnan(d))
+ d = crt_copysignl(0, d);
+ recalc = 1;
+ }
+ if (recalc) {
+ __real__ z = CRT_INFINITY * (a * c - b * d);
+ __imag__ z = CRT_INFINITY * (a * d + b * c);
+ }
+ }
+ return z;
}
diff --git a/contrib/libs/cxxsupp/builtins/multf3.c b/contrib/libs/cxxsupp/builtins/multf3.c
index 0b915923ea..0626fb8c7f 100644
--- a/contrib/libs/cxxsupp/builtins/multf3.c
+++ b/contrib/libs/cxxsupp/builtins/multf3.c
@@ -1,9 +1,8 @@
//===-- lib/multf3.c - Quad-precision multiplication --------------*- C -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -18,8 +17,6 @@
#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT)
#include "fp_mul_impl.inc"
-COMPILER_RT_ABI fp_t __multf3(fp_t a, fp_t b) {
- return __mulXf3__(a, b);
-}
+COMPILER_RT_ABI fp_t __multf3(fp_t a, fp_t b) { return __mulXf3__(a, b); }
#endif
diff --git a/contrib/libs/cxxsupp/builtins/multi3.c b/contrib/libs/cxxsupp/builtins/multi3.c
index e0d52d430b..d9d8b59cd3 100644
--- a/contrib/libs/cxxsupp/builtins/multi3.c
+++ b/contrib/libs/cxxsupp/builtins/multi3.c
@@ -1,58 +1,51 @@
-/* ===-- multi3.c - Implement __multi3 -------------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
-
- * This file implements __multi3 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- multi3.c - Implement __multi3 -------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __multi3 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
#ifdef CRT_HAS_128BIT
-/* Returns: a * b */
-
-static
-ti_int
-__mulddi3(du_int a, du_int b)
-{
- twords r;
- const int bits_in_dword_2 = (int)(sizeof(di_int) * CHAR_BIT) / 2;
- const du_int lower_mask = (du_int)~0 >> bits_in_dword_2;
- r.s.low = (a & lower_mask) * (b & lower_mask);
- du_int t = r.s.low >> bits_in_dword_2;
- r.s.low &= lower_mask;
- t += (a >> bits_in_dword_2) * (b & lower_mask);
- r.s.low += (t & lower_mask) << bits_in_dword_2;
- r.s.high = t >> bits_in_dword_2;
- t = r.s.low >> bits_in_dword_2;
- r.s.low &= lower_mask;
- t += (b >> bits_in_dword_2) * (a & lower_mask);
- r.s.low += (t & lower_mask) << bits_in_dword_2;
- r.s.high += t >> bits_in_dword_2;
- r.s.high += (a >> bits_in_dword_2) * (b >> bits_in_dword_2);
- return r.all;
+// Returns: a * b
+
+static ti_int __mulddi3(du_int a, du_int b) {
+ twords r;
+ const int bits_in_dword_2 = (int)(sizeof(di_int) * CHAR_BIT) / 2;
+ const du_int lower_mask = (du_int)~0 >> bits_in_dword_2;
+ r.s.low = (a & lower_mask) * (b & lower_mask);
+ du_int t = r.s.low >> bits_in_dword_2;
+ r.s.low &= lower_mask;
+ t += (a >> bits_in_dword_2) * (b & lower_mask);
+ r.s.low += (t & lower_mask) << bits_in_dword_2;
+ r.s.high = t >> bits_in_dword_2;
+ t = r.s.low >> bits_in_dword_2;
+ r.s.low &= lower_mask;
+ t += (b >> bits_in_dword_2) * (a & lower_mask);
+ r.s.low += (t & lower_mask) << bits_in_dword_2;
+ r.s.high += t >> bits_in_dword_2;
+ r.s.high += (a >> bits_in_dword_2) * (b >> bits_in_dword_2);
+ return r.all;
}
-/* Returns: a * b */
-
-COMPILER_RT_ABI ti_int
-__multi3(ti_int a, ti_int b)
-{
- twords x;
- x.all = a;
- twords y;
- y.all = b;
- twords r;
- r.all = __mulddi3(x.s.low, y.s.low);
- r.s.high += x.s.high * y.s.low + x.s.low * y.s.high;
- return r.all;
+// Returns: a * b
+
+COMPILER_RT_ABI ti_int __multi3(ti_int a, ti_int b) {
+ twords x;
+ x.all = a;
+ twords y;
+ y.all = b;
+ twords r;
+ r.all = __mulddi3(x.s.low, y.s.low);
+ r.s.high += x.s.high * y.s.low + x.s.low * y.s.high;
+ return r.all;
}
-#endif /* CRT_HAS_128BIT */
+#endif // CRT_HAS_128BIT
diff --git a/contrib/libs/cxxsupp/builtins/mulvdi3.c b/contrib/libs/cxxsupp/builtins/mulvdi3.c
index e63249e0a0..1d672c6dc1 100644
--- a/contrib/libs/cxxsupp/builtins/mulvdi3.c
+++ b/contrib/libs/cxxsupp/builtins/mulvdi3.c
@@ -1,56 +1,20 @@
-/*===-- mulvdi3.c - Implement __mulvdi3 -----------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __mulvdi3 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- mulvdi3.c - Implement __mulvdi3 -----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __mulvdi3 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
-#include "int_lib.h"
+#define fixint_t di_int
+#include "int_mulv_impl.inc"
-/* Returns: a * b */
+// Returns: a * b
-/* Effects: aborts if a * b overflows */
+// Effects: aborts if a * b overflows
-COMPILER_RT_ABI di_int
-__mulvdi3(di_int a, di_int b)
-{
- const int N = (int)(sizeof(di_int) * CHAR_BIT);
- const di_int MIN = (di_int)1 << (N-1);
- const di_int MAX = ~MIN;
- if (a == MIN)
- {
- if (b == 0 || b == 1)
- return a * b;
- compilerrt_abort();
- }
- if (b == MIN)
- {
- if (a == 0 || a == 1)
- return a * b;
- compilerrt_abort();
- }
- di_int sa = a >> (N - 1);
- di_int abs_a = (a ^ sa) - sa;
- di_int sb = b >> (N - 1);
- di_int abs_b = (b ^ sb) - sb;
- if (abs_a < 2 || abs_b < 2)
- return a * b;
- if (sa == sb)
- {
- if (abs_a > MAX / abs_b)
- compilerrt_abort();
- }
- else
- {
- if (abs_a > MIN / -abs_b)
- compilerrt_abort();
- }
- return a * b;
-}
+COMPILER_RT_ABI di_int __mulvdi3(di_int a, di_int b) { return __mulvXi3(a, b); }
diff --git a/contrib/libs/cxxsupp/builtins/mulvsi3.c b/contrib/libs/cxxsupp/builtins/mulvsi3.c
index 74ea4f2da2..00b2e50eec 100644
--- a/contrib/libs/cxxsupp/builtins/mulvsi3.c
+++ b/contrib/libs/cxxsupp/builtins/mulvsi3.c
@@ -1,56 +1,20 @@
-/* ===-- mulvsi3.c - Implement __mulvsi3 -----------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __mulvsi3 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- mulvsi3.c - Implement __mulvsi3 -----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __mulvsi3 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
-#include "int_lib.h"
+#define fixint_t si_int
+#include "int_mulv_impl.inc"
-/* Returns: a * b */
+// Returns: a * b
-/* Effects: aborts if a * b overflows */
+// Effects: aborts if a * b overflows
-COMPILER_RT_ABI si_int
-__mulvsi3(si_int a, si_int b)
-{
- const int N = (int)(sizeof(si_int) * CHAR_BIT);
- const si_int MIN = (si_int)1 << (N-1);
- const si_int MAX = ~MIN;
- if (a == MIN)
- {
- if (b == 0 || b == 1)
- return a * b;
- compilerrt_abort();
- }
- if (b == MIN)
- {
- if (a == 0 || a == 1)
- return a * b;
- compilerrt_abort();
- }
- si_int sa = a >> (N - 1);
- si_int abs_a = (a ^ sa) - sa;
- si_int sb = b >> (N - 1);
- si_int abs_b = (b ^ sb) - sb;
- if (abs_a < 2 || abs_b < 2)
- return a * b;
- if (sa == sb)
- {
- if (abs_a > MAX / abs_b)
- compilerrt_abort();
- }
- else
- {
- if (abs_a > MIN / -abs_b)
- compilerrt_abort();
- }
- return a * b;
-}
+COMPILER_RT_ABI si_int __mulvsi3(si_int a, si_int b) { return __mulvXi3(a, b); }
diff --git a/contrib/libs/cxxsupp/builtins/mulvti3.c b/contrib/libs/cxxsupp/builtins/mulvti3.c
index f4c7d1612b..ba355149f9 100644
--- a/contrib/libs/cxxsupp/builtins/mulvti3.c
+++ b/contrib/libs/cxxsupp/builtins/mulvti3.c
@@ -1,60 +1,26 @@
-/* ===-- mulvti3.c - Implement __mulvti3 -----------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __mulvti3 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- mulvti3.c - Implement __mulvti3 -----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __mulvti3 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
#ifdef CRT_HAS_128BIT
-/* Returns: a * b */
+// Returns: a * b
-/* Effects: aborts if a * b overflows */
+// Effects: aborts if a * b overflows
-COMPILER_RT_ABI ti_int
-__mulvti3(ti_int a, ti_int b)
-{
- const int N = (int)(sizeof(ti_int) * CHAR_BIT);
- const ti_int MIN = (ti_int)1 << (N-1);
- const ti_int MAX = ~MIN;
- if (a == MIN)
- {
- if (b == 0 || b == 1)
- return a * b;
- compilerrt_abort();
- }
- if (b == MIN)
- {
- if (a == 0 || a == 1)
- return a * b;
- compilerrt_abort();
- }
- ti_int sa = a >> (N - 1);
- ti_int abs_a = (a ^ sa) - sa;
- ti_int sb = b >> (N - 1);
- ti_int abs_b = (b ^ sb) - sb;
- if (abs_a < 2 || abs_b < 2)
- return a * b;
- if (sa == sb)
- {
- if (abs_a > MAX / abs_b)
- compilerrt_abort();
- }
- else
- {
- if (abs_a > MIN / -abs_b)
- compilerrt_abort();
- }
- return a * b;
-}
+#define fixint_t ti_int
+#include "int_mulv_impl.inc"
-#endif /* CRT_HAS_128BIT */
+COMPILER_RT_ABI ti_int __mulvti3(ti_int a, ti_int b) { return __mulvXi3(a, b); }
+
+#endif // CRT_HAS_128BIT
diff --git a/contrib/libs/cxxsupp/builtins/mulxc3.c b/contrib/libs/cxxsupp/builtins/mulxc3.c
index ba32216918..2f7f14c284 100644
--- a/contrib/libs/cxxsupp/builtins/mulxc3.c
+++ b/contrib/libs/cxxsupp/builtins/mulxc3.c
@@ -1,77 +1,69 @@
-/* ===-- mulxc3.c - Implement __mulxc3 -------------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __mulxc3 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- mulxc3.c - Implement __mulxc3 -------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __mulxc3 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#if !_ARCH_PPC
#include "int_lib.h"
#include "int_math.h"
-/* Returns: the product of a + ib and c + id */
+// Returns: the product of a + ib and c + id
-COMPILER_RT_ABI Lcomplex
-__mulxc3(long double __a, long double __b, long double __c, long double __d)
-{
- long double __ac = __a * __c;
- long double __bd = __b * __d;
- long double __ad = __a * __d;
- long double __bc = __b * __c;
- Lcomplex z;
- COMPLEX_REAL(z) = __ac - __bd;
- COMPLEX_IMAGINARY(z) = __ad + __bc;
- if (crt_isnan(COMPLEX_REAL(z)) && crt_isnan(COMPLEX_IMAGINARY(z)))
- {
- int __recalc = 0;
- if (crt_isinf(__a) || crt_isinf(__b))
- {
- __a = crt_copysignl(crt_isinf(__a) ? 1 : 0, __a);
- __b = crt_copysignl(crt_isinf(__b) ? 1 : 0, __b);
- if (crt_isnan(__c))
- __c = crt_copysignl(0, __c);
- if (crt_isnan(__d))
- __d = crt_copysignl(0, __d);
- __recalc = 1;
- }
- if (crt_isinf(__c) || crt_isinf(__d))
- {
- __c = crt_copysignl(crt_isinf(__c) ? 1 : 0, __c);
- __d = crt_copysignl(crt_isinf(__d) ? 1 : 0, __d);
- if (crt_isnan(__a))
- __a = crt_copysignl(0, __a);
- if (crt_isnan(__b))
- __b = crt_copysignl(0, __b);
- __recalc = 1;
- }
- if (!__recalc && (crt_isinf(__ac) || crt_isinf(__bd) ||
- crt_isinf(__ad) || crt_isinf(__bc)))
- {
- if (crt_isnan(__a))
- __a = crt_copysignl(0, __a);
- if (crt_isnan(__b))
- __b = crt_copysignl(0, __b);
- if (crt_isnan(__c))
- __c = crt_copysignl(0, __c);
- if (crt_isnan(__d))
- __d = crt_copysignl(0, __d);
- __recalc = 1;
- }
- if (__recalc)
- {
- COMPLEX_REAL(z) = CRT_INFINITY * (__a * __c - __b * __d);
- COMPLEX_IMAGINARY(z) = CRT_INFINITY * (__a * __d + __b * __c);
- }
+COMPILER_RT_ABI Lcomplex __mulxc3(long double __a, long double __b,
+ long double __c, long double __d) {
+ long double __ac = __a * __c;
+ long double __bd = __b * __d;
+ long double __ad = __a * __d;
+ long double __bc = __b * __c;
+ Lcomplex z;
+ COMPLEX_REAL(z) = __ac - __bd;
+ COMPLEX_IMAGINARY(z) = __ad + __bc;
+ if (crt_isnan(COMPLEX_REAL(z)) && crt_isnan(COMPLEX_IMAGINARY(z))) {
+ int __recalc = 0;
+ if (crt_isinf(__a) || crt_isinf(__b)) {
+ __a = crt_copysignl(crt_isinf(__a) ? 1 : 0, __a);
+ __b = crt_copysignl(crt_isinf(__b) ? 1 : 0, __b);
+ if (crt_isnan(__c))
+ __c = crt_copysignl(0, __c);
+ if (crt_isnan(__d))
+ __d = crt_copysignl(0, __d);
+ __recalc = 1;
}
- return z;
+ if (crt_isinf(__c) || crt_isinf(__d)) {
+ __c = crt_copysignl(crt_isinf(__c) ? 1 : 0, __c);
+ __d = crt_copysignl(crt_isinf(__d) ? 1 : 0, __d);
+ if (crt_isnan(__a))
+ __a = crt_copysignl(0, __a);
+ if (crt_isnan(__b))
+ __b = crt_copysignl(0, __b);
+ __recalc = 1;
+ }
+ if (!__recalc && (crt_isinf(__ac) || crt_isinf(__bd) || crt_isinf(__ad) ||
+ crt_isinf(__bc))) {
+ if (crt_isnan(__a))
+ __a = crt_copysignl(0, __a);
+ if (crt_isnan(__b))
+ __b = crt_copysignl(0, __b);
+ if (crt_isnan(__c))
+ __c = crt_copysignl(0, __c);
+ if (crt_isnan(__d))
+ __d = crt_copysignl(0, __d);
+ __recalc = 1;
+ }
+ if (__recalc) {
+ COMPLEX_REAL(z) = CRT_INFINITY * (__a * __c - __b * __d);
+ COMPLEX_IMAGINARY(z) = CRT_INFINITY * (__a * __d + __b * __c);
+ }
+ }
+ return z;
}
#endif
diff --git a/contrib/libs/cxxsupp/builtins/negdf2.c b/contrib/libs/cxxsupp/builtins/negdf2.c
index d634b421cb..f9ceaa3745 100644
--- a/contrib/libs/cxxsupp/builtins/negdf2.c
+++ b/contrib/libs/cxxsupp/builtins/negdf2.c
@@ -1,9 +1,8 @@
//===-- lib/negdf2.c - double-precision negation ------------------*- C -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -14,9 +13,12 @@
#define DOUBLE_PRECISION
#include "fp_lib.h"
-ARM_EABI_FNALIAS(dneg, negdf2)
+COMPILER_RT_ABI fp_t __negdf2(fp_t a) { return fromRep(toRep(a) ^ signBit); }
-COMPILER_RT_ABI fp_t
-__negdf2(fp_t a) {
- return fromRep(toRep(a) ^ signBit);
-}
+#if defined(__ARM_EABI__)
+#if defined(COMPILER_RT_ARMHF_TARGET)
+AEABI_RTABI fp_t __aeabi_dneg(fp_t a) { return __negdf2(a); }
+#else
+COMPILER_RT_ALIAS(__negdf2, __aeabi_dneg)
+#endif
+#endif
diff --git a/contrib/libs/cxxsupp/builtins/negdi2.c b/contrib/libs/cxxsupp/builtins/negdi2.c
index 3d49ba2899..5a525d4b0e 100644
--- a/contrib/libs/cxxsupp/builtins/negdi2.c
+++ b/contrib/libs/cxxsupp/builtins/negdi2.c
@@ -1,26 +1,21 @@
-/* ===-- negdi2.c - Implement __negdi2 -------------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __negdi2 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- negdi2.c - Implement __negdi2 -------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __negdi2 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
-/* Returns: -a */
+// Returns: -a
-COMPILER_RT_ABI di_int
-__negdi2(di_int a)
-{
- /* Note: this routine is here for API compatibility; any sane compiler
- * should expand it inline.
- */
- return -a;
+COMPILER_RT_ABI di_int __negdi2(di_int a) {
+ // Note: this routine is here for API compatibility; any sane compiler
+ // should expand it inline.
+ return -a;
}
diff --git a/contrib/libs/cxxsupp/builtins/negsf2.c b/contrib/libs/cxxsupp/builtins/negsf2.c
index 29c17be414..d59dfe7cf9 100644
--- a/contrib/libs/cxxsupp/builtins/negsf2.c
+++ b/contrib/libs/cxxsupp/builtins/negsf2.c
@@ -1,9 +1,8 @@
//===-- lib/negsf2.c - single-precision negation ------------------*- C -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -14,9 +13,12 @@
#define SINGLE_PRECISION
#include "fp_lib.h"
-ARM_EABI_FNALIAS(fneg, negsf2)
+COMPILER_RT_ABI fp_t __negsf2(fp_t a) { return fromRep(toRep(a) ^ signBit); }
-COMPILER_RT_ABI fp_t
-__negsf2(fp_t a) {
- return fromRep(toRep(a) ^ signBit);
-}
+#if defined(__ARM_EABI__)
+#if defined(COMPILER_RT_ARMHF_TARGET)
+AEABI_RTABI fp_t __aeabi_fneg(fp_t a) { return __negsf2(a); }
+#else
+COMPILER_RT_ALIAS(__negsf2, __aeabi_fneg)
+#endif
+#endif
diff --git a/contrib/libs/cxxsupp/builtins/negti2.c b/contrib/libs/cxxsupp/builtins/negti2.c
index 9b00b303f8..d52ba4e13a 100644
--- a/contrib/libs/cxxsupp/builtins/negti2.c
+++ b/contrib/libs/cxxsupp/builtins/negti2.c
@@ -1,30 +1,25 @@
-/* ===-- negti2.c - Implement __negti2 -------------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __negti2 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- negti2.c - Implement __negti2 -------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __negti2 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
#ifdef CRT_HAS_128BIT
-/* Returns: -a */
+// Returns: -a
-COMPILER_RT_ABI ti_int
-__negti2(ti_int a)
-{
- /* Note: this routine is here for API compatibility; any sane compiler
- * should expand it inline.
- */
- return -a;
+COMPILER_RT_ABI ti_int __negti2(ti_int a) {
+ // Note: this routine is here for API compatibility; any sane compiler
+ // should expand it inline.
+ return -a;
}
-#endif /* CRT_HAS_128BIT */
+#endif // CRT_HAS_128BIT
diff --git a/contrib/libs/cxxsupp/builtins/negvdi2.c b/contrib/libs/cxxsupp/builtins/negvdi2.c
index e336ecf28f..5c52b3ec2a 100644
--- a/contrib/libs/cxxsupp/builtins/negvdi2.c
+++ b/contrib/libs/cxxsupp/builtins/negvdi2.c
@@ -1,28 +1,24 @@
-/* ===-- negvdi2.c - Implement __negvdi2 -----------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __negvdi2 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- negvdi2.c - Implement __negvdi2 -----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __negvdi2 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
-/* Returns: -a */
+// Returns: -a
-/* Effects: aborts if -a overflows */
+// Effects: aborts if -a overflows
-COMPILER_RT_ABI di_int
-__negvdi2(di_int a)
-{
- const di_int MIN = (di_int)1 << ((int)(sizeof(di_int) * CHAR_BIT)-1);
- if (a == MIN)
- compilerrt_abort();
- return -a;
+COMPILER_RT_ABI di_int __negvdi2(di_int a) {
+ const di_int MIN = (di_int)1 << ((int)(sizeof(di_int) * CHAR_BIT) - 1);
+ if (a == MIN)
+ compilerrt_abort();
+ return -a;
}
diff --git a/contrib/libs/cxxsupp/builtins/negvsi2.c b/contrib/libs/cxxsupp/builtins/negvsi2.c
index b9e93fef06..cccdee6dc5 100644
--- a/contrib/libs/cxxsupp/builtins/negvsi2.c
+++ b/contrib/libs/cxxsupp/builtins/negvsi2.c
@@ -1,28 +1,24 @@
-/* ===-- negvsi2.c - Implement __negvsi2 -----------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __negvsi2 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- negvsi2.c - Implement __negvsi2 -----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __negvsi2 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
-/* Returns: -a */
+// Returns: -a
-/* Effects: aborts if -a overflows */
+// Effects: aborts if -a overflows
-COMPILER_RT_ABI si_int
-__negvsi2(si_int a)
-{
- const si_int MIN = (si_int)1 << ((int)(sizeof(si_int) * CHAR_BIT)-1);
- if (a == MIN)
- compilerrt_abort();
- return -a;
+COMPILER_RT_ABI si_int __negvsi2(si_int a) {
+ const si_int MIN = (si_int)1 << ((int)(sizeof(si_int) * CHAR_BIT) - 1);
+ if (a == MIN)
+ compilerrt_abort();
+ return -a;
}
diff --git a/contrib/libs/cxxsupp/builtins/negvti2.c b/contrib/libs/cxxsupp/builtins/negvti2.c
index 85f9f7d19d..8f92e1046d 100644
--- a/contrib/libs/cxxsupp/builtins/negvti2.c
+++ b/contrib/libs/cxxsupp/builtins/negvti2.c
@@ -1,32 +1,28 @@
-/*===-- negvti2.c - Implement __negvti2 -----------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- *===----------------------------------------------------------------------===
- *
- *This file implements __negvti2 for the compiler_rt library.
- *
- *===----------------------------------------------------------------------===
- */
+//===-- negvti2.c - Implement __negvti2 -----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __negvti2 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
#ifdef CRT_HAS_128BIT
-/* Returns: -a */
+// Returns: -a
-/* Effects: aborts if -a overflows */
+// Effects: aborts if -a overflows
-COMPILER_RT_ABI ti_int
-__negvti2(ti_int a)
-{
- const ti_int MIN = (ti_int)1 << ((int)(sizeof(ti_int) * CHAR_BIT)-1);
- if (a == MIN)
- compilerrt_abort();
- return -a;
+COMPILER_RT_ABI ti_int __negvti2(ti_int a) {
+ const ti_int MIN = (ti_int)1 << ((int)(sizeof(ti_int) * CHAR_BIT) - 1);
+ if (a == MIN)
+ compilerrt_abort();
+ return -a;
}
-#endif /* CRT_HAS_128BIT */
+#endif // CRT_HAS_128BIT
diff --git a/contrib/libs/cxxsupp/builtins/os_version_check.c b/contrib/libs/cxxsupp/builtins/os_version_check.c
index a3cb63886d..ebfb2dfc72 100644
--- a/contrib/libs/cxxsupp/builtins/os_version_check.c
+++ b/contrib/libs/cxxsupp/builtins/os_version_check.c
@@ -1,17 +1,15 @@
-/* ===-- os_version_check.c - OS version checking -------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements the function __isOSVersionAtLeast, used by
- * Objective-C's @available
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- os_version_check.c - OS version checking -------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the function __isOSVersionAtLeast, used by
+// Objective-C's @available
+//
+//===----------------------------------------------------------------------===//
#ifdef __APPLE__
@@ -23,9 +21,10 @@
#include <stdlib.h>
#include <string.h>
-/* These three variables hold the host's OS version. */
+// These three variables hold the host's OS version.
static int32_t GlobalMajor, GlobalMinor, GlobalSubminor;
static dispatch_once_t DispatchOnceCounter;
+static dispatch_once_t CompatibilityDispatchOnceCounter;
// _availability_version_check darwin API support.
typedef uint32_t dyld_platform_t;
@@ -40,11 +39,11 @@ typedef bool (*AvailabilityVersionCheckFuncTy)(uint32_t count,
static AvailabilityVersionCheckFuncTy AvailabilityVersionCheck;
-/* We can't include <CoreFoundation/CoreFoundation.h> directly from here, so
- * just forward declare everything that we need from it. */
+// We can't include <CoreFoundation/CoreFoundation.h> directly from here, so
+// just forward declare everything that we need from it.
typedef const void *CFDataRef, *CFAllocatorRef, *CFPropertyListRef,
- *CFStringRef, *CFDictionaryRef, *CFTypeRef, *CFErrorRef;
+ *CFStringRef, *CFDictionaryRef, *CFTypeRef, *CFErrorRef;
#if __LLP64__
typedef unsigned long long CFTypeID;
@@ -61,9 +60,9 @@ typedef _Bool Boolean;
typedef CFIndex CFPropertyListFormat;
typedef uint32_t CFStringEncoding;
-/* kCFStringEncodingASCII analog. */
+// kCFStringEncodingASCII analog.
#define CF_STRING_ENCODING_ASCII 0x0600
-/* kCFStringEncodingUTF8 analog. */
+// kCFStringEncodingUTF8 analog.
#define CF_STRING_ENCODING_UTF8 0x08000100
#define CF_PROPERTY_LIST_IMMUTABLE 0
@@ -87,17 +86,26 @@ typedef Boolean (*CFStringGetCStringFuncTy)(CFStringRef, char *, CFIndex,
CFStringEncoding);
typedef void (*CFReleaseFuncTy)(CFTypeRef);
-/* Find and parse the SystemVersion.plist file. */
-static void initializeAvailabilityCheck(void *Unused) {
- (void)Unused;
+static void _initializeAvailabilityCheck(bool LoadPlist) {
+ if (AvailabilityVersionCheck && !LoadPlist) {
+ // New API is supported and we're not being asked to load the plist,
+ // exit early!
+ return;
+ }
- // Use the new API if it's is available. Still load the PLIST to ensure that the
- // existing calls to __isOSVersionAtLeast still work even with new
- // compiler-rt and new OSes.
+ // Use the new API if it's is available.
AvailabilityVersionCheck = (AvailabilityVersionCheckFuncTy)dlsym(
RTLD_DEFAULT, "_availability_version_check");
- /* Load CoreFoundation dynamically */
+ if (AvailabilityVersionCheck && !LoadPlist) {
+ // New API is supported and we're not being asked to load the plist,
+ // exit early!
+ return;
+ }
+ // Still load the PLIST to ensure that the existing calls to
+ // __isOSVersionAtLeast still work even with new compiler-rt and old OSes.
+
+ // Load CoreFoundation dynamically
const void *NullAllocator = dlsym(RTLD_DEFAULT, "kCFAllocatorNull");
if (!NullAllocator)
return;
@@ -108,18 +116,18 @@ static void initializeAvailabilityCheck(void *Unused) {
if (!CFDataCreateWithBytesNoCopyFunc)
return;
CFPropertyListCreateWithDataFuncTy CFPropertyListCreateWithDataFunc =
- (CFPropertyListCreateWithDataFuncTy)dlsym(
- RTLD_DEFAULT, "CFPropertyListCreateWithData");
-/* CFPropertyListCreateWithData was introduced only in macOS 10.6+, so it
- * will be NULL on earlier OS versions. */
+ (CFPropertyListCreateWithDataFuncTy)dlsym(RTLD_DEFAULT,
+ "CFPropertyListCreateWithData");
+// CFPropertyListCreateWithData was introduced only in macOS 10.6+, so it
+// will be NULL on earlier OS versions.
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
CFPropertyListCreateFromXMLDataFuncTy CFPropertyListCreateFromXMLDataFunc =
(CFPropertyListCreateFromXMLDataFuncTy)dlsym(
RTLD_DEFAULT, "CFPropertyListCreateFromXMLData");
#pragma clang diagnostic pop
- /* CFPropertyListCreateFromXMLDataFunc is deprecated in macOS 10.10, so it
- * might be NULL in future OS versions. */
+ // CFPropertyListCreateFromXMLDataFunc is deprecated in macOS 10.10, so it
+ // might be NULL in future OS versions.
if (!CFPropertyListCreateWithDataFunc && !CFPropertyListCreateFromXMLDataFunc)
return;
CFStringCreateWithCStringNoCopyFuncTy CFStringCreateWithCStringNoCopyFunc =
@@ -163,7 +171,7 @@ static void initializeAvailabilityCheck(void *Unused) {
if (!PropertyList)
return;
- /* Dynamically allocated stuff. */
+ // Dynamically allocated stuff.
CFDictionaryRef PListRef = NULL;
CFDataRef FileContentsRef = NULL;
UInt8 *PListBuf = NULL;
@@ -182,8 +190,8 @@ static void initializeAvailabilityCheck(void *Unused) {
if (NumRead != (size_t)PListFileSize)
goto Fail;
- /* Get the file buffer into CF's format. We pass in a null allocator here *
- * because we free PListBuf ourselves */
+ // Get the file buffer into CF's format. We pass in a null allocator here *
+ // because we free PListBuf ourselves
FileContentsRef = (*CFDataCreateWithBytesNoCopyFunc)(
NULL, PListBuf, (CFIndex)NumRead, AllocatorNull);
if (!FileContentsRef)
@@ -223,12 +231,24 @@ Fail:
fclose(PropertyList);
}
-// This old API entry point is no longer used by Clang. We still need to keep it
-// around to ensure that object files that reference it are still usable when
-// linked with new compiler-rt.
+// Find and parse the SystemVersion.plist file.
+static void compatibilityInitializeAvailabilityCheck(void *Unused) {
+ (void)Unused;
+ _initializeAvailabilityCheck(/*LoadPlist=*/true);
+}
+
+static void initializeAvailabilityCheck(void *Unused) {
+ (void)Unused;
+ _initializeAvailabilityCheck(/*LoadPlist=*/false);
+}
+
+// This old API entry point is no longer used by Clang for Darwin. We still need
+// to keep it around to ensure that object files that reference it are still
+// usable when linked with new compiler-rt.
int32_t __isOSVersionAtLeast(int32_t Major, int32_t Minor, int32_t Subminor) {
- /* Populate the global version variables, if they haven't already. */
- dispatch_once_f(&DispatchOnceCounter, NULL, initializeAvailabilityCheck);
+ // Populate the global version variables, if they haven't already.
+ dispatch_once_f(&CompatibilityDispatchOnceCounter, NULL,
+ compatibilityInitializeAvailabilityCheck);
if (Major < GlobalMajor)
return 1;
@@ -258,9 +278,47 @@ int32_t __isPlatformVersionAtLeast(uint32_t Platform, uint32_t Major,
return AvailabilityVersionCheck(1, Versions);
}
+#elif __ANDROID__
+
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/system_properties.h>
+
+static int SdkVersion;
+static int IsPreRelease;
+
+static void readSystemProperties(void) {
+ char buf[PROP_VALUE_MAX];
+
+ if (__system_property_get("ro.build.version.sdk", buf) == 0) {
+ // When the system property doesn't exist, defaults to future API level.
+ SdkVersion = __ANDROID_API_FUTURE__;
+ } else {
+ SdkVersion = atoi(buf);
+ }
+
+ if (__system_property_get("ro.build.version.codename", buf) == 0) {
+ IsPreRelease = 1;
+ } else {
+ IsPreRelease = strcmp(buf, "REL") != 0;
+ }
+ return;
+}
+
+int32_t __isOSVersionAtLeast(int32_t Major, int32_t Minor, int32_t Subminor) {
+ (void) Minor;
+ (void) Subminor;
+ static pthread_once_t once = PTHREAD_ONCE_INIT;
+ pthread_once(&once, readSystemProperties);
+
+ return SdkVersion >= Major ||
+ (IsPreRelease && Major == __ANDROID_API_FUTURE__);
+}
+
#else
-/* Silence an empty translation unit warning. */
+// Silence an empty translation unit warning.
typedef int unused;
#endif
diff --git a/contrib/libs/cxxsupp/builtins/paritydi2.c b/contrib/libs/cxxsupp/builtins/paritydi2.c
index 8ea5ab4214..350dceb8ce 100644
--- a/contrib/libs/cxxsupp/builtins/paritydi2.c
+++ b/contrib/libs/cxxsupp/builtins/paritydi2.c
@@ -1,25 +1,25 @@
-/* ===-- paritydi2.c - Implement __paritydi2 -------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __paritydi2 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- paritydi2.c - Implement __paritydi2 -------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __paritydi2 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
-/* Returns: 1 if number of bits is odd else returns 0 */
+// Returns: 1 if number of bits is odd else returns 0
-COMPILER_RT_ABI si_int
-__paritydi2(di_int a)
-{
- dwords x;
- x.all = a;
- return __paritysi2(x.s.high ^ x.s.low);
+COMPILER_RT_ABI int __paritydi2(di_int a) {
+ dwords x;
+ x.all = a;
+ su_int x2 = x.s.high ^ x.s.low;
+ x2 ^= x2 >> 16;
+ x2 ^= x2 >> 8;
+ x2 ^= x2 >> 4;
+ return (0x6996 >> (x2 & 0xF)) & 1;
}
diff --git a/contrib/libs/cxxsupp/builtins/paritysi2.c b/contrib/libs/cxxsupp/builtins/paritysi2.c
index 5999846638..a4b84e0806 100644
--- a/contrib/libs/cxxsupp/builtins/paritysi2.c
+++ b/contrib/libs/cxxsupp/builtins/paritysi2.c
@@ -1,27 +1,23 @@
-/* ===-- paritysi2.c - Implement __paritysi2 -------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __paritysi2 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- paritysi2.c - Implement __paritysi2 -------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __paritysi2 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
-/* Returns: 1 if number of bits is odd else returns 0 */
+// Returns: 1 if number of bits is odd else returns 0
-COMPILER_RT_ABI si_int
-__paritysi2(si_int a)
-{
- su_int x = (su_int)a;
- x ^= x >> 16;
- x ^= x >> 8;
- x ^= x >> 4;
- return (0x6996 >> (x & 0xF)) & 1;
+COMPILER_RT_ABI int __paritysi2(si_int a) {
+ su_int x = (su_int)a;
+ x ^= x >> 16;
+ x ^= x >> 8;
+ x ^= x >> 4;
+ return (0x6996 >> (x & 0xF)) & 1;
}
diff --git a/contrib/libs/cxxsupp/builtins/parityti2.c b/contrib/libs/cxxsupp/builtins/parityti2.c
index 5a4fe49248..011c8dd455 100644
--- a/contrib/libs/cxxsupp/builtins/parityti2.c
+++ b/contrib/libs/cxxsupp/builtins/parityti2.c
@@ -1,29 +1,31 @@
-/* ===-- parityti2.c - Implement __parityti2 -------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __parityti2 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- parityti2.c - Implement __parityti2 -------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __parityti2 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
#ifdef CRT_HAS_128BIT
-/* Returns: 1 if number of bits is odd else returns 0 */
+// Returns: 1 if number of bits is odd else returns 0
-COMPILER_RT_ABI si_int
-__parityti2(ti_int a)
-{
- twords x;
- x.all = a;
- return __paritydi2(x.s.high ^ x.s.low);
+COMPILER_RT_ABI int __parityti2(ti_int a) {
+ twords x;
+ dwords x2;
+ x.all = a;
+ x2.all = x.s.high ^ x.s.low;
+ su_int x3 = x2.s.high ^ x2.s.low;
+ x3 ^= x3 >> 16;
+ x3 ^= x3 >> 8;
+ x3 ^= x3 >> 4;
+ return (0x6996 >> (x3 & 0xF)) & 1;
}
-#endif /* CRT_HAS_128BIT */
+#endif // CRT_HAS_128BIT
diff --git a/contrib/libs/cxxsupp/builtins/popcountdi2.c b/contrib/libs/cxxsupp/builtins/popcountdi2.c
index 5e8a62f075..20dd0b0239 100644
--- a/contrib/libs/cxxsupp/builtins/popcountdi2.c
+++ b/contrib/libs/cxxsupp/builtins/popcountdi2.c
@@ -1,36 +1,32 @@
-/* ===-- popcountdi2.c - Implement __popcountdi2 ----------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __popcountdi2 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- popcountdi2.c - Implement __popcountdi2 ---------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __popcountdi2 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
-/* Returns: count of 1 bits */
+// Returns: count of 1 bits
-COMPILER_RT_ABI si_int
-__popcountdi2(di_int a)
-{
- du_int x2 = (du_int)a;
- x2 = x2 - ((x2 >> 1) & 0x5555555555555555uLL);
- /* Every 2 bits holds the sum of every pair of bits (32) */
- x2 = ((x2 >> 2) & 0x3333333333333333uLL) + (x2 & 0x3333333333333333uLL);
- /* Every 4 bits holds the sum of every 4-set of bits (3 significant bits) (16) */
- x2 = (x2 + (x2 >> 4)) & 0x0F0F0F0F0F0F0F0FuLL;
- /* Every 8 bits holds the sum of every 8-set of bits (4 significant bits) (8) */
- su_int x = (su_int)(x2 + (x2 >> 32));
- /* The lower 32 bits hold four 16 bit sums (5 significant bits). */
- /* Upper 32 bits are garbage */
- x = x + (x >> 16);
- /* The lower 16 bits hold two 32 bit sums (6 significant bits). */
- /* Upper 16 bits are garbage */
- return (x + (x >> 8)) & 0x0000007F; /* (7 significant bits) */
+COMPILER_RT_ABI int __popcountdi2(di_int a) {
+ du_int x2 = (du_int)a;
+ x2 = x2 - ((x2 >> 1) & 0x5555555555555555uLL);
+ // Every 2 bits holds the sum of every pair of bits (32)
+ x2 = ((x2 >> 2) & 0x3333333333333333uLL) + (x2 & 0x3333333333333333uLL);
+ // Every 4 bits holds the sum of every 4-set of bits (3 significant bits) (16)
+ x2 = (x2 + (x2 >> 4)) & 0x0F0F0F0F0F0F0F0FuLL;
+ // Every 8 bits holds the sum of every 8-set of bits (4 significant bits) (8)
+ su_int x = (su_int)(x2 + (x2 >> 32));
+ // The lower 32 bits hold four 16 bit sums (5 significant bits).
+ // Upper 32 bits are garbage
+ x = x + (x >> 16);
+ // The lower 16 bits hold two 32 bit sums (6 significant bits).
+ // Upper 16 bits are garbage
+ return (x + (x >> 8)) & 0x0000007F; // (7 significant bits)
}
diff --git a/contrib/libs/cxxsupp/builtins/popcountsi2.c b/contrib/libs/cxxsupp/builtins/popcountsi2.c
index 44544ff498..4d346c45d9 100644
--- a/contrib/libs/cxxsupp/builtins/popcountsi2.c
+++ b/contrib/libs/cxxsupp/builtins/popcountsi2.c
@@ -1,33 +1,29 @@
-/* ===-- popcountsi2.c - Implement __popcountsi2 ---------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __popcountsi2 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- popcountsi2.c - Implement __popcountsi2 ---------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __popcountsi2 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
-/* Returns: count of 1 bits */
+// Returns: count of 1 bits
-COMPILER_RT_ABI si_int
-__popcountsi2(si_int a)
-{
- su_int x = (su_int)a;
- x = x - ((x >> 1) & 0x55555555);
- /* Every 2 bits holds the sum of every pair of bits */
- x = ((x >> 2) & 0x33333333) + (x & 0x33333333);
- /* Every 4 bits holds the sum of every 4-set of bits (3 significant bits) */
- x = (x + (x >> 4)) & 0x0F0F0F0F;
- /* Every 8 bits holds the sum of every 8-set of bits (4 significant bits) */
- x = (x + (x >> 16));
- /* The lower 16 bits hold two 8 bit sums (5 significant bits).*/
- /* Upper 16 bits are garbage */
- return (x + (x >> 8)) & 0x0000003F; /* (6 significant bits) */
+COMPILER_RT_ABI int __popcountsi2(si_int a) {
+ su_int x = (su_int)a;
+ x = x - ((x >> 1) & 0x55555555);
+ // Every 2 bits holds the sum of every pair of bits
+ x = ((x >> 2) & 0x33333333) + (x & 0x33333333);
+ // Every 4 bits holds the sum of every 4-set of bits (3 significant bits)
+ x = (x + (x >> 4)) & 0x0F0F0F0F;
+ // Every 8 bits holds the sum of every 8-set of bits (4 significant bits)
+ x = (x + (x >> 16));
+ // The lower 16 bits hold two 8 bit sums (5 significant bits).
+ // Upper 16 bits are garbage
+ return (x + (x >> 8)) & 0x0000003F; // (6 significant bits)
}
diff --git a/contrib/libs/cxxsupp/builtins/popcountti2.c b/contrib/libs/cxxsupp/builtins/popcountti2.c
index 7451bbb286..79cbb2fb34 100644
--- a/contrib/libs/cxxsupp/builtins/popcountti2.c
+++ b/contrib/libs/cxxsupp/builtins/popcountti2.c
@@ -1,44 +1,43 @@
-/* ===-- popcountti2.c - Implement __popcountti2 ----------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __popcountti2 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- popcountti2.c - Implement __popcountti2
+//----------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __popcountti2 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
#ifdef CRT_HAS_128BIT
-/* Returns: count of 1 bits */
+// Returns: count of 1 bits
-COMPILER_RT_ABI si_int
-__popcountti2(ti_int a)
-{
- tu_int x3 = (tu_int)a;
- x3 = x3 - ((x3 >> 1) & (((tu_int)0x5555555555555555uLL << 64) |
- 0x5555555555555555uLL));
- /* Every 2 bits holds the sum of every pair of bits (64) */
- x3 = ((x3 >> 2) & (((tu_int)0x3333333333333333uLL << 64) | 0x3333333333333333uLL))
- + (x3 & (((tu_int)0x3333333333333333uLL << 64) | 0x3333333333333333uLL));
- /* Every 4 bits holds the sum of every 4-set of bits (3 significant bits) (32) */
- x3 = (x3 + (x3 >> 4))
- & (((tu_int)0x0F0F0F0F0F0F0F0FuLL << 64) | 0x0F0F0F0F0F0F0F0FuLL);
- /* Every 8 bits holds the sum of every 8-set of bits (4 significant bits) (16) */
- du_int x2 = (du_int)(x3 + (x3 >> 64));
- /* Every 8 bits holds the sum of every 8-set of bits (5 significant bits) (8) */
- su_int x = (su_int)(x2 + (x2 >> 32));
- /* Every 8 bits holds the sum of every 8-set of bits (6 significant bits) (4) */
- x = x + (x >> 16);
- /* Every 8 bits holds the sum of every 8-set of bits (7 significant bits) (2) */
- /* Upper 16 bits are garbage */
- return (x + (x >> 8)) & 0xFF; /* (8 significant bits) */
+COMPILER_RT_ABI int __popcountti2(ti_int a) {
+ tu_int x3 = (tu_int)a;
+ x3 = x3 - ((x3 >> 1) &
+ (((tu_int)0x5555555555555555uLL << 64) | 0x5555555555555555uLL));
+ // Every 2 bits holds the sum of every pair of bits (64)
+ x3 = ((x3 >> 2) &
+ (((tu_int)0x3333333333333333uLL << 64) | 0x3333333333333333uLL)) +
+ (x3 & (((tu_int)0x3333333333333333uLL << 64) | 0x3333333333333333uLL));
+ // Every 4 bits holds the sum of every 4-set of bits (3 significant bits) (32)
+ x3 = (x3 + (x3 >> 4)) &
+ (((tu_int)0x0F0F0F0F0F0F0F0FuLL << 64) | 0x0F0F0F0F0F0F0F0FuLL);
+ // Every 8 bits holds the sum of every 8-set of bits (4 significant bits) (16)
+ du_int x2 = (du_int)(x3 + (x3 >> 64));
+ // Every 8 bits holds the sum of every 8-set of bits (5 significant bits) (8)
+ su_int x = (su_int)(x2 + (x2 >> 32));
+ // Every 8 bits holds the sum of every 8-set of bits (6 significant bits) (4)
+ x = x + (x >> 16);
+ // Every 8 bits holds the sum of every 8-set of bits (7 significant bits) (2)
+ //
+ // Upper 16 bits are garbage
+ return (x + (x >> 8)) & 0xFF; // (8 significant bits)
}
-#endif /* CRT_HAS_128BIT */
+#endif // CRT_HAS_128BIT
diff --git a/contrib/libs/cxxsupp/builtins/powidf2.c b/contrib/libs/cxxsupp/builtins/powidf2.c
index ac13b172b0..81058af508 100644
--- a/contrib/libs/cxxsupp/builtins/powidf2.c
+++ b/contrib/libs/cxxsupp/builtins/powidf2.c
@@ -1,34 +1,29 @@
-/* ===-- powidf2.cpp - Implement __powidf2 ---------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __powidf2 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- powidf2.cpp - Implement __powidf2 ---------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __powidf2 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
-/* Returns: a ^ b */
+// Returns: a ^ b
-COMPILER_RT_ABI double
-__powidf2(double a, si_int b)
-{
- const int recip = b < 0;
- double r = 1;
- while (1)
- {
- if (b & 1)
- r *= a;
- b /= 2;
- if (b == 0)
- break;
- a *= a;
- }
- return recip ? 1/r : r;
+COMPILER_RT_ABI double __powidf2(double a, int b) {
+ const int recip = b < 0;
+ double r = 1;
+ while (1) {
+ if (b & 1)
+ r *= a;
+ b /= 2;
+ if (b == 0)
+ break;
+ a *= a;
+ }
+ return recip ? 1 / r : r;
}
diff --git a/contrib/libs/cxxsupp/builtins/powisf2.c b/contrib/libs/cxxsupp/builtins/powisf2.c
index 0c400ec6dd..d0ab26167b 100644
--- a/contrib/libs/cxxsupp/builtins/powisf2.c
+++ b/contrib/libs/cxxsupp/builtins/powisf2.c
@@ -1,34 +1,29 @@
-/*===-- powisf2.cpp - Implement __powisf2 ---------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __powisf2 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- powisf2.cpp - Implement __powisf2 ---------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __powisf2 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
-/* Returns: a ^ b */
+// Returns: a ^ b
-COMPILER_RT_ABI float
-__powisf2(float a, si_int b)
-{
- const int recip = b < 0;
- float r = 1;
- while (1)
- {
- if (b & 1)
- r *= a;
- b /= 2;
- if (b == 0)
- break;
- a *= a;
- }
- return recip ? 1/r : r;
+COMPILER_RT_ABI float __powisf2(float a, int b) {
+ const int recip = b < 0;
+ float r = 1;
+ while (1) {
+ if (b & 1)
+ r *= a;
+ b /= 2;
+ if (b == 0)
+ break;
+ a *= a;
+ }
+ return recip ? 1 / r : r;
}
diff --git a/contrib/libs/cxxsupp/builtins/powitf2.c b/contrib/libs/cxxsupp/builtins/powitf2.c
index 172f29f58f..8e639a03a3 100644
--- a/contrib/libs/cxxsupp/builtins/powitf2.c
+++ b/contrib/libs/cxxsupp/builtins/powitf2.c
@@ -1,38 +1,34 @@
-/* ===-- powitf2.cpp - Implement __powitf2 ---------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __powitf2 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- powitf2.cpp - Implement __powitf2 ---------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __powitf2 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
-#include "int_lib.h"
+#define QUAD_PRECISION
+#include "fp_lib.h"
-#if _ARCH_PPC
+#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT)
-/* Returns: a ^ b */
+// Returns: a ^ b
-COMPILER_RT_ABI long double
-__powitf2(long double a, si_int b)
-{
- const int recip = b < 0;
- long double r = 1;
- while (1)
- {
- if (b & 1)
- r *= a;
- b /= 2;
- if (b == 0)
- break;
- a *= a;
- }
- return recip ? 1/r : r;
+COMPILER_RT_ABI long double __powitf2(long double a, int b) {
+ const int recip = b < 0;
+ long double r = 1;
+ while (1) {
+ if (b & 1)
+ r *= a;
+ b /= 2;
+ if (b == 0)
+ break;
+ a *= a;
+ }
+ return recip ? 1 / r : r;
}
#endif
diff --git a/contrib/libs/cxxsupp/builtins/powixf2.c b/contrib/libs/cxxsupp/builtins/powixf2.c
index 0fd96e503e..3edfe9fd7a 100644
--- a/contrib/libs/cxxsupp/builtins/powixf2.c
+++ b/contrib/libs/cxxsupp/builtins/powixf2.c
@@ -1,38 +1,33 @@
-/* ===-- powixf2.cpp - Implement __powixf2 ---------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __powixf2 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- powixf2.cpp - Implement __powixf2 ---------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __powixf2 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#if !_ARCH_PPC
#include "int_lib.h"
-/* Returns: a ^ b */
+// Returns: a ^ b
-COMPILER_RT_ABI long double
-__powixf2(long double a, si_int b)
-{
- const int recip = b < 0;
- long double r = 1;
- while (1)
- {
- if (b & 1)
- r *= a;
- b /= 2;
- if (b == 0)
- break;
- a *= a;
- }
- return recip ? 1/r : r;
+COMPILER_RT_ABI long double __powixf2(long double a, int b) {
+ const int recip = b < 0;
+ long double r = 1;
+ while (1) {
+ if (b & 1)
+ r *= a;
+ b /= 2;
+ if (b == 0)
+ break;
+ a *= a;
+ }
+ return recip ? 1 / r : r;
}
#endif
diff --git a/contrib/libs/cxxsupp/builtins/ppc/DD.h b/contrib/libs/cxxsupp/builtins/ppc/DD.h
index 3e5f9e58c1..8f31a962fc 100644
--- a/contrib/libs/cxxsupp/builtins/ppc/DD.h
+++ b/contrib/libs/cxxsupp/builtins/ppc/DD.h
@@ -4,20 +4,20 @@
#include "../int_lib.h"
typedef union {
- long double ld;
- struct {
- double hi;
- double lo;
- }s;
+ long double ld;
+ struct {
+ double hi;
+ double lo;
+ } s;
} DD;
-typedef union {
- double d;
- uint64_t x;
+typedef union {
+ double d;
+ uint64_t x;
} doublebits;
-#define LOWORDER(xy,xHi,xLo,yHi,yLo) \
- (((((xHi)*(yHi) - (xy)) + (xHi)*(yLo)) + (xLo)*(yHi)) + (xLo)*(yLo))
+#define LOWORDER(xy, xHi, xLo, yHi, yLo) \
+ (((((xHi) * (yHi) - (xy)) + (xHi) * (yLo)) + (xLo) * (yHi)) + (xLo) * (yLo))
static __inline ALWAYS_INLINE double local_fabs(double x) {
doublebits result = {.d = x};
@@ -42,4 +42,4 @@ long double __gcc_qsub(long double, long double);
long double __gcc_qmul(long double, long double);
long double __gcc_qdiv(long double, long double);
-#endif /* COMPILERRT_DD_HEADER */
+#endif // COMPILERRT_DD_HEADER
diff --git a/contrib/libs/cxxsupp/builtins/ppc/Makefile.mk b/contrib/libs/cxxsupp/builtins/ppc/Makefile.mk
deleted file mode 100644
index 0adc623aa0..0000000000
--- a/contrib/libs/cxxsupp/builtins/ppc/Makefile.mk
+++ /dev/null
@@ -1,20 +0,0 @@
-#===- lib/builtins/ppc/Makefile.mk -------------------------*- Makefile -*--===#
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-#===------------------------------------------------------------------------===#
-
-ModuleName := builtins
-SubDirs :=
-OnlyArchs := ppc
-
-AsmSources := $(foreach file,$(wildcard $(Dir)/*.S),$(notdir $(file)))
-Sources := $(foreach file,$(wildcard $(Dir)/*.c),$(notdir $(file)))
-ObjNames := $(Sources:%.c=%.o) $(AsmSources:%.S=%.o)
-Implementation := Optimized
-
-# FIXME: use automatic dependencies?
-Dependencies := $(wildcard lib/*.h $(Dir)/*.h)
diff --git a/contrib/libs/cxxsupp/builtins/ppc/atomic.exp b/contrib/libs/cxxsupp/builtins/ppc/atomic.exp
new file mode 100644
index 0000000000..98f759de98
--- /dev/null
+++ b/contrib/libs/cxxsupp/builtins/ppc/atomic.exp
@@ -0,0 +1,41 @@
+__atomic_compare_exchange
+__atomic_compare_exchange_1
+__atomic_compare_exchange_2
+__atomic_compare_exchange_4
+__atomic_compare_exchange_8
+__atomic_exchange
+__atomic_exchange_1
+__atomic_exchange_2
+__atomic_exchange_4
+__atomic_exchange_8
+__atomic_fetch_add_1
+__atomic_fetch_add_2
+__atomic_fetch_add_4
+__atomic_fetch_add_8
+__atomic_fetch_and_1
+__atomic_fetch_and_2
+__atomic_fetch_and_4
+__atomic_fetch_and_8
+__atomic_fetch_or_1
+__atomic_fetch_or_2
+__atomic_fetch_or_4
+__atomic_fetch_or_8
+__atomic_fetch_sub_1
+__atomic_fetch_sub_2
+__atomic_fetch_sub_4
+__atomic_fetch_sub_8
+__atomic_fetch_xor_1
+__atomic_fetch_xor_2
+__atomic_fetch_xor_4
+__atomic_fetch_xor_8
+__atomic_is_lock_free
+__atomic_load
+__atomic_load_1
+__atomic_load_2
+__atomic_load_4
+__atomic_load_8
+__atomic_store
+__atomic_store_1
+__atomic_store_2
+__atomic_store_4
+__atomic_store_8
diff --git a/contrib/libs/cxxsupp/builtins/ppc/divtc3.c b/contrib/libs/cxxsupp/builtins/ppc/divtc3.c
index 8ec41c528a..671bd4ddbb 100644
--- a/contrib/libs/cxxsupp/builtins/ppc/divtc3.c
+++ b/contrib/libs/cxxsupp/builtins/ppc/divtc3.c
@@ -1,91 +1,97 @@
-/* This file is distributed under the University of Illinois Open Source
- * License. See LICENSE.TXT for details.
- */
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-#include "DD.h"
#include "../int_math.h"
+#include "DD.h"
+// Use DOUBLE_PRECISION because the soft-fp method we use is logb (on the upper
+// half of the long doubles), even though this file defines complex division for
+// 128-bit floats.
+#define DOUBLE_PRECISION
+#include "../fp_lib.h"
#if !defined(CRT_INFINITY) && defined(HUGE_VAL)
#define CRT_INFINITY HUGE_VAL
-#endif /* CRT_INFINITY */
+#endif // CRT_INFINITY
+
+#define makeFinite(x) \
+ { \
+ (x).s.hi = crt_copysign(crt_isinf((x).s.hi) ? 1.0 : 0.0, (x).s.hi); \
+ (x).s.lo = 0.0; \
+ }
+
+long double _Complex __divtc3(long double a, long double b, long double c,
+ long double d) {
+ DD cDD = {.ld = c};
+ DD dDD = {.ld = d};
+
+ int ilogbw = 0;
+ const double logbw =
+ __compiler_rt_logb(__compiler_rt_fmax(crt_fabs(cDD.s.hi),
+ crt_fabs(dDD.s.hi)));
+
+ if (crt_isfinite(logbw)) {
+ ilogbw = (int)logbw;
+
+ cDD.s.hi = __compiler_rt_scalbn(cDD.s.hi, -ilogbw);
+ cDD.s.lo = __compiler_rt_scalbn(cDD.s.lo, -ilogbw);
+ dDD.s.hi = __compiler_rt_scalbn(dDD.s.hi, -ilogbw);
+ dDD.s.lo = __compiler_rt_scalbn(dDD.s.lo, -ilogbw);
+ }
+
+ const long double denom =
+ __gcc_qadd(__gcc_qmul(cDD.ld, cDD.ld), __gcc_qmul(dDD.ld, dDD.ld));
+ const long double realNumerator =
+ __gcc_qadd(__gcc_qmul(a, cDD.ld), __gcc_qmul(b, dDD.ld));
+ const long double imagNumerator =
+ __gcc_qsub(__gcc_qmul(b, cDD.ld), __gcc_qmul(a, dDD.ld));
+
+ DD real = {.ld = __gcc_qdiv(realNumerator, denom)};
+ DD imag = {.ld = __gcc_qdiv(imagNumerator, denom)};
+
+ real.s.hi = __compiler_rt_scalbn(real.s.hi, -ilogbw);
+ real.s.lo = __compiler_rt_scalbn(real.s.lo, -ilogbw);
+ imag.s.hi = __compiler_rt_scalbn(imag.s.hi, -ilogbw);
+ imag.s.lo = __compiler_rt_scalbn(imag.s.lo, -ilogbw);
-#define makeFinite(x) { \
- (x).s.hi = crt_copysign(crt_isinf((x).s.hi) ? 1.0 : 0.0, (x).s.hi); \
- (x).s.lo = 0.0; \
+ if (crt_isnan(real.s.hi) && crt_isnan(imag.s.hi)) {
+ DD aDD = {.ld = a};
+ DD bDD = {.ld = b};
+ DD rDD = {.ld = denom};
+
+ if ((rDD.s.hi == 0.0) && (!crt_isnan(aDD.s.hi) || !crt_isnan(bDD.s.hi))) {
+ real.s.hi = crt_copysign(CRT_INFINITY, cDD.s.hi) * aDD.s.hi;
+ real.s.lo = 0.0;
+ imag.s.hi = crt_copysign(CRT_INFINITY, cDD.s.hi) * bDD.s.hi;
+ imag.s.lo = 0.0;
+ }
+
+ else if ((crt_isinf(aDD.s.hi) || crt_isinf(bDD.s.hi)) &&
+ crt_isfinite(cDD.s.hi) && crt_isfinite(dDD.s.hi)) {
+ makeFinite(aDD);
+ makeFinite(bDD);
+ real.s.hi = CRT_INFINITY * (aDD.s.hi * cDD.s.hi + bDD.s.hi * dDD.s.hi);
+ real.s.lo = 0.0;
+ imag.s.hi = CRT_INFINITY * (bDD.s.hi * cDD.s.hi - aDD.s.hi * dDD.s.hi);
+ imag.s.lo = 0.0;
+ }
+
+ else if ((crt_isinf(cDD.s.hi) || crt_isinf(dDD.s.hi)) &&
+ crt_isfinite(aDD.s.hi) && crt_isfinite(bDD.s.hi)) {
+ makeFinite(cDD);
+ makeFinite(dDD);
+ real.s.hi =
+ crt_copysign(0.0, (aDD.s.hi * cDD.s.hi + bDD.s.hi * dDD.s.hi));
+ real.s.lo = 0.0;
+ imag.s.hi =
+ crt_copysign(0.0, (bDD.s.hi * cDD.s.hi - aDD.s.hi * dDD.s.hi));
+ imag.s.lo = 0.0;
+ }
}
-long double _Complex
-__divtc3(long double a, long double b, long double c, long double d)
-{
- DD cDD = { .ld = c };
- DD dDD = { .ld = d };
-
- int ilogbw = 0;
- const double logbw = crt_logb(crt_fmax(crt_fabs(cDD.s.hi), crt_fabs(dDD.s.hi) ));
-
- if (crt_isfinite(logbw))
- {
- ilogbw = (int)logbw;
-
- cDD.s.hi = crt_scalbn(cDD.s.hi, -ilogbw);
- cDD.s.lo = crt_scalbn(cDD.s.lo, -ilogbw);
- dDD.s.hi = crt_scalbn(dDD.s.hi, -ilogbw);
- dDD.s.lo = crt_scalbn(dDD.s.lo, -ilogbw);
- }
-
- const long double denom = __gcc_qadd(__gcc_qmul(cDD.ld, cDD.ld), __gcc_qmul(dDD.ld, dDD.ld));
- const long double realNumerator = __gcc_qadd(__gcc_qmul(a,cDD.ld), __gcc_qmul(b,dDD.ld));
- const long double imagNumerator = __gcc_qsub(__gcc_qmul(b,cDD.ld), __gcc_qmul(a,dDD.ld));
-
- DD real = { .ld = __gcc_qdiv(realNumerator, denom) };
- DD imag = { .ld = __gcc_qdiv(imagNumerator, denom) };
-
- real.s.hi = crt_scalbn(real.s.hi, -ilogbw);
- real.s.lo = crt_scalbn(real.s.lo, -ilogbw);
- imag.s.hi = crt_scalbn(imag.s.hi, -ilogbw);
- imag.s.lo = crt_scalbn(imag.s.lo, -ilogbw);
-
- if (crt_isnan(real.s.hi) && crt_isnan(imag.s.hi))
- {
- DD aDD = { .ld = a };
- DD bDD = { .ld = b };
- DD rDD = { .ld = denom };
-
- if ((rDD.s.hi == 0.0) && (!crt_isnan(aDD.s.hi) ||
- !crt_isnan(bDD.s.hi)))
- {
- real.s.hi = crt_copysign(CRT_INFINITY,cDD.s.hi) * aDD.s.hi;
- real.s.lo = 0.0;
- imag.s.hi = crt_copysign(CRT_INFINITY,cDD.s.hi) * bDD.s.hi;
- imag.s.lo = 0.0;
- }
-
- else if ((crt_isinf(aDD.s.hi) || crt_isinf(bDD.s.hi)) &&
- crt_isfinite(cDD.s.hi) && crt_isfinite(dDD.s.hi))
- {
- makeFinite(aDD);
- makeFinite(bDD);
- real.s.hi = CRT_INFINITY * (aDD.s.hi*cDD.s.hi + bDD.s.hi*dDD.s.hi);
- real.s.lo = 0.0;
- imag.s.hi = CRT_INFINITY * (bDD.s.hi*cDD.s.hi - aDD.s.hi*dDD.s.hi);
- imag.s.lo = 0.0;
- }
-
- else if ((crt_isinf(cDD.s.hi) || crt_isinf(dDD.s.hi)) &&
- crt_isfinite(aDD.s.hi) && crt_isfinite(bDD.s.hi))
- {
- makeFinite(cDD);
- makeFinite(dDD);
- real.s.hi = crt_copysign(0.0,(aDD.s.hi*cDD.s.hi + bDD.s.hi*dDD.s.hi));
- real.s.lo = 0.0;
- imag.s.hi = crt_copysign(0.0,(bDD.s.hi*cDD.s.hi - aDD.s.hi*dDD.s.hi));
- imag.s.lo = 0.0;
- }
- }
-
- long double _Complex z;
- __real__ z = real.ld;
- __imag__ z = imag.ld;
-
- return z;
+ long double _Complex z;
+ __real__ z = real.ld;
+ __imag__ z = imag.ld;
+
+ return z;
}
diff --git a/contrib/libs/cxxsupp/builtins/ppc/fixtfdi.c b/contrib/libs/cxxsupp/builtins/ppc/fixtfdi.c
index 2c7c0f8e27..a97aaf0958 100644
--- a/contrib/libs/cxxsupp/builtins/ppc/fixtfdi.c
+++ b/contrib/libs/cxxsupp/builtins/ppc/fixtfdi.c
@@ -1,104 +1,98 @@
-/* This file is distributed under the University of Illinois Open Source
- * License. See LICENSE.TXT for details.
- */
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-/* int64_t __fixunstfdi(long double x);
- * This file implements the PowerPC 128-bit double-double -> int64_t conversion
- */
+// int64_t __fixunstfdi(long double x);
+// This file implements the PowerPC 128-bit double-double -> int64_t conversion
-#include "DD.h"
#include "../int_math.h"
+#include "DD.h"
+
+uint64_t __fixtfdi(long double input) {
+ const DD x = {.ld = input};
+ const doublebits hibits = {.d = x.s.hi};
+
+ const uint32_t absHighWord =
+ (uint32_t)(hibits.x >> 32) & UINT32_C(0x7fffffff);
+ const uint32_t absHighWordMinusOne = absHighWord - UINT32_C(0x3ff00000);
+
+ // If (1.0 - tiny) <= input < 0x1.0p63:
+ if (UINT32_C(0x03f00000) > absHighWordMinusOne) {
+ // Do an unsigned conversion of the absolute value, then restore the sign.
+ const int unbiasedHeadExponent = absHighWordMinusOne >> 20;
+
+ int64_t result = hibits.x & INT64_C(0x000fffffffffffff); // mantissa(hi)
+ result |= INT64_C(0x0010000000000000); // matissa(hi) with implicit bit
+ result <<= 10; // mantissa(hi) with one zero preceding bit.
+
+ const int64_t hiNegationMask = ((int64_t)(hibits.x)) >> 63;
+
+ // If the tail is non-zero, we need to patch in the tail bits.
+ if (0.0 != x.s.lo) {
+ const doublebits lobits = {.d = x.s.lo};
+ int64_t tailMantissa = lobits.x & INT64_C(0x000fffffffffffff);
+ tailMantissa |= INT64_C(0x0010000000000000);
+
+ // At this point we have the mantissa of |tail|
+ // We need to negate it if head and tail have different signs.
+ const int64_t loNegationMask = ((int64_t)(lobits.x)) >> 63;
+ const int64_t negationMask = loNegationMask ^ hiNegationMask;
+ tailMantissa = (tailMantissa ^ negationMask) - negationMask;
+
+ // Now we have the mantissa of tail as a signed 2s-complement integer
+
+ const int biasedTailExponent = (int)(lobits.x >> 52) & 0x7ff;
+
+ // Shift the tail mantissa into the right position, accounting for the
+ // bias of 10 that we shifted the head mantissa by.
+ tailMantissa >>=
+ (unbiasedHeadExponent - (biasedTailExponent - (1023 - 10)));
+
+ result += tailMantissa;
+ }
+
+ result >>= (62 - unbiasedHeadExponent);
+
+ // Restore the sign of the result and return
+ result = (result ^ hiNegationMask) - hiNegationMask;
+ return result;
+ }
+
+ // Edge cases handled here:
+
+ // |x| < 1, result is zero.
+ if (1.0 > crt_fabs(x.s.hi))
+ return INT64_C(0);
+
+ // x very close to INT64_MIN, care must be taken to see which side we are on.
+ if (x.s.hi == -0x1.0p63) {
+
+ int64_t result = INT64_MIN;
+
+ if (0.0 < x.s.lo) {
+ // If the tail is positive, the correct result is something other than
+ // INT64_MIN. we'll need to figure out what it is.
+
+ const doublebits lobits = {.d = x.s.lo};
+ int64_t tailMantissa = lobits.x & INT64_C(0x000fffffffffffff);
+ tailMantissa |= INT64_C(0x0010000000000000);
+
+ // Now we negate the tailMantissa
+ tailMantissa = (tailMantissa ^ INT64_C(-1)) + INT64_C(1);
+
+ // And shift it by the appropriate amount
+ const int biasedTailExponent = (int)(lobits.x >> 52) & 0x7ff;
+ tailMantissa >>= 1075 - biasedTailExponent;
+
+ result -= tailMantissa;
+ }
+
+ return result;
+ }
-uint64_t __fixtfdi(long double input)
-{
- const DD x = { .ld = input };
- const doublebits hibits = { .d = x.s.hi };
-
- const uint32_t absHighWord = (uint32_t)(hibits.x >> 32) & UINT32_C(0x7fffffff);
- const uint32_t absHighWordMinusOne = absHighWord - UINT32_C(0x3ff00000);
-
- /* If (1.0 - tiny) <= input < 0x1.0p63: */
- if (UINT32_C(0x03f00000) > absHighWordMinusOne)
- {
- /* Do an unsigned conversion of the absolute value, then restore the sign. */
- const int unbiasedHeadExponent = absHighWordMinusOne >> 20;
-
- int64_t result = hibits.x & INT64_C(0x000fffffffffffff); /* mantissa(hi) */
- result |= INT64_C(0x0010000000000000); /* matissa(hi) with implicit bit */
- result <<= 10; /* mantissa(hi) with one zero preceding bit. */
-
- const int64_t hiNegationMask = ((int64_t)(hibits.x)) >> 63;
-
- /* If the tail is non-zero, we need to patch in the tail bits. */
- if (0.0 != x.s.lo)
- {
- const doublebits lobits = { .d = x.s.lo };
- int64_t tailMantissa = lobits.x & INT64_C(0x000fffffffffffff);
- tailMantissa |= INT64_C(0x0010000000000000);
-
- /* At this point we have the mantissa of |tail| */
- /* We need to negate it if head and tail have different signs. */
- const int64_t loNegationMask = ((int64_t)(lobits.x)) >> 63;
- const int64_t negationMask = loNegationMask ^ hiNegationMask;
- tailMantissa = (tailMantissa ^ negationMask) - negationMask;
-
- /* Now we have the mantissa of tail as a signed 2s-complement integer */
-
- const int biasedTailExponent = (int)(lobits.x >> 52) & 0x7ff;
-
- /* Shift the tail mantissa into the right position, accounting for the
- * bias of 10 that we shifted the head mantissa by.
- */
- tailMantissa >>= (unbiasedHeadExponent - (biasedTailExponent - (1023 - 10)));
-
- result += tailMantissa;
- }
-
- result >>= (62 - unbiasedHeadExponent);
-
- /* Restore the sign of the result and return */
- result = (result ^ hiNegationMask) - hiNegationMask;
- return result;
-
- }
-
- /* Edge cases handled here: */
-
- /* |x| < 1, result is zero. */
- if (1.0 > crt_fabs(x.s.hi))
- return INT64_C(0);
-
- /* x very close to INT64_MIN, care must be taken to see which side we are on. */
- if (x.s.hi == -0x1.0p63) {
-
- int64_t result = INT64_MIN;
-
- if (0.0 < x.s.lo)
- {
- /* If the tail is positive, the correct result is something other than INT64_MIN.
- * we'll need to figure out what it is.
- */
-
- const doublebits lobits = { .d = x.s.lo };
- int64_t tailMantissa = lobits.x & INT64_C(0x000fffffffffffff);
- tailMantissa |= INT64_C(0x0010000000000000);
-
- /* Now we negate the tailMantissa */
- tailMantissa = (tailMantissa ^ INT64_C(-1)) + INT64_C(1);
-
- /* And shift it by the appropriate amount */
- const int biasedTailExponent = (int)(lobits.x >> 52) & 0x7ff;
- tailMantissa >>= 1075 - biasedTailExponent;
-
- result -= tailMantissa;
- }
-
- return result;
- }
-
- /* Signed overflows, infinities, and NaNs */
- if (x.s.hi > 0.0)
- return INT64_MAX;
- else
- return INT64_MIN;
+ // Signed overflows, infinities, and NaNs
+ if (x.s.hi > 0.0)
+ return INT64_MAX;
+ else
+ return INT64_MIN;
}
diff --git a/contrib/libs/cxxsupp/builtins/ppc/fixtfti.c b/contrib/libs/cxxsupp/builtins/ppc/fixtfti.c
new file mode 100644
index 0000000000..4180e7494d
--- /dev/null
+++ b/contrib/libs/cxxsupp/builtins/ppc/fixtfti.c
@@ -0,0 +1,38 @@
+//===--- lib/builtins/ppc/fixtfti.c - Convert long double->int128 *-C -*---===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements converting the 128bit IBM/PowerPC long double (double-
+// double) data type to a signed 128 bit integer.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../int_math.h"
+
+// Convert long double into a signed 128-bit integer.
+__int128_t __fixtfti(long double input) {
+
+ // If we are trying to convert a NaN, return the NaN bit pattern.
+ if (crt_isnan(input)) {
+ return ((__uint128_t)0x7FF8000000000000ll) << 64 |
+ (__uint128_t)0x0000000000000000ll;
+ }
+
+ // Note: overflow is an undefined behavior for this conversion.
+ // For this reason, overflow is not checked here.
+
+ // If the long double is negative, use unsigned conversion from its absolute
+ // value.
+ if (input < 0.0) {
+ __uint128_t result = (__uint128_t)(-input);
+ return -((__int128_t)result);
+ }
+
+ // Otherwise, use unsigned conversion from the input value.
+ __uint128_t result = (__uint128_t)input;
+ return result;
+}
diff --git a/contrib/libs/cxxsupp/builtins/ppc/fixunstfdi.c b/contrib/libs/cxxsupp/builtins/ppc/fixunstfdi.c
index 5e6e2cedf6..8d53f37252 100644
--- a/contrib/libs/cxxsupp/builtins/ppc/fixunstfdi.c
+++ b/contrib/libs/cxxsupp/builtins/ppc/fixunstfdi.c
@@ -1,59 +1,57 @@
-/* This file is distributed under the University of Illinois Open Source
- * License. See LICENSE.TXT for details.
- */
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-/* uint64_t __fixunstfdi(long double x); */
-/* This file implements the PowerPC 128-bit double-double -> uint64_t conversion */
+// uint64_t __fixunstfdi(long double x);
+// This file implements the PowerPC 128-bit double-double -> uint64_t conversion
#include "DD.h"
-uint64_t __fixunstfdi(long double input)
-{
- const DD x = { .ld = input };
- const doublebits hibits = { .d = x.s.hi };
-
- const uint32_t highWordMinusOne = (uint32_t)(hibits.x >> 32) - UINT32_C(0x3ff00000);
-
- /* If (1.0 - tiny) <= input < 0x1.0p64: */
- if (UINT32_C(0x04000000) > highWordMinusOne)
- {
- const int unbiasedHeadExponent = highWordMinusOne >> 20;
-
- uint64_t result = hibits.x & UINT64_C(0x000fffffffffffff); /* mantissa(hi) */
- result |= UINT64_C(0x0010000000000000); /* matissa(hi) with implicit bit */
- result <<= 11; /* mantissa(hi) left aligned in the int64 field. */
-
- /* If the tail is non-zero, we need to patch in the tail bits. */
- if (0.0 != x.s.lo)
- {
- const doublebits lobits = { .d = x.s.lo };
- int64_t tailMantissa = lobits.x & INT64_C(0x000fffffffffffff);
- tailMantissa |= INT64_C(0x0010000000000000);
-
- /* At this point we have the mantissa of |tail| */
-
- const int64_t negationMask = ((int64_t)(lobits.x)) >> 63;
- tailMantissa = (tailMantissa ^ negationMask) - negationMask;
-
- /* Now we have the mantissa of tail as a signed 2s-complement integer */
-
- const int biasedTailExponent = (int)(lobits.x >> 52) & 0x7ff;
-
- /* Shift the tail mantissa into the right position, accounting for the
- * bias of 11 that we shifted the head mantissa by.
- */
- tailMantissa >>= (unbiasedHeadExponent - (biasedTailExponent - (1023 - 11)));
-
- result += tailMantissa;
- }
-
- result >>= (63 - unbiasedHeadExponent);
- return result;
- }
-
- /* Edge cases are handled here, with saturation. */
- if (1.0 > x.s.hi)
- return UINT64_C(0);
- else
- return UINT64_MAX;
+uint64_t __fixunstfdi(long double input) {
+ const DD x = {.ld = input};
+ const doublebits hibits = {.d = x.s.hi};
+
+ const uint32_t highWordMinusOne =
+ (uint32_t)(hibits.x >> 32) - UINT32_C(0x3ff00000);
+
+ // If (1.0 - tiny) <= input < 0x1.0p64:
+ if (UINT32_C(0x04000000) > highWordMinusOne) {
+ const int unbiasedHeadExponent = highWordMinusOne >> 20;
+
+ uint64_t result = hibits.x & UINT64_C(0x000fffffffffffff); // mantissa(hi)
+ result |= UINT64_C(0x0010000000000000); // matissa(hi) with implicit bit
+ result <<= 11; // mantissa(hi) left aligned in the int64 field.
+
+ // If the tail is non-zero, we need to patch in the tail bits.
+ if (0.0 != x.s.lo) {
+ const doublebits lobits = {.d = x.s.lo};
+ int64_t tailMantissa = lobits.x & INT64_C(0x000fffffffffffff);
+ tailMantissa |= INT64_C(0x0010000000000000);
+
+ // At this point we have the mantissa of |tail|
+
+ const int64_t negationMask = ((int64_t)(lobits.x)) >> 63;
+ tailMantissa = (tailMantissa ^ negationMask) - negationMask;
+
+ // Now we have the mantissa of tail as a signed 2s-complement integer
+
+ const int biasedTailExponent = (int)(lobits.x >> 52) & 0x7ff;
+
+ // Shift the tail mantissa into the right position, accounting for the
+ // bias of 11 that we shifted the head mantissa by.
+ tailMantissa >>=
+ (unbiasedHeadExponent - (biasedTailExponent - (1023 - 11)));
+
+ result += tailMantissa;
+ }
+
+ result >>= (63 - unbiasedHeadExponent);
+ return result;
+ }
+
+ // Edge cases are handled here, with saturation.
+ if (1.0 > x.s.hi)
+ return UINT64_C(0);
+ else
+ return UINT64_MAX;
}
diff --git a/contrib/libs/cxxsupp/builtins/ppc/fixunstfti.c b/contrib/libs/cxxsupp/builtins/ppc/fixunstfti.c
new file mode 100644
index 0000000000..2469585369
--- /dev/null
+++ b/contrib/libs/cxxsupp/builtins/ppc/fixunstfti.c
@@ -0,0 +1,115 @@
+//===-- lib/builtins/ppc/fixunstfti.c - Convert long double->int128 *-C -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements converting the 128bit IBM/PowerPC long double (double-
+// double) data type to an unsigned 128 bit integer.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../int_math.h"
+#define BIAS 1023
+
+// Convert long double into an unsigned 128-bit integer.
+__uint128_t __fixunstfti(long double input) {
+
+ // If we are trying to convert a NaN, return the NaN bit pattern.
+ if (crt_isnan(input)) {
+ return ((__uint128_t)0x7FF8000000000000ll) << 64 |
+ (__uint128_t)0x0000000000000000ll;
+ }
+
+ __uint128_t result, hiResult, loResult;
+ int hiExponent, loExponent, shift;
+ // The long double representation, with the high and low portions of
+ // the long double, and the corresponding bit patterns of each double.
+ union {
+ long double ld;
+ double d[2]; // [0] is the high double, [1] is the low double.
+ unsigned long long ull[2]; // High and low doubles as 64-bit integers.
+ } ldUnion;
+
+ // If the long double is less than 1.0 or negative,
+ // return 0.
+ if (input < 1.0)
+ return 0;
+
+ // Retrieve the 64-bit patterns of high and low doubles.
+ // Compute the unbiased exponent of both high and low doubles by
+ // removing the signs, isolating the exponent, and subtracting
+ // the bias from it.
+ ldUnion.ld = input;
+ hiExponent = ((ldUnion.ull[0] & 0x7FFFFFFFFFFFFFFFll) >> 52) - BIAS;
+ loExponent = ((ldUnion.ull[1] & 0x7FFFFFFFFFFFFFFFll) >> 52) - BIAS;
+
+ // Convert each double into int64; they will be added to the int128 result.
+ // CASE 1: High or low double fits in int64
+ // - Convert the each double normally into int64.
+ //
+ // CASE 2: High or low double does not fit in int64
+ // - Scale the double to fit within a 64-bit integer
+ // - Calculate the shift (amount to scale the double by in the int128)
+ // - Clear all the bits of the exponent (with 0x800FFFFFFFFFFFFF)
+ // - Add BIAS+53 (0x4350000000000000) to exponent to correct the value
+ // - Scale (move) the double to the correct place in the int128
+ // (Move it by 2^53 places)
+ //
+ // Note: If the high double is assumed to be positive, an unsigned conversion
+ // from long double to 64-bit integer is needed. The low double can be either
+ // positive or negative, so a signed conversion is needed to retain the result
+ // of the low double and to ensure it does not simply get converted to 0.
+
+ // CASE 1 - High double fits in int64.
+ if (hiExponent < 63) {
+ hiResult = (unsigned long long)ldUnion.d[0];
+ } else if (hiExponent < 128) {
+ // CASE 2 - High double does not fit in int64, scale and convert it.
+ shift = hiExponent - 54;
+ ldUnion.ull[0] &= 0x800FFFFFFFFFFFFFll;
+ ldUnion.ull[0] |= 0x4350000000000000ll;
+ hiResult = (unsigned long long)ldUnion.d[0];
+ hiResult <<= shift;
+ } else {
+ // Detect cases for overflow. When the exponent of the high
+ // double is greater than 128 bits and when the long double
+ // input is positive, return the max 128-bit integer.
+ // For negative inputs with exponents > 128, return 1, like gcc.
+ if (ldUnion.d[0] > 0) {
+ return ((__uint128_t)0xFFFFFFFFFFFFFFFFll) << 64 |
+ (__uint128_t)0xFFFFFFFFFFFFFFFFll;
+ } else {
+ return ((__uint128_t)0x0000000000000000ll) << 64 |
+ (__uint128_t)0x0000000000000001ll;
+ }
+ }
+
+ // CASE 1 - Low double fits in int64.
+ if (loExponent < 63) {
+ loResult = (long long)ldUnion.d[1];
+ } else {
+ // CASE 2 - Low double does not fit in int64, scale and convert it.
+ shift = loExponent - 54;
+ ldUnion.ull[1] &= 0x800FFFFFFFFFFFFFll;
+ ldUnion.ull[1] |= 0x4350000000000000ll;
+ loResult = (long long)ldUnion.d[1];
+ loResult <<= shift;
+ }
+
+ // If the low double is negative, it may change the integer value of the
+ // whole number if the absolute value of its fractional part is bigger than
+ // the fractional part of the high double. Because both doubles cannot
+ // overlap, this situation only occurs when the high double has no
+ // fractional part.
+ ldUnion.ld = input;
+ if ((ldUnion.d[0] == (double)hiResult) &&
+ (ldUnion.d[1] < (double)((__int128_t)loResult)))
+ loResult--;
+
+ // Add the high and low doublewords together to form a 128 bit integer.
+ result = loResult + hiResult;
+ return result;
+}
diff --git a/contrib/libs/cxxsupp/builtins/ppc/floatditf.c b/contrib/libs/cxxsupp/builtins/ppc/floatditf.c
index beabdd0174..4c365418f0 100644
--- a/contrib/libs/cxxsupp/builtins/ppc/floatditf.c
+++ b/contrib/libs/cxxsupp/builtins/ppc/floatditf.c
@@ -1,36 +1,33 @@
-/* This file is distributed under the University of Illinois Open Source
- * License. See LICENSE.TXT for details.
- */
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-/* long double __floatditf(long long x); */
-/* This file implements the PowerPC long long -> long double conversion */
+// long double __floatditf(long long x);
+// This file implements the PowerPC long long -> long double conversion
#include "DD.h"
long double __floatditf(int64_t a) {
-
- static const double twop32 = 0x1.0p32;
- static const double twop52 = 0x1.0p52;
-
- doublebits low = { .d = twop52 };
- low.x |= a & UINT64_C(0x00000000ffffffff); /* 0x1.0p52 + low 32 bits of a. */
-
- const double high_addend = (double)((int32_t)(a >> 32))*twop32 - twop52;
-
- /* At this point, we have two double precision numbers
- * high_addend and low.d, and we wish to return their sum
- * as a canonicalized long double:
- */
-
- /* This implementation sets the inexact flag spuriously.
- * This could be avoided, but at some substantial cost.
- */
-
- DD result;
-
- result.s.hi = high_addend + low.d;
- result.s.lo = (high_addend - result.s.hi) + low.d;
-
- return result.ld;
-
+
+ static const double twop32 = 0x1.0p32;
+ static const double twop52 = 0x1.0p52;
+
+ doublebits low = {.d = twop52};
+ low.x |= a & UINT64_C(0x00000000ffffffff); // 0x1.0p52 + low 32 bits of a.
+
+ const double high_addend = (double)((int32_t)(a >> 32)) * twop32 - twop52;
+
+ // At this point, we have two double precision numbers
+ // high_addend and low.d, and we wish to return their sum
+ // as a canonicalized long double:
+
+ // This implementation sets the inexact flag spuriously.
+ // This could be avoided, but at some substantial cost.
+
+ DD result;
+
+ result.s.hi = high_addend + low.d;
+ result.s.lo = (high_addend - result.s.hi) + low.d;
+
+ return result.ld;
}
diff --git a/contrib/libs/cxxsupp/builtins/ppc/floattitf.c b/contrib/libs/cxxsupp/builtins/ppc/floattitf.c
new file mode 100644
index 0000000000..6deac64981
--- /dev/null
+++ b/contrib/libs/cxxsupp/builtins/ppc/floattitf.c
@@ -0,0 +1,46 @@
+//===-- lib/builtins/ppc/floattitf.c - Convert int128->long double -*-C -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements converting a signed 128 bit integer to a 128bit IBM /
+// PowerPC long double (double-double) value.
+//
+//===----------------------------------------------------------------------===//
+
+#include <stdint.h>
+
+// Conversions from signed and unsigned 64-bit int to long double.
+long double __floatditf(int64_t);
+long double __floatunditf(uint64_t);
+
+// Convert a signed 128-bit integer to long double.
+// This uses the following property: Let hi and lo be 64-bits each,
+// and let signed_val_k() and unsigned_val_k() be the value of the
+// argument interpreted as a signed or unsigned k-bit integer. Then,
+//
+// signed_val_128(hi,lo) = signed_val_64(hi) * 2^64 + unsigned_val_64(lo)
+// = (long double)hi * 2^64 + (long double)lo,
+//
+// where (long double)hi and (long double)lo are signed and
+// unsigned 64-bit integer to long double conversions, respectively.
+long double __floattitf(__int128_t arg) {
+ // Split the int128 argument into 64-bit high and low int64 parts.
+ int64_t ArgHiPart = (int64_t)(arg >> 64);
+ uint64_t ArgLoPart = (uint64_t)arg;
+
+ // Convert each 64-bit part into long double. The high part
+ // must be a signed conversion and the low part an unsigned conversion
+ // to ensure the correct result.
+ long double ConvertedHiPart = __floatditf(ArgHiPart);
+ long double ConvertedLoPart = __floatunditf(ArgLoPart);
+
+ // The low bit of ArgHiPart corresponds to the 2^64 bit in arg.
+ // Multiply the high part by 2^64 to undo the right shift by 64-bits
+ // done in the splitting. Then, add to the low part to obtain the
+ // final result.
+ return ((ConvertedHiPart * 0x1.0p64) + ConvertedLoPart);
+}
diff --git a/contrib/libs/cxxsupp/builtins/ppc/floatunditf.c b/contrib/libs/cxxsupp/builtins/ppc/floatunditf.c
index b12e1e738f..fb4cd3f91d 100644
--- a/contrib/libs/cxxsupp/builtins/ppc/floatunditf.c
+++ b/contrib/libs/cxxsupp/builtins/ppc/floatunditf.c
@@ -1,41 +1,39 @@
-/* This file is distributed under the University of Illinois Open Source
- * License. See LICENSE.TXT for details.
- */
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-/* long double __floatunditf(unsigned long long x); */
-/* This file implements the PowerPC unsigned long long -> long double conversion */
+// long double __floatunditf(unsigned long long x);
+// This file implements the PowerPC unsigned long long -> long double conversion
#include "DD.h"
long double __floatunditf(uint64_t a) {
-
- /* Begins with an exact copy of the code from __floatundidf */
-
- static const double twop52 = 0x1.0p52;
- static const double twop84 = 0x1.0p84;
- static const double twop84_plus_twop52 = 0x1.00000001p84;
-
- doublebits high = { .d = twop84 };
- doublebits low = { .d = twop52 };
-
- high.x |= a >> 32; /* 0x1.0p84 + high 32 bits of a */
- low.x |= a & UINT64_C(0x00000000ffffffff); /* 0x1.0p52 + low 32 bits of a */
-
- const double high_addend = high.d - twop84_plus_twop52;
-
- /* At this point, we have two double precision numbers
- * high_addend and low.d, and we wish to return their sum
- * as a canonicalized long double:
- */
-
- /* This implementation sets the inexact flag spuriously. */
- /* This could be avoided, but at some substantial cost. */
-
- DD result;
-
- result.s.hi = high_addend + low.d;
- result.s.lo = (high_addend - result.s.hi) + low.d;
-
- return result.ld;
-
+
+ // Begins with an exact copy of the code from __floatundidf
+
+ static const double twop52 = 0x1.0p52;
+ static const double twop84 = 0x1.0p84;
+ static const double twop84_plus_twop52 = 0x1.00000001p84;
+
+ doublebits high = {.d = twop84};
+ doublebits low = {.d = twop52};
+
+ high.x |= a >> 32; // 0x1.0p84 + high 32 bits of a
+ low.x |= a & UINT64_C(0x00000000ffffffff); // 0x1.0p52 + low 32 bits of a
+
+ const double high_addend = high.d - twop84_plus_twop52;
+
+ // At this point, we have two double precision numbers
+ // high_addend and low.d, and we wish to return their sum
+ // as a canonicalized long double:
+
+ // This implementation sets the inexact flag spuriously.
+ // This could be avoided, but at some substantial cost.
+
+ DD result;
+
+ result.s.hi = high_addend + low.d;
+ result.s.lo = (high_addend - result.s.hi) + low.d;
+
+ return result.ld;
}
diff --git a/contrib/libs/cxxsupp/builtins/ppc/gcc_qadd.c b/contrib/libs/cxxsupp/builtins/ppc/gcc_qadd.c
index 32e16e9d1d..6e1e63cb53 100644
--- a/contrib/libs/cxxsupp/builtins/ppc/gcc_qadd.c
+++ b/contrib/libs/cxxsupp/builtins/ppc/gcc_qadd.c
@@ -1,76 +1,74 @@
-/* This file is distributed under the University of Illinois Open Source
- * License. See LICENSE.TXT for details.
- */
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-/* long double __gcc_qadd(long double x, long double y);
- * This file implements the PowerPC 128-bit double-double add operation.
- * This implementation is shamelessly cribbed from Apple's DDRT, circa 1993(!)
- */
+// long double __gcc_qadd(long double x, long double y);
+// This file implements the PowerPC 128-bit double-double add operation.
+// This implementation is shamelessly cribbed from Apple's DDRT, circa 1993(!)
#include "DD.h"
-long double __gcc_qadd(long double x, long double y)
-{
- static const uint32_t infinityHi = UINT32_C(0x7ff00000);
-
- DD dst = { .ld = x }, src = { .ld = y };
-
- register double A = dst.s.hi, a = dst.s.lo,
- B = src.s.hi, b = src.s.lo;
-
- /* If both operands are zero: */
- if ((A == 0.0) && (B == 0.0)) {
- dst.s.hi = A + B;
- dst.s.lo = 0.0;
- return dst.ld;
- }
-
- /* If either operand is NaN or infinity: */
- const doublebits abits = { .d = A };
- const doublebits bbits = { .d = B };
- if ((((uint32_t)(abits.x >> 32) & infinityHi) == infinityHi) ||
- (((uint32_t)(bbits.x >> 32) & infinityHi) == infinityHi)) {
- dst.s.hi = A + B;
- dst.s.lo = 0.0;
- return dst.ld;
- }
-
- /* If the computation overflows: */
- /* This may be playing things a little bit fast and loose, but it will do for a start. */
- const double testForOverflow = A + (B + (a + b));
- const doublebits testbits = { .d = testForOverflow };
- if (((uint32_t)(testbits.x >> 32) & infinityHi) == infinityHi) {
- dst.s.hi = testForOverflow;
- dst.s.lo = 0.0;
- return dst.ld;
- }
-
- double H, h;
- double T, t;
- double W, w;
- double Y;
-
- H = B + (A - (A + B));
- T = b + (a - (a + b));
- h = A + (B - (A + B));
- t = a + (b - (a + b));
-
- if (local_fabs(A) <= local_fabs(B))
- w = (a + b) + h;
- else
- w = (a + b) + H;
-
- W = (A + B) + w;
- Y = (A + B) - W;
- Y += w;
-
- if (local_fabs(a) <= local_fabs(b))
- w = t + Y;
- else
- w = T + Y;
-
- dst.s.hi = Y = W + w;
- dst.s.lo = (W - Y) + w;
-
- return dst.ld;
+long double __gcc_qadd(long double x, long double y) {
+ static const uint32_t infinityHi = UINT32_C(0x7ff00000);
+
+ DD dst = {.ld = x}, src = {.ld = y};
+
+ register double A = dst.s.hi, a = dst.s.lo, B = src.s.hi, b = src.s.lo;
+
+ // If both operands are zero:
+ if ((A == 0.0) && (B == 0.0)) {
+ dst.s.hi = A + B;
+ dst.s.lo = 0.0;
+ return dst.ld;
+ }
+
+ // If either operand is NaN or infinity:
+ const doublebits abits = {.d = A};
+ const doublebits bbits = {.d = B};
+ if ((((uint32_t)(abits.x >> 32) & infinityHi) == infinityHi) ||
+ (((uint32_t)(bbits.x >> 32) & infinityHi) == infinityHi)) {
+ dst.s.hi = A + B;
+ dst.s.lo = 0.0;
+ return dst.ld;
+ }
+
+ // If the computation overflows:
+ // This may be playing things a little bit fast and loose, but it will do for
+ // a start.
+ const double testForOverflow = A + (B + (a + b));
+ const doublebits testbits = {.d = testForOverflow};
+ if (((uint32_t)(testbits.x >> 32) & infinityHi) == infinityHi) {
+ dst.s.hi = testForOverflow;
+ dst.s.lo = 0.0;
+ return dst.ld;
+ }
+
+ double H, h;
+ double T, t;
+ double W, w;
+ double Y;
+
+ H = B + (A - (A + B));
+ T = b + (a - (a + b));
+ h = A + (B - (A + B));
+ t = a + (b - (a + b));
+
+ if (local_fabs(A) <= local_fabs(B))
+ w = (a + b) + h;
+ else
+ w = (a + b) + H;
+
+ W = (A + B) + w;
+ Y = (A + B) - W;
+ Y += w;
+
+ if (local_fabs(a) <= local_fabs(b))
+ w = t + Y;
+ else
+ w = T + Y;
+
+ dst.s.hi = Y = W + w;
+ dst.s.lo = (W - Y) + w;
+
+ return dst.ld;
}
diff --git a/contrib/libs/cxxsupp/builtins/ppc/gcc_qdiv.c b/contrib/libs/cxxsupp/builtins/ppc/gcc_qdiv.c
index 70aa00b644..35a3cbc3d3 100644
--- a/contrib/libs/cxxsupp/builtins/ppc/gcc_qdiv.c
+++ b/contrib/libs/cxxsupp/builtins/ppc/gcc_qdiv.c
@@ -1,55 +1,52 @@
-/* This file is distributed under the University of Illinois Open Source
- * License. See LICENSE.TXT for details.
- */
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-/* long double __gcc_qdiv(long double x, long double y);
- * This file implements the PowerPC 128-bit double-double division operation.
- * This implementation is shamelessly cribbed from Apple's DDRT, circa 1993(!)
- */
+// long double __gcc_qdiv(long double x, long double y);
+// This file implements the PowerPC 128-bit double-double division operation.
+// This implementation is shamelessly cribbed from Apple's DDRT, circa 1993(!)
#include "DD.h"
-long double __gcc_qdiv(long double a, long double b)
-{
- static const uint32_t infinityHi = UINT32_C(0x7ff00000);
- DD dst = { .ld = a }, src = { .ld = b };
-
- register double x = dst.s.hi, x1 = dst.s.lo,
- y = src.s.hi, y1 = src.s.lo;
-
- double yHi, yLo, qHi, qLo;
- double yq, tmp, q;
-
- q = x / y;
-
- /* Detect special cases */
- if (q == 0.0) {
- dst.s.hi = q;
- dst.s.lo = 0.0;
- return dst.ld;
- }
-
- const doublebits qBits = { .d = q };
- if (((uint32_t)(qBits.x >> 32) & infinityHi) == infinityHi) {
- dst.s.hi = q;
- dst.s.lo = 0.0;
- return dst.ld;
- }
-
- yHi = high26bits(y);
- qHi = high26bits(q);
-
- yq = y * q;
- yLo = y - yHi;
- qLo = q - qHi;
-
- tmp = LOWORDER(yq, yHi, yLo, qHi, qLo);
- tmp = (x - yq) - tmp;
- tmp = ((tmp + x1) - y1 * q) / y;
- x = q + tmp;
-
- dst.s.lo = (q - x) + tmp;
- dst.s.hi = x;
-
+long double __gcc_qdiv(long double a, long double b) {
+ static const uint32_t infinityHi = UINT32_C(0x7ff00000);
+ DD dst = {.ld = a}, src = {.ld = b};
+
+ register double x = dst.s.hi, x1 = dst.s.lo, y = src.s.hi, y1 = src.s.lo;
+
+ double yHi, yLo, qHi, qLo;
+ double yq, tmp, q;
+
+ q = x / y;
+
+ // Detect special cases
+ if (q == 0.0) {
+ dst.s.hi = q;
+ dst.s.lo = 0.0;
+ return dst.ld;
+ }
+
+ const doublebits qBits = {.d = q};
+ if (((uint32_t)(qBits.x >> 32) & infinityHi) == infinityHi) {
+ dst.s.hi = q;
+ dst.s.lo = 0.0;
return dst.ld;
+ }
+
+ yHi = high26bits(y);
+ qHi = high26bits(q);
+
+ yq = y * q;
+ yLo = y - yHi;
+ qLo = q - qHi;
+
+ tmp = LOWORDER(yq, yHi, yLo, qHi, qLo);
+ tmp = (x - yq) - tmp;
+ tmp = ((tmp + x1) - y1 * q) / y;
+ x = q + tmp;
+
+ dst.s.lo = (q - x) + tmp;
+ dst.s.hi = x;
+
+ return dst.ld;
}
diff --git a/contrib/libs/cxxsupp/builtins/ppc/gcc_qmul.c b/contrib/libs/cxxsupp/builtins/ppc/gcc_qmul.c
index fb4c5164cc..75f519aad6 100644
--- a/contrib/libs/cxxsupp/builtins/ppc/gcc_qmul.c
+++ b/contrib/libs/cxxsupp/builtins/ppc/gcc_qmul.c
@@ -1,53 +1,50 @@
-/* This file is distributed under the University of Illinois Open Source
- * License. See LICENSE.TXT for details.
- */
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-/* long double __gcc_qmul(long double x, long double y);
- * This file implements the PowerPC 128-bit double-double multiply operation.
- * This implementation is shamelessly cribbed from Apple's DDRT, circa 1993(!)
- */
+// long double __gcc_qmul(long double x, long double y);
+// This file implements the PowerPC 128-bit double-double multiply operation.
+// This implementation is shamelessly cribbed from Apple's DDRT, circa 1993(!)
#include "DD.h"
-long double __gcc_qmul(long double x, long double y)
-{
- static const uint32_t infinityHi = UINT32_C(0x7ff00000);
- DD dst = { .ld = x }, src = { .ld = y };
-
- register double A = dst.s.hi, a = dst.s.lo,
- B = src.s.hi, b = src.s.lo;
-
- double aHi, aLo, bHi, bLo;
- double ab, tmp, tau;
-
- ab = A * B;
-
- /* Detect special cases */
- if (ab == 0.0) {
- dst.s.hi = ab;
- dst.s.lo = 0.0;
- return dst.ld;
- }
-
- const doublebits abBits = { .d = ab };
- if (((uint32_t)(abBits.x >> 32) & infinityHi) == infinityHi) {
- dst.s.hi = ab;
- dst.s.lo = 0.0;
- return dst.ld;
- }
-
- /* Generic cases handled here. */
- aHi = high26bits(A);
- bHi = high26bits(B);
- aLo = A - aHi;
- bLo = B - bHi;
-
- tmp = LOWORDER(ab, aHi, aLo, bHi, bLo);
- tmp += (A * b + a * B);
- tau = ab + tmp;
-
- dst.s.lo = (ab - tau) + tmp;
- dst.s.hi = tau;
-
+long double __gcc_qmul(long double x, long double y) {
+ static const uint32_t infinityHi = UINT32_C(0x7ff00000);
+ DD dst = {.ld = x}, src = {.ld = y};
+
+ register double A = dst.s.hi, a = dst.s.lo, B = src.s.hi, b = src.s.lo;
+
+ double aHi, aLo, bHi, bLo;
+ double ab, tmp, tau;
+
+ ab = A * B;
+
+ // Detect special cases
+ if (ab == 0.0) {
+ dst.s.hi = ab;
+ dst.s.lo = 0.0;
+ return dst.ld;
+ }
+
+ const doublebits abBits = {.d = ab};
+ if (((uint32_t)(abBits.x >> 32) & infinityHi) == infinityHi) {
+ dst.s.hi = ab;
+ dst.s.lo = 0.0;
return dst.ld;
+ }
+
+ // Generic cases handled here.
+ aHi = high26bits(A);
+ bHi = high26bits(B);
+ aLo = A - aHi;
+ bLo = B - bHi;
+
+ tmp = LOWORDER(ab, aHi, aLo, bHi, bLo);
+ tmp += (A * b + a * B);
+ tau = ab + tmp;
+
+ dst.s.lo = (ab - tau) + tmp;
+ dst.s.hi = tau;
+
+ return dst.ld;
}
diff --git a/contrib/libs/cxxsupp/builtins/ppc/gcc_qsub.c b/contrib/libs/cxxsupp/builtins/ppc/gcc_qsub.c
index c092e24dbd..ac08120be0 100644
--- a/contrib/libs/cxxsupp/builtins/ppc/gcc_qsub.c
+++ b/contrib/libs/cxxsupp/builtins/ppc/gcc_qsub.c
@@ -1,76 +1,74 @@
-/* This file is distributed under the University of Illinois Open Source
- * License. See LICENSE.TXT for details.
- */
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-/* long double __gcc_qsub(long double x, long double y);
- * This file implements the PowerPC 128-bit double-double add operation.
- * This implementation is shamelessly cribbed from Apple's DDRT, circa 1993(!)
- */
+// long double __gcc_qsub(long double x, long double y);
+// This file implements the PowerPC 128-bit double-double add operation.
+// This implementation is shamelessly cribbed from Apple's DDRT, circa 1993(!)
#include "DD.h"
-long double __gcc_qsub(long double x, long double y)
-{
- static const uint32_t infinityHi = UINT32_C(0x7ff00000);
-
- DD dst = { .ld = x }, src = { .ld = y };
-
- register double A = dst.s.hi, a = dst.s.lo,
- B = -src.s.hi, b = -src.s.lo;
-
- /* If both operands are zero: */
- if ((A == 0.0) && (B == 0.0)) {
- dst.s.hi = A + B;
- dst.s.lo = 0.0;
- return dst.ld;
- }
-
- /* If either operand is NaN or infinity: */
- const doublebits abits = { .d = A };
- const doublebits bbits = { .d = B };
- if ((((uint32_t)(abits.x >> 32) & infinityHi) == infinityHi) ||
- (((uint32_t)(bbits.x >> 32) & infinityHi) == infinityHi)) {
- dst.s.hi = A + B;
- dst.s.lo = 0.0;
- return dst.ld;
- }
-
- /* If the computation overflows: */
- /* This may be playing things a little bit fast and loose, but it will do for a start. */
- const double testForOverflow = A + (B + (a + b));
- const doublebits testbits = { .d = testForOverflow };
- if (((uint32_t)(testbits.x >> 32) & infinityHi) == infinityHi) {
- dst.s.hi = testForOverflow;
- dst.s.lo = 0.0;
- return dst.ld;
- }
-
- double H, h;
- double T, t;
- double W, w;
- double Y;
-
- H = B + (A - (A + B));
- T = b + (a - (a + b));
- h = A + (B - (A + B));
- t = a + (b - (a + b));
-
- if (local_fabs(A) <= local_fabs(B))
- w = (a + b) + h;
- else
- w = (a + b) + H;
-
- W = (A + B) + w;
- Y = (A + B) - W;
- Y += w;
-
- if (local_fabs(a) <= local_fabs(b))
- w = t + Y;
- else
- w = T + Y;
-
- dst.s.hi = Y = W + w;
- dst.s.lo = (W - Y) + w;
-
- return dst.ld;
+long double __gcc_qsub(long double x, long double y) {
+ static const uint32_t infinityHi = UINT32_C(0x7ff00000);
+
+ DD dst = {.ld = x}, src = {.ld = y};
+
+ register double A = dst.s.hi, a = dst.s.lo, B = -src.s.hi, b = -src.s.lo;
+
+ // If both operands are zero:
+ if ((A == 0.0) && (B == 0.0)) {
+ dst.s.hi = A + B;
+ dst.s.lo = 0.0;
+ return dst.ld;
+ }
+
+ // If either operand is NaN or infinity:
+ const doublebits abits = {.d = A};
+ const doublebits bbits = {.d = B};
+ if ((((uint32_t)(abits.x >> 32) & infinityHi) == infinityHi) ||
+ (((uint32_t)(bbits.x >> 32) & infinityHi) == infinityHi)) {
+ dst.s.hi = A + B;
+ dst.s.lo = 0.0;
+ return dst.ld;
+ }
+
+ // If the computation overflows:
+ // This may be playing things a little bit fast and loose, but it will do for
+ // a start.
+ const double testForOverflow = A + (B + (a + b));
+ const doublebits testbits = {.d = testForOverflow};
+ if (((uint32_t)(testbits.x >> 32) & infinityHi) == infinityHi) {
+ dst.s.hi = testForOverflow;
+ dst.s.lo = 0.0;
+ return dst.ld;
+ }
+
+ double H, h;
+ double T, t;
+ double W, w;
+ double Y;
+
+ H = B + (A - (A + B));
+ T = b + (a - (a + b));
+ h = A + (B - (A + B));
+ t = a + (b - (a + b));
+
+ if (local_fabs(A) <= local_fabs(B))
+ w = (a + b) + h;
+ else
+ w = (a + b) + H;
+
+ W = (A + B) + w;
+ Y = (A + B) - W;
+ Y += w;
+
+ if (local_fabs(a) <= local_fabs(b))
+ w = t + Y;
+ else
+ w = T + Y;
+
+ dst.s.hi = Y = W + w;
+ dst.s.lo = (W - Y) + w;
+
+ return dst.ld;
}
diff --git a/contrib/libs/cxxsupp/builtins/ppc/multc3.c b/contrib/libs/cxxsupp/builtins/ppc/multc3.c
index 9dd79c975d..f1fd6816d6 100644
--- a/contrib/libs/cxxsupp/builtins/ppc/multc3.c
+++ b/contrib/libs/cxxsupp/builtins/ppc/multc3.c
@@ -1,90 +1,85 @@
-/* This file is distributed under the University of Illinois Open Source
- * License. See LICENSE.TXT for details.
- */
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-#include "DD.h"
#include "../int_math.h"
+#include "DD.h"
-#define makeFinite(x) { \
- (x).s.hi = crt_copysign(crt_isinf((x).s.hi) ? 1.0 : 0.0, (x).s.hi); \
- (x).s.lo = 0.0; \
+#define makeFinite(x) \
+ { \
+ (x).s.hi = crt_copysign(crt_isinf((x).s.hi) ? 1.0 : 0.0, (x).s.hi); \
+ (x).s.lo = 0.0; \
}
-#define zeroNaN(x) { \
- if (crt_isnan((x).s.hi)) { \
- (x).s.hi = crt_copysign(0.0, (x).s.hi); \
- (x).s.lo = 0.0; \
- } \
+#define zeroNaN(x) \
+ { \
+ if (crt_isnan((x).s.hi)) { \
+ (x).s.hi = crt_copysign(0.0, (x).s.hi); \
+ (x).s.lo = 0.0; \
+ } \
}
-long double _Complex
-__multc3(long double a, long double b, long double c, long double d)
-{
- long double ac = __gcc_qmul(a,c);
- long double bd = __gcc_qmul(b,d);
- long double ad = __gcc_qmul(a,d);
- long double bc = __gcc_qmul(b,c);
-
- DD real = { .ld = __gcc_qsub(ac,bd) };
- DD imag = { .ld = __gcc_qadd(ad,bc) };
-
- if (crt_isnan(real.s.hi) && crt_isnan(imag.s.hi))
- {
- int recalc = 0;
-
- DD aDD = { .ld = a };
- DD bDD = { .ld = b };
- DD cDD = { .ld = c };
- DD dDD = { .ld = d };
-
- if (crt_isinf(aDD.s.hi) || crt_isinf(bDD.s.hi))
- {
- makeFinite(aDD);
- makeFinite(bDD);
- zeroNaN(cDD);
- zeroNaN(dDD);
- recalc = 1;
- }
-
- if (crt_isinf(cDD.s.hi) || crt_isinf(dDD.s.hi))
- {
- makeFinite(cDD);
- makeFinite(dDD);
- zeroNaN(aDD);
- zeroNaN(bDD);
- recalc = 1;
- }
-
- if (!recalc)
- {
- DD acDD = { .ld = ac };
- DD bdDD = { .ld = bd };
- DD adDD = { .ld = ad };
- DD bcDD = { .ld = bc };
-
- if (crt_isinf(acDD.s.hi) || crt_isinf(bdDD.s.hi) ||
- crt_isinf(adDD.s.hi) || crt_isinf(bcDD.s.hi))
- {
- zeroNaN(aDD);
- zeroNaN(bDD);
- zeroNaN(cDD);
- zeroNaN(dDD);
- recalc = 1;
- }
- }
-
- if (recalc)
- {
- real.s.hi = CRT_INFINITY * (aDD.s.hi*cDD.s.hi - bDD.s.hi*dDD.s.hi);
- real.s.lo = 0.0;
- imag.s.hi = CRT_INFINITY * (aDD.s.hi*dDD.s.hi + bDD.s.hi*cDD.s.hi);
- imag.s.lo = 0.0;
- }
- }
-
- long double _Complex z;
- __real__ z = real.ld;
- __imag__ z = imag.ld;
-
- return z;
+long double _Complex __multc3(long double a, long double b, long double c,
+ long double d) {
+ long double ac = __gcc_qmul(a, c);
+ long double bd = __gcc_qmul(b, d);
+ long double ad = __gcc_qmul(a, d);
+ long double bc = __gcc_qmul(b, c);
+
+ DD real = {.ld = __gcc_qsub(ac, bd)};
+ DD imag = {.ld = __gcc_qadd(ad, bc)};
+
+ if (crt_isnan(real.s.hi) && crt_isnan(imag.s.hi)) {
+ int recalc = 0;
+
+ DD aDD = {.ld = a};
+ DD bDD = {.ld = b};
+ DD cDD = {.ld = c};
+ DD dDD = {.ld = d};
+
+ if (crt_isinf(aDD.s.hi) || crt_isinf(bDD.s.hi)) {
+ makeFinite(aDD);
+ makeFinite(bDD);
+ zeroNaN(cDD);
+ zeroNaN(dDD);
+ recalc = 1;
+ }
+
+ if (crt_isinf(cDD.s.hi) || crt_isinf(dDD.s.hi)) {
+ makeFinite(cDD);
+ makeFinite(dDD);
+ zeroNaN(aDD);
+ zeroNaN(bDD);
+ recalc = 1;
+ }
+
+ if (!recalc) {
+ DD acDD = {.ld = ac};
+ DD bdDD = {.ld = bd};
+ DD adDD = {.ld = ad};
+ DD bcDD = {.ld = bc};
+
+ if (crt_isinf(acDD.s.hi) || crt_isinf(bdDD.s.hi) ||
+ crt_isinf(adDD.s.hi) || crt_isinf(bcDD.s.hi)) {
+ zeroNaN(aDD);
+ zeroNaN(bDD);
+ zeroNaN(cDD);
+ zeroNaN(dDD);
+ recalc = 1;
+ }
+ }
+
+ if (recalc) {
+ real.s.hi = CRT_INFINITY * (aDD.s.hi * cDD.s.hi - bDD.s.hi * dDD.s.hi);
+ real.s.lo = 0.0;
+ imag.s.hi = CRT_INFINITY * (aDD.s.hi * dDD.s.hi + bDD.s.hi * cDD.s.hi);
+ imag.s.lo = 0.0;
+ }
+ }
+
+ long double _Complex z;
+ __real__ z = real.ld;
+ __imag__ z = imag.ld;
+
+ return z;
}
diff --git a/contrib/libs/cxxsupp/builtins/ppc/restFP.S b/contrib/libs/cxxsupp/builtins/ppc/restFP.S
index 95032897c0..02317bd6a6 100644
--- a/contrib/libs/cxxsupp/builtins/ppc/restFP.S
+++ b/contrib/libs/cxxsupp/builtins/ppc/restFP.S
@@ -1,9 +1,8 @@
//===-- restFP.S - Implement restFP ---------------------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -41,3 +40,6 @@ DEFINE_COMPILERRT_PRIVATE_FUNCTION_UNMANGLED(restFP)
lwz r0,8(r1)
mtlr r0
blr
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/ppc/saveFP.S b/contrib/libs/cxxsupp/builtins/ppc/saveFP.S
index 72bd459f4c..1ef5532c8a 100644
--- a/contrib/libs/cxxsupp/builtins/ppc/saveFP.S
+++ b/contrib/libs/cxxsupp/builtins/ppc/saveFP.S
@@ -1,9 +1,8 @@
//===-- saveFP.S - Implement saveFP ---------------------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -38,3 +37,6 @@ DEFINE_COMPILERRT_PRIVATE_FUNCTION_UNMANGLED(saveFP)
stfd f31,-8(r1)
stw r0,8(r1)
blr
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/riscv/fp_mode.c b/contrib/libs/cxxsupp/builtins/riscv/fp_mode.c
new file mode 100644
index 0000000000..c542c34c9c
--- /dev/null
+++ b/contrib/libs/cxxsupp/builtins/riscv/fp_mode.c
@@ -0,0 +1,42 @@
+//=== lib/builtins/riscv/fp_mode.c - Floaing-point mode utilities -*- C -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+#include "../fp_mode.h"
+
+#define RISCV_TONEAREST 0x0
+#define RISCV_TOWARDZERO 0x1
+#define RISCV_DOWNWARD 0x2
+#define RISCV_UPWARD 0x3
+
+#define RISCV_INEXACT 0x1
+
+CRT_FE_ROUND_MODE __fe_getround(void) {
+#if defined(__riscv_f)
+ int frm;
+ __asm__ __volatile__("frrm %0" : "=r" (frm));
+ switch (frm) {
+ case RISCV_TOWARDZERO:
+ return CRT_FE_TOWARDZERO;
+ case RISCV_DOWNWARD:
+ return CRT_FE_DOWNWARD;
+ case RISCV_UPWARD:
+ return CRT_FE_UPWARD;
+ case RISCV_TONEAREST:
+ default:
+ return CRT_FE_TONEAREST;
+ }
+#else
+ return CRT_FE_TONEAREST;
+#endif
+}
+
+int __fe_raise_inexact(void) {
+#if defined(__riscv_f)
+ __asm__ __volatile__("csrsi fflags, %0" :: "i" (RISCV_INEXACT));
+#endif
+ return 0;
+}
diff --git a/contrib/libs/cxxsupp/builtins/riscv/int_mul_impl.inc b/contrib/libs/cxxsupp/builtins/riscv/int_mul_impl.inc
new file mode 100644
index 0000000000..53699b356f
--- /dev/null
+++ b/contrib/libs/cxxsupp/builtins/riscv/int_mul_impl.inc
@@ -0,0 +1,33 @@
+//===-- int_mul_impl.inc - Integer multiplication -------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Helpers used by __mulsi3, __muldi3.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __mulxi3
+#error "__mulxi3 must be defined to use this generic implementation"
+#endif
+
+ .text
+ .align 2
+
+ .globl __mulxi3
+ .type __mulxi3, @function
+__mulxi3:
+ mv a2, a0
+ mv a0, zero
+.L1:
+ andi a3, a1, 1
+ beqz a3, .L2
+ add a0, a0, a2
+.L2:
+ srli a1, a1, 1
+ slli a2, a2, 1
+ bnez a1, .L1
+ ret
diff --git a/contrib/libs/cxxsupp/builtins/riscv/muldi3.S b/contrib/libs/cxxsupp/builtins/riscv/muldi3.S
new file mode 100644
index 0000000000..9e292e8dd8
--- /dev/null
+++ b/contrib/libs/cxxsupp/builtins/riscv/muldi3.S
@@ -0,0 +1,11 @@
+//===--- muldi3.S - Integer multiplication routines -----------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+#if __riscv_xlen == 64
+#define __mulxi3 __muldi3
+#include "int_mul_impl.inc"
+#endif
diff --git a/contrib/libs/cxxsupp/builtins/riscv/mulsi3.S b/contrib/libs/cxxsupp/builtins/riscv/mulsi3.S
new file mode 100644
index 0000000000..cfafb7a0d7
--- /dev/null
+++ b/contrib/libs/cxxsupp/builtins/riscv/mulsi3.S
@@ -0,0 +1,12 @@
+//===--- mulsi3.S - Integer multiplication routines -----------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#if __riscv_xlen == 32
+#define __mulxi3 __mulsi3
+#include "int_mul_impl.inc"
+#endif
diff --git a/contrib/libs/cxxsupp/builtins/riscv/restore.S b/contrib/libs/cxxsupp/builtins/riscv/restore.S
new file mode 100644
index 0000000000..73f64a920d
--- /dev/null
+++ b/contrib/libs/cxxsupp/builtins/riscv/restore.S
@@ -0,0 +1,166 @@
+//===-- restore.S - restore up to 12 callee-save registers ----------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Multiple entry points depending on number of registers to restore
+//
+//===----------------------------------------------------------------------===//
+
+// All of the entry points are in the same section since we rely on many of
+// them falling through into each other and don't want the linker to
+// accidentally split them up, garbage collect, or reorder them.
+//
+// The entry points are grouped up into 2s for rv64 and 4s for rv32 since this
+// is the minimum grouping which will maintain the required 16-byte stack
+// alignment.
+
+ .text
+
+#if __riscv_xlen == 32
+
+ .globl __riscv_restore_12
+ .type __riscv_restore_12,@function
+__riscv_restore_12:
+ lw s11, 12(sp)
+ addi sp, sp, 16
+ // fallthrough into __riscv_restore_11/10/9/8
+
+ .globl __riscv_restore_11
+ .type __riscv_restore_11,@function
+ .globl __riscv_restore_10
+ .type __riscv_restore_10,@function
+ .globl __riscv_restore_9
+ .type __riscv_restore_9,@function
+ .globl __riscv_restore_8
+ .type __riscv_restore_8,@function
+__riscv_restore_11:
+__riscv_restore_10:
+__riscv_restore_9:
+__riscv_restore_8:
+ lw s10, 0(sp)
+ lw s9, 4(sp)
+ lw s8, 8(sp)
+ lw s7, 12(sp)
+ addi sp, sp, 16
+ // fallthrough into __riscv_restore_7/6/5/4
+
+ .globl __riscv_restore_7
+ .type __riscv_restore_7,@function
+ .globl __riscv_restore_6
+ .type __riscv_restore_6,@function
+ .globl __riscv_restore_5
+ .type __riscv_restore_5,@function
+ .globl __riscv_restore_4
+ .type __riscv_restore_4,@function
+__riscv_restore_7:
+__riscv_restore_6:
+__riscv_restore_5:
+__riscv_restore_4:
+ lw s6, 0(sp)
+ lw s5, 4(sp)
+ lw s4, 8(sp)
+ lw s3, 12(sp)
+ addi sp, sp, 16
+ // fallthrough into __riscv_restore_3/2/1/0
+
+ .globl __riscv_restore_3
+ .type __riscv_restore_3,@function
+ .globl __riscv_restore_2
+ .type __riscv_restore_2,@function
+ .globl __riscv_restore_1
+ .type __riscv_restore_1,@function
+ .globl __riscv_restore_0
+ .type __riscv_restore_0,@function
+__riscv_restore_3:
+__riscv_restore_2:
+__riscv_restore_1:
+__riscv_restore_0:
+ lw s2, 0(sp)
+ lw s1, 4(sp)
+ lw s0, 8(sp)
+ lw ra, 12(sp)
+ addi sp, sp, 16
+ ret
+
+#elif __riscv_xlen == 64
+
+ .globl __riscv_restore_12
+ .type __riscv_restore_12,@function
+__riscv_restore_12:
+ ld s11, 8(sp)
+ addi sp, sp, 16
+ // fallthrough into __riscv_restore_11/10
+
+ .globl __riscv_restore_11
+ .type __riscv_restore_11,@function
+ .globl __riscv_restore_10
+ .type __riscv_restore_10,@function
+__riscv_restore_11:
+__riscv_restore_10:
+ ld s10, 0(sp)
+ ld s9, 8(sp)
+ addi sp, sp, 16
+ // fallthrough into __riscv_restore_9/8
+
+ .globl __riscv_restore_9
+ .type __riscv_restore_9,@function
+ .globl __riscv_restore_8
+ .type __riscv_restore_8,@function
+__riscv_restore_9:
+__riscv_restore_8:
+ ld s8, 0(sp)
+ ld s7, 8(sp)
+ addi sp, sp, 16
+ // fallthrough into __riscv_restore_7/6
+
+ .globl __riscv_restore_7
+ .type __riscv_restore_7,@function
+ .globl __riscv_restore_6
+ .type __riscv_restore_6,@function
+__riscv_restore_7:
+__riscv_restore_6:
+ ld s6, 0(sp)
+ ld s5, 8(sp)
+ addi sp, sp, 16
+ // fallthrough into __riscv_restore_5/4
+
+ .globl __riscv_restore_5
+ .type __riscv_restore_5,@function
+ .globl __riscv_restore_4
+ .type __riscv_restore_4,@function
+__riscv_restore_5:
+__riscv_restore_4:
+ ld s4, 0(sp)
+ ld s3, 8(sp)
+ addi sp, sp, 16
+ // fallthrough into __riscv_restore_3/2
+
+ .globl __riscv_restore_3
+ .type __riscv_restore_3,@function
+ .globl __riscv_restore_2
+ .type __riscv_restore_2,@function
+__riscv_restore_3:
+__riscv_restore_2:
+ ld s2, 0(sp)
+ ld s1, 8(sp)
+ addi sp, sp, 16
+ // fallthrough into __riscv_restore_1/0
+
+ .globl __riscv_restore_1
+ .type __riscv_restore_1,@function
+ .globl __riscv_restore_0
+ .type __riscv_restore_0,@function
+__riscv_restore_1:
+__riscv_restore_0:
+ ld s0, 0(sp)
+ ld ra, 8(sp)
+ addi sp, sp, 16
+ ret
+
+#else
+# error "xlen must be 32 or 64 for save-restore implementation
+#endif
diff --git a/contrib/libs/cxxsupp/builtins/riscv/save.S b/contrib/libs/cxxsupp/builtins/riscv/save.S
new file mode 100644
index 0000000000..85501aeb4c
--- /dev/null
+++ b/contrib/libs/cxxsupp/builtins/riscv/save.S
@@ -0,0 +1,186 @@
+//===-- save.S - save up to 12 callee-saved registers ---------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Multiple entry points depending on number of registers to save
+//
+//===----------------------------------------------------------------------===//
+
+// The entry points are grouped up into 2s for rv64 and 4s for rv32 since this
+// is the minimum grouping which will maintain the required 16-byte stack
+// alignment.
+
+ .text
+
+#if __riscv_xlen == 32
+
+ .globl __riscv_save_12
+ .type __riscv_save_12,@function
+__riscv_save_12:
+ addi sp, sp, -64
+ mv t1, zero
+ sw s11, 12(sp)
+ j .Lriscv_save_11_8
+
+ .globl __riscv_save_11
+ .type __riscv_save_11,@function
+ .globl __riscv_save_10
+ .type __riscv_save_10,@function
+ .globl __riscv_save_9
+ .type __riscv_save_9,@function
+ .globl __riscv_save_8
+ .type __riscv_save_8,@function
+__riscv_save_11:
+__riscv_save_10:
+__riscv_save_9:
+__riscv_save_8:
+ addi sp, sp, -64
+ li t1, 16
+.Lriscv_save_11_8:
+ sw s10, 16(sp)
+ sw s9, 20(sp)
+ sw s8, 24(sp)
+ sw s7, 28(sp)
+ j .Lriscv_save_7_4
+
+ .globl __riscv_save_7
+ .type __riscv_save_7,@function
+ .globl __riscv_save_6
+ .type __riscv_save_6,@function
+ .globl __riscv_save_5
+ .type __riscv_save_5,@function
+ .globl __riscv_save_4
+ .type __riscv_save_4,@function
+__riscv_save_7:
+__riscv_save_6:
+__riscv_save_5:
+__riscv_save_4:
+ addi sp, sp, -64
+ li t1, 32
+.Lriscv_save_7_4:
+ sw s6, 32(sp)
+ sw s5, 36(sp)
+ sw s4, 40(sp)
+ sw s3, 44(sp)
+ sw s2, 48(sp)
+ sw s1, 52(sp)
+ sw s0, 56(sp)
+ sw ra, 60(sp)
+ add sp, sp, t1
+ jr t0
+
+ .globl __riscv_save_3
+ .type __riscv_save_3,@function
+ .globl __riscv_save_2
+ .type __riscv_save_2,@function
+ .globl __riscv_save_1
+ .type __riscv_save_1,@function
+ .globl __riscv_save_0
+ .type __riscv_save_0,@function
+__riscv_save_3:
+__riscv_save_2:
+__riscv_save_1:
+__riscv_save_0:
+ addi sp, sp, -16
+ sw s2, 0(sp)
+ sw s1, 4(sp)
+ sw s0, 8(sp)
+ sw ra, 12(sp)
+ jr t0
+
+#elif __riscv_xlen == 64
+
+ .globl __riscv_save_12
+ .type __riscv_save_12,@function
+__riscv_save_12:
+ addi sp, sp, -112
+ mv t1, zero
+ sd s11, 8(sp)
+ j .Lriscv_save_11_10
+
+ .globl __riscv_save_11
+ .type __riscv_save_11,@function
+ .globl __riscv_save_10
+ .type __riscv_save_10,@function
+__riscv_save_11:
+__riscv_save_10:
+ addi sp, sp, -112
+ li t1, 16
+.Lriscv_save_11_10:
+ sd s10, 16(sp)
+ sd s9, 24(sp)
+ j .Lriscv_save_9_8
+
+ .globl __riscv_save_9
+ .type __riscv_save_9,@function
+ .globl __riscv_save_8
+ .type __riscv_save_8,@function
+__riscv_save_9:
+__riscv_save_8:
+ addi sp, sp, -112
+ li t1, 32
+.Lriscv_save_9_8:
+ sd s8, 32(sp)
+ sd s7, 40(sp)
+ j .Lriscv_save_7_6
+
+ .globl __riscv_save_7
+ .type __riscv_save_7,@function
+ .globl __riscv_save_6
+ .type __riscv_save_6,@function
+__riscv_save_7:
+__riscv_save_6:
+ addi sp, sp, -112
+ li t1, 48
+.Lriscv_save_7_6:
+ sd s6, 48(sp)
+ sd s5, 56(sp)
+ j .Lriscv_save_5_4
+
+ .globl __riscv_save_5
+ .type __riscv_save_5,@function
+ .globl __riscv_save_4
+ .type __riscv_save_4,@function
+__riscv_save_5:
+__riscv_save_4:
+ addi sp, sp, -112
+ li t1, 64
+.Lriscv_save_5_4:
+ sd s4, 64(sp)
+ sd s3, 72(sp)
+ j .Lriscv_save_3_2
+
+ .globl __riscv_save_3
+ .type __riscv_save_3,@function
+ .globl __riscv_save_2
+ .type __riscv_save_2,@function
+__riscv_save_3:
+__riscv_save_2:
+ addi sp, sp, -112
+ li t1, 80
+.Lriscv_save_3_2:
+ sd s2, 80(sp)
+ sd s1, 88(sp)
+ sd s0, 96(sp)
+ sd ra, 104(sp)
+ add sp, sp, t1
+ jr t0
+
+ .globl __riscv_save_1
+ .type __riscv_save_1,@function
+ .globl __riscv_save_0
+ .type __riscv_save_0,@function
+__riscv_save_1:
+__riscv_save_0:
+ addi sp, sp, -16
+ sd s0, 0(sp)
+ sd ra, 8(sp)
+ jr t0
+
+#else
+# error "xlen must be 32 or 64 for save-restore implementation
+#endif
diff --git a/contrib/libs/cxxsupp/builtins/subdf3.c b/contrib/libs/cxxsupp/builtins/subdf3.c
index 7a79e5e776..2100fd39c4 100644
--- a/contrib/libs/cxxsupp/builtins/subdf3.c
+++ b/contrib/libs/cxxsupp/builtins/subdf3.c
@@ -1,25 +1,27 @@
//===-- lib/adddf3.c - Double-precision subtraction ---------------*- C -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
-// This file implements double-precision soft-float subtraction with the
-// IEEE-754 default rounding (to nearest, ties to even).
+// This file implements double-precision soft-float subtraction.
//
//===----------------------------------------------------------------------===//
#define DOUBLE_PRECISION
#include "fp_lib.h"
-ARM_EABI_FNALIAS(dsub, subdf3)
-
// Subtraction; flip the sign bit of b and add.
-COMPILER_RT_ABI fp_t
-__subdf3(fp_t a, fp_t b) {
- return __adddf3(a, fromRep(toRep(b) ^ signBit));
+COMPILER_RT_ABI fp_t __subdf3(fp_t a, fp_t b) {
+ return __adddf3(a, fromRep(toRep(b) ^ signBit));
}
+#if defined(__ARM_EABI__)
+#if defined(COMPILER_RT_ARMHF_TARGET)
+AEABI_RTABI fp_t __aeabi_dsub(fp_t a, fp_t b) { return __subdf3(a, b); }
+#else
+COMPILER_RT_ALIAS(__subdf3, __aeabi_dsub)
+#endif
+#endif
diff --git a/contrib/libs/cxxsupp/builtins/subsf3.c b/contrib/libs/cxxsupp/builtins/subsf3.c
index c3b85144af..ecfc24f7dd 100644
--- a/contrib/libs/cxxsupp/builtins/subsf3.c
+++ b/contrib/libs/cxxsupp/builtins/subsf3.c
@@ -1,25 +1,27 @@
//===-- lib/subsf3.c - Single-precision subtraction ---------------*- C -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
-// This file implements single-precision soft-float subtraction with the
-// IEEE-754 default rounding (to nearest, ties to even).
+// This file implements single-precision soft-float subtraction.
//
//===----------------------------------------------------------------------===//
#define SINGLE_PRECISION
#include "fp_lib.h"
-ARM_EABI_FNALIAS(fsub, subsf3)
-
// Subtraction; flip the sign bit of b and add.
-COMPILER_RT_ABI fp_t
-__subsf3(fp_t a, fp_t b) {
- return __addsf3(a, fromRep(toRep(b) ^ signBit));
+COMPILER_RT_ABI fp_t __subsf3(fp_t a, fp_t b) {
+ return __addsf3(a, fromRep(toRep(b) ^ signBit));
}
+#if defined(__ARM_EABI__)
+#if defined(COMPILER_RT_ARMHF_TARGET)
+AEABI_RTABI fp_t __aeabi_fsub(fp_t a, fp_t b) { return __subsf3(a, b); }
+#else
+COMPILER_RT_ALIAS(__subsf3, __aeabi_fsub)
+#endif
+#endif
diff --git a/contrib/libs/cxxsupp/builtins/subtf3.c b/contrib/libs/cxxsupp/builtins/subtf3.c
index 609b816f41..3364c28f81 100644
--- a/contrib/libs/cxxsupp/builtins/subtf3.c
+++ b/contrib/libs/cxxsupp/builtins/subtf3.c
@@ -1,14 +1,12 @@
//===-- lib/subtf3.c - Quad-precision subtraction -----------------*- C -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
-// This file implements quad-precision soft-float subtraction with the
-// IEEE-754 default rounding (to nearest, ties to even).
+// This file implements quad-precision soft-float subtraction.
//
//===----------------------------------------------------------------------===//
@@ -19,9 +17,8 @@
COMPILER_RT_ABI fp_t __addtf3(fp_t a, fp_t b);
// Subtraction; flip the sign bit of b and add.
-COMPILER_RT_ABI fp_t
-__subtf3(fp_t a, fp_t b) {
- return __addtf3(a, fromRep(toRep(b) ^ signBit));
+COMPILER_RT_ABI fp_t __subtf3(fp_t a, fp_t b) {
+ return __addtf3(a, fromRep(toRep(b) ^ signBit));
}
#endif
diff --git a/contrib/libs/cxxsupp/builtins/subvdi3.c b/contrib/libs/cxxsupp/builtins/subvdi3.c
index 71fc70ffa9..d7d78f1bb3 100644
--- a/contrib/libs/cxxsupp/builtins/subvdi3.c
+++ b/contrib/libs/cxxsupp/builtins/subvdi3.c
@@ -1,36 +1,29 @@
-/* ===-- subvdi3.c - Implement __subvdi3 -----------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __subvdi3 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- subvdi3.c - Implement __subvdi3 -----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __subvdi3 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
-/* Returns: a - b */
+// Returns: a - b
-/* Effects: aborts if a - b overflows */
+// Effects: aborts if a - b overflows
-COMPILER_RT_ABI di_int
-__subvdi3(di_int a, di_int b)
-{
- di_int s = (du_int) a - (du_int) b;
- if (b >= 0)
- {
- if (s > a)
- compilerrt_abort();
- }
- else
- {
- if (s <= a)
- compilerrt_abort();
- }
- return s;
+COMPILER_RT_ABI di_int __subvdi3(di_int a, di_int b) {
+ di_int s = (du_int)a - (du_int)b;
+ if (b >= 0) {
+ if (s > a)
+ compilerrt_abort();
+ } else {
+ if (s <= a)
+ compilerrt_abort();
+ }
+ return s;
}
diff --git a/contrib/libs/cxxsupp/builtins/subvsi3.c b/contrib/libs/cxxsupp/builtins/subvsi3.c
index e6c0fb688c..c3cb6e8a21 100644
--- a/contrib/libs/cxxsupp/builtins/subvsi3.c
+++ b/contrib/libs/cxxsupp/builtins/subvsi3.c
@@ -1,36 +1,29 @@
-/* ===-- subvsi3.c - Implement __subvsi3 -----------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __subvsi3 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- subvsi3.c - Implement __subvsi3 -----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __subvsi3 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
-/* Returns: a - b */
+// Returns: a - b
-/* Effects: aborts if a - b overflows */
+// Effects: aborts if a - b overflows
-COMPILER_RT_ABI si_int
-__subvsi3(si_int a, si_int b)
-{
- si_int s = (su_int) a - (su_int) b;
- if (b >= 0)
- {
- if (s > a)
- compilerrt_abort();
- }
- else
- {
- if (s <= a)
- compilerrt_abort();
- }
- return s;
+COMPILER_RT_ABI si_int __subvsi3(si_int a, si_int b) {
+ si_int s = (su_int)a - (su_int)b;
+ if (b >= 0) {
+ if (s > a)
+ compilerrt_abort();
+ } else {
+ if (s <= a)
+ compilerrt_abort();
+ }
+ return s;
}
diff --git a/contrib/libs/cxxsupp/builtins/subvti3.c b/contrib/libs/cxxsupp/builtins/subvti3.c
index a6804d2d7b..91ac188340 100644
--- a/contrib/libs/cxxsupp/builtins/subvti3.c
+++ b/contrib/libs/cxxsupp/builtins/subvti3.c
@@ -1,40 +1,33 @@
-/* ===-- subvti3.c - Implement __subvti3 -----------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __subvti3 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- subvti3.c - Implement __subvti3 -----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __subvti3 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
#ifdef CRT_HAS_128BIT
-/* Returns: a - b */
+// Returns: a - b
-/* Effects: aborts if a - b overflows */
+// Effects: aborts if a - b overflows
-COMPILER_RT_ABI ti_int
-__subvti3(ti_int a, ti_int b)
-{
- ti_int s = (tu_int) a - (tu_int) b;
- if (b >= 0)
- {
- if (s > a)
- compilerrt_abort();
- }
- else
- {
- if (s <= a)
- compilerrt_abort();
- }
- return s;
+COMPILER_RT_ABI ti_int __subvti3(ti_int a, ti_int b) {
+ ti_int s = (tu_int)a - (tu_int)b;
+ if (b >= 0) {
+ if (s > a)
+ compilerrt_abort();
+ } else {
+ if (s <= a)
+ compilerrt_abort();
+ }
+ return s;
}
-#endif /* CRT_HAS_128BIT */
+#endif // CRT_HAS_128BIT
diff --git a/contrib/libs/cxxsupp/builtins/trampoline_setup.c b/contrib/libs/cxxsupp/builtins/trampoline_setup.c
index 25b627ab76..844eb27944 100644
--- a/contrib/libs/cxxsupp/builtins/trampoline_setup.c
+++ b/contrib/libs/cxxsupp/builtins/trampoline_setup.c
@@ -1,48 +1,43 @@
-/* ===----- trampoline_setup.c - Implement __trampoline_setup -------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- */
+//===----- trampoline_setup.c - Implement __trampoline_setup -------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
-extern void __clear_cache(void* start, void* end);
+extern void __clear_cache(void *start, void *end);
-/*
- * The ppc compiler generates calls to __trampoline_setup() when creating
- * trampoline functions on the stack for use with nested functions.
- * This function creates a custom 40-byte trampoline function on the stack
- * which loads r11 with a pointer to the outer function's locals
- * and then jumps to the target nested function.
- */
+// The ppc compiler generates calls to __trampoline_setup() when creating
+// trampoline functions on the stack for use with nested functions.
+// This function creates a custom 40-byte trampoline function on the stack
+// which loads r11 with a pointer to the outer function's locals
+// and then jumps to the target nested function.
-#if __ppc__ && !defined(__powerpc64__)
-COMPILER_RT_ABI void
-__trampoline_setup(uint32_t* trampOnStack, int trampSizeAllocated,
- const void* realFunc, void* localsPtr)
-{
- /* should never happen, but if compiler did not allocate */
- /* enough space on stack for the trampoline, abort */
- if ( trampSizeAllocated < 40 )
- compilerrt_abort();
-
- /* create trampoline */
- trampOnStack[0] = 0x7c0802a6; /* mflr r0 */
- trampOnStack[1] = 0x4800000d; /* bl Lbase */
- trampOnStack[2] = (uint32_t)realFunc;
- trampOnStack[3] = (uint32_t)localsPtr;
- trampOnStack[4] = 0x7d6802a6; /* Lbase: mflr r11 */
- trampOnStack[5] = 0x818b0000; /* lwz r12,0(r11) */
- trampOnStack[6] = 0x7c0803a6; /* mtlr r0 */
- trampOnStack[7] = 0x7d8903a6; /* mtctr r12 */
- trampOnStack[8] = 0x816b0004; /* lwz r11,4(r11) */
- trampOnStack[9] = 0x4e800420; /* bctr */
-
- /* clear instruction cache */
- __clear_cache(trampOnStack, &trampOnStack[10]);
+#if __powerpc__ && !defined(__powerpc64__)
+COMPILER_RT_ABI void __trampoline_setup(uint32_t *trampOnStack,
+ int trampSizeAllocated,
+ const void *realFunc, void *localsPtr) {
+ // should never happen, but if compiler did not allocate
+ // enough space on stack for the trampoline, abort
+ if (trampSizeAllocated < 40)
+ compilerrt_abort();
+
+ // create trampoline
+ trampOnStack[0] = 0x7c0802a6; // mflr r0
+ trampOnStack[1] = 0x4800000d; // bl Lbase
+ trampOnStack[2] = (uint32_t)realFunc;
+ trampOnStack[3] = (uint32_t)localsPtr;
+ trampOnStack[4] = 0x7d6802a6; // Lbase: mflr r11
+ trampOnStack[5] = 0x818b0000; // lwz r12,0(r11)
+ trampOnStack[6] = 0x7c0803a6; // mtlr r0
+ trampOnStack[7] = 0x7d8903a6; // mtctr r12
+ trampOnStack[8] = 0x816b0004; // lwz r11,4(r11)
+ trampOnStack[9] = 0x4e800420; // bctr
+
+ // clear instruction cache
+ __clear_cache(trampOnStack, &trampOnStack[10]);
}
-#endif /* __ppc__ && !defined(__powerpc64__) */
+#endif // __powerpc__ && !defined(__powerpc64__)
diff --git a/contrib/libs/cxxsupp/builtins/truncdfbf2.c b/contrib/libs/cxxsupp/builtins/truncdfbf2.c
new file mode 100644
index 0000000000..dbd54dcd50
--- /dev/null
+++ b/contrib/libs/cxxsupp/builtins/truncdfbf2.c
@@ -0,0 +1,13 @@
+//===-- lib/truncdfbf2.c - double -> bfloat conversion ------------*- C -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#define SRC_DOUBLE
+#define DST_BFLOAT
+#include "fp_trunc_impl.inc"
+
+COMPILER_RT_ABI dst_t __truncdfbf2(double a) { return __truncXfYf2__(a); }
diff --git a/contrib/libs/cxxsupp/builtins/truncdfhf2.c b/contrib/libs/cxxsupp/builtins/truncdfhf2.c
index 17195cd9e7..24c6e62f71 100644
--- a/contrib/libs/cxxsupp/builtins/truncdfhf2.c
+++ b/contrib/libs/cxxsupp/builtins/truncdfhf2.c
@@ -1,9 +1,8 @@
//===-- lib/truncdfhf2.c - double -> half conversion --------------*- C -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -11,8 +10,12 @@
#define DST_HALF
#include "fp_trunc_impl.inc"
-ARM_EABI_FNALIAS(d2h, truncdfhf2)
+COMPILER_RT_ABI dst_t __truncdfhf2(double a) { return __truncXfYf2__(a); }
-COMPILER_RT_ABI uint16_t __truncdfhf2(double a) {
- return __truncXfYf2__(a);
-}
+#if defined(__ARM_EABI__)
+#if defined(COMPILER_RT_ARMHF_TARGET)
+AEABI_RTABI dst_t __aeabi_d2h(double a) { return __truncdfhf2(a); }
+#else
+COMPILER_RT_ALIAS(__truncdfhf2, __aeabi_d2h)
+#endif
+#endif
diff --git a/contrib/libs/cxxsupp/builtins/truncdfsf2.c b/contrib/libs/cxxsupp/builtins/truncdfsf2.c
index 46ec11dccd..44a1299e30 100644
--- a/contrib/libs/cxxsupp/builtins/truncdfsf2.c
+++ b/contrib/libs/cxxsupp/builtins/truncdfsf2.c
@@ -1,9 +1,8 @@
//===-- lib/truncdfsf2.c - double -> single conversion ------------*- C -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -11,8 +10,12 @@
#define DST_SINGLE
#include "fp_trunc_impl.inc"
-ARM_EABI_FNALIAS(d2f, truncdfsf2)
+COMPILER_RT_ABI float __truncdfsf2(double a) { return __truncXfYf2__(a); }
-COMPILER_RT_ABI float __truncdfsf2(double a) {
- return __truncXfYf2__(a);
-}
+#if defined(__ARM_EABI__)
+#if defined(COMPILER_RT_ARMHF_TARGET)
+AEABI_RTABI float __aeabi_d2f(double a) { return __truncdfsf2(a); }
+#else
+COMPILER_RT_ALIAS(__truncdfsf2, __aeabi_d2f)
+#endif
+#endif
diff --git a/contrib/libs/cxxsupp/builtins/truncsfbf2.c b/contrib/libs/cxxsupp/builtins/truncsfbf2.c
new file mode 100644
index 0000000000..6bed116af9
--- /dev/null
+++ b/contrib/libs/cxxsupp/builtins/truncsfbf2.c
@@ -0,0 +1,13 @@
+//===-- lib/truncsfbf2.c - single -> bfloat conversion ------------*- C -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#define SRC_SINGLE
+#define DST_BFLOAT
+#include "fp_trunc_impl.inc"
+
+COMPILER_RT_ABI dst_t __truncsfbf2(float a) { return __truncXfYf2__(a); }
diff --git a/contrib/libs/cxxsupp/builtins/truncsfhf2.c b/contrib/libs/cxxsupp/builtins/truncsfhf2.c
index 9d61895bfd..379e7cb6f7 100644
--- a/contrib/libs/cxxsupp/builtins/truncsfhf2.c
+++ b/contrib/libs/cxxsupp/builtins/truncsfhf2.c
@@ -1,9 +1,8 @@
//===-- lib/truncsfhf2.c - single -> half conversion --------------*- C -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -11,14 +10,18 @@
#define DST_HALF
#include "fp_trunc_impl.inc"
-ARM_EABI_FNALIAS(f2h, truncsfhf2)
-
// Use a forwarding definition and noinline to implement a poor man's alias,
// as there isn't a good cross-platform way of defining one.
-COMPILER_RT_ABI NOINLINE uint16_t __truncsfhf2(float a) {
- return __truncXfYf2__(a);
+COMPILER_RT_ABI NOINLINE dst_t __truncsfhf2(float a) {
+ return __truncXfYf2__(a);
}
-COMPILER_RT_ABI uint16_t __gnu_f2h_ieee(float a) {
- return __truncsfhf2(a);
-}
+COMPILER_RT_ABI dst_t __gnu_f2h_ieee(float a) { return __truncsfhf2(a); }
+
+#if defined(__ARM_EABI__)
+#if defined(COMPILER_RT_ARMHF_TARGET)
+AEABI_RTABI dst_t __aeabi_f2h(float a) { return __truncsfhf2(a); }
+#else
+COMPILER_RT_ALIAS(__truncsfhf2, __aeabi_f2h)
+#endif
+#endif
diff --git a/contrib/libs/cxxsupp/builtins/trunctfdf2.c b/contrib/libs/cxxsupp/builtins/trunctfdf2.c
index 741a71b33c..6857ea54d8 100644
--- a/contrib/libs/cxxsupp/builtins/trunctfdf2.c
+++ b/contrib/libs/cxxsupp/builtins/trunctfdf2.c
@@ -1,9 +1,8 @@
//===-- lib/truncdfsf2.c - quad -> double conversion --------------*- C -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -15,8 +14,6 @@
#define DST_DOUBLE
#include "fp_trunc_impl.inc"
-COMPILER_RT_ABI double __trunctfdf2(long double a) {
- return __truncXfYf2__(a);
-}
+COMPILER_RT_ABI double __trunctfdf2(long double a) { return __truncXfYf2__(a); }
#endif
diff --git a/contrib/libs/cxxsupp/builtins/trunctfhf2.c b/contrib/libs/cxxsupp/builtins/trunctfhf2.c
new file mode 100644
index 0000000000..e3a2309d95
--- /dev/null
+++ b/contrib/libs/cxxsupp/builtins/trunctfhf2.c
@@ -0,0 +1,23 @@
+//===-- lib/trunctfhf2.c - quad -> half conversion ----------------*- C -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#define QUAD_PRECISION
+#include "fp_lib.h"
+
+#if defined(CRT_HAS_128BIT) && defined(CRT_LDBL_128BIT) && \
+ defined(COMPILER_RT_HAS_FLOAT16)
+#define SRC_QUAD
+#define DST_HALF
+#include "fp_trunc_impl.inc"
+
+COMPILER_RT_ABI _Float16 __trunctfhf2(long double a) {
+ return __truncXfYf2__(a);
+}
+
+#endif
diff --git a/contrib/libs/cxxsupp/builtins/trunctfsf2.c b/contrib/libs/cxxsupp/builtins/trunctfsf2.c
index de96c1decf..0261b1e90f 100644
--- a/contrib/libs/cxxsupp/builtins/trunctfsf2.c
+++ b/contrib/libs/cxxsupp/builtins/trunctfsf2.c
@@ -1,9 +1,8 @@
//===-- lib/trunctfsf2.c - quad -> single conversion --------------*- C -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -15,8 +14,6 @@
#define DST_SINGLE
#include "fp_trunc_impl.inc"
-COMPILER_RT_ABI float __trunctfsf2(long double a) {
- return __truncXfYf2__(a);
-}
+COMPILER_RT_ABI float __trunctfsf2(long double a) { return __truncXfYf2__(a); }
#endif
diff --git a/contrib/libs/cxxsupp/builtins/ucmpdi2.c b/contrib/libs/cxxsupp/builtins/ucmpdi2.c
index 40af23613b..0f2edde835 100644
--- a/contrib/libs/cxxsupp/builtins/ucmpdi2.c
+++ b/contrib/libs/cxxsupp/builtins/ucmpdi2.c
@@ -1,51 +1,42 @@
-/* ===-- ucmpdi2.c - Implement __ucmpdi2 -----------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __ucmpdi2 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- ucmpdi2.c - Implement __ucmpdi2 -----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __ucmpdi2 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
-/* Returns: if (a < b) returns 0
- * if (a == b) returns 1
- * if (a > b) returns 2
- */
+// Returns: if (a < b) returns 0
+// if (a == b) returns 1
+// if (a > b) returns 2
-COMPILER_RT_ABI si_int
-__ucmpdi2(du_int a, du_int b)
-{
- udwords x;
- x.all = a;
- udwords y;
- y.all = b;
- if (x.s.high < y.s.high)
- return 0;
- if (x.s.high > y.s.high)
- return 2;
- if (x.s.low < y.s.low)
- return 0;
- if (x.s.low > y.s.low)
- return 2;
- return 1;
+COMPILER_RT_ABI si_int __ucmpdi2(du_int a, du_int b) {
+ udwords x;
+ x.all = a;
+ udwords y;
+ y.all = b;
+ if (x.s.high < y.s.high)
+ return 0;
+ if (x.s.high > y.s.high)
+ return 2;
+ if (x.s.low < y.s.low)
+ return 0;
+ if (x.s.low > y.s.low)
+ return 2;
+ return 1;
}
#ifdef __ARM_EABI__
-/* Returns: if (a < b) returns -1
-* if (a == b) returns 0
-* if (a > b) returns 1
-*/
-COMPILER_RT_ABI si_int
-__aeabi_ulcmp(di_int a, di_int b)
-{
- return __ucmpdi2(a, b) - 1;
+// Returns: if (a < b) returns -1
+// if (a == b) returns 0
+// if (a > b) returns 1
+COMPILER_RT_ABI si_int __aeabi_ulcmp(di_int a, di_int b) {
+ return __ucmpdi2(a, b) - 1;
}
#endif
-
diff --git a/contrib/libs/cxxsupp/builtins/ucmpti2.c b/contrib/libs/cxxsupp/builtins/ucmpti2.c
index bda8083bb2..4eb6655b05 100644
--- a/contrib/libs/cxxsupp/builtins/ucmpti2.c
+++ b/contrib/libs/cxxsupp/builtins/ucmpti2.c
@@ -1,42 +1,37 @@
-/* ===-- ucmpti2.c - Implement __ucmpti2 -----------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __ucmpti2 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- ucmpti2.c - Implement __ucmpti2 -----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __ucmpti2 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
#ifdef CRT_HAS_128BIT
-/* Returns: if (a < b) returns 0
- * if (a == b) returns 1
- * if (a > b) returns 2
- */
+// Returns: if (a < b) returns 0
+// if (a == b) returns 1
+// if (a > b) returns 2
-COMPILER_RT_ABI si_int
-__ucmpti2(tu_int a, tu_int b)
-{
- utwords x;
- x.all = a;
- utwords y;
- y.all = b;
- if (x.s.high < y.s.high)
- return 0;
- if (x.s.high > y.s.high)
- return 2;
- if (x.s.low < y.s.low)
- return 0;
- if (x.s.low > y.s.low)
- return 2;
- return 1;
+COMPILER_RT_ABI si_int __ucmpti2(tu_int a, tu_int b) {
+ utwords x;
+ x.all = a;
+ utwords y;
+ y.all = b;
+ if (x.s.high < y.s.high)
+ return 0;
+ if (x.s.high > y.s.high)
+ return 2;
+ if (x.s.low < y.s.low)
+ return 0;
+ if (x.s.low > y.s.low)
+ return 2;
+ return 1;
}
-#endif /* CRT_HAS_128BIT */
+#endif // CRT_HAS_128BIT
diff --git a/contrib/libs/cxxsupp/builtins/udivdi3.c b/contrib/libs/cxxsupp/builtins/udivdi3.c
index dc68e154b1..74319cbe71 100644
--- a/contrib/libs/cxxsupp/builtins/udivdi3.c
+++ b/contrib/libs/cxxsupp/builtins/udivdi3.c
@@ -1,23 +1,23 @@
-/* ===-- udivdi3.c - Implement __udivdi3 -----------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __udivdi3 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- udivdi3.c - Implement __udivdi3 -----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __udivdi3 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
-/* Returns: a / b */
+typedef du_int fixuint_t;
+typedef di_int fixint_t;
+#include "int_div_impl.inc"
-COMPILER_RT_ABI du_int
-__udivdi3(du_int a, du_int b)
-{
- return __udivmoddi4(a, b, 0);
+// Returns: a / b
+
+COMPILER_RT_ABI du_int __udivdi3(du_int a, du_int b) {
+ return __udivXi3(a, b);
}
diff --git a/contrib/libs/cxxsupp/builtins/udivmoddi4.c b/contrib/libs/cxxsupp/builtins/udivmoddi4.c
index 0c8b4ff464..123e5fb05f 100644
--- a/contrib/libs/cxxsupp/builtins/udivmoddi4.c
+++ b/contrib/libs/cxxsupp/builtins/udivmoddi4.c
@@ -1,231 +1,200 @@
-/* ===-- udivmoddi4.c - Implement __udivmoddi4 -----------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __udivmoddi4 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- udivmoddi4.c - Implement __udivmoddi4 -----------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __udivmoddi4 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
-/* Effects: if rem != 0, *rem = a % b
- * Returns: a / b
- */
+// Effects: if rem != 0, *rem = a % b
+// Returns: a / b
-/* Translated from Figure 3-40 of The PowerPC Compiler Writer's Guide */
+// Translated from Figure 3-40 of The PowerPC Compiler Writer's Guide
-COMPILER_RT_ABI du_int
-__udivmoddi4(du_int a, du_int b, du_int* rem)
-{
- const unsigned n_uword_bits = sizeof(su_int) * CHAR_BIT;
- const unsigned n_udword_bits = sizeof(du_int) * CHAR_BIT;
- udwords n;
- n.all = a;
- udwords d;
- d.all = b;
- udwords q;
- udwords r;
- unsigned sr;
- /* special cases, X is unknown, K != 0 */
- if (n.s.high == 0)
- {
- if (d.s.high == 0)
- {
- /* 0 X
- * ---
- * 0 X
- */
- if (rem)
- *rem = n.s.low % d.s.low;
- return n.s.low / d.s.low;
- }
- /* 0 X
- * ---
- * K X
- */
- if (rem)
- *rem = n.s.low;
- return 0;
+#if defined(_MSC_VER) && !defined(__clang__)
+// MSVC throws a warning about mod 0 here, disable it for builds that
+// warn-as-error
+#pragma warning(push)
+#pragma warning(disable : 4723 4724)
+#endif
+
+COMPILER_RT_ABI du_int __udivmoddi4(du_int a, du_int b, du_int *rem) {
+ const unsigned n_uword_bits = sizeof(su_int) * CHAR_BIT;
+ const unsigned n_udword_bits = sizeof(du_int) * CHAR_BIT;
+ udwords n;
+ n.all = a;
+ udwords d;
+ d.all = b;
+ udwords q;
+ udwords r;
+ unsigned sr;
+ // special cases, X is unknown, K != 0
+ if (n.s.high == 0) {
+ if (d.s.high == 0) {
+ // 0 X
+ // ---
+ // 0 X
+ if (rem)
+ *rem = n.s.low % d.s.low;
+ return n.s.low / d.s.low;
}
- /* n.s.high != 0 */
- if (d.s.low == 0)
- {
- if (d.s.high == 0)
- {
- /* K X
- * ---
- * 0 0
- */
- if (rem)
- *rem = n.s.high % d.s.low;
- return n.s.high / d.s.low;
- }
- /* d.s.high != 0 */
- if (n.s.low == 0)
- {
- /* K 0
- * ---
- * K 0
- */
- if (rem)
- {
- r.s.high = n.s.high % d.s.high;
- r.s.low = 0;
- *rem = r.all;
- }
- return n.s.high / d.s.high;
- }
- /* K K
- * ---
- * K 0
- */
- if ((d.s.high & (d.s.high - 1)) == 0) /* if d is a power of 2 */
- {
- if (rem)
- {
- r.s.low = n.s.low;
- r.s.high = n.s.high & (d.s.high - 1);
- *rem = r.all;
- }
- return n.s.high >> __builtin_ctz(d.s.high);
- }
- /* K K
- * ---
- * K 0
- */
- sr = __builtin_clz(d.s.high) - __builtin_clz(n.s.high);
- /* 0 <= sr <= n_uword_bits - 2 or sr large */
- if (sr > n_uword_bits - 2)
- {
- if (rem)
- *rem = n.all;
- return 0;
- }
- ++sr;
- /* 1 <= sr <= n_uword_bits - 1 */
- /* q.all = n.all << (n_udword_bits - sr); */
+ // 0 X
+ // ---
+ // K X
+ if (rem)
+ *rem = n.s.low;
+ return 0;
+ }
+ // n.s.high != 0
+ if (d.s.low == 0) {
+ if (d.s.high == 0) {
+ // K X
+ // ---
+ // 0 0
+ if (rem)
+ *rem = n.s.high % d.s.low;
+ return n.s.high / d.s.low;
+ }
+ // d.s.high != 0
+ if (n.s.low == 0) {
+ // K 0
+ // ---
+ // K 0
+ if (rem) {
+ r.s.high = n.s.high % d.s.high;
+ r.s.low = 0;
+ *rem = r.all;
+ }
+ return n.s.high / d.s.high;
+ }
+ // K K
+ // ---
+ // K 0
+ if ((d.s.high & (d.s.high - 1)) == 0) /* if d is a power of 2 */ {
+ if (rem) {
+ r.s.low = n.s.low;
+ r.s.high = n.s.high & (d.s.high - 1);
+ *rem = r.all;
+ }
+ return n.s.high >> ctzsi(d.s.high);
+ }
+ // K K
+ // ---
+ // K 0
+ sr = clzsi(d.s.high) - clzsi(n.s.high);
+ // 0 <= sr <= n_uword_bits - 2 or sr large
+ if (sr > n_uword_bits - 2) {
+ if (rem)
+ *rem = n.all;
+ return 0;
+ }
+ ++sr;
+ // 1 <= sr <= n_uword_bits - 1
+ // q.all = n.all << (n_udword_bits - sr);
+ q.s.low = 0;
+ q.s.high = n.s.low << (n_uword_bits - sr);
+ // r.all = n.all >> sr;
+ r.s.high = n.s.high >> sr;
+ r.s.low = (n.s.high << (n_uword_bits - sr)) | (n.s.low >> sr);
+ } else /* d.s.low != 0 */ {
+ if (d.s.high == 0) {
+ // K X
+ // ---
+ // 0 K
+ if ((d.s.low & (d.s.low - 1)) == 0) /* if d is a power of 2 */ {
+ if (rem)
+ *rem = n.s.low & (d.s.low - 1);
+ if (d.s.low == 1)
+ return n.all;
+ sr = ctzsi(d.s.low);
+ q.s.high = n.s.high >> sr;
+ q.s.low = (n.s.high << (n_uword_bits - sr)) | (n.s.low >> sr);
+ return q.all;
+ }
+ // K X
+ // ---
+ // 0 K
+ sr = 1 + n_uword_bits + clzsi(d.s.low) - clzsi(n.s.high);
+ // 2 <= sr <= n_udword_bits - 1
+ // q.all = n.all << (n_udword_bits - sr);
+ // r.all = n.all >> sr;
+ if (sr == n_uword_bits) {
+ q.s.low = 0;
+ q.s.high = n.s.low;
+ r.s.high = 0;
+ r.s.low = n.s.high;
+ } else if (sr < n_uword_bits) /* 2 <= sr <= n_uword_bits - 1 */ {
q.s.low = 0;
q.s.high = n.s.low << (n_uword_bits - sr);
- /* r.all = n.all >> sr; */
r.s.high = n.s.high >> sr;
r.s.low = (n.s.high << (n_uword_bits - sr)) | (n.s.low >> sr);
+ } else /* n_uword_bits + 1 <= sr <= n_udword_bits - 1 */ {
+ q.s.low = n.s.low << (n_udword_bits - sr);
+ q.s.high = (n.s.high << (n_udword_bits - sr)) |
+ (n.s.low >> (sr - n_uword_bits));
+ r.s.high = 0;
+ r.s.low = n.s.high >> (sr - n_uword_bits);
+ }
+ } else {
+ // K X
+ // ---
+ // K K
+ sr = clzsi(d.s.high) - clzsi(n.s.high);
+ // 0 <= sr <= n_uword_bits - 1 or sr large
+ if (sr > n_uword_bits - 1) {
+ if (rem)
+ *rem = n.all;
+ return 0;
+ }
+ ++sr;
+ // 1 <= sr <= n_uword_bits
+ // q.all = n.all << (n_udword_bits - sr);
+ q.s.low = 0;
+ if (sr == n_uword_bits) {
+ q.s.high = n.s.low;
+ r.s.high = 0;
+ r.s.low = n.s.high;
+ } else {
+ q.s.high = n.s.low << (n_uword_bits - sr);
+ r.s.high = n.s.high >> sr;
+ r.s.low = (n.s.high << (n_uword_bits - sr)) | (n.s.low >> sr);
+ }
}
- else /* d.s.low != 0 */
- {
- if (d.s.high == 0)
- {
- /* K X
- * ---
- * 0 K
- */
- if ((d.s.low & (d.s.low - 1)) == 0) /* if d is a power of 2 */
- {
- if (rem)
- *rem = n.s.low & (d.s.low - 1);
- if (d.s.low == 1)
- return n.all;
- sr = __builtin_ctz(d.s.low);
- q.s.high = n.s.high >> sr;
- q.s.low = (n.s.high << (n_uword_bits - sr)) | (n.s.low >> sr);
- return q.all;
- }
- /* K X
- * ---
- * 0 K
- */
- sr = 1 + n_uword_bits + __builtin_clz(d.s.low) - __builtin_clz(n.s.high);
- /* 2 <= sr <= n_udword_bits - 1
- * q.all = n.all << (n_udword_bits - sr);
- * r.all = n.all >> sr;
- */
- if (sr == n_uword_bits)
- {
- q.s.low = 0;
- q.s.high = n.s.low;
- r.s.high = 0;
- r.s.low = n.s.high;
- }
- else if (sr < n_uword_bits) // 2 <= sr <= n_uword_bits - 1
- {
- q.s.low = 0;
- q.s.high = n.s.low << (n_uword_bits - sr);
- r.s.high = n.s.high >> sr;
- r.s.low = (n.s.high << (n_uword_bits - sr)) | (n.s.low >> sr);
- }
- else // n_uword_bits + 1 <= sr <= n_udword_bits - 1
- {
- q.s.low = n.s.low << (n_udword_bits - sr);
- q.s.high = (n.s.high << (n_udword_bits - sr)) |
- (n.s.low >> (sr - n_uword_bits));
- r.s.high = 0;
- r.s.low = n.s.high >> (sr - n_uword_bits);
- }
- }
- else
- {
- /* K X
- * ---
- * K K
- */
- sr = __builtin_clz(d.s.high) - __builtin_clz(n.s.high);
- /* 0 <= sr <= n_uword_bits - 1 or sr large */
- if (sr > n_uword_bits - 1)
- {
- if (rem)
- *rem = n.all;
- return 0;
- }
- ++sr;
- /* 1 <= sr <= n_uword_bits */
- /* q.all = n.all << (n_udword_bits - sr); */
- q.s.low = 0;
- if (sr == n_uword_bits)
- {
- q.s.high = n.s.low;
- r.s.high = 0;
- r.s.low = n.s.high;
- }
- else
- {
- q.s.high = n.s.low << (n_uword_bits - sr);
- r.s.high = n.s.high >> sr;
- r.s.low = (n.s.high << (n_uword_bits - sr)) | (n.s.low >> sr);
- }
- }
- }
- /* Not a special case
- * q and r are initialized with:
- * q.all = n.all << (n_udword_bits - sr);
- * r.all = n.all >> sr;
- * 1 <= sr <= n_udword_bits - 1
- */
- su_int carry = 0;
- for (; sr > 0; --sr)
- {
- /* r:q = ((r:q) << 1) | carry */
- r.s.high = (r.s.high << 1) | (r.s.low >> (n_uword_bits - 1));
- r.s.low = (r.s.low << 1) | (q.s.high >> (n_uword_bits - 1));
- q.s.high = (q.s.high << 1) | (q.s.low >> (n_uword_bits - 1));
- q.s.low = (q.s.low << 1) | carry;
- /* carry = 0;
- * if (r.all >= d.all)
- * {
- * r.all -= d.all;
- * carry = 1;
- * }
- */
- const di_int s = (di_int)(d.all - r.all - 1) >> (n_udword_bits - 1);
- carry = s & 1;
- r.all -= d.all & s;
- }
- q.all = (q.all << 1) | carry;
- if (rem)
- *rem = r.all;
- return q.all;
+ }
+ // Not a special case
+ // q and r are initialized with:
+ // q.all = n.all << (n_udword_bits - sr);
+ // r.all = n.all >> sr;
+ // 1 <= sr <= n_udword_bits - 1
+ su_int carry = 0;
+ for (; sr > 0; --sr) {
+ // r:q = ((r:q) << 1) | carry
+ r.s.high = (r.s.high << 1) | (r.s.low >> (n_uword_bits - 1));
+ r.s.low = (r.s.low << 1) | (q.s.high >> (n_uword_bits - 1));
+ q.s.high = (q.s.high << 1) | (q.s.low >> (n_uword_bits - 1));
+ q.s.low = (q.s.low << 1) | carry;
+ // carry = 0;
+ // if (r.all >= d.all)
+ // {
+ // r.all -= d.all;
+ // carry = 1;
+ // }
+ const di_int s = (di_int)(d.all - r.all - 1) >> (n_udword_bits - 1);
+ carry = s & 1;
+ r.all -= d.all & s;
+ }
+ q.all = (q.all << 1) | carry;
+ if (rem)
+ *rem = r.all;
+ return q.all;
}
+
+#if defined(_MSC_VER) && !defined(__clang__)
+#pragma warning(pop)
+#endif
diff --git a/contrib/libs/cxxsupp/builtins/udivmodsi4.c b/contrib/libs/cxxsupp/builtins/udivmodsi4.c
index 789c4b5061..753ad6dd96 100644
--- a/contrib/libs/cxxsupp/builtins/udivmodsi4.c
+++ b/contrib/libs/cxxsupp/builtins/udivmodsi4.c
@@ -1,27 +1,21 @@
-/*===-- udivmodsi4.c - Implement __udivmodsi4 ------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __udivmodsi4 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- udivmodsi4.c - Implement __udivmodsi4 -----------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __udivmodsi4 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
-/* Returns: a / b, *rem = a % b */
+// Returns: a / b, *rem = a % b
-COMPILER_RT_ABI su_int
-__udivmodsi4(su_int a, su_int b, su_int* rem)
-{
- si_int d = __udivsi3(a,b);
- *rem = a - (d*b);
+COMPILER_RT_ABI su_int __udivmodsi4(su_int a, su_int b, su_int *rem) {
+ si_int d = __udivsi3(a, b);
+ *rem = a - (d * b);
return d;
}
-
-
diff --git a/contrib/libs/cxxsupp/builtins/udivmodti4.c b/contrib/libs/cxxsupp/builtins/udivmodti4.c
index 803168849c..55def37c9e 100644
--- a/contrib/libs/cxxsupp/builtins/udivmodti4.c
+++ b/contrib/libs/cxxsupp/builtins/udivmodti4.c
@@ -1,238 +1,158 @@
-/* ===-- udivmodti4.c - Implement __udivmodti4 -----------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __udivmodti4 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- udivmodti4.c - Implement __udivmodti4 -----------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __udivmodti4 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
#ifdef CRT_HAS_128BIT
-/* Effects: if rem != 0, *rem = a % b
- * Returns: a / b
- */
-
-/* Translated from Figure 3-40 of The PowerPC Compiler Writer's Guide */
-
-COMPILER_RT_ABI tu_int
-__udivmodti4(tu_int a, tu_int b, tu_int* rem)
-{
- const unsigned n_udword_bits = sizeof(du_int) * CHAR_BIT;
- const unsigned n_utword_bits = sizeof(tu_int) * CHAR_BIT;
- utwords n;
- n.all = a;
- utwords d;
- d.all = b;
- utwords q;
- utwords r;
- unsigned sr;
- /* special cases, X is unknown, K != 0 */
- if (n.s.high == 0)
- {
- if (d.s.high == 0)
- {
- /* 0 X
- * ---
- * 0 X
- */
- if (rem)
- *rem = n.s.low % d.s.low;
- return n.s.low / d.s.low;
- }
- /* 0 X
- * ---
- * K X
- */
- if (rem)
- *rem = n.s.low;
- return 0;
- }
- /* n.s.high != 0 */
- if (d.s.low == 0)
- {
- if (d.s.high == 0)
- {
- /* K X
- * ---
- * 0 0
- */
- if (rem)
- *rem = n.s.high % d.s.low;
- return n.s.high / d.s.low;
- }
- /* d.s.high != 0 */
- if (n.s.low == 0)
- {
- /* K 0
- * ---
- * K 0
- */
- if (rem)
- {
- r.s.high = n.s.high % d.s.high;
- r.s.low = 0;
- *rem = r.all;
- }
- return n.s.high / d.s.high;
- }
- /* K K
- * ---
- * K 0
- */
- if ((d.s.high & (d.s.high - 1)) == 0) /* if d is a power of 2 */
- {
- if (rem)
- {
- r.s.low = n.s.low;
- r.s.high = n.s.high & (d.s.high - 1);
- *rem = r.all;
- }
- return n.s.high >> __builtin_ctzll(d.s.high);
- }
- /* K K
- * ---
- * K 0
- */
- sr = __builtin_clzll(d.s.high) - __builtin_clzll(n.s.high);
- /* 0 <= sr <= n_udword_bits - 2 or sr large */
- if (sr > n_udword_bits - 2)
- {
- if (rem)
- *rem = n.all;
- return 0;
- }
- ++sr;
- /* 1 <= sr <= n_udword_bits - 1 */
- /* q.all = n.all << (n_utword_bits - sr); */
- q.s.low = 0;
- q.s.high = n.s.low << (n_udword_bits - sr);
- /* r.all = n.all >> sr; */
- r.s.high = n.s.high >> sr;
- r.s.low = (n.s.high << (n_udword_bits - sr)) | (n.s.low >> sr);
- }
- else /* d.s.low != 0 */
- {
- if (d.s.high == 0)
- {
- /* K X
- * ---
- * 0 K
- */
- if ((d.s.low & (d.s.low - 1)) == 0) /* if d is a power of 2 */
- {
- if (rem)
- *rem = n.s.low & (d.s.low - 1);
- if (d.s.low == 1)
- return n.all;
- sr = __builtin_ctzll(d.s.low);
- q.s.high = n.s.high >> sr;
- q.s.low = (n.s.high << (n_udword_bits - sr)) | (n.s.low >> sr);
- return q.all;
- }
- /* K X
- * ---
- * 0 K
- */
- sr = 1 + n_udword_bits + __builtin_clzll(d.s.low)
- - __builtin_clzll(n.s.high);
- /* 2 <= sr <= n_utword_bits - 1
- * q.all = n.all << (n_utword_bits - sr);
- * r.all = n.all >> sr;
- */
- if (sr == n_udword_bits)
- {
- q.s.low = 0;
- q.s.high = n.s.low;
- r.s.high = 0;
- r.s.low = n.s.high;
- }
- else if (sr < n_udword_bits) // 2 <= sr <= n_udword_bits - 1
- {
- q.s.low = 0;
- q.s.high = n.s.low << (n_udword_bits - sr);
- r.s.high = n.s.high >> sr;
- r.s.low = (n.s.high << (n_udword_bits - sr)) | (n.s.low >> sr);
- }
- else // n_udword_bits + 1 <= sr <= n_utword_bits - 1
- {
- q.s.low = n.s.low << (n_utword_bits - sr);
- q.s.high = (n.s.high << (n_utword_bits - sr)) |
- (n.s.low >> (sr - n_udword_bits));
- r.s.high = 0;
- r.s.low = n.s.high >> (sr - n_udword_bits);
- }
- }
- else
- {
- /* K X
- * ---
- * K K
- */
- sr = __builtin_clzll(d.s.high) - __builtin_clzll(n.s.high);
- /*0 <= sr <= n_udword_bits - 1 or sr large */
- if (sr > n_udword_bits - 1)
- {
- if (rem)
- *rem = n.all;
- return 0;
- }
- ++sr;
- /* 1 <= sr <= n_udword_bits
- * q.all = n.all << (n_utword_bits - sr);
- * r.all = n.all >> sr;
- */
- q.s.low = 0;
- if (sr == n_udword_bits)
- {
- q.s.high = n.s.low;
- r.s.high = 0;
- r.s.low = n.s.high;
- }
- else
- {
- r.s.high = n.s.high >> sr;
- r.s.low = (n.s.high << (n_udword_bits - sr)) | (n.s.low >> sr);
- q.s.high = n.s.low << (n_udword_bits - sr);
- }
- }
- }
- /* Not a special case
- * q and r are initialized with:
- * q.all = n.all << (n_utword_bits - sr);
- * r.all = n.all >> sr;
- * 1 <= sr <= n_utword_bits - 1
- */
- su_int carry = 0;
- for (; sr > 0; --sr)
- {
- /* r:q = ((r:q) << 1) | carry */
- r.s.high = (r.s.high << 1) | (r.s.low >> (n_udword_bits - 1));
- r.s.low = (r.s.low << 1) | (q.s.high >> (n_udword_bits - 1));
- q.s.high = (q.s.high << 1) | (q.s.low >> (n_udword_bits - 1));
- q.s.low = (q.s.low << 1) | carry;
- /* carry = 0;
- * if (r.all >= d.all)
- * {
- * r.all -= d.all;
- * carry = 1;
- * }
- */
- const ti_int s = (ti_int)(d.all - r.all - 1) >> (n_utword_bits - 1);
- carry = s & 1;
- r.all -= d.all & s;
+// Returns the 128 bit division result by 64 bit. Result must fit in 64 bits.
+// Remainder stored in r.
+// Taken and adjusted from libdivide libdivide_128_div_64_to_64 division
+// fallback. For a correctness proof see the reference for this algorithm
+// in Knuth, Volume 2, section 4.3.1, Algorithm D.
+UNUSED
+static inline du_int udiv128by64to64default(du_int u1, du_int u0, du_int v,
+ du_int *r) {
+ const unsigned n_udword_bits = sizeof(du_int) * CHAR_BIT;
+ const du_int b = (1ULL << (n_udword_bits / 2)); // Number base (32 bits)
+ du_int un1, un0; // Norm. dividend LSD's
+ du_int vn1, vn0; // Norm. divisor digits
+ du_int q1, q0; // Quotient digits
+ du_int un64, un21, un10; // Dividend digit pairs
+ du_int rhat; // A remainder
+ si_int s; // Shift amount for normalization
+
+ s = __builtin_clzll(v);
+ if (s > 0) {
+ // Normalize the divisor.
+ v = v << s;
+ un64 = (u1 << s) | (u0 >> (n_udword_bits - s));
+ un10 = u0 << s; // Shift dividend left
+ } else {
+ // Avoid undefined behavior of (u0 >> 64).
+ un64 = u1;
+ un10 = u0;
+ }
+
+ // Break divisor up into two 32-bit digits.
+ vn1 = v >> (n_udword_bits / 2);
+ vn0 = v & 0xFFFFFFFF;
+
+ // Break right half of dividend into two digits.
+ un1 = un10 >> (n_udword_bits / 2);
+ un0 = un10 & 0xFFFFFFFF;
+
+ // Compute the first quotient digit, q1.
+ q1 = un64 / vn1;
+ rhat = un64 - q1 * vn1;
+
+ // q1 has at most error 2. No more than 2 iterations.
+ while (q1 >= b || q1 * vn0 > b * rhat + un1) {
+ q1 = q1 - 1;
+ rhat = rhat + vn1;
+ if (rhat >= b)
+ break;
+ }
+
+ un21 = un64 * b + un1 - q1 * v;
+
+ // Compute the second quotient digit.
+ q0 = un21 / vn1;
+ rhat = un21 - q0 * vn1;
+
+ // q0 has at most error 2. No more than 2 iterations.
+ while (q0 >= b || q0 * vn0 > b * rhat + un0) {
+ q0 = q0 - 1;
+ rhat = rhat + vn1;
+ if (rhat >= b)
+ break;
+ }
+
+ *r = (un21 * b + un0 - q0 * v) >> s;
+ return q1 * b + q0;
+}
+
+static inline du_int udiv128by64to64(du_int u1, du_int u0, du_int v,
+ du_int *r) {
+#if defined(__x86_64__)
+ du_int result;
+ __asm__("divq %[v]"
+ : "=a"(result), "=d"(*r)
+ : [ v ] "r"(v), "a"(u0), "d"(u1));
+ return result;
+#else
+ return udiv128by64to64default(u1, u0, v, r);
+#endif
+}
+
+// Effects: if rem != 0, *rem = a % b
+// Returns: a / b
+
+COMPILER_RT_ABI tu_int __udivmodti4(tu_int a, tu_int b, tu_int *rem) {
+ const unsigned n_utword_bits = sizeof(tu_int) * CHAR_BIT;
+ utwords dividend;
+ dividend.all = a;
+ utwords divisor;
+ divisor.all = b;
+ utwords quotient;
+ utwords remainder;
+ if (divisor.all > dividend.all) {
+ if (rem)
+ *rem = dividend.all;
+ return 0;
+ }
+ // When the divisor fits in 64 bits, we can use an optimized path.
+ if (divisor.s.high == 0) {
+ remainder.s.high = 0;
+ if (dividend.s.high < divisor.s.low) {
+ // The result fits in 64 bits.
+ quotient.s.low = udiv128by64to64(dividend.s.high, dividend.s.low,
+ divisor.s.low, &remainder.s.low);
+ quotient.s.high = 0;
+ } else {
+ // First, divide with the high part to get the remainder in dividend.s.high.
+ // After that dividend.s.high < divisor.s.low.
+ quotient.s.high = dividend.s.high / divisor.s.low;
+ dividend.s.high = dividend.s.high % divisor.s.low;
+ quotient.s.low = udiv128by64to64(dividend.s.high, dividend.s.low,
+ divisor.s.low, &remainder.s.low);
}
- q.all = (q.all << 1) | carry;
if (rem)
- *rem = r.all;
- return q.all;
+ *rem = remainder.all;
+ return quotient.all;
+ }
+ // 0 <= shift <= 63.
+ si_int shift =
+ __builtin_clzll(divisor.s.high) - __builtin_clzll(dividend.s.high);
+ divisor.all <<= shift;
+ quotient.s.high = 0;
+ quotient.s.low = 0;
+ for (; shift >= 0; --shift) {
+ quotient.s.low <<= 1;
+ // Branch free version of.
+ // if (dividend.all >= divisor.all)
+ // {
+ // dividend.all -= divisor.all;
+ // carry = 1;
+ // }
+ const ti_int s =
+ (ti_int)(divisor.all - dividend.all - 1) >> (n_utword_bits - 1);
+ quotient.s.low |= s & 1;
+ dividend.all -= divisor.all & s;
+ divisor.all >>= 1;
+ }
+ if (rem)
+ *rem = dividend.all;
+ return quotient.all;
}
-#endif /* CRT_HAS_128BIT */
+#endif // CRT_HAS_128BIT
diff --git a/contrib/libs/cxxsupp/builtins/udivsi3.c b/contrib/libs/cxxsupp/builtins/udivsi3.c
index 5d0140cc3e..3894e15975 100644
--- a/contrib/libs/cxxsupp/builtins/udivsi3.c
+++ b/contrib/libs/cxxsupp/builtins/udivsi3.c
@@ -1,66 +1,27 @@
-/* ===-- udivsi3.c - Implement __udivsi3 -----------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __udivsi3 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- udivsi3.c - Implement __udivsi3 -----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __udivsi3 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
-/* Returns: a / b */
+typedef su_int fixuint_t;
+typedef si_int fixint_t;
+#include "int_div_impl.inc"
-/* Translated from Figure 3-40 of The PowerPC Compiler Writer's Guide */
+// Returns: a / b
-ARM_EABI_FNALIAS(uidiv, udivsi3)
-
-/* This function should not call __divsi3! */
-COMPILER_RT_ABI su_int
-__udivsi3(su_int n, su_int d)
-{
- const unsigned n_uword_bits = sizeof(su_int) * CHAR_BIT;
- su_int q;
- su_int r;
- unsigned sr;
- /* special cases */
- if (d == 0)
- return 0; /* ?! */
- if (n == 0)
- return 0;
- sr = __builtin_clz(d) - __builtin_clz(n);
- /* 0 <= sr <= n_uword_bits - 1 or sr large */
- if (sr > n_uword_bits - 1) /* d > r */
- return 0;
- if (sr == n_uword_bits - 1) /* d == 1 */
- return n;
- ++sr;
- /* 1 <= sr <= n_uword_bits - 1 */
- /* Not a special case */
- q = n << (n_uword_bits - sr);
- r = n >> sr;
- su_int carry = 0;
- for (; sr > 0; --sr)
- {
- /* r:q = ((r:q) << 1) | carry */
- r = (r << 1) | (q >> (n_uword_bits - 1));
- q = (q << 1) | carry;
- /* carry = 0;
- * if (r.all >= d.all)
- * {
- * r.all -= d.all;
- * carry = 1;
- * }
- */
- const si_int s = (si_int)(d - r - 1) >> (n_uword_bits - 1);
- carry = s & 1;
- r -= d & s;
- }
- q = (q << 1) | carry;
- return q;
+COMPILER_RT_ABI su_int __udivsi3(su_int a, su_int b) {
+ return __udivXi3(a, b);
}
+
+#if defined(__ARM_EABI__)
+COMPILER_RT_ALIAS(__udivsi3, __aeabi_uidiv)
+#endif
diff --git a/contrib/libs/cxxsupp/builtins/udivti3.c b/contrib/libs/cxxsupp/builtins/udivti3.c
index ec94673e25..4c82040b88 100644
--- a/contrib/libs/cxxsupp/builtins/udivti3.c
+++ b/contrib/libs/cxxsupp/builtins/udivti3.c
@@ -1,27 +1,23 @@
-/* ===-- udivti3.c - Implement __udivti3 -----------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __udivti3 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- udivti3.c - Implement __udivti3 -----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __udivti3 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
#ifdef CRT_HAS_128BIT
-/* Returns: a / b */
+// Returns: a / b
-COMPILER_RT_ABI tu_int
-__udivti3(tu_int a, tu_int b)
-{
- return __udivmodti4(a, b, 0);
+COMPILER_RT_ABI tu_int __udivti3(tu_int a, tu_int b) {
+ return __udivmodti4(a, b, 0);
}
-#endif /* CRT_HAS_128BIT */
+#endif // CRT_HAS_128BIT
diff --git a/contrib/libs/cxxsupp/builtins/umoddi3.c b/contrib/libs/cxxsupp/builtins/umoddi3.c
index d513f080a1..e672da96ef 100644
--- a/contrib/libs/cxxsupp/builtins/umoddi3.c
+++ b/contrib/libs/cxxsupp/builtins/umoddi3.c
@@ -1,25 +1,23 @@
-/* ===-- umoddi3.c - Implement __umoddi3 -----------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __umoddi3 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- umoddi3.c - Implement __umoddi3 -----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __umoddi3 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
-/* Returns: a % b */
+typedef du_int fixuint_t;
+typedef di_int fixint_t;
+#include "int_div_impl.inc"
-COMPILER_RT_ABI du_int
-__umoddi3(du_int a, du_int b)
-{
- du_int r;
- __udivmoddi4(a, b, &r);
- return r;
+// Returns: a % b
+
+COMPILER_RT_ABI du_int __umoddi3(du_int a, du_int b) {
+ return __umodXi3(a, b);
}
diff --git a/contrib/libs/cxxsupp/builtins/umodsi3.c b/contrib/libs/cxxsupp/builtins/umodsi3.c
index d5fda4a6af..5383aea656 100644
--- a/contrib/libs/cxxsupp/builtins/umodsi3.c
+++ b/contrib/libs/cxxsupp/builtins/umodsi3.c
@@ -1,23 +1,23 @@
-/* ===-- umodsi3.c - Implement __umodsi3 -----------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __umodsi3 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- umodsi3.c - Implement __umodsi3 -----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __umodsi3 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
-/* Returns: a % b */
+typedef su_int fixuint_t;
+typedef si_int fixint_t;
+#include "int_div_impl.inc"
-COMPILER_RT_ABI su_int
-__umodsi3(su_int a, su_int b)
-{
- return a - __udivsi3(a, b) * b;
+// Returns: a % b
+
+COMPILER_RT_ABI su_int __umodsi3(su_int a, su_int b) {
+ return __umodXi3(a, b);
}
diff --git a/contrib/libs/cxxsupp/builtins/umodti3.c b/contrib/libs/cxxsupp/builtins/umodti3.c
index 6d1ca7a8cf..8cc5cb6b88 100644
--- a/contrib/libs/cxxsupp/builtins/umodti3.c
+++ b/contrib/libs/cxxsupp/builtins/umodti3.c
@@ -1,29 +1,25 @@
-/* ===-- umodti3.c - Implement __umodti3 -----------------------------------===
- *
- * The LLVM Compiler Infrastructure
- *
- * This file is dual licensed under the MIT and the University of Illinois Open
- * Source Licenses. See LICENSE.TXT for details.
- *
- * ===----------------------------------------------------------------------===
- *
- * This file implements __umodti3 for the compiler_rt library.
- *
- * ===----------------------------------------------------------------------===
- */
+//===-- umodti3.c - Implement __umodti3 -----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements __umodti3 for the compiler_rt library.
+//
+//===----------------------------------------------------------------------===//
#include "int_lib.h"
#ifdef CRT_HAS_128BIT
-/* Returns: a % b */
+// Returns: a % b
-COMPILER_RT_ABI tu_int
-__umodti3(tu_int a, tu_int b)
-{
- tu_int r;
- __udivmodti4(a, b, &r);
- return r;
+COMPILER_RT_ABI tu_int __umodti3(tu_int a, tu_int b) {
+ tu_int r;
+ __udivmodti4(a, b, &r);
+ return r;
}
-#endif /* CRT_HAS_128BIT */
+#endif // CRT_HAS_128BIT
diff --git a/contrib/libs/cxxsupp/builtins/unwind-ehabi-helpers.h b/contrib/libs/cxxsupp/builtins/unwind-ehabi-helpers.h
new file mode 100644
index 0000000000..1b48cdb75e
--- /dev/null
+++ b/contrib/libs/cxxsupp/builtins/unwind-ehabi-helpers.h
@@ -0,0 +1,51 @@
+//===-- arm-ehabi-helpers.h - Supplementary ARM EHABI declarations --------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===--------------------------------------------------------------------===//
+
+#ifndef UNWIND_EHABI_HELPERS_H
+#define UNWIND_EHABI_HELPERS_H
+
+#include <stdint.h>
+// NOTE: see reasoning for this inclusion below
+#include <unwind.h>
+
+#if !defined(__ARM_EABI_UNWINDER__)
+
+// NOTE: _URC_OK, _URC_FAILURE must be present as preprocessor tokens. This
+// allows for a substitution of a constant which can be cast into the
+// appropriate enumerated type. This header is expected to always be included
+// AFTER unwind.h (which is why it is forcefully included above). This ensures
+// that we do not overwrite the token for the enumeration. Subsequent uses of
+// the token would be clean to rewrite with constant values.
+//
+// The typedef redeclaration should be safe. Due to the protection granted to
+// us by the `__ARM_EABI_UNWINDER__` above, we are guaranteed that we are in a
+// header not vended by gcc. The HP unwinder (being an itanium unwinder) does
+// not support EHABI, and the GNU unwinder, derived from the HP unwinder, also
+// does not support EHABI as of the introduction of this header. As such, we
+// are fairly certain that we are in the LLVM case. Here, _Unwind_State is a
+// typedef, and so we can get away with a redeclaration.
+//
+// Guarded redefinitions of the needed unwind state prevent the redefinition of
+// those states.
+
+#define _URC_OK 0
+#define _URC_FAILURE 9
+
+typedef uint32_t _Unwind_State;
+
+#if !defined(_US_UNWIND_FRAME_STARTING)
+#define _US_UNWIND_FRAME_STARTING ((_Unwind_State)1)
+#endif
+
+#if !defined(_US_ACTION_MASK)
+#define _US_ACTION_MASK ((_Unwind_State)3)
+#endif
+
+#endif
+
+#endif
diff --git a/contrib/libs/cxxsupp/builtins/ve/grow_stack.S b/contrib/libs/cxxsupp/builtins/ve/grow_stack.S
new file mode 100644
index 0000000000..f403798495
--- /dev/null
+++ b/contrib/libs/cxxsupp/builtins/ve/grow_stack.S
@@ -0,0 +1,31 @@
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+#include "../assembly.h"
+
+// grow_stack routine
+// This routine is VE specific
+// https://www.nec.com/en/global/prod/hpc/aurora/document/VE-ABI_v1.1.pdf
+
+// destroy %s62 and %s63 only
+
+#ifdef __ve__
+
+.text
+.p2align 4
+DEFINE_COMPILERRT_FUNCTION(__ve_grow_stack)
+ subu.l %sp, %sp, %s0 # sp -= alloca size
+ and %sp, -16, %sp # align sp
+ brge.l.t %sp, %sl, 1f
+ ld %s63, 0x18(,%tp) # load param area
+ lea %s62, 0x13b # syscall # of grow
+ shm.l %s62, 0x0(%s63) # stored at addr:0
+ shm.l %sl, 0x8(%s63) # old limit at addr:8
+ shm.l %sp, 0x10(%s63) # new limit at addr:16
+ monc
+1:
+ b.l (,%lr)
+END_COMPILERRT_FUNCTION(__ve_grow_stack)
+
+#endif // __ve__
diff --git a/contrib/libs/cxxsupp/builtins/ve/grow_stack_align.S b/contrib/libs/cxxsupp/builtins/ve/grow_stack_align.S
new file mode 100644
index 0000000000..19a1dfa872
--- /dev/null
+++ b/contrib/libs/cxxsupp/builtins/ve/grow_stack_align.S
@@ -0,0 +1,31 @@
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+#include "../assembly.h"
+
+// grow_stack routine
+// This routine is VE specific
+// https://www.nec.com/en/global/prod/hpc/aurora/document/VE-ABI_v1.1.pdf
+
+// destroy %s62 and %s63 only
+
+#ifdef __ve__
+
+.text
+.p2align 4
+DEFINE_COMPILERRT_FUNCTION(__ve_grow_stack_align)
+ subu.l %sp, %sp, %s0 # sp -= alloca size
+ and %sp, %sp, %s1 # align sp
+ brge.l.t %sp, %sl, 1f
+ ld %s63, 0x18(,%tp) # load param area
+ lea %s62, 0x13b # syscall # of grow
+ shm.l %s62, 0x0(%s63) # stored at addr:0
+ shm.l %sl, 0x8(%s63) # old limit at addr:8
+ shm.l %sp, 0x10(%s63) # new limit at addr:16
+ monc
+1:
+ b.l (,%lr)
+END_COMPILERRT_FUNCTION(__ve_grow_stack_align)
+
+#endif // __ve__
diff --git a/contrib/libs/cxxsupp/builtins/x86_64/Makefile.mk b/contrib/libs/cxxsupp/builtins/x86_64/Makefile.mk
deleted file mode 100644
index 83848dddd9..0000000000
--- a/contrib/libs/cxxsupp/builtins/x86_64/Makefile.mk
+++ /dev/null
@@ -1,20 +0,0 @@
-#===- lib/builtins/x86_64/Makefile.mk ----------------------*- Makefile -*--===#
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-#===------------------------------------------------------------------------===#
-
-ModuleName := builtins
-SubDirs :=
-OnlyArchs := x86_64 x86_64h
-
-AsmSources := $(foreach file,$(wildcard $(Dir)/*.S),$(notdir $(file)))
-Sources := $(foreach file,$(wildcard $(Dir)/*.c),$(notdir $(file)))
-ObjNames := $(Sources:%.c=%.o) $(AsmSources:%.S=%.o)
-Implementation := Optimized
-
-# FIXME: use automatic dependencies?
-Dependencies := $(wildcard lib/*.h $(Dir)/*.h)
diff --git a/contrib/libs/cxxsupp/builtins/x86_64/chkstk.S b/contrib/libs/cxxsupp/builtins/x86_64/chkstk.S
index 4149ac63d9..ad7953a116 100644
--- a/contrib/libs/cxxsupp/builtins/x86_64/chkstk.S
+++ b/contrib/libs/cxxsupp/builtins/x86_64/chkstk.S
@@ -1,5 +1,6 @@
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#include "../assembly.h"
diff --git a/contrib/libs/cxxsupp/builtins/x86_64/chkstk2.S b/contrib/libs/cxxsupp/builtins/x86_64/chkstk2.S
index ac1eb920e0..33d10d5b63 100644
--- a/contrib/libs/cxxsupp/builtins/x86_64/chkstk2.S
+++ b/contrib/libs/cxxsupp/builtins/x86_64/chkstk2.S
@@ -1,5 +1,6 @@
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#include "../assembly.h"
diff --git a/contrib/libs/cxxsupp/builtins/x86_64/floatdidf.c b/contrib/libs/cxxsupp/builtins/x86_64/floatdidf.c
index 388404e5e0..f83f53a38e 100644
--- a/contrib/libs/cxxsupp/builtins/x86_64/floatdidf.c
+++ b/contrib/libs/cxxsupp/builtins/x86_64/floatdidf.c
@@ -1,16 +1,13 @@
-/* This file is distributed under the University of Illinois Open Source
- * License. See LICENSE.TXT for details.
- */
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-/* double __floatdidf(di_int a); */
+// double __floatdidf(di_int a);
-#ifdef __x86_64__
+#if defined(__x86_64__) || defined(_M_X64)
#include "../int_lib.h"
-double __floatdidf(int64_t a)
-{
- return (double)a;
-}
+double __floatdidf(int64_t a) { return (double)a; }
-#endif /* __x86_64__ */
+#endif // __x86_64__
diff --git a/contrib/libs/cxxsupp/builtins/x86_64/floatdisf.c b/contrib/libs/cxxsupp/builtins/x86_64/floatdisf.c
index 96c3728e92..06c118cfa1 100644
--- a/contrib/libs/cxxsupp/builtins/x86_64/floatdisf.c
+++ b/contrib/libs/cxxsupp/builtins/x86_64/floatdisf.c
@@ -1,14 +1,11 @@
-/* This file is distributed under the University of Illinois Open Source
- * License. See LICENSE.TXT for details.
- */
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-#ifdef __x86_64__
+#if defined(__x86_64__) || defined(_M_X64)
#include "../int_lib.h"
-float __floatdisf(int64_t a)
-{
- return (float)a;
-}
+float __floatdisf(int64_t a) { return (float)a; }
-#endif /* __x86_64__ */
+#endif // __x86_64__
diff --git a/contrib/libs/cxxsupp/builtins/x86_64/floatdixf.c b/contrib/libs/cxxsupp/builtins/x86_64/floatdixf.c
index c01193a82b..cf8450ce6f 100644
--- a/contrib/libs/cxxsupp/builtins/x86_64/floatdixf.c
+++ b/contrib/libs/cxxsupp/builtins/x86_64/floatdixf.c
@@ -1,16 +1,13 @@
-/* This file is distributed under the University of Illinois Open Source
- * License. See LICENSE.TXT for details.
- */
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-/* long double __floatdixf(di_int a); */
+// long double __floatdixf(di_int a);
#ifdef __x86_64__
#include "../int_lib.h"
-long double __floatdixf(int64_t a)
-{
- return (long double)a;
-}
+long double __floatdixf(int64_t a) { return (long double)a; }
-#endif /* __i386__ */
+#endif // __i386__
diff --git a/contrib/libs/cxxsupp/builtins/x86_64/floatundidf.S b/contrib/libs/cxxsupp/builtins/x86_64/floatundidf.S
index 3cd5d02a74..7f6ef3bbb6 100644
--- a/contrib/libs/cxxsupp/builtins/x86_64/floatundidf.S
+++ b/contrib/libs/cxxsupp/builtins/x86_64/floatundidf.S
@@ -1,9 +1,8 @@
//===-- floatundidf.S - Implement __floatundidf for x86_64 ----------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -47,3 +46,6 @@ DEFINE_COMPILERRT_FUNCTION(__floatundidf)
END_COMPILERRT_FUNCTION(__floatundidf)
#endif // __x86_64__
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/x86_64/floatundisf.S b/contrib/libs/cxxsupp/builtins/x86_64/floatundisf.S
index 61952f4047..246bdff5a4 100644
--- a/contrib/libs/cxxsupp/builtins/x86_64/floatundisf.S
+++ b/contrib/libs/cxxsupp/builtins/x86_64/floatundisf.S
@@ -1,5 +1,6 @@
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#include "../assembly.h"
@@ -23,7 +24,7 @@ DEFINE_COMPILERRT_FUNCTION(__floatundisf)
js 1f
cvtsi2ssq %rdi, %xmm0
ret
-
+
1: andq %rdi, %rsi
shrq %rdi
orq %rsi, %rdi
@@ -33,3 +34,6 @@ DEFINE_COMPILERRT_FUNCTION(__floatundisf)
END_COMPILERRT_FUNCTION(__floatundisf)
#endif // __x86_64__
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/x86_64/floatundixf.S b/contrib/libs/cxxsupp/builtins/x86_64/floatundixf.S
index 92961c8911..9e3bcedcb7 100644
--- a/contrib/libs/cxxsupp/builtins/x86_64/floatundixf.S
+++ b/contrib/libs/cxxsupp/builtins/x86_64/floatundixf.S
@@ -1,5 +1,6 @@
-// This file is dual licensed under the MIT and the University of Illinois Open
-// Source Licenses. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#include "../assembly.h"
@@ -57,7 +58,7 @@ DEFINE_COMPILERRT_FUNCTION(__floatundixf)
orq REL_ADDR(twop52), %rsi // 2^52 + lo (as a double)
movq %rdi, -8(%rsp)
movq %rsi, -16(%rsp)
- fldl REL_ADDR(twop84_plus_twop52_neg)
+ fldl REL_ADDR(twop84_plus_twop52_neg)
faddl -8(%rsp) // hi - 2^52 (as double extended, no rounding occurs)
faddl -16(%rsp) // hi + lo (as double extended)
ret
@@ -66,3 +67,6 @@ END_COMPILERRT_FUNCTION(__floatundixf)
#endif // __x86_64__
*/
+
+NO_EXEC_STACK_DIRECTIVE
+
diff --git a/contrib/libs/cxxsupp/builtins/ya.make b/contrib/libs/cxxsupp/builtins/ya.make
index b8b603670a..8b0bb97bd9 100644
--- a/contrib/libs/cxxsupp/builtins/ya.make
+++ b/contrib/libs/cxxsupp/builtins/ya.make
@@ -1,13 +1,6 @@
-LIBRARY()
-
-# Part of compiler-rt LLVM subproject
+# Generated by devtools/yamaker/ym2
-# git repository: https://github.com/llvm/llvm-project.git
-# directory: compiler-rt/lib/builtins
-# revision: 08f0372c351a57b01afee6c64066961203da28c5
-
-# os_version_check.c was taken from revision 81b89fd7bdddb7da66f2cdace97d6ede5f99d58a
-# os_version_check.c was patched from git repository https://github.com/apple/llvm-project.git revision a02454b91d2aec347b9ce03020656c445f3b2841
+LIBRARY()
LICENSE(
Apache-2.0 AND
@@ -18,9 +11,11 @@ LICENSE(
LICENSE_TEXTS(.yandex_meta/licenses.list.txt)
-VERSION(2016-03-03-08f0372c351a57b01afee6c64066961203da28c5)
+VERSION(16.0.6)
-ORIGINAL_SOURCE(https://github.com/llvm/llvm-project)
+ORIGINAL_SOURCE(https://github.com/llvm/llvm-project/releases/download/llvmorg-16.0.6/compiler-rt-16.0.6.src.tar.xz)
+
+NO_COMPILER_WARNINGS()
# Check MUSL before NO_PLATFORM() disables it.
IF (MUSL)
@@ -33,13 +28,11 @@ IF (MUSL)
contrib/libs/musl/arch/x86_64
)
ENDIF()
-
IF (ARCH_AARCH64)
ADDINCL(
contrib/libs/musl/arch/aarch64
)
ENDIF()
-
ADDINCL(
contrib/libs/musl/arch/generic
contrib/libs/musl/include
@@ -67,64 +60,197 @@ IF (GCC OR CLANG)
ENDIF()
SRCS(
+ absvdi2.c
+ absvsi2.c
+ absvti2.c
+ adddf3.c
+ addsf3.c
addtf3.c
+ addvdi3.c
+ addvsi3.c
+ addvti3.c
+ apple_versioning.c
+ ashldi3.c
ashlti3.c
+ ashrdi3.c
+ ashrti3.c
+ atomic.c
+ atomic_flag_clear.c
+ atomic_flag_clear_explicit.c
+ atomic_flag_test_and_set.c
+ atomic_flag_test_and_set_explicit.c
+ atomic_signal_fence.c
+ atomic_thread_fence.c
+ bswapdi2.c
+ bswapsi2.c
+ clear_cache.c
+ clzdi2.c
+ clzsi2.c
clzti2.c
+ cmpdi2.c
+ cmpti2.c
+ comparedf2.c
+ comparesf2.c
comparetf2.c
+ cpu_model.c
+ ctzdi2.c
+ ctzsi2.c
+ ctzti2.c
divdc3.c
+ divdf3.c
+ divdi3.c
+ divmoddi4.c
+ divmodsi4.c
+ divmodti4.c
divsc3.c
+ divsf3.c
+ divsi3.c
+ divtc3.c
divtf3.c
divti3.c
divxc3.c
+ emutls.c
+ enable_execute_stack.c
+ eprintf.c
extenddftf2.c
+ extendhfsf2.c
+ extendhftf2.c
+ extendsfdf2.c
extendsftf2.c
+ ffsdi2.c
+ ffssi2.c
+ ffsti2.c
+ fixdfdi.c
+ fixdfsi.c
fixdfti.c
+ fixsfdi.c
+ fixsfsi.c
fixsfti.c
fixtfdi.c
fixtfsi.c
+ fixtfti.c
+ fixunsdfdi.c
+ fixunsdfsi.c
fixunsdfti.c
+ fixunssfdi.c
+ fixunssfsi.c
fixunssfti.c
fixunstfdi.c
fixunstfsi.c
fixunstfti.c
+ fixunsxfdi.c
+ fixunsxfsi.c
fixunsxfti.c
+ fixxfdi.c
+ fixxfti.c
+ floatdidf.c
+ floatdisf.c
floatditf.c
+ floatdixf.c
+ floatsidf.c
+ floatsisf.c
floatsitf.c
floattidf.c
floattisf.c
+ floattitf.c
floattixf.c
+ floatundidf.c
+ floatundisf.c
floatunditf.c
+ floatundixf.c
+ floatunsidf.c
+ floatunsisf.c
floatunsitf.c
floatuntidf.c
floatuntisf.c
+ floatuntitf.c
+ floatuntixf.c
+ fp_mode.c
gcc_personality_v0.c
int_util.c
+ lshrdi3.c
lshrti3.c
+ moddi3.c
+ modsi3.c
modti3.c
muldc3.c
+ muldf3.c
+ muldi3.c
+ mulodi4.c
+ mulosi4.c
muloti4.c
mulsc3.c
+ mulsf3.c
+ multc3.c
multf3.c
+ multi3.c
+ mulvdi3.c
+ mulvsi3.c
+ mulvti3.c
mulxc3.c
+ negdf2.c
+ negdi2.c
+ negsf2.c
+ negti2.c
+ negvdi2.c
+ negvsi2.c
+ negvti2.c
+ os_version_check.c
+ paritydi2.c
+ paritysi2.c
+ parityti2.c
popcountdi2.c
+ popcountsi2.c
+ popcountti2.c
+ powidf2.c
+ powisf2.c
+ powitf2.c
+ powixf2.c
+ subdf3.c
+ subsf3.c
subtf3.c
+ subvdi3.c
+ subvsi3.c
+ subvti3.c
+ trampoline_setup.c
+ truncdfbf2.c
+ truncdfhf2.c
+ truncdfsf2.c
+ truncsfbf2.c
+ truncsfhf2.c
trunctfdf2.c
+ trunctfhf2.c
trunctfsf2.c
+ ucmpdi2.c
+ ucmpti2.c
+ udivdi3.c
+ udivmoddi4.c
+ udivmodsi4.c
udivmodti4.c
+ udivsi3.c
udivti3.c
+ umoddi3.c
+ umodsi3.c
umodti3.c
)
-IF (OS_DARWIN OR OS_IOS)
+IF (ARCH_AARCH64)
SRCS(
- os_version_check.c
+ aarch64/fp_mode.c
+ aarch64/chkstk.S
)
ENDIF()
-IF (ARCH_ARM)
+IF (ARCH_X86_64)
SRCS(
- clear_cache.c
- multc3.c
+ x86_64/floatdidf.c
+ x86_64/floatdisf.c
+ x86_64/floatdixf.c
+ x86_64/chkstk2.S
+ x86_64/chkstk.S
+ x86_64/floatundidf.S
+ x86_64/floatundisf.S
+ x86_64/floatundixf.S
)
ENDIF()
diff --git a/contrib/libs/cxxsupp/libcxxmsvc/ya.make b/contrib/libs/cxxsupp/libcxxmsvc/ya.make
index db9c8f112d..ea8eefb5cc 100644
--- a/contrib/libs/cxxsupp/libcxxmsvc/ya.make
+++ b/contrib/libs/cxxsupp/libcxxmsvc/ya.make
@@ -2,7 +2,8 @@
LIBRARY()
-BUILD_ONLY_IF(OS_WINDOWS)
+BUILD_ONLY_IF(MSVC)
+NO_BUILD_IF(CLANG_CL)
LICENSE(
Apache-2.0 AND
diff --git a/contrib/libs/isa-l/erasure_code/Makefile.am b/contrib/libs/isa-l/erasure_code/Makefile.am
index bad2aae2f3..8f334462ac 100644
--- a/contrib/libs/isa-l/erasure_code/Makefile.am
+++ b/contrib/libs/isa-l/erasure_code/Makefile.am
@@ -1,5 +1,5 @@
########################################################################
-# Copyright(c) 2011-2017 Intel Corporation All rights reserved.
+# Copyright(c) 2011-2019 Intel Corporation All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
@@ -27,11 +27,13 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
########################################################################
+include erasure_code/aarch64/Makefile.am
+
+include erasure_code/ppc64le/Makefile.am
+
lsrc += erasure_code/ec_base.c
lsrc_base_aliases += erasure_code/ec_base_aliases.c
-lsrc_aarch64 += erasure_code/ec_base_aliases.c
-
lsrc_x86_64 += \
erasure_code/ec_highlevel_func.c \
erasure_code/gf_vect_mul_sse.asm \
@@ -76,14 +78,38 @@ lsrc_x86_64 += \
#if HAVE_AVX512
lsrc_x86_64 += \
+ erasure_code/gf_vect_mad_avx2_gfni.asm \
+ erasure_code/gf_2vect_mad_avx2_gfni.asm \
+ erasure_code/gf_3vect_mad_avx2_gfni.asm \
+ erasure_code/gf_4vect_mad_avx2_gfni.asm \
+ erasure_code/gf_5vect_mad_avx2_gfni.asm \
erasure_code/gf_vect_dot_prod_avx512.asm \
erasure_code/gf_2vect_dot_prod_avx512.asm \
erasure_code/gf_3vect_dot_prod_avx512.asm \
erasure_code/gf_4vect_dot_prod_avx512.asm \
+ erasure_code/gf_5vect_dot_prod_avx512.asm \
+ erasure_code/gf_6vect_dot_prod_avx512.asm \
+ erasure_code/gf_vect_dot_prod_avx512_gfni.asm \
+ erasure_code/gf_vect_dot_prod_avx2_gfni.asm \
+ erasure_code/gf_2vect_dot_prod_avx2_gfni.asm \
+ erasure_code/gf_3vect_dot_prod_avx2_gfni.asm \
+ erasure_code/gf_2vect_dot_prod_avx512_gfni.asm \
+ erasure_code/gf_3vect_dot_prod_avx512_gfni.asm \
+ erasure_code/gf_4vect_dot_prod_avx512_gfni.asm \
+ erasure_code/gf_5vect_dot_prod_avx512_gfni.asm \
+ erasure_code/gf_6vect_dot_prod_avx512_gfni.asm \
erasure_code/gf_vect_mad_avx512.asm \
erasure_code/gf_2vect_mad_avx512.asm \
erasure_code/gf_3vect_mad_avx512.asm \
- erasure_code/gf_4vect_mad_avx512.asm
+ erasure_code/gf_4vect_mad_avx512.asm \
+ erasure_code/gf_5vect_mad_avx512.asm \
+ erasure_code/gf_6vect_mad_avx512.asm \
+ erasure_code/gf_vect_mad_avx512_gfni.asm \
+ erasure_code/gf_2vect_mad_avx512_gfni.asm \
+ erasure_code/gf_3vect_mad_avx512_gfni.asm \
+ erasure_code/gf_4vect_mad_avx512_gfni.asm \
+ erasure_code/gf_5vect_mad_avx512_gfni.asm \
+ erasure_code/gf_6vect_mad_avx512_gfni.asm
lsrc_x86_32 += \
erasure_code/ec_highlevel_func.c \
@@ -143,19 +169,4 @@ perf_tests += erasure_code/gf_vect_mul_perf \
other_tests += erasure_code/gen_rs_matrix_limits
-other_tests_x86_64 += \
- erasure_code/gf_2vect_dot_prod_sse_test \
- erasure_code/gf_3vect_dot_prod_sse_test \
- erasure_code/gf_4vect_dot_prod_sse_test \
- erasure_code/gf_5vect_dot_prod_sse_test \
- erasure_code/gf_6vect_dot_prod_sse_test
-
-other_tests_x86_32 += \
- erasure_code/gf_2vect_dot_prod_sse_test \
- erasure_code/gf_3vect_dot_prod_sse_test \
- erasure_code/gf_4vect_dot_prod_sse_test \
- erasure_code/gf_5vect_dot_prod_sse_test \
- erasure_code/gf_6vect_dot_prod_sse_test
-
-other_src += include/test.h \
- include/types.h
+other_src += include/test.h
diff --git a/contrib/libs/isa-l/erasure_code/ut/gf_2vect_dot_prod_sse_test/.yandex_meta/licenses.list.txt b/contrib/libs/isa-l/erasure_code/aarch64/.yandex_meta/licenses.list.txt
index 8f218b47cb..8f218b47cb 100644
--- a/contrib/libs/isa-l/erasure_code/ut/gf_2vect_dot_prod_sse_test/.yandex_meta/licenses.list.txt
+++ b/contrib/libs/isa-l/erasure_code/aarch64/.yandex_meta/licenses.list.txt
diff --git a/contrib/libs/isa-l/erasure_code/aarch64/Makefile.am b/contrib/libs/isa-l/erasure_code/aarch64/Makefile.am
new file mode 100644
index 0000000000..47bbf12d2b
--- /dev/null
+++ b/contrib/libs/isa-l/erasure_code/aarch64/Makefile.am
@@ -0,0 +1,60 @@
+##################################################################
+# Copyright (c) 2019 Huawei Technologies Co., Ltd.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in
+# the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Huawei Corporation nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+########################################################################
+
+lsrc_aarch64 += \
+ erasure_code/aarch64/ec_aarch64_highlevel_func.c \
+ erasure_code/aarch64/ec_aarch64_dispatcher.c \
+ erasure_code/aarch64/gf_vect_dot_prod_neon.S \
+ erasure_code/aarch64/gf_2vect_dot_prod_neon.S \
+ erasure_code/aarch64/gf_3vect_dot_prod_neon.S \
+ erasure_code/aarch64/gf_4vect_dot_prod_neon.S \
+ erasure_code/aarch64/gf_5vect_dot_prod_neon.S \
+ erasure_code/aarch64/gf_vect_mad_neon.S \
+ erasure_code/aarch64/gf_2vect_mad_neon.S \
+ erasure_code/aarch64/gf_3vect_mad_neon.S \
+ erasure_code/aarch64/gf_4vect_mad_neon.S \
+ erasure_code/aarch64/gf_5vect_mad_neon.S \
+ erasure_code/aarch64/gf_6vect_mad_neon.S \
+ erasure_code/aarch64/gf_vect_mul_neon.S \
+ erasure_code/aarch64/gf_vect_mad_sve.S \
+ erasure_code/aarch64/gf_2vect_mad_sve.S \
+ erasure_code/aarch64/gf_3vect_mad_sve.S \
+ erasure_code/aarch64/gf_4vect_mad_sve.S \
+ erasure_code/aarch64/gf_5vect_mad_sve.S \
+ erasure_code/aarch64/gf_6vect_mad_sve.S \
+ erasure_code/aarch64/gf_vect_dot_prod_sve.S \
+ erasure_code/aarch64/gf_2vect_dot_prod_sve.S \
+ erasure_code/aarch64/gf_3vect_dot_prod_sve.S \
+ erasure_code/aarch64/gf_4vect_dot_prod_sve.S \
+ erasure_code/aarch64/gf_5vect_dot_prod_sve.S \
+ erasure_code/aarch64/gf_6vect_dot_prod_sve.S \
+ erasure_code/aarch64/gf_7vect_dot_prod_sve.S \
+ erasure_code/aarch64/gf_8vect_dot_prod_sve.S \
+ erasure_code/aarch64/gf_vect_mul_sve.S \
+ erasure_code/aarch64/ec_multibinary_arm.S
diff --git a/contrib/libs/isa-l/erasure_code/aarch64/ec_aarch64_dispatcher.c b/contrib/libs/isa-l/erasure_code/aarch64/ec_aarch64_dispatcher.c
new file mode 100644
index 0000000000..0a11604076
--- /dev/null
+++ b/contrib/libs/isa-l/erasure_code/aarch64/ec_aarch64_dispatcher.c
@@ -0,0 +1,124 @@
+/**************************************************************
+ Copyright (c) 2019 Huawei Technologies Co., Ltd.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name of Huawei Corporation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+**********************************************************************/
+#include <aarch64_multibinary.h>
+
+DEFINE_INTERFACE_DISPATCHER(gf_vect_dot_prod)
+{
+#if defined(__linux__)
+ unsigned long auxval = getauxval(AT_HWCAP);
+
+ if (auxval & HWCAP_SVE)
+ return PROVIDER_INFO(gf_vect_dot_prod_sve);
+ if (auxval & HWCAP_ASIMD)
+ return PROVIDER_INFO(gf_vect_dot_prod_neon);
+#elif defined(__APPLE__)
+ if (sysctlEnabled(SYSCTL_SVE_KEY))
+ return PROVIDER_INFO(gf_vect_dot_prod_sve);
+ return PROVIDER_INFO(gf_vect_dot_prod_neon);
+#endif
+ return PROVIDER_BASIC(gf_vect_dot_prod);
+
+}
+
+DEFINE_INTERFACE_DISPATCHER(gf_vect_mad)
+{
+#if defined(__linux__)
+ unsigned long auxval = getauxval(AT_HWCAP);
+
+ if (auxval & HWCAP_SVE)
+ return PROVIDER_INFO(gf_vect_mad_sve);
+ if (auxval & HWCAP_ASIMD)
+ return PROVIDER_INFO(gf_vect_mad_neon);
+#elif defined(__APPLE__)
+ if (sysctlEnabled(SYSCTL_SVE_KEY))
+ return PROVIDER_INFO(gf_vect_mad_sve);
+ return PROVIDER_INFO(gf_vect_mad_neon);
+#endif
+ return PROVIDER_BASIC(gf_vect_mad);
+
+}
+
+DEFINE_INTERFACE_DISPATCHER(ec_encode_data)
+{
+#if defined(__linux__)
+ unsigned long auxval = getauxval(AT_HWCAP);
+
+ if (auxval & HWCAP_SVE)
+ return PROVIDER_INFO(ec_encode_data_sve);
+ if (auxval & HWCAP_ASIMD)
+ return PROVIDER_INFO(ec_encode_data_neon);
+#elif defined(__APPLE__)
+ if (sysctlEnabled(SYSCTL_SVE_KEY))
+ return PROVIDER_INFO(ec_encode_data_sve);
+ return PROVIDER_INFO(ec_encode_data_neon);
+#endif
+ return PROVIDER_BASIC(ec_encode_data);
+
+}
+
+DEFINE_INTERFACE_DISPATCHER(ec_encode_data_update)
+{
+#if defined(__linux__)
+ unsigned long auxval = getauxval(AT_HWCAP);
+
+ if (auxval & HWCAP_SVE)
+ return PROVIDER_INFO(ec_encode_data_update_sve);
+ if (auxval & HWCAP_ASIMD)
+ return PROVIDER_INFO(ec_encode_data_update_neon);
+#elif defined(__APPLE__)
+ if (sysctlEnabled(SYSCTL_SVE_KEY))
+ return PROVIDER_INFO(ec_encode_data_update_sve);
+ return PROVIDER_INFO(ec_encode_data_update_neon);
+#endif
+ return PROVIDER_BASIC(ec_encode_data_update);
+
+}
+
+DEFINE_INTERFACE_DISPATCHER(gf_vect_mul)
+{
+#if defined(__linux__)
+ unsigned long auxval = getauxval(AT_HWCAP);
+
+ if (auxval & HWCAP_SVE)
+ return PROVIDER_INFO(gf_vect_mul_sve);
+ if (auxval & HWCAP_ASIMD)
+ return PROVIDER_INFO(gf_vect_mul_neon);
+#elif defined(__APPLE__)
+ if (sysctlEnabled(SYSCTL_SVE_KEY))
+ return PROVIDER_INFO(gf_vect_mul_sve);
+ return PROVIDER_INFO(gf_vect_mul_neon);
+#endif
+ return PROVIDER_BASIC(gf_vect_mul);
+
+}
+
+DEFINE_INTERFACE_DISPATCHER(ec_init_tables)
+{
+ return PROVIDER_BASIC(ec_init_tables);
+}
diff --git a/contrib/libs/isa-l/erasure_code/aarch64/ec_aarch64_highlevel_func.c b/contrib/libs/isa-l/erasure_code/aarch64/ec_aarch64_highlevel_func.c
new file mode 100644
index 0000000000..e001fd72a0
--- /dev/null
+++ b/contrib/libs/isa-l/erasure_code/aarch64/ec_aarch64_highlevel_func.c
@@ -0,0 +1,264 @@
+/**************************************************************
+ Copyright (c) 2019 Huawei Technologies Co., Ltd.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name of Huawei Corporation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+**********************************************************************/
+#include "erasure_code.h"
+
+/*external function*/
+extern void gf_vect_dot_prod_neon(int len, int vlen, unsigned char *gftbls,
+ unsigned char **src, unsigned char *dest);
+extern void gf_2vect_dot_prod_neon(int len, int vlen, unsigned char *gftbls,
+ unsigned char **src, unsigned char **dest);
+extern void gf_3vect_dot_prod_neon(int len, int vlen, unsigned char *gftbls,
+ unsigned char **src, unsigned char **dest);
+extern void gf_4vect_dot_prod_neon(int len, int vlen, unsigned char *gftbls,
+ unsigned char **src, unsigned char **dest);
+extern void gf_5vect_dot_prod_neon(int len, int vlen, unsigned char *gftbls,
+ unsigned char **src, unsigned char **dest);
+extern void gf_vect_mad_neon(int len, int vec, int vec_i, unsigned char *gftbls,
+ unsigned char *src, unsigned char *dest);
+extern void gf_2vect_mad_neon(int len, int vec, int vec_i, unsigned char *gftbls,
+ unsigned char *src, unsigned char **dest);
+extern void gf_3vect_mad_neon(int len, int vec, int vec_i, unsigned char *gftbls,
+ unsigned char *src, unsigned char **dest);
+extern void gf_4vect_mad_neon(int len, int vec, int vec_i, unsigned char *gftbls,
+ unsigned char *src, unsigned char **dest);
+extern void gf_5vect_mad_neon(int len, int vec, int vec_i, unsigned char *gftbls,
+ unsigned char *src, unsigned char **dest);
+extern void gf_6vect_mad_neon(int len, int vec, int vec_i, unsigned char *gftbls,
+ unsigned char *src, unsigned char **dest);
+
+void ec_encode_data_neon(int len, int k, int rows, unsigned char *g_tbls, unsigned char **data,
+ unsigned char **coding)
+{
+ if (len < 16) {
+ ec_encode_data_base(len, k, rows, g_tbls, data, coding);
+ return;
+ }
+
+ while (rows > 5) {
+ gf_5vect_dot_prod_neon(len, k, g_tbls, data, coding);
+ g_tbls += 5 * k * 32;
+ coding += 5;
+ rows -= 5;
+ }
+ switch (rows) {
+ case 5:
+ gf_5vect_dot_prod_neon(len, k, g_tbls, data, coding);
+ break;
+ case 4:
+ gf_4vect_dot_prod_neon(len, k, g_tbls, data, coding);
+ break;
+ case 3:
+ gf_3vect_dot_prod_neon(len, k, g_tbls, data, coding);
+ break;
+ case 2:
+ gf_2vect_dot_prod_neon(len, k, g_tbls, data, coding);
+ break;
+ case 1:
+ gf_vect_dot_prod_neon(len, k, g_tbls, data, *coding);
+ break;
+ case 0:
+ break;
+ default:
+ break;
+ }
+}
+
+void ec_encode_data_update_neon(int len, int k, int rows, int vec_i, unsigned char *g_tbls,
+ unsigned char *data, unsigned char **coding)
+{
+ if (len < 16) {
+ ec_encode_data_update_base(len, k, rows, vec_i, g_tbls, data, coding);
+ return;
+ }
+ while (rows > 6) {
+ gf_6vect_mad_neon(len, k, vec_i, g_tbls, data, coding);
+ g_tbls += 6 * k * 32;
+ coding += 6;
+ rows -= 6;
+ }
+ switch (rows) {
+ case 6:
+ gf_6vect_mad_neon(len, k, vec_i, g_tbls, data, coding);
+ break;
+ case 5:
+ gf_5vect_mad_neon(len, k, vec_i, g_tbls, data, coding);
+ break;
+ case 4:
+ gf_4vect_mad_neon(len, k, vec_i, g_tbls, data, coding);
+ break;
+ case 3:
+ gf_3vect_mad_neon(len, k, vec_i, g_tbls, data, coding);
+ break;
+ case 2:
+ gf_2vect_mad_neon(len, k, vec_i, g_tbls, data, coding);
+ break;
+ case 1:
+ gf_vect_mad_neon(len, k, vec_i, g_tbls, data, *coding);
+ break;
+ case 0:
+ break;
+ }
+}
+
+/* SVE */
+extern void gf_vect_dot_prod_sve(int len, int vlen, unsigned char *gftbls,
+ unsigned char **src, unsigned char *dest);
+extern void gf_2vect_dot_prod_sve(int len, int vlen, unsigned char *gftbls,
+ unsigned char **src, unsigned char **dest);
+extern void gf_3vect_dot_prod_sve(int len, int vlen, unsigned char *gftbls,
+ unsigned char **src, unsigned char **dest);
+extern void gf_4vect_dot_prod_sve(int len, int vlen, unsigned char *gftbls,
+ unsigned char **src, unsigned char **dest);
+extern void gf_5vect_dot_prod_sve(int len, int vlen, unsigned char *gftbls,
+ unsigned char **src, unsigned char **dest);
+extern void gf_6vect_dot_prod_sve(int len, int vlen, unsigned char *gftbls,
+ unsigned char **src, unsigned char **dest);
+extern void gf_7vect_dot_prod_sve(int len, int vlen, unsigned char *gftbls,
+ unsigned char **src, unsigned char **dest);
+extern void gf_8vect_dot_prod_sve(int len, int vlen, unsigned char *gftbls,
+ unsigned char **src, unsigned char **dest);
+extern void gf_vect_mad_sve(int len, int vec, int vec_i, unsigned char *gftbls,
+ unsigned char *src, unsigned char *dest);
+extern void gf_2vect_mad_sve(int len, int vec, int vec_i, unsigned char *gftbls,
+ unsigned char *src, unsigned char **dest);
+extern void gf_3vect_mad_sve(int len, int vec, int vec_i, unsigned char *gftbls,
+ unsigned char *src, unsigned char **dest);
+extern void gf_4vect_mad_sve(int len, int vec, int vec_i, unsigned char *gftbls,
+ unsigned char *src, unsigned char **dest);
+extern void gf_5vect_mad_sve(int len, int vec, int vec_i, unsigned char *gftbls,
+ unsigned char *src, unsigned char **dest);
+extern void gf_6vect_mad_sve(int len, int vec, int vec_i, unsigned char *gftbls,
+ unsigned char *src, unsigned char **dest);
+
+void ec_encode_data_sve(int len, int k, int rows, unsigned char *g_tbls, unsigned char **data,
+ unsigned char **coding)
+{
+ if (len < 16) {
+ ec_encode_data_base(len, k, rows, g_tbls, data, coding);
+ return;
+ }
+
+ while (rows > 11) {
+ gf_6vect_dot_prod_sve(len, k, g_tbls, data, coding);
+ g_tbls += 6 * k * 32;
+ coding += 6;
+ rows -= 6;
+ }
+
+ switch (rows) {
+ case 11:
+ /* 7 + 4 */
+ gf_7vect_dot_prod_sve(len, k, g_tbls, data, coding);
+ g_tbls += 7 * k * 32;
+ coding += 7;
+ gf_4vect_dot_prod_sve(len, k, g_tbls, data, coding);
+ break;
+ case 10:
+ /* 6 + 4 */
+ gf_6vect_dot_prod_sve(len, k, g_tbls, data, coding);
+ g_tbls += 6 * k * 32;
+ coding += 6;
+ gf_4vect_dot_prod_sve(len, k, g_tbls, data, coding);
+ break;
+ case 9:
+ /* 5 + 4 */
+ gf_5vect_dot_prod_sve(len, k, g_tbls, data, coding);
+ g_tbls += 5 * k * 32;
+ coding += 5;
+ gf_4vect_dot_prod_sve(len, k, g_tbls, data, coding);
+ break;
+ case 8:
+ /* 4 + 4 */
+ gf_4vect_dot_prod_sve(len, k, g_tbls, data, coding);
+ g_tbls += 4 * k * 32;
+ coding += 4;
+ gf_4vect_dot_prod_sve(len, k, g_tbls, data, coding);
+ break;
+ case 7:
+ gf_7vect_dot_prod_sve(len, k, g_tbls, data, coding);
+ break;
+ case 6:
+ gf_6vect_dot_prod_sve(len, k, g_tbls, data, coding);
+ break;
+ case 5:
+ gf_5vect_dot_prod_sve(len, k, g_tbls, data, coding);
+ break;
+ case 4:
+ gf_4vect_dot_prod_sve(len, k, g_tbls, data, coding);
+ break;
+ case 3:
+ gf_3vect_dot_prod_sve(len, k, g_tbls, data, coding);
+ break;
+ case 2:
+ gf_2vect_dot_prod_sve(len, k, g_tbls, data, coding);
+ break;
+ case 1:
+ gf_vect_dot_prod_sve(len, k, g_tbls, data, *coding);
+ break;
+ default:
+ break;
+ }
+}
+
+void ec_encode_data_update_sve(int len, int k, int rows, int vec_i, unsigned char *g_tbls,
+ unsigned char *data, unsigned char **coding)
+{
+ if (len < 16) {
+ ec_encode_data_update_base(len, k, rows, vec_i, g_tbls, data, coding);
+ return;
+ }
+ while (rows > 6) {
+ gf_6vect_mad_sve(len, k, vec_i, g_tbls, data, coding);
+ g_tbls += 6 * k * 32;
+ coding += 6;
+ rows -= 6;
+ }
+ switch (rows) {
+ case 6:
+ gf_6vect_mad_sve(len, k, vec_i, g_tbls, data, coding);
+ break;
+ case 5:
+ gf_5vect_mad_sve(len, k, vec_i, g_tbls, data, coding);
+ break;
+ case 4:
+ gf_4vect_mad_sve(len, k, vec_i, g_tbls, data, coding);
+ break;
+ case 3:
+ gf_3vect_mad_sve(len, k, vec_i, g_tbls, data, coding);
+ break;
+ case 2:
+ gf_2vect_mad_sve(len, k, vec_i, g_tbls, data, coding);
+ break;
+ case 1:
+ gf_vect_mad_sve(len, k, vec_i, g_tbls, data, *coding);
+ break;
+ default:
+ break;
+ }
+}
diff --git a/contrib/libs/isa-l/erasure_code/aarch64/ec_multibinary_arm.S b/contrib/libs/isa-l/erasure_code/aarch64/ec_multibinary_arm.S
new file mode 100644
index 0000000000..c276e63780
--- /dev/null
+++ b/contrib/libs/isa-l/erasure_code/aarch64/ec_multibinary_arm.S
@@ -0,0 +1,37 @@
+/**************************************************************
+ Copyright (c) 2019 Huawei Technologies Co., Ltd.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name of Huawei Corporation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+**********************************************************************/
+
+#include "aarch64_multibinary.h"
+
+mbin_interface ec_encode_data
+mbin_interface gf_vect_mul
+mbin_interface gf_vect_dot_prod
+mbin_interface gf_vect_mad
+mbin_interface ec_encode_data_update
+mbin_interface ec_init_tables
diff --git a/contrib/libs/isa-l/erasure_code/aarch64/gf_2vect_dot_prod_neon.S b/contrib/libs/isa-l/erasure_code/aarch64/gf_2vect_dot_prod_neon.S
new file mode 100644
index 0000000000..4ff7e7ce16
--- /dev/null
+++ b/contrib/libs/isa-l/erasure_code/aarch64/gf_2vect_dot_prod_neon.S
@@ -0,0 +1,402 @@
+/**************************************************************
+ Copyright (c) 2019 Huawei Technologies Co., Ltd.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name of Huawei Corporation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+**********************************************************************/
+
+#include "../include/aarch64_label.h"
+
+.text
+
+.global cdecl(gf_2vect_dot_prod_neon)
+#ifndef __APPLE__
+.type gf_2vect_dot_prod_neon, %function
+#endif
+
+/* arguments */
+x_len .req x0
+x_vec .req x1
+x_tbl .req x2
+x_src .req x3
+x_dest .req x4
+
+/* returns */
+w_ret .req w0
+
+/* local variables */
+x_vec_i .req x5
+x_ptr .req x6
+x_pos .req x7
+x_tmp .req x8
+x_tbl1 .req x9
+x_tbl2 .req x10
+x_dest1 .req x11
+x_dest2 .req x12
+
+/* vectors */
+v_gft1_lo .req v0
+v_gft1_hi .req v1
+v_gft2_lo .req v2
+v_gft2_hi .req v3
+q_gft1_lo .req q0
+q_gft1_hi .req q1
+q_gft2_lo .req q2
+q_gft2_hi .req q3
+
+v_mask0f .req v4
+q_mask0f .req q4
+
+v_tmp1_lo .req v5
+v_tmp1_hi .req v6
+v_tmp1 .req v7
+
+v_data_0 .req v8
+v_data_1 .req v9
+v_data_2 .req v10
+v_data_3 .req v11
+v_data_4 .req v12
+v_data_5 .req v13
+v_data_6 .req v14
+v_data_7 .req v15
+q_data_0 .req q8
+q_data_1 .req q9
+q_data_2 .req q10
+q_data_3 .req q11
+q_data_4 .req q12
+q_data_5 .req q13
+q_data_6 .req q14
+q_data_7 .req q15
+
+v_p1_0 .req v16
+v_p1_1 .req v17
+v_p1_2 .req v18
+v_p1_3 .req v19
+v_p1_4 .req v20
+v_p1_5 .req v21
+v_p1_6 .req v22
+v_p1_7 .req v23
+v_p2_0 .req v24
+v_p2_1 .req v25
+v_p2_2 .req v26
+v_p2_3 .req v27
+v_p2_4 .req v28
+v_p2_5 .req v29
+v_p2_6 .req v30
+v_p2_7 .req v31
+
+q_p1_0 .req q16
+q_p1_1 .req q17
+q_p1_2 .req q18
+q_p1_3 .req q19
+q_p1_4 .req q20
+q_p1_5 .req q21
+q_p1_6 .req q22
+q_p1_7 .req q23
+q_p2_0 .req q24
+q_p2_1 .req q25
+q_p2_2 .req q26
+q_p2_3 .req q27
+q_p2_4 .req q28
+q_p2_5 .req q29
+q_p2_6 .req q30
+q_p2_7 .req q31
+
+v_p1 .req v_p1_0
+q_p1 .req q_p1_0
+v_p2 .req v_p2_0
+q_p2 .req q_p2_0
+v_data .req v_p1_1
+q_data .req q_p1_1
+v_data_lo .req v_p1_2
+v_data_hi .req v_p1_3
+
+cdecl(gf_2vect_dot_prod_neon):
+ /* less than 16 bytes, return_fail */
+ cmp x_len, #16
+ blt .return_fail
+
+ movi v_mask0f.16b, #0x0f
+ mov x_pos, #0
+ lsl x_vec, x_vec, #3
+ ldr x_dest1, [x_dest, #8*0]
+ ldr x_dest2, [x_dest, #8*1]
+
+.Lloop128_init:
+ /* less than 128 bytes, goto Lloop16_init */
+ cmp x_len, #128
+ blt .Lloop16_init
+
+ /* save d8 ~ d15 to stack */
+ sub sp, sp, #64
+ stp d8, d9, [sp]
+ stp d10, d11, [sp, #16]
+ stp d12, d13, [sp, #32]
+ stp d14, d15, [sp, #48]
+
+ sub x_len, x_len, #128
+
+.Lloop128:
+ movi v_p1_0.16b, #0
+ movi v_p1_1.16b, #0
+ movi v_p1_2.16b, #0
+ movi v_p1_3.16b, #0
+ movi v_p1_4.16b, #0
+ movi v_p1_5.16b, #0
+ movi v_p1_6.16b, #0
+ movi v_p1_7.16b, #0
+
+ movi v_p2_0.16b, #0
+ movi v_p2_1.16b, #0
+ movi v_p2_2.16b, #0
+ movi v_p2_3.16b, #0
+ movi v_p2_4.16b, #0
+ movi v_p2_5.16b, #0
+ movi v_p2_6.16b, #0
+ movi v_p2_7.16b, #0
+
+ mov x_tbl1, x_tbl
+ add x_tbl2, x_tbl, x_vec, lsl #2
+ mov x_vec_i, #0
+
+.Lloop128_vects:
+ ldr x_ptr, [x_src, x_vec_i]
+ add x_vec_i, x_vec_i, #8
+ add x_ptr, x_ptr, x_pos
+
+ ldp q_data_0, q_data_1, [x_ptr], #32
+ ldp q_data_2, q_data_3, [x_ptr], #32
+
+ ldp q_gft1_lo, q_gft1_hi, [x_tbl1], #32
+ ldp q_gft2_lo, q_gft2_hi, [x_tbl2], #32
+ ldp q_data_4, q_data_5, [x_ptr], #32
+ ldp q_data_6, q_data_7, [x_ptr], #32
+ prfm pldl1strm, [x_ptr]
+ prfm pldl1keep, [x_tbl1]
+ prfm pldl1keep, [x_tbl2]
+
+ /* data_0 */
+ and v_tmp1.16b, v_data_0.16b, v_mask0f.16b
+ ushr v_data_0.16b, v_data_0.16b, #4
+
+ tbl v_tmp1_lo.16b, {v_gft1_lo.16b}, v_tmp1.16b
+ tbl v_tmp1_hi.16b, {v_gft1_hi.16b}, v_data_0.16b
+ eor v_p1_0.16b, v_tmp1_lo.16b, v_p1_0.16b
+ eor v_p1_0.16b, v_p1_0.16b, v_tmp1_hi.16b
+
+ tbl v_tmp1_lo.16b, {v_gft2_lo.16b}, v_tmp1.16b
+ tbl v_tmp1_hi.16b, {v_gft2_hi.16b}, v_data_0.16b
+ eor v_p2_0.16b, v_tmp1_lo.16b, v_p2_0.16b
+ eor v_p2_0.16b, v_p2_0.16b, v_tmp1_hi.16b
+
+ /* data_1 */
+ and v_tmp1.16b, v_data_1.16b, v_mask0f.16b
+ ushr v_data_1.16b, v_data_1.16b, #4
+
+ tbl v_tmp1_lo.16b, {v_gft1_lo.16b}, v_tmp1.16b
+ tbl v_tmp1_hi.16b, {v_gft1_hi.16b}, v_data_1.16b
+ eor v_p1_1.16b, v_tmp1_lo.16b, v_p1_1.16b
+ eor v_p1_1.16b, v_p1_1.16b, v_tmp1_hi.16b
+
+ tbl v_tmp1_lo.16b, {v_gft2_lo.16b}, v_tmp1.16b
+ tbl v_tmp1_hi.16b, {v_gft2_hi.16b}, v_data_1.16b
+ eor v_p2_1.16b, v_tmp1_lo.16b, v_p2_1.16b
+ eor v_p2_1.16b, v_p2_1.16b, v_tmp1_hi.16b
+
+ /* data_2 */
+ and v_tmp1.16b, v_data_2.16b, v_mask0f.16b
+ ushr v_data_2.16b, v_data_2.16b, #4
+
+ tbl v_tmp1_lo.16b, {v_gft1_lo.16b}, v_tmp1.16b
+ tbl v_tmp1_hi.16b, {v_gft1_hi.16b}, v_data_2.16b
+ eor v_p1_2.16b, v_tmp1_lo.16b, v_p1_2.16b
+ eor v_p1_2.16b, v_p1_2.16b, v_tmp1_hi.16b
+
+ tbl v_tmp1_lo.16b, {v_gft2_lo.16b}, v_tmp1.16b
+ tbl v_tmp1_hi.16b, {v_gft2_hi.16b}, v_data_2.16b
+ eor v_p2_2.16b, v_tmp1_lo.16b, v_p2_2.16b
+ eor v_p2_2.16b, v_p2_2.16b, v_tmp1_hi.16b
+
+ /* data_3 */
+ and v_tmp1.16b, v_data_3.16b, v_mask0f.16b
+ ushr v_data_3.16b, v_data_3.16b, #4
+
+ tbl v_tmp1_lo.16b, {v_gft1_lo.16b}, v_tmp1.16b
+ tbl v_tmp1_hi.16b, {v_gft1_hi.16b}, v_data_3.16b
+ eor v_p1_3.16b, v_tmp1_lo.16b, v_p1_3.16b
+ eor v_p1_3.16b, v_p1_3.16b, v_tmp1_hi.16b
+
+ tbl v_tmp1_lo.16b, {v_gft2_lo.16b}, v_tmp1.16b
+ tbl v_tmp1_hi.16b, {v_gft2_hi.16b}, v_data_3.16b
+ eor v_p2_3.16b, v_tmp1_lo.16b, v_p2_3.16b
+ eor v_p2_3.16b, v_p2_3.16b, v_tmp1_hi.16b
+
+ /* data_4 */
+ and v_tmp1.16b, v_data_4.16b, v_mask0f.16b
+ ushr v_data_4.16b, v_data_4.16b, #4
+
+ tbl v_tmp1_lo.16b, {v_gft1_lo.16b}, v_tmp1.16b
+ tbl v_tmp1_hi.16b, {v_gft1_hi.16b}, v_data_4.16b
+ eor v_p1_4.16b, v_tmp1_lo.16b, v_p1_4.16b
+ eor v_p1_4.16b, v_p1_4.16b, v_tmp1_hi.16b
+
+ tbl v_tmp1_lo.16b, {v_gft2_lo.16b}, v_tmp1.16b
+ tbl v_tmp1_hi.16b, {v_gft2_hi.16b}, v_data_4.16b
+ eor v_p2_4.16b, v_tmp1_lo.16b, v_p2_4.16b
+ eor v_p2_4.16b, v_p2_4.16b, v_tmp1_hi.16b
+
+ /* data_5 */
+ and v_tmp1.16b, v_data_5.16b, v_mask0f.16b
+ ushr v_data_5.16b, v_data_5.16b, #4
+
+ tbl v_tmp1_lo.16b, {v_gft1_lo.16b}, v_tmp1.16b
+ tbl v_tmp1_hi.16b, {v_gft1_hi.16b}, v_data_5.16b
+ eor v_p1_5.16b, v_tmp1_lo.16b, v_p1_5.16b
+ eor v_p1_5.16b, v_p1_5.16b, v_tmp1_hi.16b
+
+ tbl v_tmp1_lo.16b, {v_gft2_lo.16b}, v_tmp1.16b
+ tbl v_tmp1_hi.16b, {v_gft2_hi.16b}, v_data_5.16b
+ eor v_p2_5.16b, v_tmp1_lo.16b, v_p2_5.16b
+ eor v_p2_5.16b, v_p2_5.16b, v_tmp1_hi.16b
+
+ /* data_6 */
+ and v_tmp1.16b, v_data_6.16b, v_mask0f.16b
+ ushr v_data_6.16b, v_data_6.16b, #4
+
+ tbl v_tmp1_lo.16b, {v_gft1_lo.16b}, v_tmp1.16b
+ tbl v_tmp1_hi.16b, {v_gft1_hi.16b}, v_data_6.16b
+ eor v_p1_6.16b, v_tmp1_lo.16b, v_p1_6.16b
+ eor v_p1_6.16b, v_p1_6.16b, v_tmp1_hi.16b
+
+ tbl v_tmp1_lo.16b, {v_gft2_lo.16b}, v_tmp1.16b
+ tbl v_tmp1_hi.16b, {v_gft2_hi.16b}, v_data_6.16b
+ eor v_p2_6.16b, v_tmp1_lo.16b, v_p2_6.16b
+ eor v_p2_6.16b, v_p2_6.16b, v_tmp1_hi.16b
+
+ /* data_7 */
+ and v_tmp1.16b, v_data_7.16b, v_mask0f.16b
+ ushr v_data_7.16b, v_data_7.16b, #4
+
+ tbl v_tmp1_lo.16b, {v_gft1_lo.16b}, v_tmp1.16b
+ tbl v_tmp1_hi.16b, {v_gft1_hi.16b}, v_data_7.16b
+ eor v_p1_7.16b, v_tmp1_lo.16b, v_p1_7.16b
+ eor v_p1_7.16b, v_p1_7.16b, v_tmp1_hi.16b
+
+ tbl v_tmp1_lo.16b, {v_gft2_lo.16b}, v_tmp1.16b
+ tbl v_tmp1_hi.16b, {v_gft2_hi.16b}, v_data_7.16b
+ eor v_p2_7.16b, v_tmp1_lo.16b, v_p2_7.16b
+ eor v_p2_7.16b, v_p2_7.16b, v_tmp1_hi.16b
+
+ cmp x_vec_i, x_vec
+ blt .Lloop128_vects
+
+.Lloop128_vects_end:
+ add x_ptr, x_dest1, x_pos
+ stp q_p1_0, q_p1_1, [x_ptr], #32
+ stp q_p1_2, q_p1_3, [x_ptr], #32
+ stp q_p1_4, q_p1_5, [x_ptr], #32
+ stp q_p1_6, q_p1_7, [x_ptr]
+
+ add x_ptr, x_dest2, x_pos
+ stp q_p2_0, q_p2_1, [x_ptr], #32
+ stp q_p2_2, q_p2_3, [x_ptr], #32
+ stp q_p2_4, q_p2_5, [x_ptr], #32
+ stp q_p2_6, q_p2_7, [x_ptr]
+
+ add x_pos, x_pos, #128
+ cmp x_pos, x_len
+ ble .Lloop128
+
+.Lloop128_end:
+ /* restore d8 ~ d15 */
+ ldp d8, d9, [sp]
+ ldp d10, d11, [sp, #16]
+ ldp d12, d13, [sp, #32]
+ ldp d14, d15, [sp, #48]
+ add sp, sp, #64
+
+ add x_len, x_len, #128
+ cmp x_pos, x_len
+ beq .return_pass
+
+.Lloop16_init:
+ sub x_len, x_len, #16
+ cmp x_pos, x_len
+ bgt .lessthan16_init
+
+.Lloop16:
+ movi v_p1.16b, #0
+ movi v_p2.16b, #0
+ mov x_tbl1, x_tbl
+ add x_tbl2, x_tbl, x_vec, lsl #2
+ mov x_vec_i, #0
+
+.Lloop16_vects:
+ ldr x_ptr, [x_src, x_vec_i]
+ ldr q_data, [x_ptr, x_pos]
+ add x_vec_i, x_vec_i, #8
+
+ ldp q_gft1_lo, q_gft1_hi, [x_tbl1], #32
+ ldp q_gft2_lo, q_gft2_hi, [x_tbl2], #32
+
+ and v_data_lo.16b, v_data.16b, v_mask0f.16b
+ ushr v_data_hi.16b, v_data.16b, #4
+
+ tbl v_tmp1_hi.16b, {v_gft1_hi.16b}, v_data_hi.16b
+ tbl v_tmp1_lo.16b, {v_gft1_lo.16b}, v_data_lo.16b
+ eor v_p1.16b, v_tmp1_lo.16b, v_p1.16b
+ eor v_p1.16b, v_p1.16b, v_tmp1_hi.16b
+
+ tbl v_tmp1_hi.16b, {v_gft2_hi.16b}, v_data_hi.16b
+ tbl v_tmp1_lo.16b, {v_gft2_lo.16b}, v_data_lo.16b
+ eor v_p2.16b, v_tmp1_lo.16b, v_p2.16b
+ eor v_p2.16b, v_p2.16b, v_tmp1_hi.16b
+
+ cmp x_vec_i, x_vec
+ bne .Lloop16_vects
+
+.Lloop16_vects_end:
+ str q_p1, [x_dest1, x_pos]
+ str q_p2, [x_dest2, x_pos]
+ add x_pos, x_pos, #16
+ cmp x_pos, x_len
+ ble .Lloop16
+
+.Lloop16_end:
+ sub x_tmp, x_pos, x_len
+ cmp x_tmp, #16
+ beq .return_pass
+
+.lessthan16_init:
+ mov x_pos, x_len
+ b .Lloop16
+
+.return_pass:
+ mov w_ret, #0
+ ret
+
+.return_fail:
+ mov w_ret, #1
+ ret
diff --git a/contrib/libs/isa-l/erasure_code/aarch64/gf_2vect_dot_prod_sve.S b/contrib/libs/isa-l/erasure_code/aarch64/gf_2vect_dot_prod_sve.S
new file mode 100644
index 0000000000..99b5f15cfb
--- /dev/null
+++ b/contrib/libs/isa-l/erasure_code/aarch64/gf_2vect_dot_prod_sve.S
@@ -0,0 +1,168 @@
+/*************************************************************
+ Copyright (c) 2021 Linaro Ltd.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name of Huawei Corporation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+**********************************************************************/
+.text
+.align 6
+.arch armv8-a+sve
+
+#include "../include/aarch64_label.h"
+
+.global cdecl(gf_2vect_dot_prod_sve)
+#ifndef __APPLE__
+.type gf_2vect_dot_prod_sve, %function
+#endif
+/* void gf_2vect_dot_prod_sve(int len, int vlen, unsigned char *gftbls,
+ unsigned char **src, unsigned char **dest);
+ */
+
+/* arguments */
+x_len .req x0 /* vector length */
+x_vec .req x1 /* number of source vectors (ie. data blocks) */
+x_tbl .req x2
+x_src .req x3
+x_dest .req x4
+
+/* returns */
+w_ret .req w0
+
+/* local variables */
+x_vec_i .req x5
+x_ptr .req x6
+x_pos .req x7
+
+x_tbl1 .req x8
+x_tbl2 .req x9
+x_dest1 .req x10
+x_dest2 .req x_dest /* reused */
+
+/* r16,r17,r18,r29,r30: special role registers, avoided */
+/* r19..r29 and SP must be preserved */
+
+/* vectors */
+z_mask0f .req z0
+
+z_src .req z1
+z_src_lo .req z2
+z_src_hi .req z_src
+
+z_dest1 .req z3
+
+z_gft1_lo .req z4
+z_gft1_hi .req z5
+q_gft1_lo .req q4
+q_gft1_hi .req q5
+
+/* bottom 64-bit of v8..v15 must be preserved if used */
+z_gft2_lo .req z17
+z_gft2_hi .req z18
+q_gft2_lo .req q17
+q_gft2_hi .req q18
+
+z_dest2 .req z27
+
+cdecl(gf_2vect_dot_prod_sve):
+ /* less than 16 bytes, return_fail */
+ cmp x_len, #16
+ blt .return_fail
+
+ mov z_mask0f.b, #0x0f /* z_mask0f = 0x0F0F...0F */
+ mov x_pos, #0
+ lsl x_vec, x_vec, #3
+ ldp x_dest1, x_dest2, [x_dest, #8*0]
+
+/* Loop 1: x_len, vector length */
+.Lloopsve_vl:
+ whilelo p0.b, x_pos, x_len
+ b.none .return_pass
+
+ mov x_vec_i, #0 /* clear x_vec_i */
+ ldr x_ptr, [x_src, x_vec_i] /* x_ptr: src base addr. */
+
+ mov z_dest1.b, #0 /* clear z_dest1 */
+ mov z_dest2.b, #0 /* clear z_dest2 */
+
+ /* gf_tbl base = (x_tbl + dest_idx * x_vec * 32) */
+ mov x_tbl1, x_tbl /* reset x_tbl1 */
+ add x_tbl2, x_tbl1, x_vec, LSL #2 /* reset x_tbl2 */
+
+/* Loop 2: x_vec, number of source vectors (ie. data blocks) */
+.Lloopsve_vl_vects:
+ /* load src data, governed by p0 */
+ ld1b z_src.b, p0/z, [x_ptr, x_pos] /* load from: src base + pos offset */
+ /* split 4-bit lo; 4-bit hi */
+ and z_src_lo.d, z_src.d, z_mask0f.d
+ lsr z_src_hi.b, z_src.b, #4
+
+
+ /* gf_tbl addr: (x_tbl + dest_idx * x_vec * 32) + src_vec_idx * 32 */
+ /* load gf_table's */
+ ldp q_gft1_lo, q_gft1_hi, [x_tbl1], #32 /* x_tbl1 is post-added by #32 for each src vect */
+ ldp q_gft2_lo, q_gft2_hi, [x_tbl2], #32
+
+ /* prefetch */
+ prfb pldl2keep, p0, [x_tbl1]
+ prfb pldl2keep, p0, [x_tbl2]
+
+ /* calc for next */
+ add x_vec_i, x_vec_i, #8 /* move x_vec_i to next */
+ ldr x_ptr, [x_src, x_vec_i] /* x_ptr: src base addr. */
+
+ /* dest 1 */
+ /* table indexing, ie. gf(2^8) multiplication */
+ tbl z_gft1_lo.b, {z_gft1_lo.b}, z_src_lo.b
+ tbl z_gft1_hi.b, {z_gft1_hi.b}, z_src_hi.b
+ /* exclusive or, ie. gf(2^8) add */
+ eor z_dest1.d, z_gft1_lo.d, z_dest1.d
+ eor z_dest1.d, z_dest1.d, z_gft1_hi.d
+
+ /* dest 2 */
+ tbl z_gft2_lo.b, {z_gft2_lo.b}, z_src_lo.b
+ tbl z_gft2_hi.b, {z_gft2_hi.b}, z_src_hi.b
+ eor z_dest2.d, z_gft2_lo.d, z_dest2.d
+ eor z_dest2.d, z_dest2.d, z_gft2_hi.d
+
+ cmp x_vec_i, x_vec
+ blt .Lloopsve_vl_vects
+/* end of Loop 2 */
+
+ /* store dest data, governed by p0 */
+ st1b z_dest1.b, p0, [x_dest1, x_pos]
+ st1b z_dest2.b, p0, [x_dest2, x_pos]
+
+ /* increment one vector length */
+ incb x_pos
+ b .Lloopsve_vl
+/* end of Loop 1 */
+
+.return_pass:
+ mov w_ret, #0
+ ret
+
+.return_fail:
+ mov w_ret, #1
+ ret
diff --git a/contrib/libs/isa-l/erasure_code/aarch64/gf_2vect_mad_neon.S b/contrib/libs/isa-l/erasure_code/aarch64/gf_2vect_mad_neon.S
new file mode 100644
index 0000000000..453524a221
--- /dev/null
+++ b/contrib/libs/isa-l/erasure_code/aarch64/gf_2vect_mad_neon.S
@@ -0,0 +1,411 @@
+/**************************************************************
+ Copyright (c) 2019 Huawei Technologies Co., Ltd.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name of Huawei Corporation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+**********************************************************************/
+
+#include "../include/aarch64_label.h"
+
+.text
+
+.global cdecl(gf_2vect_mad_neon)
+#ifndef __APPLE__
+.type gf_2vect_mad_neon, %function
+#endif
+
+/* arguments */
+x_len .req x0
+x_vec .req x1
+x_vec_i .req x2
+x_tbl .req x3
+x_src .req x4
+x_dest .req x5
+
+/* returns */
+w_ret .req w0
+
+/* local variables */
+x_src_end .req x6
+x_dest1 .req x7
+x_dest2 .req x8
+x_tmp .req x9
+x_tbl1 .req x10
+x_tbl2 .req x11
+x_const .req x12
+
+/* vectors */
+v_mask0f .req v0
+v_tmp_lo .req v1
+v_tmp_hi .req v2
+v_tmp .req v3
+q_tmp .req q3
+
+v_gft1_lo .req v4
+v_gft1_hi .req v5
+v_gft2_lo .req v6
+v_gft2_hi .req v7
+q_gft1_lo .req q4
+q_gft1_hi .req q5
+q_gft2_lo .req q6
+q_gft2_hi .req q7
+
+v_data_0 .req v8
+v_data_1 .req v9
+v_data_2 .req v10
+v_data_3 .req v11
+v_data_4 .req v12
+v_data_5 .req v13
+v_data_6 .req v14
+v_data_7 .req v15
+q_data_0 .req q8
+q_data_1 .req q9
+q_data_2 .req q10
+q_data_3 .req q11
+q_data_4 .req q12
+q_data_5 .req q13
+q_data_6 .req q14
+q_data_7 .req q15
+
+v_data_0_lo .req v16
+v_data_1_lo .req v17
+v_data_2_lo .req v18
+v_data_3_lo .req v19
+v_data_4_lo .req v20
+v_data_5_lo .req v21
+v_data_6_lo .req v22
+v_data_7_lo .req v23
+v_data_0_hi .req v_data_0
+v_data_1_hi .req v_data_1
+v_data_2_hi .req v_data_2
+v_data_3_hi .req v_data_3
+v_data_4_hi .req v_data_4
+v_data_5_hi .req v_data_5
+v_data_6_hi .req v_data_6
+v_data_7_hi .req v_data_7
+
+v_d0 .req v24
+v_d1 .req v25
+v_d2 .req v26
+v_d3 .req v27
+v_d4 .req v28
+v_d5 .req v29
+v_d6 .req v30
+v_d7 .req v31
+q_d0 .req q24
+q_d1 .req q25
+q_d2 .req q26
+q_d3 .req q27
+q_d4 .req q28
+q_d5 .req q29
+q_d6 .req q30
+q_d7 .req q31
+
+v_data .req v16
+q_data .req q16
+v_data_lo .req v17
+v_data_hi .req v18
+
+
+cdecl(gf_2vect_mad_neon):
+ /* less than 16 bytes, return_fail */
+ cmp x_len, #16
+ blt .return_fail
+
+ movi v_mask0f.16b, #0x0f
+ lsl x_vec_i, x_vec_i, #5
+ lsl x_vec, x_vec, #5
+ add x_tbl1, x_tbl, x_vec_i
+ add x_tbl2, x_tbl1, x_vec
+ add x_src_end, x_src, x_len
+
+ ldr x_dest1, [x_dest]
+ ldr x_dest2, [x_dest, #8]
+ ldr q_gft1_lo, [x_tbl1]
+ ldr q_gft1_hi, [x_tbl1, #16]
+ ldr q_gft2_lo, [x_tbl2]
+ ldr q_gft2_hi, [x_tbl2, #16]
+
+.Lloop128_init:
+ /* less than 128 bytes, goto Lloop16_init */
+ cmp x_len, #128
+ blt .Lloop16_init
+
+ /* save d8 ~ d15 to stack */
+ sub sp, sp, #64
+ stp d8, d9, [sp]
+ stp d10, d11, [sp, #16]
+ stp d12, d13, [sp, #32]
+ stp d14, d15, [sp, #48]
+
+ sub x_src_end, x_src_end, #128
+
+.Lloop128:
+ ldr q_data_0, [x_src, #16*0]
+ ldr q_data_1, [x_src, #16*1]
+ ldr q_data_2, [x_src, #16*2]
+ ldr q_data_3, [x_src, #16*3]
+ ldr q_data_4, [x_src, #16*4]
+ ldr q_data_5, [x_src, #16*5]
+ ldr q_data_6, [x_src, #16*6]
+ ldr q_data_7, [x_src, #16*7]
+
+ ldr q_d0, [x_dest1, #16*0]
+ ldr q_d1, [x_dest1, #16*1]
+ ldr q_d2, [x_dest1, #16*2]
+ ldr q_d3, [x_dest1, #16*3]
+ ldr q_d4, [x_dest1, #16*4]
+ ldr q_d5, [x_dest1, #16*5]
+ ldr q_d6, [x_dest1, #16*6]
+ ldr q_d7, [x_dest1, #16*7]
+
+ and v_data_0_lo.16b, v_data_0.16b, v_mask0f.16b
+ and v_data_1_lo.16b, v_data_1.16b, v_mask0f.16b
+ and v_data_2_lo.16b, v_data_2.16b, v_mask0f.16b
+ and v_data_3_lo.16b, v_data_3.16b, v_mask0f.16b
+ and v_data_4_lo.16b, v_data_4.16b, v_mask0f.16b
+ and v_data_5_lo.16b, v_data_5.16b, v_mask0f.16b
+ and v_data_6_lo.16b, v_data_6.16b, v_mask0f.16b
+ and v_data_7_lo.16b, v_data_7.16b, v_mask0f.16b
+
+ ushr v_data_0_hi.16b, v_data_0.16b, #4
+ ushr v_data_1_hi.16b, v_data_1.16b, #4
+ ushr v_data_2_hi.16b, v_data_2.16b, #4
+ ushr v_data_3_hi.16b, v_data_3.16b, #4
+ ushr v_data_4_hi.16b, v_data_4.16b, #4
+ ushr v_data_5_hi.16b, v_data_5.16b, #4
+ ushr v_data_6_hi.16b, v_data_6.16b, #4
+ ushr v_data_7_hi.16b, v_data_7.16b, #4
+
+ tbl v_tmp_lo.16b, {v_gft1_lo.16b}, v_data_0_lo.16b
+ tbl v_tmp_hi.16b, {v_gft1_hi.16b}, v_data_0_hi.16b
+ eor v_d0.16b, v_tmp_lo.16b, v_d0.16b
+ eor v_d0.16b, v_d0.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft1_lo.16b}, v_data_1_lo.16b
+ tbl v_tmp_hi.16b, {v_gft1_hi.16b}, v_data_1_hi.16b
+ eor v_d1.16b, v_tmp_lo.16b, v_d1.16b
+ eor v_d1.16b, v_d1.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft1_lo.16b}, v_data_2_lo.16b
+ tbl v_tmp_hi.16b, {v_gft1_hi.16b}, v_data_2_hi.16b
+ eor v_d2.16b, v_tmp_lo.16b, v_d2.16b
+ eor v_d2.16b, v_d2.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft1_lo.16b}, v_data_3_lo.16b
+ tbl v_tmp_hi.16b, {v_gft1_hi.16b}, v_data_3_hi.16b
+ eor v_d3.16b, v_tmp_lo.16b, v_d3.16b
+ eor v_d3.16b, v_d3.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft1_lo.16b}, v_data_4_lo.16b
+ tbl v_tmp_hi.16b, {v_gft1_hi.16b}, v_data_4_hi.16b
+ eor v_d4.16b, v_tmp_lo.16b, v_d4.16b
+ eor v_d4.16b, v_d4.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft1_lo.16b}, v_data_5_lo.16b
+ tbl v_tmp_hi.16b, {v_gft1_hi.16b}, v_data_5_hi.16b
+ eor v_d5.16b, v_tmp_lo.16b, v_d5.16b
+ eor v_d5.16b, v_d5.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft1_lo.16b}, v_data_6_lo.16b
+ tbl v_tmp_hi.16b, {v_gft1_hi.16b}, v_data_6_hi.16b
+ eor v_d6.16b, v_tmp_lo.16b, v_d6.16b
+ eor v_d6.16b, v_d6.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft1_lo.16b}, v_data_7_lo.16b
+ tbl v_tmp_hi.16b, {v_gft1_hi.16b}, v_data_7_hi.16b
+ eor v_d7.16b, v_tmp_lo.16b, v_d7.16b
+ eor v_d7.16b, v_d7.16b, v_tmp_hi.16b
+
+ str q_d0, [x_dest1, #16*0]
+ str q_d1, [x_dest1, #16*1]
+ str q_d2, [x_dest1, #16*2]
+ str q_d3, [x_dest1, #16*3]
+ str q_d4, [x_dest1, #16*4]
+ str q_d5, [x_dest1, #16*5]
+ str q_d6, [x_dest1, #16*6]
+ str q_d7, [x_dest1, #16*7]
+
+ ldr q_d0, [x_dest2, #16*0]
+ ldr q_d1, [x_dest2, #16*1]
+ ldr q_d2, [x_dest2, #16*2]
+ ldr q_d3, [x_dest2, #16*3]
+ ldr q_d4, [x_dest2, #16*4]
+ ldr q_d5, [x_dest2, #16*5]
+ ldr q_d6, [x_dest2, #16*6]
+ ldr q_d7, [x_dest2, #16*7]
+
+ tbl v_tmp_lo.16b, {v_gft2_lo.16b}, v_data_0_lo.16b
+ tbl v_tmp_hi.16b, {v_gft2_hi.16b}, v_data_0_hi.16b
+ eor v_d0.16b, v_tmp_lo.16b, v_d0.16b
+ eor v_d0.16b, v_d0.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft2_lo.16b}, v_data_1_lo.16b
+ tbl v_tmp_hi.16b, {v_gft2_hi.16b}, v_data_1_hi.16b
+ eor v_d1.16b, v_tmp_lo.16b, v_d1.16b
+ eor v_d1.16b, v_d1.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft2_lo.16b}, v_data_2_lo.16b
+ tbl v_tmp_hi.16b, {v_gft2_hi.16b}, v_data_2_hi.16b
+ eor v_d2.16b, v_tmp_lo.16b, v_d2.16b
+ eor v_d2.16b, v_d2.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft2_lo.16b}, v_data_3_lo.16b
+ tbl v_tmp_hi.16b, {v_gft2_hi.16b}, v_data_3_hi.16b
+ eor v_d3.16b, v_tmp_lo.16b, v_d3.16b
+ eor v_d3.16b, v_d3.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft2_lo.16b}, v_data_4_lo.16b
+ tbl v_tmp_hi.16b, {v_gft2_hi.16b}, v_data_4_hi.16b
+ eor v_d4.16b, v_tmp_lo.16b, v_d4.16b
+ eor v_d4.16b, v_d4.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft2_lo.16b}, v_data_5_lo.16b
+ tbl v_tmp_hi.16b, {v_gft2_hi.16b}, v_data_5_hi.16b
+ eor v_d5.16b, v_tmp_lo.16b, v_d5.16b
+ eor v_d5.16b, v_d5.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft2_lo.16b}, v_data_6_lo.16b
+ tbl v_tmp_hi.16b, {v_gft2_hi.16b}, v_data_6_hi.16b
+ eor v_d6.16b, v_tmp_lo.16b, v_d6.16b
+ eor v_d6.16b, v_d6.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft2_lo.16b}, v_data_7_lo.16b
+ tbl v_tmp_hi.16b, {v_gft2_hi.16b}, v_data_7_hi.16b
+ eor v_d7.16b, v_tmp_lo.16b, v_d7.16b
+ eor v_d7.16b, v_d7.16b, v_tmp_hi.16b
+
+ str q_d0, [x_dest2, #16*0]
+ str q_d1, [x_dest2, #16*1]
+ str q_d2, [x_dest2, #16*2]
+ str q_d3, [x_dest2, #16*3]
+ str q_d4, [x_dest2, #16*4]
+ str q_d5, [x_dest2, #16*5]
+ str q_d6, [x_dest2, #16*6]
+ str q_d7, [x_dest2, #16*7]
+
+ add x_src, x_src, #128
+ add x_dest1, x_dest1, #128
+ add x_dest2, x_dest2, #128
+ cmp x_src, x_src_end
+ bls .Lloop128
+
+.Lloop128_end:
+ /* restore d8 ~ d15 */
+ ldp d8, d9, [sp]
+ ldp d10, d11, [sp, #16]
+ ldp d12, d13, [sp, #32]
+ ldp d14, d15, [sp, #48]
+ add sp, sp, #64
+ add x_src_end, x_src_end, #128
+
+.Lloop16_init:
+ sub x_src_end, x_src_end, #16
+ cmp x_src, x_src_end
+ bhi .lessthan16_init
+
+.Lloop16:
+ ldr q_data, [x_src]
+
+ ldr q_d0, [x_dest1]
+ ldr q_d1, [x_dest2]
+
+ and v_data_lo.16b, v_data.16b, v_mask0f.16b
+ ushr v_data_hi.16b, v_data.16b, #4
+
+ tbl v_tmp_lo.16b, {v_gft1_lo.16b}, v_data_lo.16b
+ tbl v_tmp_hi.16b, {v_gft1_hi.16b}, v_data_hi.16b
+ eor v_d0.16b, v_tmp_lo.16b, v_d0.16b
+ eor v_d0.16b, v_d0.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft2_lo.16b}, v_data_lo.16b
+ tbl v_tmp_hi.16b, {v_gft2_hi.16b}, v_data_hi.16b
+ eor v_d1.16b, v_tmp_lo.16b, v_d1.16b
+ eor v_d1.16b, v_d1.16b, v_tmp_hi.16b
+
+ str q_d0, [x_dest1]
+ str q_d1, [x_dest2]
+
+ add x_dest1, x_dest1, #16
+ add x_dest2, x_dest2, #16
+ add x_src, x_src, #16
+ cmp x_src, x_src_end
+ bls .Lloop16
+
+.lessthan16_init:
+ sub x_tmp, x_src, x_src_end
+ cmp x_tmp, #16
+ beq .return_pass
+
+.lessthan16:
+ mov x_src, x_src_end
+ sub x_dest1, x_dest1, x_tmp
+ sub x_dest2, x_dest2, x_tmp
+
+#ifndef __APPLE__
+ adrp x_const, const_tbl
+ add x_const, x_const, :lo12:const_tbl
+#else
+ adrp x_const, const_tbl@PAGE
+ add x_const, x_const, const_tbl@PAGEOFF
+#endif
+ sub x_const, x_const, x_tmp
+ ldr q_tmp, [x_const, #16]
+
+ ldr q_data, [x_src]
+ ldr q_d0, [x_dest1]
+ ldr q_d1, [x_dest2]
+
+ and v_data_lo.16b, v_data.16b, v_mask0f.16b
+ ushr v_data_hi.16b, v_data.16b, #4
+
+ tbl v_tmp_lo.16b, {v_gft1_lo.16b}, v_data_lo.16b
+ tbl v_tmp_hi.16b, {v_gft1_hi.16b}, v_data_hi.16b
+ eor v_tmp_hi.16b, v_tmp_lo.16b, v_tmp_hi.16b
+ and v_tmp_hi.16b, v_tmp_hi.16b, v_tmp.16b
+ eor v_d0.16b, v_d0.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft2_lo.16b}, v_data_lo.16b
+ tbl v_tmp_hi.16b, {v_gft2_hi.16b}, v_data_hi.16b
+ eor v_tmp_hi.16b, v_tmp_lo.16b, v_tmp_hi.16b
+ and v_tmp_hi.16b, v_tmp_hi.16b, v_tmp.16b
+ eor v_d1.16b, v_d1.16b, v_tmp_hi.16b
+
+ str q_d0, [x_dest1]
+ str q_d1, [x_dest2]
+
+.return_pass:
+ mov w_ret, #0
+ ret
+
+.return_fail:
+ mov w_ret, #1
+ ret
+
+ASM_DEF_RODATA
+.balign 8
+const_tbl:
+ .dword 0x0000000000000000, 0x0000000000000000
+ .dword 0xffffffffffffffff, 0xffffffffffffffff
diff --git a/contrib/libs/isa-l/erasure_code/aarch64/gf_2vect_mad_sve.S b/contrib/libs/isa-l/erasure_code/aarch64/gf_2vect_mad_sve.S
new file mode 100644
index 0000000000..f0ddf01187
--- /dev/null
+++ b/contrib/libs/isa-l/erasure_code/aarch64/gf_2vect_mad_sve.S
@@ -0,0 +1,152 @@
+/**************************************************************
+ Copyright (c) 2021 Linaro Ltd.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name of Huawei Corporation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+**********************************************************************/
+.text
+.align 6
+.arch armv8-a+sve
+
+#include "../include/aarch64_label.h"
+
+.global cdecl(gf_2vect_mad_sve)
+#ifndef __APPLE__
+.type gf_2vect_mad_sve, %function
+#endif
+
+/* gf_2vect_mad_sve(int len, int vec, int vec_i, unsigned char *gftbls,
+ unsigned char *src, unsigned char **dest);
+ */
+/* arguments */
+x_len .req x0
+x_vec .req x1
+x_vec_i .req x2
+x_tbl .req x3
+x_src .req x4
+x_dest .req x5
+
+/* returns */
+w_ret .req w0
+
+/* local variables */
+x_pos .req x6
+x_dest2 .req x7
+x_dest1 .req x12
+
+/* vectors */
+z_mask0f .req z0
+
+z_src .req z1
+z_src_lo .req z2
+z_src_hi .req z_src
+
+z_dest1 .req z3
+
+z_tmp_lo .req z4
+z_tmp_hi .req z5
+
+z_gft1_lo .req z6
+z_gft1_hi .req z7
+q_gft1_lo .req q6
+q_gft1_hi .req q7
+
+/* bottom 64-bit of v8..v15 must be preserved if used */
+z_gft2_lo .req z17
+z_gft2_hi .req z18
+q_gft2_lo .req q17
+q_gft2_hi .req q18
+
+z_dest2 .req z27
+
+cdecl(gf_2vect_mad_sve):
+ /* less than 16 bytes, return_fail */
+ cmp x_len, #16
+ blt .return_fail
+
+ mov z_mask0f.b, #0x0f /* z_mask0f = 0x0F0F...0F */
+ /* load table 1 */
+ add x_tbl, x_tbl, x_vec_i, LSL #5 /* x_tbl += x_vec_i * 2^5 */
+
+ /* Load table 1 with NEON instruction ldp */
+ ldp q_gft1_lo, q_gft1_hi, [x_tbl]
+ /* load table 2 */
+ add x_tbl, x_tbl, x_vec, LSL #5 /* x_tbl += x_vec * 2^5 */
+ ldp q_gft2_lo, q_gft2_hi, [x_tbl]
+
+ ldr x_dest1, [x_dest, #8*0] /* pointer to dest1 */
+ ldr x_dest2, [x_dest, #8*1] /* pointer to dest2 */
+
+ mov x_pos, #0
+
+ /* vector length agnostic */
+.Lloopsve_vl:
+ whilelo p0.b, x_pos, x_len
+ b.none .return_pass
+
+ /* prefetch dest data */
+ prfb pldl2strm, p0, [x_dest1, x_pos]
+ prfb pldl2strm, p0, [x_dest2, x_pos]
+
+ /* load src data, governed by p0 */
+ ld1b z_src.b, p0/z, [x_src, x_pos]
+
+ /* split 4-bit lo; 4-bit hi */
+ and z_src_lo.d, z_src.d, z_mask0f.d
+ lsr z_src_hi.b, z_src.b, #4
+
+ /* load dest data, governed by p0 */
+ ld1b z_dest1.b, p0/z, [x_dest1, x_pos]
+ ld1b z_dest2.b, p0/z, [x_dest2, x_pos]
+
+ /* dest1 */
+ /* table indexing, ie. gf(2^8) multiplication */
+ tbl z_tmp_lo.b, {z_gft1_lo.b}, z_src_lo.b
+ tbl z_tmp_hi.b, {z_gft1_hi.b}, z_src_hi.b
+ /* exclusive or, ie. gf(2^8) add */
+ eor z_dest1.d, z_tmp_lo.d, z_dest1.d
+ eor z_dest1.d, z_tmp_hi.d, z_dest1.d
+
+ /* dest2 */
+ tbl z_tmp_lo.b, {z_gft2_lo.b}, z_src_lo.b
+ tbl z_tmp_hi.b, {z_gft2_hi.b}, z_src_hi.b
+ eor z_dest2.d, z_tmp_lo.d, z_dest2.d
+ eor z_dest2.d, z_tmp_hi.d, z_dest2.d
+
+ /* store dest data, governed by p0 */
+ st1b z_dest1.b, p0, [x_dest1, x_pos]
+ st1b z_dest2.b, p0, [x_dest2, x_pos]
+ /* increment one vector length */
+ incb x_pos
+
+ b .Lloopsve_vl
+
+.return_pass:
+ mov w_ret, #0
+ ret
+
+.return_fail:
+ mov w_ret, #1
+ ret
diff --git a/contrib/libs/isa-l/erasure_code/aarch64/gf_3vect_dot_prod_neon.S b/contrib/libs/isa-l/erasure_code/aarch64/gf_3vect_dot_prod_neon.S
new file mode 100644
index 0000000000..cff34fc3dd
--- /dev/null
+++ b/contrib/libs/isa-l/erasure_code/aarch64/gf_3vect_dot_prod_neon.S
@@ -0,0 +1,361 @@
+/**************************************************************
+ Copyright (c) 2019 Huawei Technologies Co., Ltd.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name of Huawei Corporation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+**********************************************************************/
+
+#include "../include/aarch64_label.h"
+
+.text
+
+.global cdecl(gf_3vect_dot_prod_neon)
+#ifndef __APPLE__
+.type gf_3vect_dot_prod_neon, %function
+#endif
+
+/* arguments */
+x_len .req x0
+x_vec .req x1
+x_tbl .req x2
+x_src .req x3
+x_dest .req x4
+
+/* returns */
+w_ret .req w0
+
+/* local variables */
+x_vec_i .req x5
+x_ptr .req x6
+x_pos .req x7
+x_tmp .req x8
+x_dest1 .req x9
+x_tbl1 .req x10
+x_dest2 .req x11
+x_tbl2 .req x12
+x_dest3 .req x13
+x_tbl3 .req x14
+
+/* vectors */
+v_gft1_lo .req v0
+v_gft1_hi .req v1
+v_gft2_lo .req v2
+v_gft2_hi .req v3
+v_gft3_lo .req v4
+v_gft3_hi .req v5
+q_gft1_lo .req q0
+q_gft1_hi .req q1
+q_gft2_lo .req q2
+q_gft2_hi .req q3
+q_gft3_lo .req q4
+q_gft3_hi .req q5
+
+v_mask0f .req v6
+q_mask0f .req q6
+v_tmp1 .req v7
+
+v_data_0 .req v8
+v_data_1 .req v9
+v_data_2 .req v10
+v_data_3 .req v11
+q_data_0 .req q8
+q_data_1 .req q9
+q_data_2 .req q10
+q_data_3 .req q11
+
+v_tmp1_lo .req v12
+v_tmp1_hi .req v13
+
+v_p1_0 .req v20
+v_p1_1 .req v21
+v_p1_2 .req v22
+v_p1_3 .req v23
+v_p2_0 .req v24
+v_p2_1 .req v25
+v_p2_2 .req v26
+v_p2_3 .req v27
+v_p3_0 .req v28
+v_p3_1 .req v29
+v_p3_2 .req v30
+v_p3_3 .req v31
+
+q_p1_0 .req q20
+q_p1_1 .req q21
+q_p1_2 .req q22
+q_p1_3 .req q23
+q_p2_0 .req q24
+q_p2_1 .req q25
+q_p2_2 .req q26
+q_p2_3 .req q27
+q_p3_0 .req q28
+q_p3_1 .req q29
+q_p3_2 .req q30
+q_p3_3 .req q31
+
+v_data .req v_p1_1
+q_data .req q_p1_1
+v_data_lo .req v_p1_2
+v_data_hi .req v_p1_3
+
+
+cdecl(gf_3vect_dot_prod_neon):
+ /* less than 16 bytes, return_fail */
+ cmp x_len, #16
+ blt .return_fail
+
+ movi v_mask0f.16b, #0x0f
+ mov x_pos, #0
+ lsl x_vec, x_vec, #3
+ ldr x_dest1, [x_dest, #8*0]
+ ldr x_dest2, [x_dest, #8*1]
+ ldr x_dest3, [x_dest, #8*2]
+
+.Lloop64_init:
+ /* less than 64 bytes, goto Lloop16_init */
+ cmp x_len, #64
+ blt .Lloop16_init
+
+ /* save d8 ~ d15 to stack */
+ sub sp, sp, #64
+ stp d8, d9, [sp]
+ stp d10, d11, [sp, #16]
+ stp d12, d13, [sp, #32]
+ stp d14, d15, [sp, #48]
+
+ sub x_len, x_len, #64
+
+.Lloop64:
+ movi v_p1_0.16b, #0
+ movi v_p1_1.16b, #0
+ movi v_p1_2.16b, #0
+ movi v_p1_3.16b, #0
+ movi v_p2_0.16b, #0
+ movi v_p2_1.16b, #0
+ movi v_p2_2.16b, #0
+ movi v_p2_3.16b, #0
+ movi v_p3_0.16b, #0
+ movi v_p3_1.16b, #0
+ movi v_p3_2.16b, #0
+ movi v_p3_3.16b, #0
+
+ mov x_tbl1, x_tbl
+ add x_tbl2, x_tbl1, x_vec, lsl #2
+ add x_tbl3, x_tbl2, x_vec, lsl #2
+ mov x_vec_i, #0
+
+.Lloop64_vects:
+ ldr x_ptr, [x_src, x_vec_i]
+ add x_vec_i, x_vec_i, #8
+ add x_ptr, x_ptr, x_pos
+
+ ldr q_data_0, [x_ptr], #16
+ ldr q_data_1, [x_ptr], #16
+
+ ldp q_gft1_lo, q_gft1_hi, [x_tbl1], #32
+ ldp q_gft2_lo, q_gft2_hi, [x_tbl2], #32
+ ldp q_gft3_lo, q_gft3_hi, [x_tbl3], #32
+
+ ldr q_data_2, [x_ptr], #16
+ ldr q_data_3, [x_ptr], #16
+ prfm pldl1strm, [x_ptr]
+ prfm pldl1keep, [x_tbl1]
+ prfm pldl1keep, [x_tbl2]
+ prfm pldl1keep, [x_tbl3]
+
+ /* data_0 */
+ and v_tmp1.16b, v_data_0.16b, v_mask0f.16b
+ ushr v_data_0.16b, v_data_0.16b, #4
+
+ tbl v_tmp1_lo.16b, {v_gft1_lo.16b}, v_tmp1.16b
+ tbl v_tmp1_hi.16b, {v_gft1_hi.16b}, v_data_0.16b
+ eor v_p1_0.16b, v_tmp1_lo.16b, v_p1_0.16b
+ eor v_p1_0.16b, v_p1_0.16b, v_tmp1_hi.16b
+
+ tbl v_tmp1_lo.16b, {v_gft2_lo.16b}, v_tmp1.16b
+ tbl v_tmp1_hi.16b, {v_gft2_hi.16b}, v_data_0.16b
+ eor v_p2_0.16b, v_tmp1_lo.16b, v_p2_0.16b
+ eor v_p2_0.16b, v_p2_0.16b, v_tmp1_hi.16b
+
+ tbl v_tmp1_lo.16b, {v_gft3_lo.16b}, v_tmp1.16b
+ tbl v_tmp1_hi.16b, {v_gft3_hi.16b}, v_data_0.16b
+ eor v_p3_0.16b, v_tmp1_lo.16b, v_p3_0.16b
+ eor v_p3_0.16b, v_p3_0.16b, v_tmp1_hi.16b
+
+ /* data_1 */
+ and v_tmp1.16b, v_data_1.16b, v_mask0f.16b
+ ushr v_data_1.16b, v_data_1.16b, #4
+
+ tbl v_tmp1_lo.16b, {v_gft1_lo.16b}, v_tmp1.16b
+ tbl v_tmp1_hi.16b, {v_gft1_hi.16b}, v_data_1.16b
+ eor v_p1_1.16b, v_tmp1_lo.16b, v_p1_1.16b
+ eor v_p1_1.16b, v_p1_1.16b, v_tmp1_hi.16b
+
+ tbl v_tmp1_lo.16b, {v_gft2_lo.16b}, v_tmp1.16b
+ tbl v_tmp1_hi.16b, {v_gft2_hi.16b}, v_data_1.16b
+ eor v_p2_1.16b, v_tmp1_lo.16b, v_p2_1.16b
+ eor v_p2_1.16b, v_p2_1.16b, v_tmp1_hi.16b
+
+ tbl v_tmp1_lo.16b, {v_gft3_lo.16b}, v_tmp1.16b
+ tbl v_tmp1_hi.16b, {v_gft3_hi.16b}, v_data_1.16b
+ eor v_p3_1.16b, v_tmp1_lo.16b, v_p3_1.16b
+ eor v_p3_1.16b, v_p3_1.16b, v_tmp1_hi.16b
+
+ /* data_2 */
+ and v_tmp1.16b, v_data_2.16b, v_mask0f.16b
+ ushr v_data_2.16b, v_data_2.16b, #4
+
+ tbl v_tmp1_lo.16b, {v_gft1_lo.16b}, v_tmp1.16b
+ tbl v_tmp1_hi.16b, {v_gft1_hi.16b}, v_data_2.16b
+ eor v_p1_2.16b, v_tmp1_lo.16b, v_p1_2.16b
+ eor v_p1_2.16b, v_p1_2.16b, v_tmp1_hi.16b
+
+ tbl v_tmp1_lo.16b, {v_gft2_lo.16b}, v_tmp1.16b
+ tbl v_tmp1_hi.16b, {v_gft2_hi.16b}, v_data_2.16b
+ eor v_p2_2.16b, v_tmp1_lo.16b, v_p2_2.16b
+ eor v_p2_2.16b, v_p2_2.16b, v_tmp1_hi.16b
+
+ tbl v_tmp1_lo.16b, {v_gft3_lo.16b}, v_tmp1.16b
+ tbl v_tmp1_hi.16b, {v_gft3_hi.16b}, v_data_2.16b
+ eor v_p3_2.16b, v_tmp1_lo.16b, v_p3_2.16b
+ eor v_p3_2.16b, v_p3_2.16b, v_tmp1_hi.16b
+
+ /* data_3 */
+ and v_tmp1.16b, v_data_3.16b, v_mask0f.16b
+ ushr v_data_3.16b, v_data_3.16b, #4
+
+ tbl v_tmp1_lo.16b, {v_gft1_lo.16b}, v_tmp1.16b
+ tbl v_tmp1_hi.16b, {v_gft1_hi.16b}, v_data_3.16b
+ eor v_p1_3.16b, v_tmp1_lo.16b, v_p1_3.16b
+ eor v_p1_3.16b, v_p1_3.16b, v_tmp1_hi.16b
+
+ tbl v_tmp1_lo.16b, {v_gft2_lo.16b}, v_tmp1.16b
+ tbl v_tmp1_hi.16b, {v_gft2_hi.16b}, v_data_3.16b
+ eor v_p2_3.16b, v_tmp1_lo.16b, v_p2_3.16b
+ eor v_p2_3.16b, v_p2_3.16b, v_tmp1_hi.16b
+
+ tbl v_tmp1_lo.16b, {v_gft3_lo.16b}, v_tmp1.16b
+ tbl v_tmp1_hi.16b, {v_gft3_hi.16b}, v_data_3.16b
+ eor v_p3_3.16b, v_tmp1_lo.16b, v_p3_3.16b
+ eor v_p3_3.16b, v_p3_3.16b, v_tmp1_hi.16b
+
+ cmp x_vec_i, x_vec
+ blt .Lloop64_vects
+
+.Lloop64_vects_end:
+ add x_ptr, x_dest1, x_pos
+ stp q_p1_0, q_p1_1, [x_ptr], #32
+ stp q_p1_2, q_p1_3, [x_ptr]
+
+ add x_ptr, x_dest2, x_pos
+ stp q_p2_0, q_p2_1, [x_ptr], #32
+ stp q_p2_2, q_p2_3, [x_ptr]
+
+ add x_ptr, x_dest3, x_pos
+ stp q_p3_0, q_p3_1, [x_ptr], #32
+ stp q_p3_2, q_p3_3, [x_ptr]
+
+ add x_pos, x_pos, #64
+ cmp x_pos, x_len
+ ble .Lloop64
+
+.Lloop64_end:
+ /* restore d8 ~ d15 */
+ ldp d8, d9, [sp]
+ ldp d10, d11, [sp, #16]
+ ldp d12, d13, [sp, #32]
+ ldp d14, d15, [sp, #48]
+ add sp, sp, #64
+
+ add x_len, x_len, #64
+ cmp x_pos, x_len
+ beq .return_pass
+
+.Lloop16_init:
+ sub x_len, x_len, #16
+ cmp x_pos, x_len
+ bgt .lessthan16_init
+
+.Lloop16:
+ movi v_p1_0.16b, #0
+ movi v_p2_0.16b, #0
+ movi v_p3_0.16b, #0
+ mov x_tbl1, x_tbl
+ add x_tbl2, x_tbl1, x_vec, lsl #2
+ add x_tbl3, x_tbl2, x_vec, lsl #2
+ mov x_vec_i, #0
+
+.Lloop16_vects:
+ ldr x_ptr, [x_src, x_vec_i]
+ add x_vec_i, x_vec_i, #8
+ ldr q_data, [x_ptr, x_pos]
+
+ ldp q_gft1_lo, q_gft1_hi, [x_tbl1], #32
+ ldp q_gft2_lo, q_gft2_hi, [x_tbl2], #32
+ ldp q_gft3_lo, q_gft3_hi, [x_tbl3], #32
+
+ and v_data_lo.16b, v_data.16b, v_mask0f.16b
+ ushr v_data_hi.16b, v_data.16b, #4
+
+ tbl v_gft1_lo.16b, {v_gft1_lo.16b}, v_data_lo.16b
+ tbl v_gft1_hi.16b, {v_gft1_hi.16b}, v_data_hi.16b
+ tbl v_gft2_lo.16b, {v_gft2_lo.16b}, v_data_lo.16b
+ tbl v_gft2_hi.16b, {v_gft2_hi.16b}, v_data_hi.16b
+ tbl v_gft3_lo.16b, {v_gft3_lo.16b}, v_data_lo.16b
+ tbl v_gft3_hi.16b, {v_gft3_hi.16b}, v_data_hi.16b
+
+ eor v_p1_0.16b, v_gft1_hi.16b, v_p1_0.16b
+ eor v_p1_0.16b, v_p1_0.16b, v_gft1_lo.16b
+ eor v_p2_0.16b, v_gft2_hi.16b, v_p2_0.16b
+ eor v_p2_0.16b, v_p2_0.16b, v_gft2_lo.16b
+ eor v_p3_0.16b, v_gft3_hi.16b, v_p3_0.16b
+ eor v_p3_0.16b, v_p3_0.16b, v_gft3_lo.16b
+
+ cmp x_vec_i, x_vec
+ bne .Lloop16_vects
+
+.Lloop16_vects_end:
+ str q_p1_0, [x_dest1, x_pos]
+ str q_p2_0, [x_dest2, x_pos]
+ str q_p3_0, [x_dest3, x_pos]
+ add x_pos, x_pos, #16
+ cmp x_pos, x_len
+ ble .Lloop16
+
+.Lloop16_end:
+ sub x_tmp, x_pos, x_len
+ cmp x_tmp, #16
+ beq .return_pass
+
+.lessthan16_init:
+ mov x_pos, x_len
+ b .Lloop16
+
+.return_pass:
+ mov w_ret, #0
+ ret
+
+.return_fail:
+ mov w_ret, #1
+ ret
diff --git a/contrib/libs/isa-l/erasure_code/aarch64/gf_3vect_dot_prod_sve.S b/contrib/libs/isa-l/erasure_code/aarch64/gf_3vect_dot_prod_sve.S
new file mode 100644
index 0000000000..8f6414ee52
--- /dev/null
+++ b/contrib/libs/isa-l/erasure_code/aarch64/gf_3vect_dot_prod_sve.S
@@ -0,0 +1,189 @@
+/*************************************************************
+ Copyright (c) 2021 Linaro Ltd.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name of Huawei Corporation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+**********************************************************************/
+.text
+.align 6
+.arch armv8-a+sve
+
+#include "../include/aarch64_label.h"
+
+.global cdecl(gf_3vect_dot_prod_sve)
+#ifndef __APPLE__
+.type gf_3vect_dot_prod_sve, %function
+#endif
+/* void gf_3vect_dot_prod_sve(int len, int vlen, unsigned char *gftbls,
+ unsigned char **src, unsigned char **dest);
+ */
+
+/* arguments */
+x_len .req x0 /* vector length */
+x_vec .req x1 /* number of source vectors (ie. data blocks) */
+x_tbl .req x2
+x_src .req x3
+x_dest .req x4
+
+/* returns */
+w_ret .req w0
+
+/* local variables */
+x_vec_i .req x5
+x_ptr .req x6
+x_pos .req x7
+
+x_tbl1 .req x8
+x_tbl2 .req x9
+x_tbl3 .req x10
+x_dest1 .req x11
+x_dest2 .req x12
+x_dest3 .req x_dest /* reused */
+
+/* r16,r17,r18,r29,r30: special role registers, avoided */
+/* r19..r29 and SP must be preserved */
+
+/* vectors */
+z_mask0f .req z0
+
+z_src .req z1
+z_src_lo .req z2
+z_src_hi .req z_src
+
+z_dest1 .req z3
+
+z_gft1_lo .req z4
+z_gft1_hi .req z5
+q_gft1_lo .req q4
+q_gft1_hi .req q5
+
+/* bottom 64-bit of v8..v15 must be preserved if used */
+z_gft2_lo .req z17
+z_gft2_hi .req z18
+q_gft2_lo .req q17
+q_gft2_hi .req q18
+
+z_gft3_lo .req z19
+z_gft3_hi .req z20
+q_gft3_lo .req q19
+q_gft3_hi .req q20
+
+z_dest2 .req z27
+z_dest3 .req z28
+
+cdecl(gf_3vect_dot_prod_sve):
+ /* less than 16 bytes, return_fail */
+ cmp x_len, #16
+ blt .return_fail
+
+ mov z_mask0f.b, #0x0f /* z_mask0f = 0x0F0F...0F */
+ mov x_pos, #0
+ lsl x_vec, x_vec, #3
+ ldp x_dest1, x_dest2, [x_dest, #8*0]
+ ldr x_dest3, [x_dest, #8*2]
+
+/* Loop 1: x_len, vector length */
+.Lloopsve_vl:
+ whilelo p0.b, x_pos, x_len
+ b.none .return_pass
+
+ mov x_vec_i, #0 /* clear x_vec_i */
+ ldr x_ptr, [x_src, x_vec_i] /* x_ptr: src base addr. */
+
+ mov z_dest1.b, #0 /* clear z_dest1 */
+ mov z_dest2.b, #0 /* clear z_dest2 */
+ mov z_dest3.b, #0 /* clear z_dest3 */
+
+ /* gf_tbl base = (x_tbl + dest_idx * x_vec * 32) */
+ mov x_tbl1, x_tbl /* reset x_tbl1 */
+ add x_tbl2, x_tbl1, x_vec, LSL #2 /* reset x_tbl2 */
+ add x_tbl3, x_tbl2, x_vec, LSL #2 /* reset x_tbl3 */
+
+/* Loop 2: x_vec, number of source vectors (ie. data blocks) */
+.Lloopsve_vl_vects:
+ /* load src data, governed by p0 */
+ ld1b z_src.b, p0/z, [x_ptr, x_pos] /* load from: src base + pos offset */
+ /* split 4-bit lo; 4-bit hi */
+ and z_src_lo.d, z_src.d, z_mask0f.d
+ lsr z_src_hi.b, z_src.b, #4
+
+
+ /* gf_tbl addr: (x_tbl + dest_idx * x_vec * 32) + src_vec_idx * 32 */
+ /* load gf_table's */
+ ldp q_gft1_lo, q_gft1_hi, [x_tbl1], #32 /* x_tbl1 is post-added by #32 for each src vect */
+ ldp q_gft2_lo, q_gft2_hi, [x_tbl2], #32
+
+ /* prefetch */
+ prfb pldl2keep, p0, [x_tbl1]
+ prfb pldl2keep, p0, [x_tbl2]
+
+ /* calc for next */
+ add x_vec_i, x_vec_i, #8 /* move x_vec_i to next */
+ ldr x_ptr, [x_src, x_vec_i] /* x_ptr: src base addr. */
+
+ /* dest 1 */
+ /* table indexing, ie. gf(2^8) multiplication */
+ tbl z_gft1_lo.b, {z_gft1_lo.b}, z_src_lo.b
+ tbl z_gft1_hi.b, {z_gft1_hi.b}, z_src_hi.b
+ /* exclusive or, ie. gf(2^8) add */
+ eor z_dest1.d, z_gft1_lo.d, z_dest1.d
+ eor z_dest1.d, z_dest1.d, z_gft1_hi.d
+
+ ldp q_gft3_lo, q_gft3_hi, [x_tbl3], #32
+ prfb pldl2keep, p0, [x_tbl3]
+
+ /* dest 2 */
+ tbl z_gft2_lo.b, {z_gft2_lo.b}, z_src_lo.b
+ tbl z_gft2_hi.b, {z_gft2_hi.b}, z_src_hi.b
+ eor z_dest2.d, z_gft2_lo.d, z_dest2.d
+ eor z_dest2.d, z_dest2.d, z_gft2_hi.d
+
+ /* dest 3 */
+ tbl z_gft3_lo.b, {z_gft3_lo.b}, z_src_lo.b
+ tbl z_gft3_hi.b, {z_gft3_hi.b}, z_src_hi.b
+ eor z_dest3.d, z_gft3_lo.d, z_dest3.d
+ eor z_dest3.d, z_dest3.d, z_gft3_hi.d
+
+ cmp x_vec_i, x_vec
+ blt .Lloopsve_vl_vects
+/* end of Loop 2 */
+
+ /* store dest data, governed by p0 */
+ st1b z_dest1.b, p0, [x_dest1, x_pos]
+ st1b z_dest2.b, p0, [x_dest2, x_pos]
+ st1b z_dest3.b, p0, [x_dest3, x_pos]
+
+ /* increment one vector length */
+ incb x_pos
+ b .Lloopsve_vl
+/* end of Loop 1 */
+
+.return_pass:
+ mov w_ret, #0
+ ret
+
+.return_fail:
+ mov w_ret, #1
+ ret
diff --git a/contrib/libs/isa-l/erasure_code/aarch64/gf_3vect_mad_neon.S b/contrib/libs/isa-l/erasure_code/aarch64/gf_3vect_mad_neon.S
new file mode 100644
index 0000000000..fcfeec1e23
--- /dev/null
+++ b/contrib/libs/isa-l/erasure_code/aarch64/gf_3vect_mad_neon.S
@@ -0,0 +1,391 @@
+/**************************************************************
+ Copyright (c) 2019 Huawei Technologies Co., Ltd.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name of Huawei Corporation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+**********************************************************************/
+
+#include "../include/aarch64_label.h"
+
+.text
+
+.global cdecl(gf_3vect_mad_neon)
+#ifndef __APPLE__
+.type gf_3vect_mad_neon, %function
+#endif
+
+/* arguments */
+x_len .req x0
+x_vec .req x1
+x_vec_i .req x2
+x_tbl .req x3
+x_src .req x4
+x_dest .req x5
+
+/* returns */
+w_ret .req w0
+
+/* local variables */
+x_src_end .req x6
+x_dest1 .req x7
+x_dest2 .req x8
+x_dest3 .req x_dest
+x_tmp .req x10
+x_tbl1 .req x11
+x_tbl2 .req x12
+x_tbl3 .req x13
+x_const .req x14
+
+/* vectors */
+v_mask0f .req v0
+v_tmp_lo .req v1
+v_tmp_hi .req v2
+v_tmp .req v3
+q_tmp .req q3
+
+v_gft1_lo .req v4
+v_gft1_hi .req v5
+v_gft2_lo .req v6
+v_gft2_hi .req v7
+v_gft3_lo .req v16
+v_gft3_hi .req v17
+q_gft1_lo .req q4
+q_gft1_hi .req q5
+q_gft2_lo .req q6
+q_gft2_hi .req q7
+q_gft3_lo .req q16
+q_gft3_hi .req q17
+
+v_data_0 .req v8
+v_data_1 .req v9
+v_data_2 .req v10
+v_data_3 .req v11
+q_data_0 .req q8
+q_data_1 .req q9
+q_data_2 .req q10
+q_data_3 .req q11
+
+v_data_0_lo .req v12
+v_data_1_lo .req v13
+v_data_2_lo .req v14
+v_data_3_lo .req v15
+v_data_0_hi .req v_data_0
+v_data_1_hi .req v_data_1
+v_data_2_hi .req v_data_2
+v_data_3_hi .req v_data_3
+
+v_d1_0 .req v20
+v_d1_1 .req v21
+v_d1_2 .req v22
+v_d1_3 .req v23
+v_d2_0 .req v24
+v_d2_1 .req v25
+v_d2_2 .req v26
+v_d2_3 .req v27
+v_d3_0 .req v28
+v_d3_1 .req v29
+v_d3_2 .req v30
+v_d3_3 .req v31
+q_d1_0 .req q20
+q_d1_1 .req q21
+q_d1_2 .req q22
+q_d1_3 .req q23
+q_d2_0 .req q24
+q_d2_1 .req q25
+q_d2_2 .req q26
+q_d2_3 .req q27
+q_d3_0 .req q28
+q_d3_1 .req q29
+q_d3_2 .req q30
+q_d3_3 .req q31
+
+v_data .req v21
+q_data .req q21
+v_data_lo .req v22
+v_data_hi .req v23
+
+cdecl(gf_3vect_mad_neon):
+ /* less than 16 bytes, return_fail */
+ cmp x_len, #16
+ blt .return_fail
+
+ movi v_mask0f.16b, #0x0f
+ lsl x_vec_i, x_vec_i, #5
+ lsl x_vec, x_vec, #5
+ add x_tbl1, x_tbl, x_vec_i
+ add x_tbl2, x_tbl1, x_vec
+ add x_tbl3, x_tbl2, x_vec
+ add x_src_end, x_src, x_len
+ ldr x_dest1, [x_dest]
+ ldr x_dest2, [x_dest, #8]
+ ldr x_dest3, [x_dest, #16]
+ ldr q_gft1_lo, [x_tbl1]
+ ldr q_gft1_hi, [x_tbl1, #16]
+ ldr q_gft2_lo, [x_tbl2]
+ ldr q_gft2_hi, [x_tbl2, #16]
+ ldr q_gft3_lo, [x_tbl3]
+ ldr q_gft3_hi, [x_tbl3, #16]
+
+.Lloop64_init:
+ /* less than 64 bytes, goto Lloop16_init */
+ cmp x_len, #64
+ blt .Lloop16_init
+
+ /* save d8 ~ d15 to stack */
+ sub sp, sp, #64
+ stp d8, d9, [sp]
+ stp d10, d11, [sp, #16]
+ stp d12, d13, [sp, #32]
+ stp d14, d15, [sp, #48]
+
+ sub x_src_end, x_src_end, #64
+
+.Lloop64:
+ ldr q_data_0, [x_src, #16*0]
+ ldr q_data_1, [x_src, #16*1]
+ ldr q_data_2, [x_src, #16*2]
+ ldr q_data_3, [x_src, #16*3]
+ add x_src, x_src, #64
+
+ ldr q_d1_0, [x_dest1, #16*0]
+ ldr q_d1_1, [x_dest1, #16*1]
+ ldr q_d1_2, [x_dest1, #16*2]
+ ldr q_d1_3, [x_dest1, #16*3]
+
+ ldr q_d2_0, [x_dest2, #16*0]
+ ldr q_d2_1, [x_dest2, #16*1]
+ ldr q_d2_2, [x_dest2, #16*2]
+ ldr q_d2_3, [x_dest2, #16*3]
+
+ ldr q_d3_0, [x_dest3, #16*0]
+ ldr q_d3_1, [x_dest3, #16*1]
+ ldr q_d3_2, [x_dest3, #16*2]
+ ldr q_d3_3, [x_dest3, #16*3]
+
+ and v_data_0_lo.16b, v_data_0.16b, v_mask0f.16b
+ and v_data_1_lo.16b, v_data_1.16b, v_mask0f.16b
+ and v_data_2_lo.16b, v_data_2.16b, v_mask0f.16b
+ and v_data_3_lo.16b, v_data_3.16b, v_mask0f.16b
+
+ ushr v_data_0_hi.16b, v_data_0.16b, #4
+ ushr v_data_1_hi.16b, v_data_1.16b, #4
+ ushr v_data_2_hi.16b, v_data_2.16b, #4
+ ushr v_data_3_hi.16b, v_data_3.16b, #4
+
+ tbl v_tmp_lo.16b, {v_gft1_lo.16b}, v_data_0_lo.16b
+ tbl v_tmp_hi.16b, {v_gft1_hi.16b}, v_data_0_hi.16b
+ eor v_d1_0.16b, v_tmp_lo.16b, v_d1_0.16b
+ eor v_d1_0.16b, v_d1_0.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft1_lo.16b}, v_data_1_lo.16b
+ tbl v_tmp_hi.16b, {v_gft1_hi.16b}, v_data_1_hi.16b
+ eor v_d1_1.16b, v_tmp_lo.16b, v_d1_1.16b
+ eor v_d1_1.16b, v_d1_1.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft1_lo.16b}, v_data_2_lo.16b
+ tbl v_tmp_hi.16b, {v_gft1_hi.16b}, v_data_2_hi.16b
+ eor v_d1_2.16b, v_tmp_lo.16b, v_d1_2.16b
+ eor v_d1_2.16b, v_d1_2.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft1_lo.16b}, v_data_3_lo.16b
+ tbl v_tmp_hi.16b, {v_gft1_hi.16b}, v_data_3_hi.16b
+ eor v_d1_3.16b, v_tmp_lo.16b, v_d1_3.16b
+ eor v_d1_3.16b, v_d1_3.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft2_lo.16b}, v_data_0_lo.16b
+ tbl v_tmp_hi.16b, {v_gft2_hi.16b}, v_data_0_hi.16b
+ eor v_d2_0.16b, v_tmp_lo.16b, v_d2_0.16b
+ eor v_d2_0.16b, v_d2_0.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft2_lo.16b}, v_data_1_lo.16b
+ tbl v_tmp_hi.16b, {v_gft2_hi.16b}, v_data_1_hi.16b
+ eor v_d2_1.16b, v_tmp_lo.16b, v_d2_1.16b
+ eor v_d2_1.16b, v_d2_1.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft2_lo.16b}, v_data_2_lo.16b
+ tbl v_tmp_hi.16b, {v_gft2_hi.16b}, v_data_2_hi.16b
+ eor v_d2_2.16b, v_tmp_lo.16b, v_d2_2.16b
+ eor v_d2_2.16b, v_d2_2.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft2_lo.16b}, v_data_3_lo.16b
+ tbl v_tmp_hi.16b, {v_gft2_hi.16b}, v_data_3_hi.16b
+ eor v_d2_3.16b, v_tmp_lo.16b, v_d2_3.16b
+ eor v_d2_3.16b, v_d2_3.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft3_lo.16b}, v_data_0_lo.16b
+ tbl v_tmp_hi.16b, {v_gft3_hi.16b}, v_data_0_hi.16b
+ eor v_d3_0.16b, v_tmp_lo.16b, v_d3_0.16b
+ eor v_d3_0.16b, v_d3_0.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft3_lo.16b}, v_data_1_lo.16b
+ tbl v_tmp_hi.16b, {v_gft3_hi.16b}, v_data_1_hi.16b
+ eor v_d3_1.16b, v_tmp_lo.16b, v_d3_1.16b
+ eor v_d3_1.16b, v_d3_1.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft3_lo.16b}, v_data_2_lo.16b
+ tbl v_tmp_hi.16b, {v_gft3_hi.16b}, v_data_2_hi.16b
+ eor v_d3_2.16b, v_tmp_lo.16b, v_d3_2.16b
+ eor v_d3_2.16b, v_d3_2.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft3_lo.16b}, v_data_3_lo.16b
+ tbl v_tmp_hi.16b, {v_gft3_hi.16b}, v_data_3_hi.16b
+ eor v_d3_3.16b, v_tmp_lo.16b, v_d3_3.16b
+ eor v_d3_3.16b, v_d3_3.16b, v_tmp_hi.16b
+
+ str q_d1_0, [x_dest1, #16*0]
+ str q_d1_1, [x_dest1, #16*1]
+ str q_d1_2, [x_dest1, #16*2]
+ str q_d1_3, [x_dest1, #16*3]
+ add x_dest1, x_dest1, #64
+
+ str q_d2_0, [x_dest2, #16*0]
+ str q_d2_1, [x_dest2, #16*1]
+ str q_d2_2, [x_dest2, #16*2]
+ str q_d2_3, [x_dest2, #16*3]
+ add x_dest2, x_dest2, #64
+
+ str q_d3_0, [x_dest3, #16*0]
+ str q_d3_1, [x_dest3, #16*1]
+ str q_d3_2, [x_dest3, #16*2]
+ str q_d3_3, [x_dest3, #16*3]
+ add x_dest3, x_dest3, #64
+
+ cmp x_src, x_src_end
+ bls .Lloop64
+
+.Lloop64_end:
+ /* restore d8 ~ d15 */
+ ldp d8, d9, [sp]
+ ldp d10, d11, [sp, #16]
+ ldp d12, d13, [sp, #32]
+ ldp d14, d15, [sp, #48]
+ add sp, sp, #64
+ add x_src_end, x_src_end, #64
+
+.Lloop16_init:
+ sub x_src_end, x_src_end, #16
+ cmp x_src, x_src_end
+ bhi .lessthan16_init
+
+.Lloop16:
+ ldr q_data, [x_src]
+
+ ldr q_d1_0, [x_dest1]
+ ldr q_d2_0, [x_dest2]
+ ldr q_d3_0, [x_dest3]
+
+ and v_data_lo.16b, v_data.16b, v_mask0f.16b
+ ushr v_data_hi.16b, v_data.16b, #4
+
+ tbl v_tmp_lo.16b, {v_gft1_lo.16b}, v_data_lo.16b
+ tbl v_tmp_hi.16b, {v_gft1_hi.16b}, v_data_hi.16b
+ eor v_d1_0.16b, v_tmp_lo.16b, v_d1_0.16b
+ eor v_d1_0.16b, v_d1_0.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft2_lo.16b}, v_data_lo.16b
+ tbl v_tmp_hi.16b, {v_gft2_hi.16b}, v_data_hi.16b
+ eor v_d2_0.16b, v_tmp_lo.16b, v_d2_0.16b
+ eor v_d2_0.16b, v_d2_0.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft3_lo.16b}, v_data_lo.16b
+ tbl v_tmp_hi.16b, {v_gft3_hi.16b}, v_data_hi.16b
+ eor v_d3_0.16b, v_tmp_lo.16b, v_d3_0.16b
+ eor v_d3_0.16b, v_d3_0.16b, v_tmp_hi.16b
+
+ str q_d1_0, [x_dest1]
+ str q_d2_0, [x_dest2]
+ str q_d3_0, [x_dest3]
+
+ add x_src, x_src, #16
+ add x_dest1, x_dest1, #16
+ add x_dest2, x_dest2, #16
+ add x_dest3, x_dest3, #16
+ cmp x_src, x_src_end
+ bls .Lloop16
+
+.lessthan16_init:
+ sub x_tmp, x_src, x_src_end
+ cmp x_tmp, #16
+ beq .return_pass
+
+.lessthan16:
+ mov x_src, x_src_end
+ sub x_dest1, x_dest1, x_tmp
+ sub x_dest2, x_dest2, x_tmp
+ sub x_dest3, x_dest3, x_tmp
+
+#ifndef __APPLE__
+ adrp x_const, const_tbl
+ add x_const, x_const, :lo12:const_tbl
+#else
+ adrp x_const, const_tbl@PAGE
+ add x_const, x_const, const_tbl@PAGEOFF
+#endif
+ sub x_const, x_const, x_tmp
+ ldr q_tmp, [x_const, #16]
+
+ ldr q_data, [x_src]
+ ldr q_d1_0, [x_dest1]
+ ldr q_d2_0, [x_dest2]
+ ldr q_d3_0, [x_dest3]
+
+ and v_data_lo.16b, v_data.16b, v_mask0f.16b
+ ushr v_data_hi.16b, v_data.16b, #4
+
+ tbl v_tmp_lo.16b, {v_gft1_lo.16b}, v_data_lo.16b
+ tbl v_tmp_hi.16b, {v_gft1_hi.16b}, v_data_hi.16b
+ eor v_tmp_hi.16b, v_tmp_lo.16b, v_tmp_hi.16b
+ and v_tmp_hi.16b, v_tmp_hi.16b, v_tmp.16b
+ eor v_d1_0.16b, v_d1_0.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft2_lo.16b}, v_data_lo.16b
+ tbl v_tmp_hi.16b, {v_gft2_hi.16b}, v_data_hi.16b
+ eor v_tmp_hi.16b, v_tmp_lo.16b, v_tmp_hi.16b
+ and v_tmp_hi.16b, v_tmp_hi.16b, v_tmp.16b
+ eor v_d2_0.16b, v_d2_0.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft3_lo.16b}, v_data_lo.16b
+ tbl v_tmp_hi.16b, {v_gft3_hi.16b}, v_data_hi.16b
+ eor v_tmp_hi.16b, v_tmp_lo.16b, v_tmp_hi.16b
+ and v_tmp_hi.16b, v_tmp_hi.16b, v_tmp.16b
+ eor v_d3_0.16b, v_d3_0.16b, v_tmp_hi.16b
+
+ str q_d1_0, [x_dest1]
+ str q_d2_0, [x_dest2]
+ str q_d3_0, [x_dest3]
+
+.return_pass:
+ mov w_ret, #0
+ ret
+
+.return_fail:
+ mov w_ret, #1
+ ret
+
+ASM_DEF_RODATA
+.balign 8
+const_tbl:
+ .dword 0x0000000000000000, 0x0000000000000000
+ .dword 0xffffffffffffffff, 0xffffffffffffffff
diff --git a/contrib/libs/isa-l/erasure_code/aarch64/gf_3vect_mad_sve.S b/contrib/libs/isa-l/erasure_code/aarch64/gf_3vect_mad_sve.S
new file mode 100644
index 0000000000..9e0ca5c4b3
--- /dev/null
+++ b/contrib/libs/isa-l/erasure_code/aarch64/gf_3vect_mad_sve.S
@@ -0,0 +1,175 @@
+/**************************************************************
+ Copyright (c) 2021 Linaro Ltd.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name of Huawei Corporation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+**********************************************************************/
+.text
+.align 6
+.arch armv8-a+sve
+
+#include "../include/aarch64_label.h"
+
+.global cdecl(gf_3vect_mad_sve)
+#ifndef __APPLE__
+.type gf_3vect_mad_sve, %function
+#endif
+
+/* gf_3vect_mad_sve(int len, int vec, int vec_i, unsigned char *gftbls,
+ unsigned char *src, unsigned char **dest);
+ */
+/* arguments */
+x_len .req x0
+x_vec .req x1
+x_vec_i .req x2
+x_tbl .req x3
+x_src .req x4
+x_dest .req x5
+
+/* returns */
+w_ret .req w0
+
+/* local variables */
+x_pos .req x6
+x_dest2 .req x7
+x_dest3 .req x8
+x_dest1 .req x12
+
+/* vectors */
+z_mask0f .req z0
+
+z_src .req z1
+z_src_lo .req z2
+z_src_hi .req z_src
+
+z_dest1 .req z3
+
+z_tmp_lo .req z4
+z_tmp_hi .req z5
+
+z_gft1_lo .req z6
+z_gft1_hi .req z7
+q_gft1_lo .req q6
+q_gft1_hi .req q7
+
+/* bottom 64-bit of v8..v15 must be preserved if used */
+z_gft2_lo .req z17
+z_gft2_hi .req z18
+q_gft2_lo .req q17
+q_gft2_hi .req q18
+
+z_gft3_lo .req z19
+z_gft3_hi .req z20
+q_gft3_lo .req q19
+q_gft3_hi .req q20
+
+z_dest2 .req z27
+z_dest3 .req z28
+
+cdecl(gf_3vect_mad_sve):
+ /* less than 16 bytes, return_fail */
+ cmp x_len, #16
+ blt .return_fail
+
+ mov z_mask0f.b, #0x0f /* z_mask0f = 0x0F0F...0F */
+ /* load table 1 */
+ add x_tbl, x_tbl, x_vec_i, LSL #5 /* x_tbl += x_vec_i * 2^5 */
+
+ /* Load table 1 with NEON instruction ldp */
+ ldp q_gft1_lo, q_gft1_hi, [x_tbl]
+ /* load table 2 */
+ add x_tbl, x_tbl, x_vec, LSL #5 /* x_tbl += x_vec * 2^5 */
+ ldp q_gft2_lo, q_gft2_hi, [x_tbl]
+ /* load table 3 */
+ add x_tbl, x_tbl, x_vec, LSL #5 /* x_tbl += x_vec * 2^5 */
+ ldp q_gft3_lo, q_gft3_hi, [x_tbl]
+
+ ldr x_dest1, [x_dest, #8*0] /* pointer to dest1 */
+ ldr x_dest2, [x_dest, #8*1] /* pointer to dest2 */
+ ldr x_dest3, [x_dest, #8*2] /* pointer to dest3 */
+
+ mov x_pos, #0
+
+ /* vector length agnostic */
+.Lloopsve_vl:
+ whilelo p0.b, x_pos, x_len
+ b.none .return_pass
+
+ /* dest data prefetch */
+ prfb pldl2strm, p0, [x_dest1, x_pos]
+ prfb pldl2strm, p0, [x_dest2, x_pos]
+
+ /* load src data, governed by p0 */
+ ld1b z_src.b, p0/z, [x_src, x_pos]
+
+ /* split 4-bit lo; 4-bit hi */
+ and z_src_lo.d, z_src.d, z_mask0f.d
+ lsr z_src_hi.b, z_src.b, #4
+
+ /* load dest data, governed by p0 */
+ ld1b z_dest1.b, p0/z, [x_dest1, x_pos]
+ ld1b z_dest2.b, p0/z, [x_dest2, x_pos]
+ prfb pldl2strm, p0, [x_dest3, x_pos]
+
+ /* dest1 */
+ /* table indexing, ie. gf(2^8) multiplication */
+ tbl z_tmp_lo.b, {z_gft1_lo.b}, z_src_lo.b
+ tbl z_tmp_hi.b, {z_gft1_hi.b}, z_src_hi.b
+ /* exclusive or, ie. gf(2^8) add */
+ eor z_dest1.d, z_tmp_lo.d, z_dest1.d
+ eor z_dest1.d, z_tmp_hi.d, z_dest1.d
+
+ /* dest2 */
+ tbl z_tmp_lo.b, {z_gft2_lo.b}, z_src_lo.b
+ tbl z_tmp_hi.b, {z_gft2_hi.b}, z_src_hi.b
+
+ ld1b z_dest3.b, p0/z, [x_dest3, x_pos]
+ /* store dest data, governed by p0 */
+ st1b z_dest1.b, p0, [x_dest1, x_pos]
+
+ eor z_dest2.d, z_tmp_lo.d, z_dest2.d
+ eor z_dest2.d, z_tmp_hi.d, z_dest2.d
+
+ /* dest3 */
+ tbl z_tmp_lo.b, {z_gft3_lo.b}, z_src_lo.b
+ tbl z_tmp_hi.b, {z_gft3_hi.b}, z_src_hi.b
+ eor z_dest3.d, z_tmp_lo.d, z_dest3.d
+ eor z_dest3.d, z_tmp_hi.d, z_dest3.d
+
+ /* store dest data, governed by p0 */
+ st1b z_dest2.b, p0, [x_dest2, x_pos]
+ st1b z_dest3.b, p0, [x_dest3, x_pos]
+ /* increment one vector length */
+ incb x_pos
+
+ b .Lloopsve_vl
+
+.return_pass:
+ mov w_ret, #0
+ ret
+
+.return_fail:
+ mov w_ret, #1
+ ret
diff --git a/contrib/libs/isa-l/erasure_code/aarch64/gf_4vect_dot_prod_neon.S b/contrib/libs/isa-l/erasure_code/aarch64/gf_4vect_dot_prod_neon.S
new file mode 100644
index 0000000000..6204102f68
--- /dev/null
+++ b/contrib/libs/isa-l/erasure_code/aarch64/gf_4vect_dot_prod_neon.S
@@ -0,0 +1,425 @@
+/**************************************************************
+ Copyright (c) 2019 Huawei Technologies Co., Ltd.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name of Huawei Corporation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+**********************************************************************/
+
+#include "../include/aarch64_label.h"
+
+.text
+
+.global cdecl(gf_4vect_dot_prod_neon)
+#ifndef __APPLE__
+.type gf_4vect_dot_prod_neon, %function
+#endif
+
+/* arguments */
+x_len .req x0
+x_vec .req x1
+x_tbl .req x2
+x_src .req x3
+x_dest .req x4
+
+/* returns */
+w_ret .req w0
+
+/* local variables */
+x_vec_i .req x5
+x_ptr .req x6
+x_pos .req x7
+x_tmp .req x8
+x_dest1 .req x9
+x_tbl1 .req x10
+x_dest2 .req x11
+x_tbl2 .req x12
+x_dest3 .req x13
+x_tbl3 .req x14
+x_dest4 .req x_dest
+x_tbl4 .req x15
+
+/* vectors */
+v_mask0f .req v0
+q_mask0f .req q0
+v_tmp1_lo .req v1
+v_tmp1_hi .req v2
+v_tmp1 .req v3
+q_tmp1 .req q3
+
+v_p1_0 .req v4
+v_p2_0 .req v5
+v_p3_0 .req v6
+v_p4_0 .req v7
+
+q_p1_0 .req q4
+q_p2_0 .req q5
+q_p3_0 .req q6
+q_p4_0 .req q7
+
+v_data_0 .req v8
+v_data_1 .req v9
+v_data_2 .req v10
+v_data_3 .req v11
+q_data_0 .req q8
+q_data_1 .req q9
+q_data_2 .req q10
+q_data_3 .req q11
+
+v_p1_3 .req v12
+v_p2_3 .req v13
+v_p3_3 .req v14
+v_p4_3 .req v15
+q_p1_3 .req q12
+q_p2_3 .req q13
+q_p3_3 .req q14
+q_p4_3 .req q15
+
+v_gft1_lo .req v16
+v_gft1_hi .req v17
+v_gft2_lo .req v18
+v_gft2_hi .req v19
+v_gft3_lo .req v20
+v_gft3_hi .req v21
+v_gft4_lo .req v22
+v_gft4_hi .req v23
+q_gft1_lo .req q16
+q_gft1_hi .req q17
+q_gft2_lo .req q18
+q_gft2_hi .req q19
+q_gft3_lo .req q20
+q_gft3_hi .req q21
+q_gft4_lo .req q22
+q_gft4_hi .req q23
+
+v_p1_1 .req v24
+v_p1_2 .req v25
+v_p2_1 .req v26
+v_p2_2 .req v27
+v_p3_1 .req v28
+v_p3_2 .req v29
+v_p4_1 .req v30
+v_p4_2 .req v31
+
+q_p1_1 .req q24
+q_p1_2 .req q25
+q_p2_1 .req q26
+q_p2_2 .req q27
+q_p3_1 .req q28
+q_p3_2 .req q29
+q_p4_1 .req q30
+q_p4_2 .req q31
+
+v_data .req v_tmp1
+q_data .req q_tmp1
+v_data_lo .req v_tmp1_lo
+v_data_hi .req v_tmp1_hi
+
+cdecl(gf_4vect_dot_prod_neon):
+ /* less than 16 bytes, return_fail */
+ cmp x_len, #16
+ blt .return_fail
+
+ movi v_mask0f.16b, #0x0f
+ mov x_pos, #0
+ lsl x_vec, x_vec, #3
+ ldr x_dest1, [x_dest, #8*0]
+ ldr x_dest2, [x_dest, #8*1]
+ ldr x_dest3, [x_dest, #8*2]
+ ldr x_dest4, [x_dest, #8*3]
+
+.Lloop64_init:
+ /* less than 64 bytes, goto Lloop16_init */
+ cmp x_len, #64
+ blt .Lloop16_init
+
+ /* save d8 ~ d15 to stack */
+ sub sp, sp, #64
+ stp d8, d9, [sp]
+ stp d10, d11, [sp, #16]
+ stp d12, d13, [sp, #32]
+ stp d14, d15, [sp, #48]
+
+ sub x_len, x_len, #64
+
+.Lloop64:
+ movi v_p1_0.16b, #0
+ movi v_p1_1.16b, #0
+ movi v_p1_2.16b, #0
+ movi v_p1_3.16b, #0
+ movi v_p2_0.16b, #0
+ movi v_p2_1.16b, #0
+ movi v_p2_2.16b, #0
+ movi v_p2_3.16b, #0
+ movi v_p3_0.16b, #0
+ movi v_p3_1.16b, #0
+ movi v_p3_2.16b, #0
+ movi v_p3_3.16b, #0
+ movi v_p4_0.16b, #0
+ movi v_p4_1.16b, #0
+ movi v_p4_2.16b, #0
+ movi v_p4_3.16b, #0
+
+ mov x_tbl1, x_tbl
+ add x_tbl2, x_tbl1, x_vec, lsl #2
+ add x_tbl3, x_tbl2, x_vec, lsl #2
+ add x_tbl4, x_tbl3, x_vec, lsl #2
+ mov x_vec_i, #0
+ prfm pldl1keep, [x_tbl1]
+ prfm pldl1keep, [x_tbl2]
+ prfm pldl1keep, [x_tbl3]
+ prfm pldl1keep, [x_tbl4]
+
+.Lloop64_vects:
+ ldr x_ptr, [x_src, x_vec_i]
+ add x_vec_i, x_vec_i, #8
+ add x_ptr, x_ptr, x_pos
+
+ ldr q_data_0, [x_ptr], #16
+ ldr q_data_1, [x_ptr], #16
+ ldp q_gft1_lo, q_gft1_hi, [x_tbl1], #32
+ ldp q_gft2_lo, q_gft2_hi, [x_tbl2], #32
+ ldp q_gft3_lo, q_gft3_hi, [x_tbl3], #32
+ ldp q_gft4_lo, q_gft4_hi, [x_tbl4], #32
+ ldr q_data_2, [x_ptr], #16
+ ldr q_data_3, [x_ptr], #16
+
+ prfm pldl1strm, [x_ptr]
+ prfm pldl1keep, [x_tbl1]
+ prfm pldl1keep, [x_tbl2]
+ prfm pldl1keep, [x_tbl3]
+ prfm pldl1keep, [x_tbl4]
+
+ /* data_0 */
+ and v_tmp1.16b, v_data_0.16b, v_mask0f.16b
+ ushr v_data_0.16b, v_data_0.16b, #4
+
+ tbl v_tmp1_lo.16b, {v_gft1_lo.16b}, v_tmp1.16b
+ tbl v_tmp1_hi.16b, {v_gft1_hi.16b}, v_data_0.16b
+ eor v_p1_0.16b, v_tmp1_lo.16b, v_p1_0.16b
+ eor v_p1_0.16b, v_p1_0.16b, v_tmp1_hi.16b
+
+ tbl v_tmp1_lo.16b, {v_gft2_lo.16b}, v_tmp1.16b
+ tbl v_tmp1_hi.16b, {v_gft2_hi.16b}, v_data_0.16b
+ eor v_p2_0.16b, v_tmp1_lo.16b, v_p2_0.16b
+ eor v_p2_0.16b, v_p2_0.16b, v_tmp1_hi.16b
+
+ tbl v_tmp1_lo.16b, {v_gft3_lo.16b}, v_tmp1.16b
+ tbl v_tmp1_hi.16b, {v_gft3_hi.16b}, v_data_0.16b
+ eor v_p3_0.16b, v_tmp1_lo.16b, v_p3_0.16b
+ eor v_p3_0.16b, v_p3_0.16b, v_tmp1_hi.16b
+
+ tbl v_tmp1_lo.16b, {v_gft4_lo.16b}, v_tmp1.16b
+ tbl v_tmp1_hi.16b, {v_gft4_hi.16b}, v_data_0.16b
+ eor v_p4_0.16b, v_tmp1_lo.16b, v_p4_0.16b
+ eor v_p4_0.16b, v_p4_0.16b, v_tmp1_hi.16b
+
+ /* data_1 */
+ and v_tmp1.16b, v_data_1.16b, v_mask0f.16b
+ ushr v_data_1.16b, v_data_1.16b, #4
+
+ tbl v_tmp1_lo.16b, {v_gft1_lo.16b}, v_tmp1.16b
+ tbl v_tmp1_hi.16b, {v_gft1_hi.16b}, v_data_1.16b
+ eor v_p1_1.16b, v_tmp1_lo.16b, v_p1_1.16b
+ eor v_p1_1.16b, v_p1_1.16b, v_tmp1_hi.16b
+
+ tbl v_tmp1_lo.16b, {v_gft2_lo.16b}, v_tmp1.16b
+ tbl v_tmp1_hi.16b, {v_gft2_hi.16b}, v_data_1.16b
+ eor v_p2_1.16b, v_tmp1_lo.16b, v_p2_1.16b
+ eor v_p2_1.16b, v_p2_1.16b, v_tmp1_hi.16b
+
+ tbl v_tmp1_lo.16b, {v_gft3_lo.16b}, v_tmp1.16b
+ tbl v_tmp1_hi.16b, {v_gft3_hi.16b}, v_data_1.16b
+ eor v_p3_1.16b, v_tmp1_lo.16b, v_p3_1.16b
+ eor v_p3_1.16b, v_p3_1.16b, v_tmp1_hi.16b
+
+ tbl v_tmp1_lo.16b, {v_gft4_lo.16b}, v_tmp1.16b
+ tbl v_tmp1_hi.16b, {v_gft4_hi.16b}, v_data_1.16b
+ eor v_p4_1.16b, v_tmp1_lo.16b, v_p4_1.16b
+ eor v_p4_1.16b, v_p4_1.16b, v_tmp1_hi.16b
+
+ /* data_2 */
+ and v_tmp1.16b, v_data_2.16b, v_mask0f.16b
+ ushr v_data_2.16b, v_data_2.16b, #4
+
+ tbl v_tmp1_lo.16b, {v_gft1_lo.16b}, v_tmp1.16b
+ tbl v_tmp1_hi.16b, {v_gft1_hi.16b}, v_data_2.16b
+ eor v_p1_2.16b, v_tmp1_lo.16b, v_p1_2.16b
+ eor v_p1_2.16b, v_p1_2.16b, v_tmp1_hi.16b
+
+ tbl v_tmp1_lo.16b, {v_gft2_lo.16b}, v_tmp1.16b
+ tbl v_tmp1_hi.16b, {v_gft2_hi.16b}, v_data_2.16b
+ eor v_p2_2.16b, v_tmp1_lo.16b, v_p2_2.16b
+ eor v_p2_2.16b, v_p2_2.16b, v_tmp1_hi.16b
+
+ tbl v_tmp1_lo.16b, {v_gft3_lo.16b}, v_tmp1.16b
+ tbl v_tmp1_hi.16b, {v_gft3_hi.16b}, v_data_2.16b
+ eor v_p3_2.16b, v_tmp1_lo.16b, v_p3_2.16b
+ eor v_p3_2.16b, v_p3_2.16b, v_tmp1_hi.16b
+
+ tbl v_tmp1_lo.16b, {v_gft4_lo.16b}, v_tmp1.16b
+ tbl v_tmp1_hi.16b, {v_gft4_hi.16b}, v_data_2.16b
+ eor v_p4_2.16b, v_tmp1_lo.16b, v_p4_2.16b
+ eor v_p4_2.16b, v_p4_2.16b, v_tmp1_hi.16b
+
+ /* data_3 */
+ and v_tmp1.16b, v_data_3.16b, v_mask0f.16b
+ ushr v_data_3.16b, v_data_3.16b, #4
+
+ tbl v_tmp1_lo.16b, {v_gft1_lo.16b}, v_tmp1.16b
+ tbl v_tmp1_hi.16b, {v_gft1_hi.16b}, v_data_3.16b
+ eor v_p1_3.16b, v_tmp1_lo.16b, v_p1_3.16b
+ eor v_p1_3.16b, v_p1_3.16b, v_tmp1_hi.16b
+
+ tbl v_tmp1_lo.16b, {v_gft2_lo.16b}, v_tmp1.16b
+ tbl v_tmp1_hi.16b, {v_gft2_hi.16b}, v_data_3.16b
+ eor v_p2_3.16b, v_tmp1_lo.16b, v_p2_3.16b
+ eor v_p2_3.16b, v_p2_3.16b, v_tmp1_hi.16b
+
+ tbl v_tmp1_lo.16b, {v_gft3_lo.16b}, v_tmp1.16b
+ tbl v_tmp1_hi.16b, {v_gft3_hi.16b}, v_data_3.16b
+ eor v_p3_3.16b, v_tmp1_lo.16b, v_p3_3.16b
+ eor v_p3_3.16b, v_p3_3.16b, v_tmp1_hi.16b
+
+ tbl v_tmp1_lo.16b, {v_gft4_lo.16b}, v_tmp1.16b
+ tbl v_tmp1_hi.16b, {v_gft4_hi.16b}, v_data_3.16b
+ eor v_p4_3.16b, v_tmp1_lo.16b, v_p4_3.16b
+ eor v_p4_3.16b, v_p4_3.16b, v_tmp1_hi.16b
+
+ cmp x_vec_i, x_vec
+ blt .Lloop64_vects
+
+.Lloop64_vects_end:
+ add x_ptr, x_dest1, x_pos
+ stp q_p1_0, q_p1_1, [x_ptr], #32
+ stp q_p1_2, q_p1_3, [x_ptr]
+
+ add x_ptr, x_dest2, x_pos
+ stp q_p2_0, q_p2_1, [x_ptr], #32
+ stp q_p2_2, q_p2_3, [x_ptr]
+
+ add x_ptr, x_dest3, x_pos
+ stp q_p3_0, q_p3_1, [x_ptr], #32
+ stp q_p3_2, q_p3_3, [x_ptr]
+
+ add x_ptr, x_dest4, x_pos
+ stp q_p4_0, q_p4_1, [x_ptr], #32
+ stp q_p4_2, q_p4_3, [x_ptr]
+
+ add x_pos, x_pos, #64
+ cmp x_pos, x_len
+ ble .Lloop64
+
+.Lloop64_end:
+ /* restore d8 ~ d15 */
+ ldp d8, d9, [sp]
+ ldp d10, d11, [sp, #16]
+ ldp d12, d13, [sp, #32]
+ ldp d14, d15, [sp, #48]
+ add sp, sp, #64
+
+ add x_len, x_len, #64
+ cmp x_pos, x_len
+ beq .return_pass
+
+.Lloop16_init:
+ sub x_len, x_len, #16
+ cmp x_pos, x_len
+ bgt .lessthan16_init
+
+.Lloop16:
+ movi v_p1_0.16b, #0
+ movi v_p2_0.16b, #0
+ movi v_p3_0.16b, #0
+ movi v_p4_0.16b, #0
+ mov x_tbl1, x_tbl
+ add x_tbl2, x_tbl1, x_vec, lsl #2
+ add x_tbl3, x_tbl2, x_vec, lsl #2
+ add x_tbl4, x_tbl3, x_vec, lsl #2
+ mov x_vec_i, #0
+
+.Lloop16_vects:
+ ldr x_ptr, [x_src, x_vec_i]
+ add x_vec_i, x_vec_i, #8
+ ldr q_data, [x_ptr, x_pos]
+
+ ldp q_gft1_lo, q_gft1_hi, [x_tbl1], #32
+ ldp q_gft2_lo, q_gft2_hi, [x_tbl2], #32
+ ldp q_gft3_lo, q_gft3_hi, [x_tbl3], #32
+ ldp q_gft4_lo, q_gft4_hi, [x_tbl4], #32
+
+ prfm pldl1keep, [x_tbl1]
+ prfm pldl1keep, [x_tbl2]
+ prfm pldl1keep, [x_tbl3]
+ prfm pldl1keep, [x_tbl4]
+
+ and v_data_lo.16b, v_data.16b, v_mask0f.16b
+ ushr v_data_hi.16b, v_data.16b, #4
+
+ tbl v_gft1_lo.16b, {v_gft1_lo.16b}, v_data_lo.16b
+ tbl v_gft1_hi.16b, {v_gft1_hi.16b}, v_data_hi.16b
+ tbl v_gft2_lo.16b, {v_gft2_lo.16b}, v_data_lo.16b
+ tbl v_gft2_hi.16b, {v_gft2_hi.16b}, v_data_hi.16b
+ tbl v_gft3_lo.16b, {v_gft3_lo.16b}, v_data_lo.16b
+ tbl v_gft3_hi.16b, {v_gft3_hi.16b}, v_data_hi.16b
+ tbl v_gft4_lo.16b, {v_gft4_lo.16b}, v_data_lo.16b
+ tbl v_gft4_hi.16b, {v_gft4_hi.16b}, v_data_hi.16b
+
+ eor v_p1_0.16b, v_gft1_hi.16b, v_p1_0.16b
+ eor v_p1_0.16b, v_p1_0.16b, v_gft1_lo.16b
+ eor v_p2_0.16b, v_gft2_hi.16b, v_p2_0.16b
+ eor v_p2_0.16b, v_p2_0.16b, v_gft2_lo.16b
+ eor v_p3_0.16b, v_gft3_hi.16b, v_p3_0.16b
+ eor v_p3_0.16b, v_p3_0.16b, v_gft3_lo.16b
+ eor v_p4_0.16b, v_gft4_hi.16b, v_p4_0.16b
+ eor v_p4_0.16b, v_p4_0.16b, v_gft4_lo.16b
+
+ cmp x_vec_i, x_vec
+ bne .Lloop16_vects
+
+.Lloop16_vects_end:
+ str q_p1_0, [x_dest1, x_pos]
+ str q_p2_0, [x_dest2, x_pos]
+ str q_p3_0, [x_dest3, x_pos]
+ str q_p4_0, [x_dest4, x_pos]
+ add x_pos, x_pos, #16
+ cmp x_pos, x_len
+ ble .Lloop16
+
+.Lloop16_end:
+ sub x_tmp, x_pos, x_len
+ cmp x_tmp, #16
+ beq .return_pass
+
+.lessthan16_init:
+ mov x_pos, x_len
+ b .Lloop16
+
+.return_pass:
+ mov w_ret, #0
+ ret
+
+.return_fail:
+ mov w_ret, #1
+ ret
diff --git a/contrib/libs/isa-l/erasure_code/aarch64/gf_4vect_dot_prod_sve.S b/contrib/libs/isa-l/erasure_code/aarch64/gf_4vect_dot_prod_sve.S
new file mode 100644
index 0000000000..eb354279f8
--- /dev/null
+++ b/contrib/libs/isa-l/erasure_code/aarch64/gf_4vect_dot_prod_sve.S
@@ -0,0 +1,208 @@
+/*************************************************************
+ Copyright (c) 2021 Linaro Ltd.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name of Huawei Corporation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+**********************************************************************/
+.text
+.align 6
+.arch armv8-a+sve
+
+#include "../include/aarch64_label.h"
+
+.global cdecl(gf_4vect_dot_prod_sve)
+#ifndef __APPLE__
+.type gf_4vect_dot_prod_sve, %function
+#endif
+/* void gf_4vect_dot_prod_sve(int len, int vlen, unsigned char *gftbls,
+ unsigned char **src, unsigned char **dest);
+ */
+
+/* arguments */
+x_len .req x0 /* vector length */
+x_vec .req x1 /* number of source vectors (ie. data blocks) */
+x_tbl .req x2
+x_src .req x3
+x_dest .req x4
+
+/* returns */
+w_ret .req w0
+
+/* local variables */
+x_vec_i .req x5
+x_ptr .req x6
+x_pos .req x7
+
+x_tbl1 .req x8
+x_tbl2 .req x9
+x_tbl3 .req x10
+x_tbl4 .req x11
+x_dest1 .req x12
+x_dest2 .req x13
+x_dest3 .req x14
+x_dest4 .req x_dest /* reused */
+
+/* r16,r17,r18,r29,r30: special role registers, avoided */
+/* r19..r29 and SP must be preserved */
+
+/* vectors */
+z_mask0f .req z0
+
+z_src .req z1
+z_src_lo .req z2
+z_src_hi .req z_src
+
+z_dest1 .req z3
+
+z_gft1_lo .req z4
+z_gft1_hi .req z5
+q_gft1_lo .req q4
+q_gft1_hi .req q5
+
+/* bottom 64-bit of v8..v15 must be preserved if used */
+z_gft2_lo .req z17
+z_gft2_hi .req z18
+q_gft2_lo .req q17
+q_gft2_hi .req q18
+
+z_gft3_lo .req z19
+z_gft3_hi .req z20
+q_gft3_lo .req q19
+q_gft3_hi .req q20
+
+z_gft4_lo .req z21
+z_gft4_hi .req z22
+q_gft4_lo .req q21
+q_gft4_hi .req q22
+
+z_dest2 .req z27
+z_dest3 .req z28
+z_dest4 .req z29
+
+cdecl(gf_4vect_dot_prod_sve):
+ /* less than 16 bytes, return_fail */
+ cmp x_len, #16
+ blt .return_fail
+
+ mov z_mask0f.b, #0x0f /* z_mask0f = 0x0F0F...0F */
+ mov x_pos, #0
+ lsl x_vec, x_vec, #3
+ ldp x_dest1, x_dest2, [x_dest, #8*0]
+ ldp x_dest3, x_dest4, [x_dest, #8*2]
+
+/* Loop 1: x_len, vector length */
+.Lloopsve_vl:
+ whilelo p0.b, x_pos, x_len
+ b.none .return_pass
+
+ mov x_vec_i, #0 /* clear x_vec_i */
+ ldr x_ptr, [x_src, x_vec_i] /* x_ptr: src base addr. */
+
+ mov z_dest1.b, #0 /* clear z_dest1 */
+ mov z_dest2.b, #0 /* clear z_dest2 */
+ mov z_dest3.b, #0 /* clear z_dest3 */
+ mov z_dest4.b, #0 /* clear z_dest4 */
+
+ /* gf_tbl base = (x_tbl + dest_idx * x_vec * 32) */
+ mov x_tbl1, x_tbl /* reset x_tbl1 */
+ add x_tbl2, x_tbl1, x_vec, LSL #2 /* reset x_tbl2 */
+ add x_tbl3, x_tbl2, x_vec, LSL #2 /* reset x_tbl3 */
+ add x_tbl4, x_tbl3, x_vec, LSL #2 /* reset x_tbl4 */
+
+/* Loop 2: x_vec, number of source vectors (ie. data blocks) */
+.Lloopsve_vl_vects:
+ /* load src data, governed by p0 */
+ ld1b z_src.b, p0/z, [x_ptr, x_pos] /* load from: src base + pos offset */
+ /* split 4-bit lo; 4-bit hi */
+ and z_src_lo.d, z_src.d, z_mask0f.d
+ lsr z_src_hi.b, z_src.b, #4
+
+
+ /* gf_tbl addr: (x_tbl + dest_idx * x_vec * 32) + src_vec_idx * 32 */
+ /* load gf_table's */
+ ldp q_gft1_lo, q_gft1_hi, [x_tbl1], #32 /* x_tbl1 is post-added by #32 for each src vect */
+ ldp q_gft2_lo, q_gft2_hi, [x_tbl2], #32
+
+ /* prefetch */
+ prfb pldl2keep, p0, [x_tbl1]
+ prfb pldl2keep, p0, [x_tbl2]
+
+ /* calc for next */
+ add x_vec_i, x_vec_i, #8 /* move x_vec_i to next */
+ ldr x_ptr, [x_src, x_vec_i] /* x_ptr: src base addr. */
+
+ /* dest 1 */
+ /* table indexing, ie. gf(2^8) multiplication */
+ tbl z_gft1_lo.b, {z_gft1_lo.b}, z_src_lo.b
+ tbl z_gft1_hi.b, {z_gft1_hi.b}, z_src_hi.b
+ /* exclusive or, ie. gf(2^8) add */
+ eor z_dest1.d, z_gft1_lo.d, z_dest1.d
+ eor z_dest1.d, z_dest1.d, z_gft1_hi.d
+
+ ldp q_gft3_lo, q_gft3_hi, [x_tbl3], #32
+ ldp q_gft4_lo, q_gft4_hi, [x_tbl4], #32
+ prfb pldl2keep, p0, [x_tbl3]
+ prfb pldl2keep, p0, [x_tbl4]
+
+ /* dest 2 */
+ tbl z_gft2_lo.b, {z_gft2_lo.b}, z_src_lo.b
+ tbl z_gft2_hi.b, {z_gft2_hi.b}, z_src_hi.b
+ eor z_dest2.d, z_gft2_lo.d, z_dest2.d
+ eor z_dest2.d, z_dest2.d, z_gft2_hi.d
+
+ /* dest 3 */
+ tbl z_gft3_lo.b, {z_gft3_lo.b}, z_src_lo.b
+ tbl z_gft3_hi.b, {z_gft3_hi.b}, z_src_hi.b
+ eor z_dest3.d, z_gft3_lo.d, z_dest3.d
+ eor z_dest3.d, z_dest3.d, z_gft3_hi.d
+
+ /* dest 4 */
+ tbl z_gft4_lo.b, {z_gft4_lo.b}, z_src_lo.b
+ tbl z_gft4_hi.b, {z_gft4_hi.b}, z_src_hi.b
+ eor z_dest4.d, z_gft4_lo.d, z_dest4.d
+ eor z_dest4.d, z_dest4.d, z_gft4_hi.d
+
+ cmp x_vec_i, x_vec
+ blt .Lloopsve_vl_vects
+/* end of Loop 2 */
+
+ /* store dest data, governed by p0 */
+ st1b z_dest1.b, p0, [x_dest1, x_pos]
+ st1b z_dest2.b, p0, [x_dest2, x_pos]
+ st1b z_dest3.b, p0, [x_dest3, x_pos]
+ st1b z_dest4.b, p0, [x_dest4, x_pos]
+
+ /* increment one vector length */
+ incb x_pos
+ b .Lloopsve_vl
+/* end of Loop 1 */
+
+.return_pass:
+ mov w_ret, #0
+ ret
+
+.return_fail:
+ mov w_ret, #1
+ ret
diff --git a/contrib/libs/isa-l/erasure_code/aarch64/gf_4vect_mad_neon.S b/contrib/libs/isa-l/erasure_code/aarch64/gf_4vect_mad_neon.S
new file mode 100644
index 0000000000..ebf82e7ffe
--- /dev/null
+++ b/contrib/libs/isa-l/erasure_code/aarch64/gf_4vect_mad_neon.S
@@ -0,0 +1,464 @@
+/**************************************************************
+ Copyright (c) 2019 Huawei Technologies Co., Ltd.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name of Huawei Corporation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+**********************************************************************/
+
+#include "../include/aarch64_label.h"
+
+.text
+
+.global cdecl(gf_4vect_mad_neon)
+#ifndef __APPLE__
+.type gf_4vect_mad_neon, %function
+#endif
+
+/* arguments */
+x_len .req x0
+x_vec .req x1
+x_vec_i .req x2
+x_tbl .req x3
+x_src .req x4
+x_dest .req x5
+
+/* returns */
+w_ret .req w0
+
+/* local variables */
+x_src_end .req x6
+x_dest1 .req x7
+x_dest2 .req x8
+x_dest3 .req x9
+x_dest4 .req x_dest
+x_tmp .req x10
+x_tbl1 .req x11
+x_tbl2 .req x12
+x_tbl3 .req x13
+x_tbl4 .req x14
+x_const .req x15
+
+/* vectors */
+v_mask0f .req v0
+v_tmp_lo .req v1
+v_tmp_hi .req v2
+v_tmp .req v3
+q_tmp .req q3
+
+v_gft1_lo .req v4
+v_gft1_hi .req v5
+v_gft2_lo .req v6
+v_gft2_hi .req v7
+v_gft3_lo .req v16
+v_gft3_hi .req v17
+v_gft4_lo .req v18
+v_gft4_hi .req v19
+q_gft1_lo .req q4
+q_gft1_hi .req q5
+q_gft2_lo .req q6
+q_gft2_hi .req q7
+q_gft3_lo .req q16
+q_gft3_hi .req q17
+q_gft4_lo .req q18
+q_gft4_hi .req q19
+
+v_data_0 .req v8
+v_data_1 .req v9
+v_data_2 .req v10
+v_data_3 .req v11
+q_data_0 .req q8
+q_data_1 .req q9
+q_data_2 .req q10
+q_data_3 .req q11
+
+v_data_0_lo .req v12
+v_data_1_lo .req v13
+v_data_2_lo .req v14
+v_data_3_lo .req v15
+v_data_0_hi .req v_data_0
+v_data_1_hi .req v_data_1
+v_data_2_hi .req v_data_2
+v_data_3_hi .req v_data_3
+
+v_d1_0 .req v20
+v_d1_1 .req v21
+v_d1_2 .req v22
+v_d1_3 .req v23
+v_d2_0 .req v24
+v_d2_1 .req v25
+v_d2_2 .req v26
+v_d2_3 .req v27
+v_d3_0 .req v28
+v_d3_1 .req v29
+v_d3_2 .req v30
+v_d3_3 .req v31
+q_d1_0 .req q20
+q_d1_1 .req q21
+q_d1_2 .req q22
+q_d1_3 .req q23
+q_d2_0 .req q24
+q_d2_1 .req q25
+q_d2_2 .req q26
+q_d2_3 .req q27
+q_d3_0 .req q28
+q_d3_1 .req q29
+q_d3_2 .req q30
+q_d3_3 .req q31
+
+v_d4_0 .req v_d1_0
+v_d4_1 .req v_d1_1
+v_d4_2 .req v_d1_2
+v_d4_3 .req v_d1_3
+q_d4_0 .req q_d1_0
+q_d4_1 .req q_d1_1
+q_d4_2 .req q_d1_2
+q_d4_3 .req q_d1_3
+
+v_data .req v21
+q_data .req q21
+v_data_lo .req v22
+v_data_hi .req v23
+
+cdecl(gf_4vect_mad_neon):
+ /* less than 16 bytes, return_fail */
+ cmp x_len, #16
+ blt .return_fail
+
+ movi v_mask0f.16b, #0x0f
+ lsl x_vec_i, x_vec_i, #5
+ lsl x_vec, x_vec, #5
+ add x_tbl1, x_tbl, x_vec_i
+ add x_tbl2, x_tbl1, x_vec
+ add x_tbl3, x_tbl2, x_vec
+ add x_tbl4, x_tbl3, x_vec
+ add x_src_end, x_src, x_len
+ ldr x_dest1, [x_dest, #8*0]
+ ldr x_dest2, [x_dest, #8*1]
+ ldr x_dest3, [x_dest, #8*2]
+ ldr x_dest4, [x_dest, #8*3]
+ ldr q_gft1_lo, [x_tbl1]
+ ldr q_gft1_hi, [x_tbl1, #16]
+ ldr q_gft2_lo, [x_tbl2]
+ ldr q_gft2_hi, [x_tbl2, #16]
+ ldr q_gft3_lo, [x_tbl3]
+ ldr q_gft3_hi, [x_tbl3, #16]
+ ldr q_gft4_lo, [x_tbl4]
+ ldr q_gft4_hi, [x_tbl4, #16]
+
+.Lloop64_init:
+ /* less than 64 bytes, goto Lloop16_init */
+ cmp x_len, #64
+ blt .Lloop16_init
+
+ /* save d8 ~ d15 to stack */
+ sub sp, sp, #64
+ stp d8, d9, [sp]
+ stp d10, d11, [sp, #16]
+ stp d12, d13, [sp, #32]
+ stp d14, d15, [sp, #48]
+
+ sub x_src_end, x_src_end, #64
+
+.Lloop64:
+ ldr q_data_0, [x_src, #16*0]
+ ldr q_data_1, [x_src, #16*1]
+ ldr q_data_2, [x_src, #16*2]
+ ldr q_data_3, [x_src, #16*3]
+ add x_src, x_src, #64
+
+ ldr q_d1_0, [x_dest1, #16*0]
+ ldr q_d1_1, [x_dest1, #16*1]
+ ldr q_d1_2, [x_dest1, #16*2]
+ ldr q_d1_3, [x_dest1, #16*3]
+
+ ldr q_d2_0, [x_dest2, #16*0]
+ ldr q_d2_1, [x_dest2, #16*1]
+ ldr q_d2_2, [x_dest2, #16*2]
+ ldr q_d2_3, [x_dest2, #16*3]
+
+ and v_data_0_lo.16b, v_data_0.16b, v_mask0f.16b
+ and v_data_1_lo.16b, v_data_1.16b, v_mask0f.16b
+ and v_data_2_lo.16b, v_data_2.16b, v_mask0f.16b
+ and v_data_3_lo.16b, v_data_3.16b, v_mask0f.16b
+
+ ushr v_data_0_hi.16b, v_data_0.16b, #4
+ ushr v_data_1_hi.16b, v_data_1.16b, #4
+ ushr v_data_2_hi.16b, v_data_2.16b, #4
+ ushr v_data_3_hi.16b, v_data_3.16b, #4
+
+ /* dest1 */
+ tbl v_tmp_lo.16b, {v_gft1_lo.16b}, v_data_0_lo.16b
+ tbl v_tmp_hi.16b, {v_gft1_hi.16b}, v_data_0_hi.16b
+ eor v_d1_0.16b, v_tmp_lo.16b, v_d1_0.16b
+ eor v_d1_0.16b, v_d1_0.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft1_lo.16b}, v_data_1_lo.16b
+ tbl v_tmp_hi.16b, {v_gft1_hi.16b}, v_data_1_hi.16b
+ eor v_d1_1.16b, v_tmp_lo.16b, v_d1_1.16b
+ eor v_d1_1.16b, v_d1_1.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft1_lo.16b}, v_data_2_lo.16b
+ tbl v_tmp_hi.16b, {v_gft1_hi.16b}, v_data_2_hi.16b
+ eor v_d1_2.16b, v_tmp_lo.16b, v_d1_2.16b
+ eor v_d1_2.16b, v_d1_2.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft1_lo.16b}, v_data_3_lo.16b
+ tbl v_tmp_hi.16b, {v_gft1_hi.16b}, v_data_3_hi.16b
+ eor v_d1_3.16b, v_tmp_lo.16b, v_d1_3.16b
+ eor v_d1_3.16b, v_d1_3.16b, v_tmp_hi.16b
+
+ /* dest2 */
+ tbl v_tmp_lo.16b, {v_gft2_lo.16b}, v_data_0_lo.16b
+ tbl v_tmp_hi.16b, {v_gft2_hi.16b}, v_data_0_hi.16b
+ eor v_d2_0.16b, v_tmp_lo.16b, v_d2_0.16b
+ eor v_d2_0.16b, v_d2_0.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft2_lo.16b}, v_data_1_lo.16b
+ tbl v_tmp_hi.16b, {v_gft2_hi.16b}, v_data_1_hi.16b
+ eor v_d2_1.16b, v_tmp_lo.16b, v_d2_1.16b
+ eor v_d2_1.16b, v_d2_1.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft2_lo.16b}, v_data_2_lo.16b
+ tbl v_tmp_hi.16b, {v_gft2_hi.16b}, v_data_2_hi.16b
+ eor v_d2_2.16b, v_tmp_lo.16b, v_d2_2.16b
+ eor v_d2_2.16b, v_d2_2.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft2_lo.16b}, v_data_3_lo.16b
+ tbl v_tmp_hi.16b, {v_gft2_hi.16b}, v_data_3_hi.16b
+ eor v_d2_3.16b, v_tmp_lo.16b, v_d2_3.16b
+ eor v_d2_3.16b, v_d2_3.16b, v_tmp_hi.16b
+
+ str q_d1_0, [x_dest1, #16*0]
+ str q_d1_1, [x_dest1, #16*1]
+ str q_d1_2, [x_dest1, #16*2]
+ str q_d1_3, [x_dest1, #16*3]
+ add x_dest1, x_dest1, #64
+
+ str q_d2_0, [x_dest2, #16*0]
+ str q_d2_1, [x_dest2, #16*1]
+ str q_d2_2, [x_dest2, #16*2]
+ str q_d2_3, [x_dest2, #16*3]
+ add x_dest2, x_dest2, #64
+
+ ldr q_d3_0, [x_dest3, #16*0]
+ ldr q_d3_1, [x_dest3, #16*1]
+ ldr q_d3_2, [x_dest3, #16*2]
+ ldr q_d3_3, [x_dest3, #16*3]
+
+ ldr q_d4_0, [x_dest4, #16*0]
+ ldr q_d4_1, [x_dest4, #16*1]
+ ldr q_d4_2, [x_dest4, #16*2]
+ ldr q_d4_3, [x_dest4, #16*3]
+
+ /* dest3 */
+ tbl v_tmp_lo.16b, {v_gft3_lo.16b}, v_data_0_lo.16b
+ tbl v_tmp_hi.16b, {v_gft3_hi.16b}, v_data_0_hi.16b
+ eor v_d3_0.16b, v_tmp_lo.16b, v_d3_0.16b
+ eor v_d3_0.16b, v_d3_0.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft3_lo.16b}, v_data_1_lo.16b
+ tbl v_tmp_hi.16b, {v_gft3_hi.16b}, v_data_1_hi.16b
+ eor v_d3_1.16b, v_tmp_lo.16b, v_d3_1.16b
+ eor v_d3_1.16b, v_d3_1.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft3_lo.16b}, v_data_2_lo.16b
+ tbl v_tmp_hi.16b, {v_gft3_hi.16b}, v_data_2_hi.16b
+ eor v_d3_2.16b, v_tmp_lo.16b, v_d3_2.16b
+ eor v_d3_2.16b, v_d3_2.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft3_lo.16b}, v_data_3_lo.16b
+ tbl v_tmp_hi.16b, {v_gft3_hi.16b}, v_data_3_hi.16b
+ eor v_d3_3.16b, v_tmp_lo.16b, v_d3_3.16b
+ eor v_d3_3.16b, v_d3_3.16b, v_tmp_hi.16b
+
+ /* dest4 */
+ tbl v_tmp_lo.16b, {v_gft4_lo.16b}, v_data_0_lo.16b
+ tbl v_tmp_hi.16b, {v_gft4_hi.16b}, v_data_0_hi.16b
+ eor v_d4_0.16b, v_tmp_lo.16b, v_d4_0.16b
+ eor v_d4_0.16b, v_d4_0.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft4_lo.16b}, v_data_1_lo.16b
+ tbl v_tmp_hi.16b, {v_gft4_hi.16b}, v_data_1_hi.16b
+ eor v_d4_1.16b, v_tmp_lo.16b, v_d4_1.16b
+ eor v_d4_1.16b, v_d4_1.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft4_lo.16b}, v_data_2_lo.16b
+ tbl v_tmp_hi.16b, {v_gft4_hi.16b}, v_data_2_hi.16b
+ eor v_d4_2.16b, v_tmp_lo.16b, v_d4_2.16b
+ eor v_d4_2.16b, v_d4_2.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft4_lo.16b}, v_data_3_lo.16b
+ tbl v_tmp_hi.16b, {v_gft4_hi.16b}, v_data_3_hi.16b
+ eor v_d4_3.16b, v_tmp_lo.16b, v_d4_3.16b
+ eor v_d4_3.16b, v_d4_3.16b, v_tmp_hi.16b
+
+ str q_d3_0, [x_dest3, #16*0]
+ str q_d3_1, [x_dest3, #16*1]
+ str q_d3_2, [x_dest3, #16*2]
+ str q_d3_3, [x_dest3, #16*3]
+ add x_dest3, x_dest3, #64
+
+ str q_d4_0, [x_dest4, #16*0]
+ str q_d4_1, [x_dest4, #16*1]
+ str q_d4_2, [x_dest4, #16*2]
+ str q_d4_3, [x_dest4, #16*3]
+ add x_dest4, x_dest4, #64
+
+ cmp x_src, x_src_end
+ bls .Lloop64
+
+.Lloop64_end:
+ /* restore d8 ~ d15 */
+ ldp d8, d9, [sp]
+ ldp d10, d11, [sp, #16]
+ ldp d12, d13, [sp, #32]
+ ldp d14, d15, [sp, #48]
+ add sp, sp, #64
+ add x_src_end, x_src_end, #64
+
+.Lloop16_init:
+ sub x_src_end, x_src_end, #16
+ cmp x_src, x_src_end
+ bhi .lessthan16_init
+
+.Lloop16:
+ ldr q_data, [x_src]
+
+ ldr q_d1_0, [x_dest1]
+ ldr q_d2_0, [x_dest2]
+
+ and v_data_lo.16b, v_data.16b, v_mask0f.16b
+ ushr v_data_hi.16b, v_data.16b, #4
+
+ tbl v_tmp_lo.16b, {v_gft1_lo.16b}, v_data_lo.16b
+ tbl v_tmp_hi.16b, {v_gft1_hi.16b}, v_data_hi.16b
+ eor v_d1_0.16b, v_tmp_lo.16b, v_d1_0.16b
+ eor v_d1_0.16b, v_d1_0.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft2_lo.16b}, v_data_lo.16b
+ tbl v_tmp_hi.16b, {v_gft2_hi.16b}, v_data_hi.16b
+ eor v_d2_0.16b, v_tmp_lo.16b, v_d2_0.16b
+ eor v_d2_0.16b, v_d2_0.16b, v_tmp_hi.16b
+
+ str q_d1_0, [x_dest1]
+ str q_d2_0, [x_dest2]
+ ldr q_d3_0, [x_dest3]
+ ldr q_d4_0, [x_dest4]
+
+ tbl v_tmp_lo.16b, {v_gft3_lo.16b}, v_data_lo.16b
+ tbl v_tmp_hi.16b, {v_gft3_hi.16b}, v_data_hi.16b
+ eor v_d3_0.16b, v_tmp_lo.16b, v_d3_0.16b
+ eor v_d3_0.16b, v_d3_0.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft4_lo.16b}, v_data_lo.16b
+ tbl v_tmp_hi.16b, {v_gft4_hi.16b}, v_data_hi.16b
+ eor v_d4_0.16b, v_tmp_lo.16b, v_d4_0.16b
+ eor v_d4_0.16b, v_d4_0.16b, v_tmp_hi.16b
+
+ str q_d3_0, [x_dest3]
+ str q_d4_0, [x_dest4]
+
+ add x_src, x_src, #16
+ add x_dest1, x_dest1, #16
+ add x_dest2, x_dest2, #16
+ add x_dest3, x_dest3, #16
+ add x_dest4, x_dest4, #16
+ cmp x_src, x_src_end
+ bls .Lloop16
+
+.lessthan16_init:
+ sub x_tmp, x_src, x_src_end
+ cmp x_tmp, #16
+ beq .return_pass
+
+.lessthan16:
+ mov x_src, x_src_end
+ sub x_dest1, x_dest1, x_tmp
+ sub x_dest2, x_dest2, x_tmp
+ sub x_dest3, x_dest3, x_tmp
+ sub x_dest4, x_dest4, x_tmp
+
+#ifndef __APPLE__
+ adrp x_const, const_tbl
+ add x_const, x_const, :lo12:const_tbl
+#else
+ adrp x_const, const_tbl@PAGE
+ add x_const, x_const, const_tbl@PAGEOFF
+#endif
+ sub x_const, x_const, x_tmp
+ ldr q_tmp, [x_const, #16]
+
+ ldr q_data, [x_src]
+ ldr q_d1_0, [x_dest1]
+ ldr q_d2_0, [x_dest2]
+
+ and v_data_lo.16b, v_data.16b, v_mask0f.16b
+ ushr v_data_hi.16b, v_data.16b, #4
+
+ tbl v_tmp_lo.16b, {v_gft1_lo.16b}, v_data_lo.16b
+ tbl v_tmp_hi.16b, {v_gft1_hi.16b}, v_data_hi.16b
+ eor v_tmp_hi.16b, v_tmp_lo.16b, v_tmp_hi.16b
+ and v_tmp_hi.16b, v_tmp_hi.16b, v_tmp.16b
+ eor v_d1_0.16b, v_d1_0.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft2_lo.16b}, v_data_lo.16b
+ tbl v_tmp_hi.16b, {v_gft2_hi.16b}, v_data_hi.16b
+ eor v_tmp_hi.16b, v_tmp_lo.16b, v_tmp_hi.16b
+ and v_tmp_hi.16b, v_tmp_hi.16b, v_tmp.16b
+ eor v_d2_0.16b, v_d2_0.16b, v_tmp_hi.16b
+
+ str q_d1_0, [x_dest1]
+ str q_d2_0, [x_dest2]
+ ldr q_d3_0, [x_dest3]
+ ldr q_d4_0, [x_dest4]
+
+ tbl v_tmp_lo.16b, {v_gft3_lo.16b}, v_data_lo.16b
+ tbl v_tmp_hi.16b, {v_gft3_hi.16b}, v_data_hi.16b
+ eor v_tmp_hi.16b, v_tmp_lo.16b, v_tmp_hi.16b
+ and v_tmp_hi.16b, v_tmp_hi.16b, v_tmp.16b
+ eor v_d3_0.16b, v_d3_0.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft4_lo.16b}, v_data_lo.16b
+ tbl v_tmp_hi.16b, {v_gft4_hi.16b}, v_data_hi.16b
+ eor v_tmp_hi.16b, v_tmp_lo.16b, v_tmp_hi.16b
+ and v_tmp_hi.16b, v_tmp_hi.16b, v_tmp.16b
+ eor v_d4_0.16b, v_d4_0.16b, v_tmp_hi.16b
+
+ str q_d3_0, [x_dest3]
+ str q_d4_0, [x_dest4]
+
+.return_pass:
+ mov w_ret, #0
+ ret
+
+.return_fail:
+ mov w_ret, #1
+ ret
+
+ASM_DEF_RODATA
+.balign 8
+const_tbl:
+ .dword 0x0000000000000000, 0x0000000000000000
+ .dword 0xffffffffffffffff, 0xffffffffffffffff
diff --git a/contrib/libs/isa-l/erasure_code/aarch64/gf_4vect_mad_sve.S b/contrib/libs/isa-l/erasure_code/aarch64/gf_4vect_mad_sve.S
new file mode 100644
index 0000000000..89ec89f5c6
--- /dev/null
+++ b/contrib/libs/isa-l/erasure_code/aarch64/gf_4vect_mad_sve.S
@@ -0,0 +1,194 @@
+/**************************************************************
+ Copyright (c) 2021 Linaro Ltd.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name of Huawei Corporation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+**********************************************************************/
+.text
+.align 6
+.arch armv8-a+sve
+
+#include "../include/aarch64_label.h"
+
+.global cdecl(gf_4vect_mad_sve)
+#ifndef __APPLE__
+.type gf_4vect_mad_sve, %function
+#endif
+
+/* gf_4vect_mad_sve(int len, int vec, int vec_i, unsigned char *gftbls,
+ unsigned char *src, unsigned char **dest);
+ */
+/* arguments */
+x_len .req x0
+x_vec .req x1
+x_vec_i .req x2
+x_tbl .req x3
+x_src .req x4
+x_dest .req x5
+
+/* returns */
+w_ret .req w0
+
+/* local variables */
+x_pos .req x6
+x_dest2 .req x7
+x_dest3 .req x8
+x_dest4 .req x9
+x_dest1 .req x12
+
+/* vectors */
+z_mask0f .req z0
+
+z_src .req z1
+z_src_lo .req z2
+z_src_hi .req z_src
+
+z_dest1 .req z3
+
+z_tmp_lo .req z4
+z_tmp_hi .req z5
+
+z_gft1_lo .req z6
+z_gft1_hi .req z7
+q_gft1_lo .req q6
+q_gft1_hi .req q7
+
+/* bottom 64-bit of v8..v15 must be preserved if used */
+z_gft2_lo .req z17
+z_gft2_hi .req z18
+q_gft2_lo .req q17
+q_gft2_hi .req q18
+
+z_gft3_lo .req z19
+z_gft3_hi .req z20
+q_gft3_lo .req q19
+q_gft3_hi .req q20
+
+z_gft4_lo .req z21
+z_gft4_hi .req z22
+q_gft4_lo .req q21
+q_gft4_hi .req q22
+
+z_dest2 .req z27
+z_dest3 .req z28
+z_dest4 .req z29
+
+cdecl(gf_4vect_mad_sve):
+ /* less than 16 bytes, return_fail */
+ cmp x_len, #16
+ blt .return_fail
+
+ mov z_mask0f.b, #0x0f /* z_mask0f = 0x0F0F...0F */
+ /* load table 1 */
+ add x_tbl, x_tbl, x_vec_i, LSL #5 /* x_tbl += x_vec_i * 2^5 */
+
+ /* Load table 1 with NEON instruction ldp */
+ ldp q_gft1_lo, q_gft1_hi, [x_tbl]
+ /* load table 2 */
+ add x_tbl, x_tbl, x_vec, LSL #5 /* x_tbl += x_vec * 2^5 */
+ ldp q_gft2_lo, q_gft2_hi, [x_tbl]
+ /* load table 3 */
+ add x_tbl, x_tbl, x_vec, LSL #5 /* x_tbl += x_vec * 2^5 */
+ ldp q_gft3_lo, q_gft3_hi, [x_tbl]
+ /* load table 4 */
+ add x_tbl, x_tbl, x_vec, LSL #5 /* x_tbl += x_vec * 2^5 */
+ ldp q_gft4_lo, q_gft4_hi, [x_tbl]
+
+ ldr x_dest1, [x_dest, #8*0] /* pointer to dest1 */
+ ldr x_dest2, [x_dest, #8*1] /* pointer to dest2 */
+ ldr x_dest3, [x_dest, #8*2] /* pointer to dest3 */
+ ldr x_dest4, [x_dest, #8*3] /* pointer to dest4 */
+
+ mov x_pos, #0
+
+ /* vector length agnostic */
+.Lloopsve_vl:
+ whilelo p0.b, x_pos, x_len
+ b.none .return_pass
+
+ prfb pldl2strm, p0, [x_dest1, x_pos]
+ prfb pldl2strm, p0, [x_dest2, x_pos]
+
+ /* load src data, governed by p0 */
+ ld1b z_src.b, p0/z, [x_src, x_pos]
+
+ /* split 4-bit lo; 4-bit hi */
+ and z_src_lo.d, z_src.d, z_mask0f.d
+ lsr z_src_hi.b, z_src.b, #4
+
+ /* load dest data, governed by p0 */
+ ld1b z_dest1.b, p0/z, [x_dest1, x_pos]
+ ld1b z_dest2.b, p0/z, [x_dest2, x_pos]
+
+ prfb pldl2strm, p0, [x_dest3, x_pos]
+ prfb pldl2strm, p0, [x_dest4, x_pos]
+
+ /* dest1 */
+ /* table indexing, ie. gf(2^8) multiplication */
+ tbl z_tmp_lo.b, {z_gft1_lo.b}, z_src_lo.b
+ tbl z_tmp_hi.b, {z_gft1_hi.b}, z_src_hi.b
+ /* exclusive or, ie. gf(2^8) add */
+ eor z_dest1.d, z_tmp_lo.d, z_dest1.d
+ eor z_dest1.d, z_tmp_hi.d, z_dest1.d
+
+ ld1b z_dest3.b, p0/z, [x_dest3, x_pos]
+ ld1b z_dest4.b, p0/z, [x_dest4, x_pos]
+
+ /* dest2 */
+ tbl z_tmp_lo.b, {z_gft2_lo.b}, z_src_lo.b
+ tbl z_tmp_hi.b, {z_gft2_hi.b}, z_src_hi.b
+ eor z_dest2.d, z_tmp_lo.d, z_dest2.d
+ eor z_dest2.d, z_tmp_hi.d, z_dest2.d
+
+ /* dest3 */
+ tbl z_tmp_lo.b, {z_gft3_lo.b}, z_src_lo.b
+ tbl z_tmp_hi.b, {z_gft3_hi.b}, z_src_hi.b
+ eor z_dest3.d, z_tmp_lo.d, z_dest3.d
+ eor z_dest3.d, z_tmp_hi.d, z_dest3.d
+
+ /* store dest data, governed by p0 */
+ st1b z_dest1.b, p0, [x_dest1, x_pos]
+ st1b z_dest2.b, p0, [x_dest2, x_pos]
+
+ /* dest4 */
+ tbl z_tmp_lo.b, {z_gft4_lo.b}, z_src_lo.b
+ tbl z_tmp_hi.b, {z_gft4_hi.b}, z_src_hi.b
+ eor z_dest4.d, z_tmp_lo.d, z_dest4.d
+ eor z_dest4.d, z_tmp_hi.d, z_dest4.d
+
+ st1b z_dest3.b, p0, [x_dest3, x_pos]
+ st1b z_dest4.b, p0, [x_dest4, x_pos]
+ /* increment one vector length */
+ incb x_pos
+
+ b .Lloopsve_vl
+
+.return_pass:
+ mov w_ret, #0
+ ret
+
+.return_fail:
+ mov w_ret, #1
+ ret
diff --git a/contrib/libs/isa-l/erasure_code/aarch64/gf_5vect_dot_prod_neon.S b/contrib/libs/isa-l/erasure_code/aarch64/gf_5vect_dot_prod_neon.S
new file mode 100644
index 0000000000..13166665d6
--- /dev/null
+++ b/contrib/libs/isa-l/erasure_code/aarch64/gf_5vect_dot_prod_neon.S
@@ -0,0 +1,484 @@
+/**************************************************************
+ Copyright (c) 2019 Huawei Technologies Co., Ltd.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name of Huawei Corporation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+**********************************************************************/
+
+#include "../include/aarch64_label.h"
+
+.text
+
+.global cdecl(gf_5vect_dot_prod_neon)
+#ifndef __APPLE__
+.type gf_5vect_dot_prod_neon, %function
+#endif
+
+/* arguments */
+x_len .req x0
+x_vec .req x1
+x_tbl .req x2
+x_src .req x3
+x_dest .req x4
+
+/* returns */
+w_ret .req w0
+
+/* local variables */
+x_vec_i .req x5
+x_ptr .req x6
+x_pos .req x7
+x_tmp .req x8
+x_dest1 .req x9
+x_dest2 .req x10
+x_dest3 .req x11
+x_dest4 .req x12
+x_dest5 .req x13
+
+/* vectors */
+v_tmp1 .req v0
+q_tmp1 .req q0
+v_tmp2 .req v1
+q_tmp2 .req q1
+
+v_mask0f .req v_tmp1
+q_mask0f .req q_tmp1
+v_tmp_lo .req v_tmp1
+v_tmp_hi .req v_tmp2
+
+v_gft_lo .req v2
+v_gft_hi .req v3
+q_gft_lo .req q2
+q_gft_hi .req q3
+
+v_p1_0 .req v4
+v_p2_0 .req v5
+v_p3_0 .req v6
+v_p4_0 .req v7
+
+q_p1_0 .req q4
+q_p2_0 .req q5
+q_p3_0 .req q6
+q_p4_0 .req q7
+
+v_data_0 .req v8
+v_data_1 .req v9
+v_data_2 .req v10
+v_data_3 .req v11
+q_data_0 .req q8
+q_data_1 .req q9
+q_data_2 .req q10
+q_data_3 .req q11
+
+v_data_0_lo .req v12
+v_data_1_lo .req v13
+v_data_2_lo .req v14
+v_data_3_lo .req v15
+v_data_0_hi .req v_data_0
+v_data_1_hi .req v_data_1
+v_data_2_hi .req v_data_2
+v_data_3_hi .req v_data_3
+
+v_p5_0 .req v16
+v_p1_1 .req v17
+v_p2_1 .req v18
+v_p3_1 .req v19
+v_p4_1 .req v20
+v_p5_1 .req v21
+v_p1_2 .req v22
+v_p2_2 .req v23
+v_p3_2 .req v24
+v_p4_2 .req v25
+v_p5_2 .req v26
+v_p1_3 .req v27
+v_p2_3 .req v28
+v_p3_3 .req v29
+v_p4_3 .req v30
+v_p5_3 .req v31
+
+q_p5_0 .req q16
+q_p1_1 .req q17
+q_p2_1 .req q18
+q_p3_1 .req q19
+q_p4_1 .req q20
+q_p5_1 .req q21
+q_p1_2 .req q22
+q_p2_2 .req q23
+q_p3_2 .req q24
+q_p4_2 .req q25
+q_p5_2 .req q26
+q_p1_3 .req q27
+q_p2_3 .req q28
+q_p3_3 .req q29
+q_p4_3 .req q30
+q_p5_3 .req q31
+
+v_data .req v_p1_1
+q_data .req q_p1_1
+v_data_lo .req v_p2_1
+v_data_hi .req v_p3_1
+
+v_gft1_lo .req v_p4_1
+v_gft1_hi .req v_p5_1
+v_gft2_lo .req v_p1_2
+v_gft2_hi .req v_p2_2
+v_gft3_lo .req v_p3_2
+v_gft3_hi .req v_p4_2
+v_gft4_lo .req v_p5_2
+v_gft4_hi .req v_p1_3
+v_gft5_lo .req v_p2_3
+v_gft5_hi .req v_p3_3
+q_gft1_lo .req q_p4_1
+q_gft1_hi .req q_p5_1
+q_gft2_lo .req q_p1_2
+q_gft2_hi .req q_p2_2
+q_gft3_lo .req q_p3_2
+q_gft3_hi .req q_p4_2
+q_gft4_lo .req q_p5_2
+q_gft4_hi .req q_p1_3
+q_gft5_lo .req q_p2_3
+q_gft5_hi .req q_p3_3
+
+
+cdecl(gf_5vect_dot_prod_neon):
+ /* less than 16 bytes, return_fail */
+ cmp x_len, #16
+ blt .return_fail
+
+ mov x_pos, #0
+ lsl x_vec, x_vec, #3
+ ldr x_dest1, [x_dest, #8*0]
+ ldr x_dest2, [x_dest, #8*1]
+ ldr x_dest3, [x_dest, #8*2]
+ ldr x_dest4, [x_dest, #8*3]
+ ldr x_dest5, [x_dest, #8*4]
+
+.Lloop64_init:
+ /* less than 64 bytes, goto Lloop16_init */
+ cmp x_len, #64
+ blt .Lloop16_init
+
+ /* save d8 ~ d15 to stack */
+ sub sp, sp, #64
+ stp d8, d9, [sp]
+ stp d10, d11, [sp, #16]
+ stp d12, d13, [sp, #32]
+ stp d14, d15, [sp, #48]
+
+ sub x_len, x_len, #64
+
+.Lloop64:
+ movi v_p1_0.16b, #0
+ movi v_p1_1.16b, #0
+ movi v_p1_2.16b, #0
+ movi v_p1_3.16b, #0
+ movi v_p2_0.16b, #0
+ movi v_p2_1.16b, #0
+ movi v_p2_2.16b, #0
+ movi v_p2_3.16b, #0
+ movi v_p3_0.16b, #0
+ movi v_p3_1.16b, #0
+ movi v_p3_2.16b, #0
+ movi v_p3_3.16b, #0
+ movi v_p4_0.16b, #0
+ movi v_p4_1.16b, #0
+ movi v_p4_2.16b, #0
+ movi v_p4_3.16b, #0
+ movi v_p5_0.16b, #0
+ movi v_p5_1.16b, #0
+ movi v_p5_2.16b, #0
+ movi v_p5_3.16b, #0
+ mov x_vec_i, #0
+
+.Lloop64_vects:
+ ldr x_ptr, [x_src, x_vec_i]
+ add x_ptr, x_ptr, x_pos
+
+ ldr q_data_0, [x_ptr], #16
+ ldr q_data_1, [x_ptr], #16
+ ldr q_data_2, [x_ptr], #16
+ ldr q_data_3, [x_ptr], #16
+ prfm pldl2keep, [x_ptr]
+
+ movi v_mask0f.16b, #0x0f
+ and v_data_0_lo.16b, v_data_0.16b, v_mask0f.16b
+ and v_data_1_lo.16b, v_data_1.16b, v_mask0f.16b
+ and v_data_2_lo.16b, v_data_2.16b, v_mask0f.16b
+ and v_data_3_lo.16b, v_data_3.16b, v_mask0f.16b
+ ushr v_data_0_hi.16b, v_data_0.16b, #4
+ ushr v_data_1_hi.16b, v_data_1.16b, #4
+ ushr v_data_2_hi.16b, v_data_2.16b, #4
+ ushr v_data_3_hi.16b, v_data_3.16b, #4
+
+ /* v_p1_x */
+ add x_tmp, x_tbl, x_vec_i, lsl #2
+ add x_vec_i, x_vec_i, #8
+ ldp q_gft_lo, q_gft_hi, [x_tmp]
+ prfm pldl3keep, [x_tmp, #32]
+ add x_tmp, x_tmp, x_vec, lsl #2
+
+ tbl v_tmp_lo.16b, {v_gft_lo.16b}, v_data_0_lo.16b
+ tbl v_tmp_hi.16b, {v_gft_hi.16b}, v_data_0_hi.16b
+ eor v_p1_0.16b, v_tmp_lo.16b, v_p1_0.16b
+ eor v_p1_0.16b, v_p1_0.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft_lo.16b}, v_data_1_lo.16b
+ tbl v_tmp_hi.16b, {v_gft_hi.16b}, v_data_1_hi.16b
+ eor v_p1_1.16b, v_tmp_lo.16b, v_p1_1.16b
+ eor v_p1_1.16b, v_p1_1.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft_lo.16b}, v_data_2_lo.16b
+ tbl v_tmp_hi.16b, {v_gft_hi.16b}, v_data_2_hi.16b
+ eor v_p1_2.16b, v_tmp_lo.16b, v_p1_2.16b
+ eor v_p1_2.16b, v_p1_2.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft_lo.16b}, v_data_3_lo.16b
+ tbl v_tmp_hi.16b, {v_gft_hi.16b}, v_data_3_hi.16b
+ eor v_p1_3.16b, v_tmp_lo.16b, v_p1_3.16b
+ eor v_p1_3.16b, v_p1_3.16b, v_tmp_hi.16b
+
+ /* v_p2_x */
+ ldp q_gft_lo, q_gft_hi, [x_tmp]
+ prfm pldl3keep, [x_tmp, #32]
+ add x_tmp, x_tmp, x_vec, lsl #2
+
+ tbl v_tmp_lo.16b, {v_gft_lo.16b}, v_data_0_lo.16b
+ tbl v_tmp_hi.16b, {v_gft_hi.16b}, v_data_0_hi.16b
+ eor v_p2_0.16b, v_tmp_lo.16b, v_p2_0.16b
+ eor v_p2_0.16b, v_p2_0.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft_lo.16b}, v_data_1_lo.16b
+ tbl v_tmp_hi.16b, {v_gft_hi.16b}, v_data_1_hi.16b
+ eor v_p2_1.16b, v_tmp_lo.16b, v_p2_1.16b
+ eor v_p2_1.16b, v_p2_1.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft_lo.16b}, v_data_2_lo.16b
+ tbl v_tmp_hi.16b, {v_gft_hi.16b}, v_data_2_hi.16b
+ eor v_p2_2.16b, v_tmp_lo.16b, v_p2_2.16b
+ eor v_p2_2.16b, v_p2_2.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft_lo.16b}, v_data_3_lo.16b
+ tbl v_tmp_hi.16b, {v_gft_hi.16b}, v_data_3_hi.16b
+ eor v_p2_3.16b, v_tmp_lo.16b, v_p2_3.16b
+ eor v_p2_3.16b, v_p2_3.16b, v_tmp_hi.16b
+
+ /* v_p3_x */
+ ldp q_gft_lo, q_gft_hi, [x_tmp]
+ prfm pldl3keep, [x_tmp, #32]
+ add x_tmp, x_tmp, x_vec, lsl #2
+
+ tbl v_tmp_lo.16b, {v_gft_lo.16b}, v_data_0_lo.16b
+ tbl v_tmp_hi.16b, {v_gft_hi.16b}, v_data_0_hi.16b
+ eor v_p3_0.16b, v_tmp_lo.16b, v_p3_0.16b
+ eor v_p3_0.16b, v_p3_0.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft_lo.16b}, v_data_1_lo.16b
+ tbl v_tmp_hi.16b, {v_gft_hi.16b}, v_data_1_hi.16b
+ eor v_p3_1.16b, v_tmp_lo.16b, v_p3_1.16b
+ eor v_p3_1.16b, v_p3_1.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft_lo.16b}, v_data_2_lo.16b
+ tbl v_tmp_hi.16b, {v_gft_hi.16b}, v_data_2_hi.16b
+ eor v_p3_2.16b, v_tmp_lo.16b, v_p3_2.16b
+ eor v_p3_2.16b, v_p3_2.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft_lo.16b}, v_data_3_lo.16b
+ tbl v_tmp_hi.16b, {v_gft_hi.16b}, v_data_3_hi.16b
+ eor v_p3_3.16b, v_tmp_lo.16b, v_p3_3.16b
+ eor v_p3_3.16b, v_p3_3.16b, v_tmp_hi.16b
+
+ /* v_p4_x */
+ ldp q_gft_lo, q_gft_hi, [x_tmp]
+ prfm pldl3keep, [x_tmp, #32]
+ add x_tmp, x_tmp, x_vec, lsl #2
+
+ tbl v_tmp_lo.16b, {v_gft_lo.16b}, v_data_0_lo.16b
+ tbl v_tmp_hi.16b, {v_gft_hi.16b}, v_data_0_hi.16b
+ eor v_p4_0.16b, v_tmp_lo.16b, v_p4_0.16b
+ eor v_p4_0.16b, v_p4_0.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft_lo.16b}, v_data_1_lo.16b
+ tbl v_tmp_hi.16b, {v_gft_hi.16b}, v_data_1_hi.16b
+ eor v_p4_1.16b, v_tmp_lo.16b, v_p4_1.16b
+ eor v_p4_1.16b, v_p4_1.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft_lo.16b}, v_data_2_lo.16b
+ tbl v_tmp_hi.16b, {v_gft_hi.16b}, v_data_2_hi.16b
+ eor v_p4_2.16b, v_tmp_lo.16b, v_p4_2.16b
+ eor v_p4_2.16b, v_p4_2.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft_lo.16b}, v_data_3_lo.16b
+ tbl v_tmp_hi.16b, {v_gft_hi.16b}, v_data_3_hi.16b
+ eor v_p4_3.16b, v_tmp_lo.16b, v_p4_3.16b
+ eor v_p4_3.16b, v_p4_3.16b, v_tmp_hi.16b
+
+ /* v_p5_x */
+ ldp q_gft_lo, q_gft_hi, [x_tmp]
+ prfm pldl3keep, [x_tmp, #32]
+
+ tbl v_tmp_lo.16b, {v_gft_lo.16b}, v_data_0_lo.16b
+ tbl v_tmp_hi.16b, {v_gft_hi.16b}, v_data_0_hi.16b
+ eor v_p5_0.16b, v_tmp_lo.16b, v_p5_0.16b
+ eor v_p5_0.16b, v_p5_0.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft_lo.16b}, v_data_1_lo.16b
+ tbl v_tmp_hi.16b, {v_gft_hi.16b}, v_data_1_hi.16b
+ eor v_p5_1.16b, v_tmp_lo.16b, v_p5_1.16b
+ eor v_p5_1.16b, v_p5_1.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft_lo.16b}, v_data_2_lo.16b
+ tbl v_tmp_hi.16b, {v_gft_hi.16b}, v_data_2_hi.16b
+ eor v_p5_2.16b, v_tmp_lo.16b, v_p5_2.16b
+ eor v_p5_2.16b, v_p5_2.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft_lo.16b}, v_data_3_lo.16b
+ tbl v_tmp_hi.16b, {v_gft_hi.16b}, v_data_3_hi.16b
+ eor v_p5_3.16b, v_tmp_lo.16b, v_p5_3.16b
+ eor v_p5_3.16b, v_p5_3.16b, v_tmp_hi.16b
+
+ cmp x_vec_i, x_vec
+ blt .Lloop64_vects
+
+.Lloop64_vects_end:
+ add x_ptr, x_dest1, x_pos
+ stp q_p1_0, q_p1_1, [x_ptr], #32
+ stp q_p1_2, q_p1_3, [x_ptr]
+
+ add x_ptr, x_dest2, x_pos
+ stp q_p2_0, q_p2_1, [x_ptr], #32
+ stp q_p2_2, q_p2_3, [x_ptr]
+
+ add x_ptr, x_dest3, x_pos
+ stp q_p3_0, q_p3_1, [x_ptr], #32
+ stp q_p3_2, q_p3_3, [x_ptr]
+
+ add x_ptr, x_dest4, x_pos
+ stp q_p4_0, q_p4_1, [x_ptr], #32
+ stp q_p4_2, q_p4_3, [x_ptr]
+
+ add x_ptr, x_dest5, x_pos
+ stp q_p5_0, q_p5_1, [x_ptr], #32
+ stp q_p5_2, q_p5_3, [x_ptr]
+
+ add x_pos, x_pos, #64
+ cmp x_pos, x_len
+ ble .Lloop64
+
+.Lloop64_end:
+ /* restore d8 ~ d15 */
+ ldp d8, d9, [sp]
+ ldp d10, d11, [sp, #16]
+ ldp d12, d13, [sp, #32]
+ ldp d14, d15, [sp, #48]
+ add sp, sp, #64
+
+ add x_len, x_len, #64
+ cmp x_pos, x_len
+ beq .return_pass
+
+.Lloop16_init:
+ sub x_len, x_len, #16
+ cmp x_pos, x_len
+ bgt .lessthan16_init
+
+.Lloop16:
+ movi v_p1_0.16b, #0
+ movi v_p2_0.16b, #0
+ movi v_p3_0.16b, #0
+ movi v_p4_0.16b, #0
+ movi v_p5_0.16b, #0
+ mov x_vec_i, #0
+
+.Lloop16_vects:
+ ldr x_ptr, [x_src, x_vec_i]
+ ldr q_data, [x_ptr, x_pos]
+
+ movi v_mask0f.16b, #0x0f
+ and v_data_lo.16b, v_data.16b, v_mask0f.16b
+ ushr v_data_hi.16b, v_data.16b, #4
+
+ add x_tmp, x_tbl, x_vec_i, lsl #2
+ add x_vec_i, x_vec_i, #8
+ ldp q_gft1_lo, q_gft1_hi, [x_tmp]
+ add x_tmp, x_tmp, x_vec, lsl #2
+ ldp q_gft2_lo, q_gft2_hi, [x_tmp]
+ add x_tmp, x_tmp, x_vec, lsl #2
+ ldp q_gft3_lo, q_gft3_hi, [x_tmp]
+ add x_tmp, x_tmp, x_vec, lsl #2
+ ldp q_gft4_lo, q_gft4_hi, [x_tmp]
+ add x_tmp, x_tmp, x_vec, lsl #2
+ ldp q_gft5_lo, q_gft5_hi, [x_tmp]
+
+ tbl v_gft1_lo.16b, {v_gft1_lo.16b}, v_data_lo.16b
+ tbl v_gft1_hi.16b, {v_gft1_hi.16b}, v_data_hi.16b
+ tbl v_gft2_lo.16b, {v_gft2_lo.16b}, v_data_lo.16b
+ tbl v_gft2_hi.16b, {v_gft2_hi.16b}, v_data_hi.16b
+ tbl v_gft3_lo.16b, {v_gft3_lo.16b}, v_data_lo.16b
+ tbl v_gft3_hi.16b, {v_gft3_hi.16b}, v_data_hi.16b
+ tbl v_gft4_lo.16b, {v_gft4_lo.16b}, v_data_lo.16b
+ tbl v_gft4_hi.16b, {v_gft4_hi.16b}, v_data_hi.16b
+ tbl v_gft5_lo.16b, {v_gft5_lo.16b}, v_data_lo.16b
+ tbl v_gft5_hi.16b, {v_gft5_hi.16b}, v_data_hi.16b
+
+ eor v_p1_0.16b, v_gft1_hi.16b, v_p1_0.16b
+ eor v_p1_0.16b, v_p1_0.16b, v_gft1_lo.16b
+ eor v_p2_0.16b, v_gft2_hi.16b, v_p2_0.16b
+ eor v_p2_0.16b, v_p2_0.16b, v_gft2_lo.16b
+ eor v_p3_0.16b, v_gft3_hi.16b, v_p3_0.16b
+ eor v_p3_0.16b, v_p3_0.16b, v_gft3_lo.16b
+ eor v_p4_0.16b, v_gft4_hi.16b, v_p4_0.16b
+ eor v_p4_0.16b, v_p4_0.16b, v_gft4_lo.16b
+ eor v_p5_0.16b, v_gft5_hi.16b, v_p5_0.16b
+ eor v_p5_0.16b, v_p5_0.16b, v_gft5_lo.16b
+
+ cmp x_vec_i, x_vec
+ bne .Lloop16_vects
+
+.Lloop16_vects_end:
+ str q_p1_0, [x_dest1, x_pos]
+ str q_p2_0, [x_dest2, x_pos]
+ str q_p3_0, [x_dest3, x_pos]
+ str q_p4_0, [x_dest4, x_pos]
+ str q_p5_0, [x_dest5, x_pos]
+ add x_pos, x_pos, #16
+ cmp x_pos, x_len
+ ble .Lloop16
+
+.Lloop16_end:
+ sub x_tmp, x_pos, x_len
+ cmp x_tmp, #16
+ beq .return_pass
+
+.lessthan16_init:
+ mov x_pos, x_len
+ b .Lloop16
+
+.return_pass:
+ mov w_ret, #0
+ ret
+
+.return_fail:
+ mov w_ret, #1
+ ret
diff --git a/contrib/libs/isa-l/erasure_code/aarch64/gf_5vect_dot_prod_sve.S b/contrib/libs/isa-l/erasure_code/aarch64/gf_5vect_dot_prod_sve.S
new file mode 100644
index 0000000000..bb7cd0184e
--- /dev/null
+++ b/contrib/libs/isa-l/erasure_code/aarch64/gf_5vect_dot_prod_sve.S
@@ -0,0 +1,237 @@
+/*************************************************************
+ Copyright (c) 2021 Linaro Ltd.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name of Huawei Corporation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+**********************************************************************/
+.text
+.align 6
+.arch armv8-a+sve
+
+#include "../include/aarch64_label.h"
+
+.global cdecl(gf_5vect_dot_prod_sve)
+#ifndef __APPLE__
+.type gf_5vect_dot_prod_sve, %function
+#endif
+/* void gf_5vect_dot_prod_sve(int len, int vlen, unsigned char *gftbls,
+ unsigned char **src, unsigned char **dest);
+ */
+
+/* arguments */
+x_len .req x0 /* vector length */
+x_vec .req x1 /* number of source vectors (ie. data blocks) */
+x_tbl .req x2
+x_src .req x3
+x_dest .req x4
+
+/* returns */
+w_ret .req w0
+
+/* local variables */
+x_vec_i .req x5
+x_ptr .req x6
+x_pos .req x7
+
+x_tbl1 .req x8
+x_tbl2 .req x9
+x_tbl3 .req x10
+x_tbl4 .req x11
+x_tbl5 .req x12
+x_dest1 .req x13
+x_dest2 .req x14
+x_dest4 .req x15
+x_dest5 .req x_dest /* reused */
+
+/* r16,r17,r18,r29,r30: special role registers, avoided */
+/* r19..r29 and SP must be preserved */
+x_dest3 .req x19
+
+/* vectors */
+z_mask0f .req z0
+
+z_src .req z1
+z_src_lo .req z2
+z_src_hi .req z_src
+
+z_dest1 .req z3
+
+z_gft1_lo .req z4
+z_gft1_hi .req z5
+q_gft1_lo .req q4
+q_gft1_hi .req q5
+
+/* bottom 64-bit of v8..v15 must be preserved if used */
+z_gft2_lo .req z17
+z_gft2_hi .req z18
+q_gft2_lo .req q17
+q_gft2_hi .req q18
+
+z_gft3_lo .req z19
+z_gft3_hi .req z20
+q_gft3_lo .req q19
+q_gft3_hi .req q20
+
+z_gft4_lo .req z21
+z_gft4_hi .req z22
+q_gft4_lo .req q21
+q_gft4_hi .req q22
+
+z_gft5_lo .req z23
+z_gft5_hi .req z24
+q_gft5_lo .req q23
+q_gft5_hi .req q24
+
+z_dest2 .req z27
+z_dest3 .req z28
+z_dest4 .req z29
+z_dest5 .req z30
+
+cdecl(gf_5vect_dot_prod_sve):
+ /* less than 16 bytes, return_fail */
+ cmp x_len, #16
+ blt .return_fail
+
+ /* save r19..r29 */
+ sub sp, sp, #16 /* alignment */
+ str x19, [sp]
+
+ mov z_mask0f.b, #0x0f /* z_mask0f = 0x0F0F...0F */
+ mov x_pos, #0
+ lsl x_vec, x_vec, #3
+ ldp x_dest1, x_dest2, [x_dest, #8*0]
+ ldp x_dest3, x_dest4, [x_dest, #8*2]
+ ldr x_dest5, [x_dest, #8*4]
+
+/* Loop 1: x_len, vector length */
+.Lloopsve_vl:
+ whilelo p0.b, x_pos, x_len
+ b.none .return_pass
+
+ mov x_vec_i, #0 /* clear x_vec_i */
+ ldr x_ptr, [x_src, x_vec_i] /* x_ptr: src base addr. */
+
+ mov z_dest1.b, #0 /* clear z_dest1 */
+ mov z_dest2.b, #0 /* clear z_dest2 */
+ mov z_dest3.b, #0 /* clear z_dest3 */
+ mov z_dest4.b, #0 /* clear z_dest4 */
+ mov z_dest5.b, #0 /* clear z_dest5 */
+
+ /* gf_tbl base = (x_tbl + dest_idx * x_vec * 32) */
+ mov x_tbl1, x_tbl /* reset x_tbl1 */
+ add x_tbl2, x_tbl1, x_vec, LSL #2 /* reset x_tbl2 */
+ add x_tbl3, x_tbl2, x_vec, LSL #2 /* reset x_tbl3 */
+ add x_tbl4, x_tbl3, x_vec, LSL #2 /* reset x_tbl4 */
+ add x_tbl5, x_tbl4, x_vec, LSL #2 /* reset x_tbl5 */
+
+/* Loop 2: x_vec, number of source vectors (ie. data blocks) */
+.Lloopsve_vl_vects:
+ /* load src data, governed by p0 */
+ ld1b z_src.b, p0/z, [x_ptr, x_pos] /* load from: src base + pos offset */
+ /* split 4-bit lo; 4-bit hi */
+ and z_src_lo.d, z_src.d, z_mask0f.d
+ lsr z_src_hi.b, z_src.b, #4
+
+
+ /* gf_tbl addr: (x_tbl + dest_idx * x_vec * 32) + src_vec_idx * 32 */
+ /* load gf_table's */
+ ldp q_gft1_lo, q_gft1_hi, [x_tbl1], #32 /* x_tbl1 is post-added by #32 for each src vect */
+ ldp q_gft2_lo, q_gft2_hi, [x_tbl2], #32
+
+ /* prefetch */
+ prfb pldl2keep, p0, [x_tbl1]
+ prfb pldl2keep, p0, [x_tbl2]
+
+ /* calc for next */
+ add x_vec_i, x_vec_i, #8 /* move x_vec_i to next */
+ ldr x_ptr, [x_src, x_vec_i] /* x_ptr: src base addr. */
+
+ /* dest 1 */
+ /* table indexing, ie. gf(2^8) multiplication */
+ tbl z_gft1_lo.b, {z_gft1_lo.b}, z_src_lo.b
+ tbl z_gft1_hi.b, {z_gft1_hi.b}, z_src_hi.b
+ /* exclusive or, ie. gf(2^8) add */
+ eor z_dest1.d, z_gft1_lo.d, z_dest1.d
+ eor z_dest1.d, z_dest1.d, z_gft1_hi.d
+
+ ldp q_gft3_lo, q_gft3_hi, [x_tbl3], #32
+ ldp q_gft4_lo, q_gft4_hi, [x_tbl4], #32
+ prfb pldl2keep, p0, [x_tbl3]
+ prfb pldl2keep, p0, [x_tbl4]
+
+ /* dest 2 */
+ tbl z_gft2_lo.b, {z_gft2_lo.b}, z_src_lo.b
+ tbl z_gft2_hi.b, {z_gft2_hi.b}, z_src_hi.b
+ eor z_dest2.d, z_gft2_lo.d, z_dest2.d
+ eor z_dest2.d, z_dest2.d, z_gft2_hi.d
+
+ /* dest 3 */
+ tbl z_gft3_lo.b, {z_gft3_lo.b}, z_src_lo.b
+ tbl z_gft3_hi.b, {z_gft3_hi.b}, z_src_hi.b
+ eor z_dest3.d, z_gft3_lo.d, z_dest3.d
+ eor z_dest3.d, z_dest3.d, z_gft3_hi.d
+
+ ldp q_gft5_lo, q_gft5_hi, [x_tbl5], #32
+ prfb pldl2keep, p0, [x_tbl5]
+
+ /* dest 4 */
+ tbl z_gft4_lo.b, {z_gft4_lo.b}, z_src_lo.b
+ tbl z_gft4_hi.b, {z_gft4_hi.b}, z_src_hi.b
+ eor z_dest4.d, z_gft4_lo.d, z_dest4.d
+ eor z_dest4.d, z_dest4.d, z_gft4_hi.d
+
+ /* dest 5 */
+ tbl z_gft5_lo.b, {z_gft5_lo.b}, z_src_lo.b
+ tbl z_gft5_hi.b, {z_gft5_hi.b}, z_src_hi.b
+ eor z_dest5.d, z_gft5_lo.d, z_dest5.d
+ eor z_dest5.d, z_dest5.d, z_gft5_hi.d
+
+ cmp x_vec_i, x_vec
+ blt .Lloopsve_vl_vects
+/* end of Loop 2 */
+
+ /* store dest data, governed by p0 */
+ st1b z_dest1.b, p0, [x_dest1, x_pos]
+ st1b z_dest2.b, p0, [x_dest2, x_pos]
+ st1b z_dest3.b, p0, [x_dest3, x_pos]
+ st1b z_dest4.b, p0, [x_dest4, x_pos]
+ st1b z_dest5.b, p0, [x_dest5, x_pos]
+
+ /* increment one vector length */
+ incb x_pos
+ b .Lloopsve_vl
+/* end of Loop 1 */
+
+.return_pass:
+ /* restore r19..r29 */
+ ldr x19, [sp]
+ add sp, sp, #16
+
+ mov w_ret, #0
+ ret
+
+.return_fail:
+ mov w_ret, #1
+ ret
diff --git a/contrib/libs/isa-l/erasure_code/aarch64/gf_5vect_mad_neon.S b/contrib/libs/isa-l/erasure_code/aarch64/gf_5vect_mad_neon.S
new file mode 100644
index 0000000000..473e4c5774
--- /dev/null
+++ b/contrib/libs/isa-l/erasure_code/aarch64/gf_5vect_mad_neon.S
@@ -0,0 +1,544 @@
+/**************************************************************
+ Copyright (c) 2019 Huawei Technologies Co., Ltd.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name of Huawei Corporation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+**********************************************************************/
+
+#include "../include/aarch64_label.h"
+
+.text
+
+.global cdecl(gf_5vect_mad_neon)
+#ifndef __APPLE__
+.type gf_5vect_mad_neon, %function
+#endif
+
+/* arguments */
+x_len .req x0
+x_vec .req x1
+x_vec_i .req x2
+x_tbl .req x3
+x_src .req x4
+x_dest .req x5
+
+/* returns */
+w_ret .req w0
+
+/* local variables */
+x_src_end .req x6
+x_dest1 .req x7
+x_dest2 .req x8
+x_dest3 .req x9
+x_dest4 .req x10
+x_dest5 .req x_dest
+x_tmp .req x11
+x_tbl1 .req x12
+x_tbl2 .req x13
+x_tbl3 .req x14
+x_tbl4 .req x15
+x_tbl5 .req x16
+x_const .req x17
+
+/* vectors */
+v_mask0f .req v0
+v_tmp_lo .req v1
+v_tmp_hi .req v2
+v_tmp .req v3
+q_tmp .req q3
+
+v_gft1_lo .req v4
+v_gft1_hi .req v5
+v_gft2_lo .req v6
+v_gft2_hi .req v7
+v_gft3_lo .req v16
+v_gft3_hi .req v17
+q_gft1_lo .req q4
+q_gft1_hi .req q5
+q_gft2_lo .req q6
+q_gft2_hi .req q7
+q_gft3_lo .req q16
+q_gft3_hi .req q17
+
+v_gft4_lo .req v18
+v_gft4_hi .req v19
+q_gft4_lo .req q18
+q_gft4_hi .req q19
+v_gft5_lo .req v_gft2_lo
+v_gft5_hi .req v_gft2_hi
+q_gft5_lo .req q_gft2_lo
+q_gft5_hi .req q_gft2_hi
+
+v_data_0 .req v8
+v_data_1 .req v9
+v_data_2 .req v10
+v_data_3 .req v11
+q_data_0 .req q8
+q_data_1 .req q9
+q_data_2 .req q10
+q_data_3 .req q11
+
+v_data_0_lo .req v12
+v_data_1_lo .req v13
+v_data_2_lo .req v14
+v_data_3_lo .req v15
+v_data_0_hi .req v_data_0
+v_data_1_hi .req v_data_1
+v_data_2_hi .req v_data_2
+v_data_3_hi .req v_data_3
+
+v_d1_0 .req v20
+v_d1_1 .req v21
+v_d1_2 .req v22
+v_d1_3 .req v23
+v_d2_0 .req v24
+v_d2_1 .req v25
+v_d2_2 .req v26
+v_d2_3 .req v27
+v_d3_0 .req v28
+v_d3_1 .req v29
+v_d3_2 .req v30
+v_d3_3 .req v31
+q_d1_0 .req q20
+q_d1_1 .req q21
+q_d1_2 .req q22
+q_d1_3 .req q23
+q_d2_0 .req q24
+q_d2_1 .req q25
+q_d2_2 .req q26
+q_d2_3 .req q27
+q_d3_0 .req q28
+q_d3_1 .req q29
+q_d3_2 .req q30
+q_d3_3 .req q31
+
+v_d4_0 .req v_d1_0
+v_d4_1 .req v_d1_1
+v_d4_2 .req v_d1_2
+v_d4_3 .req v_d1_3
+q_d4_0 .req q_d1_0
+q_d4_1 .req q_d1_1
+q_d4_2 .req q_d1_2
+q_d4_3 .req q_d1_3
+v_d5_0 .req v_d2_0
+v_d5_1 .req v_d2_1
+v_d5_2 .req v_d2_2
+v_d5_3 .req v_d2_3
+q_d5_0 .req q_d2_0
+q_d5_1 .req q_d2_1
+q_d5_2 .req q_d2_2
+q_d5_3 .req q_d2_3
+
+v_data .req v21
+q_data .req q21
+v_data_lo .req v22
+v_data_hi .req v23
+
+cdecl(gf_5vect_mad_neon):
+ /* less than 16 bytes, return_fail */
+ cmp x_len, #16
+ blt .return_fail
+
+ movi v_mask0f.16b, #0x0f
+ lsl x_vec_i, x_vec_i, #5
+ lsl x_vec, x_vec, #5
+ add x_tbl1, x_tbl, x_vec_i
+ add x_tbl2, x_tbl1, x_vec
+ add x_tbl3, x_tbl2, x_vec
+ add x_tbl4, x_tbl3, x_vec
+ add x_tbl5, x_tbl4, x_vec
+ add x_src_end, x_src, x_len
+ ldr x_dest1, [x_dest, #8*0]
+ ldr x_dest2, [x_dest, #8*1]
+ ldr x_dest3, [x_dest, #8*2]
+ ldr x_dest4, [x_dest, #8*3]
+ ldr x_dest5, [x_dest, #8*4]
+ ldr q_gft1_lo, [x_tbl1]
+ ldr q_gft1_hi, [x_tbl1, #16]
+ ldr q_gft3_lo, [x_tbl3]
+ ldr q_gft3_hi, [x_tbl3, #16]
+ ldr q_gft4_lo, [x_tbl4]
+ ldr q_gft4_hi, [x_tbl4, #16]
+
+.Lloop64_init:
+ /* less than 64 bytes, goto Lloop16_init */
+ cmp x_len, #64
+ blt .Lloop16_init
+
+ /* save d8 ~ d15 to stack */
+ sub sp, sp, #64
+ stp d8, d9, [sp]
+ stp d10, d11, [sp, #16]
+ stp d12, d13, [sp, #32]
+ stp d14, d15, [sp, #48]
+
+ sub x_src_end, x_src_end, #64
+
+.Lloop64:
+ ldr q_data_0, [x_src, #16*0]
+ ldr q_data_1, [x_src, #16*1]
+ ldr q_data_2, [x_src, #16*2]
+ ldr q_data_3, [x_src, #16*3]
+ add x_src, x_src, #64
+
+ ldr q_d1_0, [x_dest1, #16*0]
+ ldr q_d1_1, [x_dest1, #16*1]
+ ldr q_d1_2, [x_dest1, #16*2]
+ ldr q_d1_3, [x_dest1, #16*3]
+
+ ldr q_d2_0, [x_dest2, #16*0]
+ ldr q_d2_1, [x_dest2, #16*1]
+ ldr q_d2_2, [x_dest2, #16*2]
+ ldr q_d2_3, [x_dest2, #16*3]
+
+ ldr q_d3_0, [x_dest3, #16*0]
+ ldr q_d3_1, [x_dest3, #16*1]
+ ldr q_d3_2, [x_dest3, #16*2]
+ ldr q_d3_3, [x_dest3, #16*3]
+
+ ldr q_gft2_lo, [x_tbl2]
+ ldr q_gft2_hi, [x_tbl2, #16]
+
+ and v_data_0_lo.16b, v_data_0.16b, v_mask0f.16b
+ and v_data_1_lo.16b, v_data_1.16b, v_mask0f.16b
+ and v_data_2_lo.16b, v_data_2.16b, v_mask0f.16b
+ and v_data_3_lo.16b, v_data_3.16b, v_mask0f.16b
+
+ ushr v_data_0_hi.16b, v_data_0.16b, #4
+ ushr v_data_1_hi.16b, v_data_1.16b, #4
+ ushr v_data_2_hi.16b, v_data_2.16b, #4
+ ushr v_data_3_hi.16b, v_data_3.16b, #4
+
+ /* dest1 */
+ tbl v_tmp_lo.16b, {v_gft1_lo.16b}, v_data_0_lo.16b
+ tbl v_tmp_hi.16b, {v_gft1_hi.16b}, v_data_0_hi.16b
+ eor v_d1_0.16b, v_tmp_lo.16b, v_d1_0.16b
+ eor v_d1_0.16b, v_d1_0.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft1_lo.16b}, v_data_1_lo.16b
+ tbl v_tmp_hi.16b, {v_gft1_hi.16b}, v_data_1_hi.16b
+ eor v_d1_1.16b, v_tmp_lo.16b, v_d1_1.16b
+ eor v_d1_1.16b, v_d1_1.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft1_lo.16b}, v_data_2_lo.16b
+ tbl v_tmp_hi.16b, {v_gft1_hi.16b}, v_data_2_hi.16b
+ eor v_d1_2.16b, v_tmp_lo.16b, v_d1_2.16b
+ eor v_d1_2.16b, v_d1_2.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft1_lo.16b}, v_data_3_lo.16b
+ tbl v_tmp_hi.16b, {v_gft1_hi.16b}, v_data_3_hi.16b
+ eor v_d1_3.16b, v_tmp_lo.16b, v_d1_3.16b
+ eor v_d1_3.16b, v_d1_3.16b, v_tmp_hi.16b
+
+ /* dest2 */
+ tbl v_tmp_lo.16b, {v_gft2_lo.16b}, v_data_0_lo.16b
+ tbl v_tmp_hi.16b, {v_gft2_hi.16b}, v_data_0_hi.16b
+ eor v_d2_0.16b, v_tmp_lo.16b, v_d2_0.16b
+ eor v_d2_0.16b, v_d2_0.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft2_lo.16b}, v_data_1_lo.16b
+ tbl v_tmp_hi.16b, {v_gft2_hi.16b}, v_data_1_hi.16b
+ eor v_d2_1.16b, v_tmp_lo.16b, v_d2_1.16b
+ eor v_d2_1.16b, v_d2_1.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft2_lo.16b}, v_data_2_lo.16b
+ tbl v_tmp_hi.16b, {v_gft2_hi.16b}, v_data_2_hi.16b
+ eor v_d2_2.16b, v_tmp_lo.16b, v_d2_2.16b
+ eor v_d2_2.16b, v_d2_2.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft2_lo.16b}, v_data_3_lo.16b
+ tbl v_tmp_hi.16b, {v_gft2_hi.16b}, v_data_3_hi.16b
+ eor v_d2_3.16b, v_tmp_lo.16b, v_d2_3.16b
+ eor v_d2_3.16b, v_d2_3.16b, v_tmp_hi.16b
+
+ /* dest3 */
+ tbl v_tmp_lo.16b, {v_gft3_lo.16b}, v_data_0_lo.16b
+ tbl v_tmp_hi.16b, {v_gft3_hi.16b}, v_data_0_hi.16b
+ eor v_d3_0.16b, v_tmp_lo.16b, v_d3_0.16b
+ eor v_d3_0.16b, v_d3_0.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft3_lo.16b}, v_data_1_lo.16b
+ tbl v_tmp_hi.16b, {v_gft3_hi.16b}, v_data_1_hi.16b
+ eor v_d3_1.16b, v_tmp_lo.16b, v_d3_1.16b
+ eor v_d3_1.16b, v_d3_1.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft3_lo.16b}, v_data_2_lo.16b
+ tbl v_tmp_hi.16b, {v_gft3_hi.16b}, v_data_2_hi.16b
+ eor v_d3_2.16b, v_tmp_lo.16b, v_d3_2.16b
+ eor v_d3_2.16b, v_d3_2.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft3_lo.16b}, v_data_3_lo.16b
+ tbl v_tmp_hi.16b, {v_gft3_hi.16b}, v_data_3_hi.16b
+ eor v_d3_3.16b, v_tmp_lo.16b, v_d3_3.16b
+ eor v_d3_3.16b, v_d3_3.16b, v_tmp_hi.16b
+
+ str q_d1_0, [x_dest1, #16*0]
+ str q_d1_1, [x_dest1, #16*1]
+ str q_d1_2, [x_dest1, #16*2]
+ str q_d1_3, [x_dest1, #16*3]
+ add x_dest1, x_dest1, #64
+
+ str q_d2_0, [x_dest2, #16*0]
+ str q_d2_1, [x_dest2, #16*1]
+ str q_d2_2, [x_dest2, #16*2]
+ str q_d2_3, [x_dest2, #16*3]
+ add x_dest2, x_dest2, #64
+
+ str q_d3_0, [x_dest3, #16*0]
+ str q_d3_1, [x_dest3, #16*1]
+ str q_d3_2, [x_dest3, #16*2]
+ str q_d3_3, [x_dest3, #16*3]
+ add x_dest3, x_dest3, #64
+
+ ldr q_d4_0, [x_dest4, #16*0]
+ ldr q_d4_1, [x_dest4, #16*1]
+ ldr q_d4_2, [x_dest4, #16*2]
+ ldr q_d4_3, [x_dest4, #16*3]
+
+ ldr q_d5_0, [x_dest5, #16*0]
+ ldr q_d5_1, [x_dest5, #16*1]
+ ldr q_d5_2, [x_dest5, #16*2]
+ ldr q_d5_3, [x_dest5, #16*3]
+
+ ldr q_gft5_lo, [x_tbl5]
+ ldr q_gft5_hi, [x_tbl5, #16]
+
+ /* dest4 */
+ tbl v_tmp_lo.16b, {v_gft4_lo.16b}, v_data_0_lo.16b
+ tbl v_tmp_hi.16b, {v_gft4_hi.16b}, v_data_0_hi.16b
+ eor v_d4_0.16b, v_tmp_lo.16b, v_d4_0.16b
+ eor v_d4_0.16b, v_d4_0.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft4_lo.16b}, v_data_1_lo.16b
+ tbl v_tmp_hi.16b, {v_gft4_hi.16b}, v_data_1_hi.16b
+ eor v_d4_1.16b, v_tmp_lo.16b, v_d4_1.16b
+ eor v_d4_1.16b, v_d4_1.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft4_lo.16b}, v_data_2_lo.16b
+ tbl v_tmp_hi.16b, {v_gft4_hi.16b}, v_data_2_hi.16b
+ eor v_d4_2.16b, v_tmp_lo.16b, v_d4_2.16b
+ eor v_d4_2.16b, v_d4_2.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft4_lo.16b}, v_data_3_lo.16b
+ tbl v_tmp_hi.16b, {v_gft4_hi.16b}, v_data_3_hi.16b
+ eor v_d4_3.16b, v_tmp_lo.16b, v_d4_3.16b
+ eor v_d4_3.16b, v_d4_3.16b, v_tmp_hi.16b
+
+ /* dest5 */
+ tbl v_tmp_lo.16b, {v_gft5_lo.16b}, v_data_0_lo.16b
+ tbl v_tmp_hi.16b, {v_gft5_hi.16b}, v_data_0_hi.16b
+ eor v_d5_0.16b, v_tmp_lo.16b, v_d5_0.16b
+ eor v_d5_0.16b, v_d5_0.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft5_lo.16b}, v_data_1_lo.16b
+ tbl v_tmp_hi.16b, {v_gft5_hi.16b}, v_data_1_hi.16b
+ eor v_d5_1.16b, v_tmp_lo.16b, v_d5_1.16b
+ eor v_d5_1.16b, v_d5_1.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft5_lo.16b}, v_data_2_lo.16b
+ tbl v_tmp_hi.16b, {v_gft5_hi.16b}, v_data_2_hi.16b
+ eor v_d5_2.16b, v_tmp_lo.16b, v_d5_2.16b
+ eor v_d5_2.16b, v_d5_2.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft5_lo.16b}, v_data_3_lo.16b
+ tbl v_tmp_hi.16b, {v_gft5_hi.16b}, v_data_3_hi.16b
+ eor v_d5_3.16b, v_tmp_lo.16b, v_d5_3.16b
+ eor v_d5_3.16b, v_d5_3.16b, v_tmp_hi.16b
+
+ str q_d4_0, [x_dest4, #16*0]
+ str q_d4_1, [x_dest4, #16*1]
+ str q_d4_2, [x_dest4, #16*2]
+ str q_d4_3, [x_dest4, #16*3]
+ add x_dest4, x_dest4, #64
+
+ str q_d5_0, [x_dest5, #16*0]
+ str q_d5_1, [x_dest5, #16*1]
+ str q_d5_2, [x_dest5, #16*2]
+ str q_d5_3, [x_dest5, #16*3]
+ add x_dest5, x_dest5, #64
+
+ cmp x_src, x_src_end
+ bls .Lloop64
+
+.Lloop64_end:
+ /* restore d8 ~ d15 */
+ ldp d8, d9, [sp]
+ ldp d10, d11, [sp, #16]
+ ldp d12, d13, [sp, #32]
+ ldp d14, d15, [sp, #48]
+ add sp, sp, #64
+ add x_src_end, x_src_end, #64
+
+.Lloop16_init:
+ sub x_src_end, x_src_end, #16
+ cmp x_src, x_src_end
+ bhi .lessthan16_init
+
+.Lloop16:
+ ldr q_data, [x_src]
+
+ ldr q_d1_0, [x_dest1]
+ ldr q_d2_0, [x_dest2]
+ ldr q_d3_0, [x_dest3]
+ ldr q_gft2_lo, [x_tbl2]
+ ldr q_gft2_hi, [x_tbl2, #16]
+
+ and v_data_lo.16b, v_data.16b, v_mask0f.16b
+ ushr v_data_hi.16b, v_data.16b, #4
+
+ tbl v_tmp_lo.16b, {v_gft1_lo.16b}, v_data_lo.16b
+ tbl v_tmp_hi.16b, {v_gft1_hi.16b}, v_data_hi.16b
+ eor v_d1_0.16b, v_tmp_lo.16b, v_d1_0.16b
+ eor v_d1_0.16b, v_d1_0.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft2_lo.16b}, v_data_lo.16b
+ tbl v_tmp_hi.16b, {v_gft2_hi.16b}, v_data_hi.16b
+ eor v_d2_0.16b, v_tmp_lo.16b, v_d2_0.16b
+ eor v_d2_0.16b, v_d2_0.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft3_lo.16b}, v_data_lo.16b
+ tbl v_tmp_hi.16b, {v_gft3_hi.16b}, v_data_hi.16b
+ eor v_d3_0.16b, v_tmp_lo.16b, v_d3_0.16b
+ eor v_d3_0.16b, v_d3_0.16b, v_tmp_hi.16b
+
+ str q_d1_0, [x_dest1]
+ str q_d2_0, [x_dest2]
+ str q_d3_0, [x_dest3]
+
+ ldr q_d4_0, [x_dest4]
+ ldr q_d5_0, [x_dest5]
+ ldr q_gft5_lo, [x_tbl5]
+ ldr q_gft5_hi, [x_tbl5, #16]
+
+ tbl v_tmp_lo.16b, {v_gft4_lo.16b}, v_data_lo.16b
+ tbl v_tmp_hi.16b, {v_gft4_hi.16b}, v_data_hi.16b
+ eor v_d4_0.16b, v_tmp_lo.16b, v_d4_0.16b
+ eor v_d4_0.16b, v_d4_0.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft5_lo.16b}, v_data_lo.16b
+ tbl v_tmp_hi.16b, {v_gft5_hi.16b}, v_data_hi.16b
+ eor v_d5_0.16b, v_tmp_lo.16b, v_d5_0.16b
+ eor v_d5_0.16b, v_d5_0.16b, v_tmp_hi.16b
+
+ str q_d4_0, [x_dest4]
+ str q_d5_0, [x_dest5]
+
+ add x_src, x_src, #16
+ add x_dest1, x_dest1, #16
+ add x_dest2, x_dest2, #16
+ add x_dest3, x_dest3, #16
+ add x_dest4, x_dest4, #16
+ add x_dest5, x_dest5, #16
+ cmp x_src, x_src_end
+ bls .Lloop16
+
+.lessthan16_init:
+ sub x_tmp, x_src, x_src_end
+ cmp x_tmp, #16
+ beq .return_pass
+
+.lessthan16:
+ mov x_src, x_src_end
+ sub x_dest1, x_dest1, x_tmp
+ sub x_dest2, x_dest2, x_tmp
+ sub x_dest3, x_dest3, x_tmp
+ sub x_dest4, x_dest4, x_tmp
+ sub x_dest5, x_dest5, x_tmp
+
+#ifndef __APPLE__
+ adrp x_const, const_tbl
+ add x_const, x_const, :lo12:const_tbl
+#else
+ adrp x_const, const_tbl@PAGE
+ add x_const, x_const, const_tbl@PAGEOFF
+#endif
+ sub x_const, x_const, x_tmp
+ ldr q_tmp, [x_const, #16]
+
+ ldr q_data, [x_src]
+ ldr q_d1_0, [x_dest1]
+ ldr q_d2_0, [x_dest2]
+ ldr q_d3_0, [x_dest3]
+ ldr q_gft2_lo, [x_tbl2]
+ ldr q_gft2_hi, [x_tbl2, #16]
+
+ and v_data_lo.16b, v_data.16b, v_mask0f.16b
+ ushr v_data_hi.16b, v_data.16b, #4
+
+ tbl v_tmp_lo.16b, {v_gft1_lo.16b}, v_data_lo.16b
+ tbl v_tmp_hi.16b, {v_gft1_hi.16b}, v_data_hi.16b
+ eor v_tmp_hi.16b, v_tmp_lo.16b, v_tmp_hi.16b
+ and v_tmp_hi.16b, v_tmp_hi.16b, v_tmp.16b
+ eor v_d1_0.16b, v_d1_0.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft2_lo.16b}, v_data_lo.16b
+ tbl v_tmp_hi.16b, {v_gft2_hi.16b}, v_data_hi.16b
+ eor v_tmp_hi.16b, v_tmp_lo.16b, v_tmp_hi.16b
+ and v_tmp_hi.16b, v_tmp_hi.16b, v_tmp.16b
+ eor v_d2_0.16b, v_d2_0.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft3_lo.16b}, v_data_lo.16b
+ tbl v_tmp_hi.16b, {v_gft3_hi.16b}, v_data_hi.16b
+ eor v_tmp_hi.16b, v_tmp_lo.16b, v_tmp_hi.16b
+ and v_tmp_hi.16b, v_tmp_hi.16b, v_tmp.16b
+ eor v_d3_0.16b, v_d3_0.16b, v_tmp_hi.16b
+
+ str q_d1_0, [x_dest1]
+ str q_d2_0, [x_dest2]
+ str q_d3_0, [x_dest3]
+
+ ldr q_d4_0, [x_dest4]
+ ldr q_d5_0, [x_dest5]
+ ldr q_gft5_lo, [x_tbl5]
+ ldr q_gft5_hi, [x_tbl5, #16]
+
+ tbl v_tmp_lo.16b, {v_gft4_lo.16b}, v_data_lo.16b
+ tbl v_tmp_hi.16b, {v_gft4_hi.16b}, v_data_hi.16b
+ eor v_tmp_hi.16b, v_tmp_lo.16b, v_tmp_hi.16b
+ and v_tmp_hi.16b, v_tmp_hi.16b, v_tmp.16b
+ eor v_d4_0.16b, v_d4_0.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft5_lo.16b}, v_data_lo.16b
+ tbl v_tmp_hi.16b, {v_gft5_hi.16b}, v_data_hi.16b
+ eor v_tmp_hi.16b, v_tmp_lo.16b, v_tmp_hi.16b
+ and v_tmp_hi.16b, v_tmp_hi.16b, v_tmp.16b
+ eor v_d5_0.16b, v_d5_0.16b, v_tmp_hi.16b
+
+ str q_d4_0, [x_dest4]
+ str q_d5_0, [x_dest5]
+
+.return_pass:
+ mov w_ret, #0
+ ret
+
+.return_fail:
+ mov w_ret, #1
+ ret
+
+ASM_DEF_RODATA
+.balign 8
+const_tbl:
+ .dword 0x0000000000000000, 0x0000000000000000
+ .dword 0xffffffffffffffff, 0xffffffffffffffff
diff --git a/contrib/libs/isa-l/erasure_code/aarch64/gf_5vect_mad_sve.S b/contrib/libs/isa-l/erasure_code/aarch64/gf_5vect_mad_sve.S
new file mode 100644
index 0000000000..ab374d365a
--- /dev/null
+++ b/contrib/libs/isa-l/erasure_code/aarch64/gf_5vect_mad_sve.S
@@ -0,0 +1,218 @@
+/**************************************************************
+ Copyright (c) 2021 Linaro Ltd.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name of Huawei Corporation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+**********************************************************************/
+.text
+.align 6
+.arch armv8-a+sve
+
+#include "../include/aarch64_label.h"
+
+.global cdecl(gf_5vect_mad_sve)
+#ifndef __APPLE__
+.type gf_5vect_mad_sve, %function
+#endif
+
+/* gf_5vect_mad_sve(int len, int vec, int vec_i, unsigned char *gftbls,
+ unsigned char *src, unsigned char **dest);
+ */
+/* arguments */
+x_len .req x0
+x_vec .req x1
+x_vec_i .req x2
+x_tbl .req x3
+x_src .req x4
+x_dest .req x5
+
+/* returns */
+w_ret .req w0
+
+/* local variables */
+x_pos .req x6
+x_dest2 .req x7
+x_dest3 .req x8
+x_dest4 .req x9
+x_dest5 .req x10
+x_dest1 .req x12
+
+/* vectors */
+z_mask0f .req z0
+
+z_src .req z1
+z_src_lo .req z2
+z_src_hi .req z_src
+
+z_dest1 .req z3
+
+z_tmp_lo .req z4
+z_tmp_hi .req z5
+
+z_gft1_lo .req z6
+z_gft1_hi .req z7
+q_gft1_lo .req q6
+q_gft1_hi .req q7
+
+/* bottom 64-bit of v8..v15 must be preserved if used */
+z_gft2_lo .req z17
+z_gft2_hi .req z18
+q_gft2_lo .req q17
+q_gft2_hi .req q18
+
+z_gft3_lo .req z19
+z_gft3_hi .req z20
+q_gft3_lo .req q19
+q_gft3_hi .req q20
+
+z_gft4_lo .req z21
+z_gft4_hi .req z22
+q_gft4_lo .req q21
+q_gft4_hi .req q22
+
+z_gft5_lo .req z23
+z_gft5_hi .req z24
+q_gft5_lo .req q23
+q_gft5_hi .req q24
+
+z_dest2 .req z27
+z_dest3 .req z28
+z_dest4 .req z29
+z_dest5 .req z30
+
+cdecl(gf_5vect_mad_sve):
+ /* less than 16 bytes, return_fail */
+ cmp x_len, #16
+ blt .return_fail
+
+ mov z_mask0f.b, #0x0f /* z_mask0f = 0x0F0F...0F */
+ /* load table 1 */
+ add x_tbl, x_tbl, x_vec_i, LSL #5 /* x_tbl += x_vec_i * 2^5 */
+
+ /* Load with NEON instruction ldp */
+ ldp q_gft1_lo, q_gft1_hi, [x_tbl]
+ /* load table 2 */
+ add x_tbl, x_tbl, x_vec, LSL #5 /* x_tbl += x_vec * 2^5 */
+ ldp q_gft2_lo, q_gft2_hi, [x_tbl]
+ /* load table 3 */
+ add x_tbl, x_tbl, x_vec, LSL #5 /* x_tbl += x_vec * 2^5 */
+ ldp q_gft3_lo, q_gft3_hi, [x_tbl]
+ /* load table 4 */
+ add x_tbl, x_tbl, x_vec, LSL #5 /* x_tbl += x_vec * 2^5 */
+ ldp q_gft4_lo, q_gft4_hi, [x_tbl]
+ /* load table 5 */
+ add x_tbl, x_tbl, x_vec, LSL #5 /* x_tbl += x_vec * 2^5 */
+ ldp q_gft5_lo, q_gft5_hi, [x_tbl]
+
+ ldr x_dest1, [x_dest, #8*0] /* pointer to dest1 */
+ ldr x_dest2, [x_dest, #8*1] /* pointer to dest2 */
+ ldr x_dest3, [x_dest, #8*2] /* pointer to dest3 */
+ ldr x_dest4, [x_dest, #8*3] /* pointer to dest4 */
+ ldr x_dest5, [x_dest, #8*4] /* pointer to dest5 */
+
+ mov x_pos, #0
+
+ /* vector length agnostic */
+.Lloopsve_vl:
+ whilelo p0.b, x_pos, x_len
+ b.none .return_pass
+
+ prfb pldl2strm, p0, [x_dest1, x_pos]
+ prfb pldl2strm, p0, [x_dest2, x_pos]
+
+ /* load src data, governed by p0 */
+ ld1b z_src.b, p0/z, [x_src, x_pos]
+
+ /* split 4-bit lo; 4-bit hi */
+ and z_src_lo.d, z_src.d, z_mask0f.d
+ lsr z_src_hi.b, z_src.b, #4
+
+ /* load dest data, governed by p0 */
+ ld1b z_dest1.b, p0/z, [x_dest1, x_pos]
+ ld1b z_dest2.b, p0/z, [x_dest2, x_pos]
+
+ prfb pldl2strm, p0, [x_dest3, x_pos]
+ prfb pldl2strm, p0, [x_dest4, x_pos]
+
+ /* dest1 */
+ /* table indexing, ie. gf(2^8) multiplication */
+ tbl z_tmp_lo.b, {z_gft1_lo.b}, z_src_lo.b
+ tbl z_tmp_hi.b, {z_gft1_hi.b}, z_src_hi.b
+ /* exclusive or, ie. gf(2^8) add */
+ eor z_dest1.d, z_tmp_lo.d, z_dest1.d
+ eor z_dest1.d, z_tmp_hi.d, z_dest1.d
+
+ ld1b z_dest3.b, p0/z, [x_dest3, x_pos]
+ ld1b z_dest4.b, p0/z, [x_dest4, x_pos]
+ prfb pldl2strm, p0, [x_dest5, x_pos]
+
+ /* dest2 */
+ tbl z_tmp_lo.b, {z_gft2_lo.b}, z_src_lo.b
+ tbl z_tmp_hi.b, {z_gft2_hi.b}, z_src_hi.b
+ eor z_dest2.d, z_tmp_lo.d, z_dest2.d
+ eor z_dest2.d, z_tmp_hi.d, z_dest2.d
+
+ ld1b z_dest5.b, p0/z, [x_dest5, x_pos]
+
+ /* store dest data, governed by p0 */
+ st1b z_dest1.b, p0, [x_dest1, x_pos]
+
+ /* dest3 */
+ tbl z_tmp_lo.b, {z_gft3_lo.b}, z_src_lo.b
+ tbl z_tmp_hi.b, {z_gft3_hi.b}, z_src_hi.b
+ eor z_dest3.d, z_tmp_lo.d, z_dest3.d
+ eor z_dest3.d, z_tmp_hi.d, z_dest3.d
+
+ /* dest4 */
+ tbl z_tmp_lo.b, {z_gft4_lo.b}, z_src_lo.b
+ tbl z_tmp_hi.b, {z_gft4_hi.b}, z_src_hi.b
+ eor z_dest4.d, z_tmp_lo.d, z_dest4.d
+ eor z_dest4.d, z_tmp_hi.d, z_dest4.d
+
+ /* store dest data, governed by p0 */
+ st1b z_dest2.b, p0, [x_dest2, x_pos]
+ st1b z_dest3.b, p0, [x_dest3, x_pos]
+
+ /* dest5 */
+ tbl z_tmp_lo.b, {z_gft5_lo.b}, z_src_lo.b
+ tbl z_tmp_hi.b, {z_gft5_hi.b}, z_src_hi.b
+ eor z_dest5.d, z_tmp_lo.d, z_dest5.d
+ eor z_dest5.d, z_tmp_hi.d, z_dest5.d
+
+ /* store dest data, governed by p0 */
+ st1b z_dest4.b, p0, [x_dest4, x_pos]
+ st1b z_dest5.b, p0, [x_dest5, x_pos]
+ /* increment one vector length */
+ incb x_pos
+
+ b .Lloopsve_vl
+
+.return_pass:
+ mov w_ret, #0
+ ret
+
+.return_fail:
+ mov w_ret, #1
+ ret
diff --git a/contrib/libs/isa-l/erasure_code/aarch64/gf_6vect_dot_prod_sve.S b/contrib/libs/isa-l/erasure_code/aarch64/gf_6vect_dot_prod_sve.S
new file mode 100644
index 0000000000..acc98953b3
--- /dev/null
+++ b/contrib/libs/isa-l/erasure_code/aarch64/gf_6vect_dot_prod_sve.S
@@ -0,0 +1,258 @@
+/*************************************************************
+ Copyright (c) 2021 Linaro Ltd.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name of Huawei Corporation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+**********************************************************************/
+.text
+.align 6
+.arch armv8-a+sve
+
+#include "../include/aarch64_label.h"
+
+.global cdecl(gf_6vect_dot_prod_sve)
+#ifndef __APPLE__
+.type gf_6vect_dot_prod_sve, %function
+#endif
+/* void gf_6vect_dot_prod_sve(int len, int vlen, unsigned char *gftbls,
+ unsigned char **src, unsigned char **dest);
+ */
+
+/* arguments */
+x_len .req x0 /* vector length */
+x_vec .req x1 /* number of source vectors (ie. data blocks) */
+x_tbl .req x2
+x_src .req x3
+x_dest .req x4
+
+/* returns */
+w_ret .req w0
+
+/* local variables */
+x_vec_i .req x5
+x_ptr .req x6
+x_pos .req x7
+
+x_tbl1 .req x8
+x_tbl2 .req x9
+x_tbl3 .req x10
+x_tbl4 .req x11
+x_tbl5 .req x12
+x_tbl6 .req x13
+x_dest1 .req x14
+x_dest2 .req x15
+x_dest6 .req x_dest /* reused */
+
+/* r16,r17,r18,r29,r30: special role registers, avoided */
+/* r19..r29 and SP must be preserved */
+x_dest3 .req x19
+x_dest4 .req x20
+x_dest5 .req x21
+
+/* vectors */
+z_mask0f .req z0
+
+z_src .req z1
+z_src_lo .req z2
+z_src_hi .req z_src
+
+z_dest1 .req z3
+
+z_gft1_lo .req z4
+z_gft1_hi .req z5
+q_gft1_lo .req q4
+q_gft1_hi .req q5
+
+/* bottom 64-bit of v8..v15 must be preserved if used */
+z_gft2_lo .req z17
+z_gft2_hi .req z18
+q_gft2_lo .req q17
+q_gft2_hi .req q18
+
+z_gft3_lo .req z19
+z_gft3_hi .req z20
+q_gft3_lo .req q19
+q_gft3_hi .req q20
+
+z_gft4_lo .req z21
+z_gft4_hi .req z22
+q_gft4_lo .req q21
+q_gft4_hi .req q22
+
+z_gft5_lo .req z23
+z_gft5_hi .req z24
+q_gft5_lo .req q23
+q_gft5_hi .req q24
+
+z_gft6_lo .req z25
+z_gft6_hi .req z26
+q_gft6_lo .req q25
+q_gft6_hi .req q26
+
+z_dest2 .req z27
+z_dest3 .req z28
+z_dest4 .req z29
+z_dest5 .req z30
+z_dest6 .req z31
+
+cdecl(gf_6vect_dot_prod_sve):
+ /* less than 16 bytes, return_fail */
+ cmp x_len, #16
+ blt .return_fail
+
+ /* save r19..r29 */
+ sub sp, sp, #32 /* alignment */
+ stp x19, x20, [sp]
+ str x21, [sp, #16]
+
+ mov z_mask0f.b, #0x0f /* z_mask0f = 0x0F0F...0F */
+ mov x_pos, #0
+ lsl x_vec, x_vec, #3
+ ldp x_dest1, x_dest2, [x_dest, #8*0]
+ ldp x_dest3, x_dest4, [x_dest, #8*2]
+ ldp x_dest5, x_dest6, [x_dest, #8*4] /* x_dest6 reuses x_dest */
+
+/* Loop 1: x_len, vector length */
+.Lloopsve_vl:
+ whilelo p0.b, x_pos, x_len
+ b.none .return_pass
+
+ mov x_vec_i, #0 /* clear x_vec_i */
+ ldr x_ptr, [x_src, x_vec_i] /* x_ptr: src base addr. */
+
+ mov z_dest1.b, #0 /* clear z_dest1 */
+ mov z_dest2.b, #0 /* clear z_dest2 */
+ mov z_dest3.b, #0 /* clear z_dest3 */
+ mov z_dest4.b, #0 /* clear z_dest4 */
+ mov z_dest5.b, #0 /* clear z_dest5 */
+ mov z_dest6.b, #0 /* clear z_dest6 */
+
+ /* gf_tbl base = (x_tbl + dest_idx * x_vec * 32) */
+ mov x_tbl1, x_tbl /* reset x_tbl1 */
+ add x_tbl2, x_tbl1, x_vec, LSL #2 /* reset x_tbl2 */
+ add x_tbl3, x_tbl2, x_vec, LSL #2 /* reset x_tbl3 */
+ add x_tbl4, x_tbl3, x_vec, LSL #2 /* reset x_tbl4 */
+ add x_tbl5, x_tbl4, x_vec, LSL #2 /* reset x_tbl5 */
+ add x_tbl6, x_tbl5, x_vec, LSL #2 /* reset x_tbl6 */
+
+/* Loop 2: x_vec, number of source vectors (ie. data blocks) */
+.Lloopsve_vl_vects:
+ /* load src data, governed by p0 */
+ ld1b z_src.b, p0/z, [x_ptr, x_pos] /* load from: src base + pos offset */
+ /* split 4-bit lo; 4-bit hi */
+ and z_src_lo.d, z_src.d, z_mask0f.d
+ lsr z_src_hi.b, z_src.b, #4
+
+
+ /* gf_tbl addr: (x_tbl + dest_idx * x_vec * 32) + src_vec_idx * 32 */
+ /* load gf_table's */
+ ldp q_gft1_lo, q_gft1_hi, [x_tbl1], #32 /* x_tbl1 is post-added by #32 for each src vect */
+ ldp q_gft2_lo, q_gft2_hi, [x_tbl2], #32
+
+ /* prefetch */
+ prfb pldl2keep, p0, [x_tbl1]
+ prfb pldl2keep, p0, [x_tbl2]
+
+ /* calc for next and prefetch */
+ add x_vec_i, x_vec_i, #8 /* move x_vec_i to next */
+ ldr x_ptr, [x_src, x_vec_i] /* x_ptr: src base addr. */
+
+ /* dest 1 */
+ /* table indexing, ie. gf(2^8) multiplication */
+ tbl z_gft1_lo.b, {z_gft1_lo.b}, z_src_lo.b
+ tbl z_gft1_hi.b, {z_gft1_hi.b}, z_src_hi.b
+ /* exclusive or, ie. gf(2^8) add */
+ eor z_dest1.d, z_gft1_lo.d, z_dest1.d
+ eor z_dest1.d, z_dest1.d, z_gft1_hi.d
+
+ ldp q_gft3_lo, q_gft3_hi, [x_tbl3], #32
+ ldp q_gft4_lo, q_gft4_hi, [x_tbl4], #32
+ prfb pldl2keep, p0, [x_tbl3]
+ prfb pldl2keep, p0, [x_tbl4]
+
+ /* dest 2 */
+ tbl z_gft2_lo.b, {z_gft2_lo.b}, z_src_lo.b
+ tbl z_gft2_hi.b, {z_gft2_hi.b}, z_src_hi.b
+ eor z_dest2.d, z_gft2_lo.d, z_dest2.d
+ eor z_dest2.d, z_dest2.d, z_gft2_hi.d
+
+ /* dest 3 */
+ tbl z_gft3_lo.b, {z_gft3_lo.b}, z_src_lo.b
+ tbl z_gft3_hi.b, {z_gft3_hi.b}, z_src_hi.b
+ eor z_dest3.d, z_gft3_lo.d, z_dest3.d
+ eor z_dest3.d, z_dest3.d, z_gft3_hi.d
+
+ ldp q_gft5_lo, q_gft5_hi, [x_tbl5], #32
+ ldp q_gft6_lo, q_gft6_hi, [x_tbl6], #32
+ prfb pldl2keep, p0, [x_tbl5]
+ prfb pldl2keep, p0, [x_tbl6]
+
+ /* dest 4 */
+ tbl z_gft4_lo.b, {z_gft4_lo.b}, z_src_lo.b
+ tbl z_gft4_hi.b, {z_gft4_hi.b}, z_src_hi.b
+ eor z_dest4.d, z_gft4_lo.d, z_dest4.d
+ eor z_dest4.d, z_dest4.d, z_gft4_hi.d
+
+ /* dest 5 */
+ tbl z_gft5_lo.b, {z_gft5_lo.b}, z_src_lo.b
+ tbl z_gft5_hi.b, {z_gft5_hi.b}, z_src_hi.b
+ eor z_dest5.d, z_gft5_lo.d, z_dest5.d
+ eor z_dest5.d, z_dest5.d, z_gft5_hi.d
+
+ /* dest 6 */
+ tbl z_gft6_lo.b, {z_gft6_lo.b}, z_src_lo.b
+ tbl z_gft6_hi.b, {z_gft6_hi.b}, z_src_hi.b
+ eor z_dest6.d, z_gft6_lo.d, z_dest6.d
+ eor z_dest6.d, z_dest6.d, z_gft6_hi.d
+
+ cmp x_vec_i, x_vec
+ blt .Lloopsve_vl_vects
+/* end of Loop 2 */
+
+ /* store dest data, governed by p0 */
+ st1b z_dest1.b, p0, [x_dest1, x_pos]
+ st1b z_dest2.b, p0, [x_dest2, x_pos]
+ st1b z_dest3.b, p0, [x_dest3, x_pos]
+ st1b z_dest4.b, p0, [x_dest4, x_pos]
+ st1b z_dest5.b, p0, [x_dest5, x_pos]
+ st1b z_dest6.b, p0, [x_dest6, x_pos]
+
+ /* increment one vector length */
+ incb x_pos
+ b .Lloopsve_vl
+/* end of Loop 1 */
+
+.return_pass:
+ /* restore r19..r29 */
+ ldr x21, [sp, #16]
+ ldp x19, x20, [sp]
+ add sp, sp, #32
+
+ mov w_ret, #0
+ ret
+
+.return_fail:
+ mov w_ret, #1
+ ret
diff --git a/contrib/libs/isa-l/erasure_code/aarch64/gf_6vect_mad_neon.S b/contrib/libs/isa-l/erasure_code/aarch64/gf_6vect_mad_neon.S
new file mode 100644
index 0000000000..3b1b1b4b21
--- /dev/null
+++ b/contrib/libs/isa-l/erasure_code/aarch64/gf_6vect_mad_neon.S
@@ -0,0 +1,618 @@
+/**************************************************************
+ Copyright (c) 2019 Huawei Technologies Co., Ltd.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name of Huawei Corporation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+**********************************************************************/
+
+#include "../include/aarch64_label.h"
+
+.text
+.global cdecl(gf_6vect_mad_neon)
+#ifndef __APPLE__
+.type gf_6vect_mad_neon, %function
+#endif
+
+/* arguments */
+x_len .req x0
+x_vec .req x1
+x_vec_i .req x2
+x_tbl .req x3
+x_src .req x4
+x_dest .req x5
+
+/* returns */
+w_ret .req w0
+
+/* local variables */
+x_src_end .req x6
+x_dest1 .req x7
+x_dest2 .req x8
+x_dest3 .req x9
+x_dest4 .req x10
+x_dest5 .req x11
+x_dest6 .req x_dest
+x_tmp .req x12
+x_tbl1 .req x13
+x_tbl2 .req x14
+x_tbl3 .req x15
+x_tbl4 .req x16
+x_tbl5 .req x17
+x_tbl6 .req x_tbl
+x_const .req x18
+
+/* vectors */
+v_mask0f .req v0
+v_tmp_lo .req v1
+v_tmp_hi .req v2
+v_tmp .req v3
+q_tmp .req q3
+
+v_gft1_lo .req v4
+v_gft1_hi .req v5
+v_gft2_lo .req v6
+v_gft2_hi .req v7
+v_gft3_lo .req v16
+v_gft3_hi .req v17
+q_gft1_lo .req q4
+q_gft1_hi .req q5
+q_gft2_lo .req q6
+q_gft2_hi .req q7
+q_gft3_lo .req q16
+q_gft3_hi .req q17
+
+v_gft4_lo .req v18
+v_gft4_hi .req v19
+q_gft4_lo .req q18
+q_gft4_hi .req q19
+v_gft5_lo .req v_gft2_lo
+v_gft5_hi .req v_gft2_hi
+q_gft5_lo .req q_gft2_lo
+q_gft5_hi .req q_gft2_hi
+v_gft6_lo .req v_gft3_lo
+v_gft6_hi .req v_gft3_hi
+q_gft6_lo .req q_gft3_lo
+q_gft6_hi .req q_gft3_hi
+
+v_data_0 .req v8
+v_data_1 .req v9
+v_data_2 .req v10
+v_data_3 .req v11
+q_data_0 .req q8
+q_data_1 .req q9
+q_data_2 .req q10
+q_data_3 .req q11
+
+v_data_0_lo .req v12
+v_data_1_lo .req v13
+v_data_2_lo .req v14
+v_data_3_lo .req v15
+v_data_0_hi .req v_data_0
+v_data_1_hi .req v_data_1
+v_data_2_hi .req v_data_2
+v_data_3_hi .req v_data_3
+
+v_d1_0 .req v20
+v_d1_1 .req v21
+v_d1_2 .req v22
+v_d1_3 .req v23
+v_d2_0 .req v24
+v_d2_1 .req v25
+v_d2_2 .req v26
+v_d2_3 .req v27
+v_d3_0 .req v28
+v_d3_1 .req v29
+v_d3_2 .req v30
+v_d3_3 .req v31
+q_d1_0 .req q20
+q_d1_1 .req q21
+q_d1_2 .req q22
+q_d1_3 .req q23
+q_d2_0 .req q24
+q_d2_1 .req q25
+q_d2_2 .req q26
+q_d2_3 .req q27
+q_d3_0 .req q28
+q_d3_1 .req q29
+q_d3_2 .req q30
+q_d3_3 .req q31
+
+v_d4_0 .req v_d1_0
+v_d4_1 .req v_d1_1
+v_d4_2 .req v_d1_2
+v_d4_3 .req v_d1_3
+q_d4_0 .req q_d1_0
+q_d4_1 .req q_d1_1
+q_d4_2 .req q_d1_2
+q_d4_3 .req q_d1_3
+v_d5_0 .req v_d2_0
+v_d5_1 .req v_d2_1
+v_d5_2 .req v_d2_2
+v_d5_3 .req v_d2_3
+q_d5_0 .req q_d2_0
+q_d5_1 .req q_d2_1
+q_d5_2 .req q_d2_2
+q_d5_3 .req q_d2_3
+v_d6_0 .req v_d3_0
+v_d6_1 .req v_d3_1
+v_d6_2 .req v_d3_2
+v_d6_3 .req v_d3_3
+q_d6_0 .req q_d3_0
+q_d6_1 .req q_d3_1
+q_d6_2 .req q_d3_2
+q_d6_3 .req q_d3_3
+
+v_data .req v21
+q_data .req q21
+v_data_lo .req v22
+v_data_hi .req v23
+
+cdecl(gf_6vect_mad_neon):
+ /* less than 16 bytes, return_fail */
+ cmp x_len, #16
+ blt .return_fail
+
+ movi v_mask0f.16b, #0x0f
+ lsl x_vec_i, x_vec_i, #5
+ lsl x_vec, x_vec, #5
+ add x_tbl1, x_tbl, x_vec_i
+ add x_tbl2, x_tbl1, x_vec
+ add x_tbl3, x_tbl2, x_vec
+ add x_tbl4, x_tbl3, x_vec
+ add x_tbl5, x_tbl4, x_vec
+ add x_tbl6, x_tbl5, x_vec
+ add x_src_end, x_src, x_len
+ ldr x_dest1, [x_dest, #8*0]
+ ldr x_dest2, [x_dest, #8*1]
+ ldr x_dest3, [x_dest, #8*2]
+ ldr x_dest4, [x_dest, #8*3]
+ ldr x_dest5, [x_dest, #8*4]
+ ldr x_dest6, [x_dest, #8*5]
+ ldr q_gft1_lo, [x_tbl1]
+ ldr q_gft1_hi, [x_tbl1, #16]
+ ldr q_gft4_lo, [x_tbl4]
+ ldr q_gft4_hi, [x_tbl4, #16]
+
+.Lloop64_init:
+ /* less than 64 bytes, goto Lloop16_init */
+ cmp x_len, #64
+ blt .Lloop16_init
+
+ /* save d8 ~ d15 to stack */
+ sub sp, sp, #64
+ stp d8, d9, [sp]
+ stp d10, d11, [sp, #16]
+ stp d12, d13, [sp, #32]
+ stp d14, d15, [sp, #48]
+
+ sub x_src_end, x_src_end, #64
+
+.Lloop64:
+ ldr q_data_0, [x_src, #16*0]
+ ldr q_data_1, [x_src, #16*1]
+ ldr q_data_2, [x_src, #16*2]
+ ldr q_data_3, [x_src, #16*3]
+ add x_src, x_src, #64
+
+ ldr q_d1_0, [x_dest1, #16*0]
+ ldr q_d1_1, [x_dest1, #16*1]
+ ldr q_d1_2, [x_dest1, #16*2]
+ ldr q_d1_3, [x_dest1, #16*3]
+
+ ldr q_d2_0, [x_dest2, #16*0]
+ ldr q_d2_1, [x_dest2, #16*1]
+ ldr q_d2_2, [x_dest2, #16*2]
+ ldr q_d2_3, [x_dest2, #16*3]
+
+ ldr q_d3_0, [x_dest3, #16*0]
+ ldr q_d3_1, [x_dest3, #16*1]
+ ldr q_d3_2, [x_dest3, #16*2]
+ ldr q_d3_3, [x_dest3, #16*3]
+
+ ldr q_gft2_lo, [x_tbl2]
+ ldr q_gft2_hi, [x_tbl2, #16]
+ ldr q_gft3_lo, [x_tbl3]
+ ldr q_gft3_hi, [x_tbl3, #16]
+
+ and v_data_0_lo.16b, v_data_0.16b, v_mask0f.16b
+ and v_data_1_lo.16b, v_data_1.16b, v_mask0f.16b
+ and v_data_2_lo.16b, v_data_2.16b, v_mask0f.16b
+ and v_data_3_lo.16b, v_data_3.16b, v_mask0f.16b
+
+ ushr v_data_0_hi.16b, v_data_0.16b, #4
+ ushr v_data_1_hi.16b, v_data_1.16b, #4
+ ushr v_data_2_hi.16b, v_data_2.16b, #4
+ ushr v_data_3_hi.16b, v_data_3.16b, #4
+
+ /* dest1 */
+ tbl v_tmp_lo.16b, {v_gft1_lo.16b}, v_data_0_lo.16b
+ tbl v_tmp_hi.16b, {v_gft1_hi.16b}, v_data_0_hi.16b
+ eor v_d1_0.16b, v_tmp_lo.16b, v_d1_0.16b
+ eor v_d1_0.16b, v_d1_0.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft1_lo.16b}, v_data_1_lo.16b
+ tbl v_tmp_hi.16b, {v_gft1_hi.16b}, v_data_1_hi.16b
+ eor v_d1_1.16b, v_tmp_lo.16b, v_d1_1.16b
+ eor v_d1_1.16b, v_d1_1.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft1_lo.16b}, v_data_2_lo.16b
+ tbl v_tmp_hi.16b, {v_gft1_hi.16b}, v_data_2_hi.16b
+ eor v_d1_2.16b, v_tmp_lo.16b, v_d1_2.16b
+ eor v_d1_2.16b, v_d1_2.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft1_lo.16b}, v_data_3_lo.16b
+ tbl v_tmp_hi.16b, {v_gft1_hi.16b}, v_data_3_hi.16b
+ eor v_d1_3.16b, v_tmp_lo.16b, v_d1_3.16b
+ eor v_d1_3.16b, v_d1_3.16b, v_tmp_hi.16b
+
+ /* dest2 */
+ tbl v_tmp_lo.16b, {v_gft2_lo.16b}, v_data_0_lo.16b
+ tbl v_tmp_hi.16b, {v_gft2_hi.16b}, v_data_0_hi.16b
+ eor v_d2_0.16b, v_tmp_lo.16b, v_d2_0.16b
+ eor v_d2_0.16b, v_d2_0.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft2_lo.16b}, v_data_1_lo.16b
+ tbl v_tmp_hi.16b, {v_gft2_hi.16b}, v_data_1_hi.16b
+ eor v_d2_1.16b, v_tmp_lo.16b, v_d2_1.16b
+ eor v_d2_1.16b, v_d2_1.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft2_lo.16b}, v_data_2_lo.16b
+ tbl v_tmp_hi.16b, {v_gft2_hi.16b}, v_data_2_hi.16b
+ eor v_d2_2.16b, v_tmp_lo.16b, v_d2_2.16b
+ eor v_d2_2.16b, v_d2_2.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft2_lo.16b}, v_data_3_lo.16b
+ tbl v_tmp_hi.16b, {v_gft2_hi.16b}, v_data_3_hi.16b
+ eor v_d2_3.16b, v_tmp_lo.16b, v_d2_3.16b
+ eor v_d2_3.16b, v_d2_3.16b, v_tmp_hi.16b
+
+ /* dest3 */
+ tbl v_tmp_lo.16b, {v_gft3_lo.16b}, v_data_0_lo.16b
+ tbl v_tmp_hi.16b, {v_gft3_hi.16b}, v_data_0_hi.16b
+ eor v_d3_0.16b, v_tmp_lo.16b, v_d3_0.16b
+ eor v_d3_0.16b, v_d3_0.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft3_lo.16b}, v_data_1_lo.16b
+ tbl v_tmp_hi.16b, {v_gft3_hi.16b}, v_data_1_hi.16b
+ eor v_d3_1.16b, v_tmp_lo.16b, v_d3_1.16b
+ eor v_d3_1.16b, v_d3_1.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft3_lo.16b}, v_data_2_lo.16b
+ tbl v_tmp_hi.16b, {v_gft3_hi.16b}, v_data_2_hi.16b
+ eor v_d3_2.16b, v_tmp_lo.16b, v_d3_2.16b
+ eor v_d3_2.16b, v_d3_2.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft3_lo.16b}, v_data_3_lo.16b
+ tbl v_tmp_hi.16b, {v_gft3_hi.16b}, v_data_3_hi.16b
+ eor v_d3_3.16b, v_tmp_lo.16b, v_d3_3.16b
+ eor v_d3_3.16b, v_d3_3.16b, v_tmp_hi.16b
+
+ str q_d1_0, [x_dest1, #16*0]
+ str q_d1_1, [x_dest1, #16*1]
+ str q_d1_2, [x_dest1, #16*2]
+ str q_d1_3, [x_dest1, #16*3]
+ add x_dest1, x_dest1, #64
+
+ str q_d2_0, [x_dest2, #16*0]
+ str q_d2_1, [x_dest2, #16*1]
+ str q_d2_2, [x_dest2, #16*2]
+ str q_d2_3, [x_dest2, #16*3]
+ add x_dest2, x_dest2, #64
+
+ str q_d3_0, [x_dest3, #16*0]
+ str q_d3_1, [x_dest3, #16*1]
+ str q_d3_2, [x_dest3, #16*2]
+ str q_d3_3, [x_dest3, #16*3]
+ add x_dest3, x_dest3, #64
+
+ ldr q_d4_0, [x_dest4, #16*0]
+ ldr q_d4_1, [x_dest4, #16*1]
+ ldr q_d4_2, [x_dest4, #16*2]
+ ldr q_d4_3, [x_dest4, #16*3]
+
+ ldr q_d5_0, [x_dest5, #16*0]
+ ldr q_d5_1, [x_dest5, #16*1]
+ ldr q_d5_2, [x_dest5, #16*2]
+ ldr q_d5_3, [x_dest5, #16*3]
+
+ ldr q_d6_0, [x_dest6, #16*0]
+ ldr q_d6_1, [x_dest6, #16*1]
+ ldr q_d6_2, [x_dest6, #16*2]
+ ldr q_d6_3, [x_dest6, #16*3]
+
+ ldr q_gft5_lo, [x_tbl5]
+ ldr q_gft5_hi, [x_tbl5, #16]
+ ldr q_gft6_lo, [x_tbl6]
+ ldr q_gft6_hi, [x_tbl6, #16]
+
+ /* dest4 */
+ tbl v_tmp_lo.16b, {v_gft4_lo.16b}, v_data_0_lo.16b
+ tbl v_tmp_hi.16b, {v_gft4_hi.16b}, v_data_0_hi.16b
+ eor v_d4_0.16b, v_tmp_lo.16b, v_d4_0.16b
+ eor v_d4_0.16b, v_d4_0.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft4_lo.16b}, v_data_1_lo.16b
+ tbl v_tmp_hi.16b, {v_gft4_hi.16b}, v_data_1_hi.16b
+ eor v_d4_1.16b, v_tmp_lo.16b, v_d4_1.16b
+ eor v_d4_1.16b, v_d4_1.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft4_lo.16b}, v_data_2_lo.16b
+ tbl v_tmp_hi.16b, {v_gft4_hi.16b}, v_data_2_hi.16b
+ eor v_d4_2.16b, v_tmp_lo.16b, v_d4_2.16b
+ eor v_d4_2.16b, v_d4_2.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft4_lo.16b}, v_data_3_lo.16b
+ tbl v_tmp_hi.16b, {v_gft4_hi.16b}, v_data_3_hi.16b
+ eor v_d4_3.16b, v_tmp_lo.16b, v_d4_3.16b
+ eor v_d4_3.16b, v_d4_3.16b, v_tmp_hi.16b
+
+ /* dest5 */
+ tbl v_tmp_lo.16b, {v_gft5_lo.16b}, v_data_0_lo.16b
+ tbl v_tmp_hi.16b, {v_gft5_hi.16b}, v_data_0_hi.16b
+ eor v_d5_0.16b, v_tmp_lo.16b, v_d5_0.16b
+ eor v_d5_0.16b, v_d5_0.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft5_lo.16b}, v_data_1_lo.16b
+ tbl v_tmp_hi.16b, {v_gft5_hi.16b}, v_data_1_hi.16b
+ eor v_d5_1.16b, v_tmp_lo.16b, v_d5_1.16b
+ eor v_d5_1.16b, v_d5_1.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft5_lo.16b}, v_data_2_lo.16b
+ tbl v_tmp_hi.16b, {v_gft5_hi.16b}, v_data_2_hi.16b
+ eor v_d5_2.16b, v_tmp_lo.16b, v_d5_2.16b
+ eor v_d5_2.16b, v_d5_2.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft5_lo.16b}, v_data_3_lo.16b
+ tbl v_tmp_hi.16b, {v_gft5_hi.16b}, v_data_3_hi.16b
+ eor v_d5_3.16b, v_tmp_lo.16b, v_d5_3.16b
+ eor v_d5_3.16b, v_d5_3.16b, v_tmp_hi.16b
+
+ /* dest6 */
+ tbl v_tmp_lo.16b, {v_gft6_lo.16b}, v_data_0_lo.16b
+ tbl v_tmp_hi.16b, {v_gft6_hi.16b}, v_data_0_hi.16b
+ eor v_d6_0.16b, v_tmp_lo.16b, v_d6_0.16b
+ eor v_d6_0.16b, v_d6_0.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft6_lo.16b}, v_data_1_lo.16b
+ tbl v_tmp_hi.16b, {v_gft6_hi.16b}, v_data_1_hi.16b
+ eor v_d6_1.16b, v_tmp_lo.16b, v_d6_1.16b
+ eor v_d6_1.16b, v_d6_1.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft6_lo.16b}, v_data_2_lo.16b
+ tbl v_tmp_hi.16b, {v_gft6_hi.16b}, v_data_2_hi.16b
+ eor v_d6_2.16b, v_tmp_lo.16b, v_d6_2.16b
+ eor v_d6_2.16b, v_d6_2.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft6_lo.16b}, v_data_3_lo.16b
+ tbl v_tmp_hi.16b, {v_gft6_hi.16b}, v_data_3_hi.16b
+ eor v_d6_3.16b, v_tmp_lo.16b, v_d6_3.16b
+ eor v_d6_3.16b, v_d6_3.16b, v_tmp_hi.16b
+
+ str q_d4_0, [x_dest4, #16*0]
+ str q_d4_1, [x_dest4, #16*1]
+ str q_d4_2, [x_dest4, #16*2]
+ str q_d4_3, [x_dest4, #16*3]
+ add x_dest4, x_dest4, #64
+
+ str q_d5_0, [x_dest5, #16*0]
+ str q_d5_1, [x_dest5, #16*1]
+ str q_d5_2, [x_dest5, #16*2]
+ str q_d5_3, [x_dest5, #16*3]
+ add x_dest5, x_dest5, #64
+
+ str q_d6_0, [x_dest6, #16*0]
+ str q_d6_1, [x_dest6, #16*1]
+ str q_d6_2, [x_dest6, #16*2]
+ str q_d6_3, [x_dest6, #16*3]
+ add x_dest6, x_dest6, #64
+
+ cmp x_src, x_src_end
+ bls .Lloop64
+
+.Lloop64_end:
+ /* restore d8 ~ d15 */
+ ldp d8, d9, [sp]
+ ldp d10, d11, [sp, #16]
+ ldp d12, d13, [sp, #32]
+ ldp d14, d15, [sp, #48]
+ add sp, sp, #64
+ add x_src_end, x_src_end, #64
+
+.Lloop16_init:
+ sub x_src_end, x_src_end, #16
+ cmp x_src, x_src_end
+ bhi .lessthan16_init
+
+.Lloop16:
+ ldr q_data, [x_src]
+
+ ldr q_d1_0, [x_dest1]
+ ldr q_d2_0, [x_dest2]
+ ldr q_d3_0, [x_dest3]
+ ldr q_gft2_lo, [x_tbl2]
+ ldr q_gft2_hi, [x_tbl2, #16]
+ ldr q_gft3_lo, [x_tbl3]
+ ldr q_gft3_hi, [x_tbl3, #16]
+
+ and v_data_lo.16b, v_data.16b, v_mask0f.16b
+ ushr v_data_hi.16b, v_data.16b, #4
+
+ tbl v_tmp_lo.16b, {v_gft1_lo.16b}, v_data_lo.16b
+ tbl v_tmp_hi.16b, {v_gft1_hi.16b}, v_data_hi.16b
+ eor v_d1_0.16b, v_tmp_lo.16b, v_d1_0.16b
+ eor v_d1_0.16b, v_d1_0.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft2_lo.16b}, v_data_lo.16b
+ tbl v_tmp_hi.16b, {v_gft2_hi.16b}, v_data_hi.16b
+ eor v_d2_0.16b, v_tmp_lo.16b, v_d2_0.16b
+ eor v_d2_0.16b, v_d2_0.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft3_lo.16b}, v_data_lo.16b
+ tbl v_tmp_hi.16b, {v_gft3_hi.16b}, v_data_hi.16b
+ eor v_d3_0.16b, v_tmp_lo.16b, v_d3_0.16b
+ eor v_d3_0.16b, v_d3_0.16b, v_tmp_hi.16b
+
+ str q_d1_0, [x_dest1]
+ str q_d2_0, [x_dest2]
+ str q_d3_0, [x_dest3]
+
+ ldr q_d4_0, [x_dest4]
+ ldr q_d5_0, [x_dest5]
+ ldr q_d6_0, [x_dest6]
+ ldr q_gft5_lo, [x_tbl5]
+ ldr q_gft5_hi, [x_tbl5, #16]
+ ldr q_gft6_lo, [x_tbl6]
+ ldr q_gft6_hi, [x_tbl6, #16]
+
+ tbl v_tmp_lo.16b, {v_gft4_lo.16b}, v_data_lo.16b
+ tbl v_tmp_hi.16b, {v_gft4_hi.16b}, v_data_hi.16b
+ eor v_d4_0.16b, v_tmp_lo.16b, v_d4_0.16b
+ eor v_d4_0.16b, v_d4_0.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft5_lo.16b}, v_data_lo.16b
+ tbl v_tmp_hi.16b, {v_gft5_hi.16b}, v_data_hi.16b
+ eor v_d5_0.16b, v_tmp_lo.16b, v_d5_0.16b
+ eor v_d5_0.16b, v_d5_0.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft6_lo.16b}, v_data_lo.16b
+ tbl v_tmp_hi.16b, {v_gft6_hi.16b}, v_data_hi.16b
+ eor v_d6_0.16b, v_tmp_lo.16b, v_d6_0.16b
+ eor v_d6_0.16b, v_d6_0.16b, v_tmp_hi.16b
+
+ str q_d4_0, [x_dest4]
+ str q_d5_0, [x_dest5]
+ str q_d6_0, [x_dest6]
+
+ add x_src, x_src, #16
+ add x_dest1, x_dest1, #16
+ add x_dest2, x_dest2, #16
+ add x_dest3, x_dest3, #16
+ add x_dest4, x_dest4, #16
+ add x_dest5, x_dest5, #16
+ add x_dest6, x_dest6, #16
+ cmp x_src, x_src_end
+ bls .Lloop16
+
+.lessthan16_init:
+ sub x_tmp, x_src, x_src_end
+ cmp x_tmp, #16
+ beq .return_pass
+
+.lessthan16:
+ mov x_src, x_src_end
+ sub x_dest1, x_dest1, x_tmp
+ sub x_dest2, x_dest2, x_tmp
+ sub x_dest3, x_dest3, x_tmp
+ sub x_dest4, x_dest4, x_tmp
+ sub x_dest5, x_dest5, x_tmp
+ sub x_dest6, x_dest6, x_tmp
+
+#ifndef __APPLE__
+ adrp x_const, const_tbl
+ add x_const, x_const, :lo12:const_tbl
+#else
+ adrp x_const, const_tbl@PAGE
+ add x_const, x_const, const_tbl@PAGEOFF
+#endif
+ sub x_const, x_const, x_tmp
+ ldr q_tmp, [x_const, #16]
+
+ ldr q_data, [x_src]
+ ldr q_d1_0, [x_dest1]
+ ldr q_d2_0, [x_dest2]
+ ldr q_d3_0, [x_dest3]
+ ldr q_gft2_lo, [x_tbl2]
+ ldr q_gft2_hi, [x_tbl2, #16]
+ ldr q_gft3_lo, [x_tbl3]
+ ldr q_gft3_hi, [x_tbl3, #16]
+
+ and v_data_lo.16b, v_data.16b, v_mask0f.16b
+ ushr v_data_hi.16b, v_data.16b, #4
+
+ tbl v_tmp_lo.16b, {v_gft1_lo.16b}, v_data_lo.16b
+ tbl v_tmp_hi.16b, {v_gft1_hi.16b}, v_data_hi.16b
+ eor v_tmp_hi.16b, v_tmp_lo.16b, v_tmp_hi.16b
+ and v_tmp_hi.16b, v_tmp_hi.16b, v_tmp.16b
+ eor v_d1_0.16b, v_d1_0.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft2_lo.16b}, v_data_lo.16b
+ tbl v_tmp_hi.16b, {v_gft2_hi.16b}, v_data_hi.16b
+ eor v_tmp_hi.16b, v_tmp_lo.16b, v_tmp_hi.16b
+ and v_tmp_hi.16b, v_tmp_hi.16b, v_tmp.16b
+ eor v_d2_0.16b, v_d2_0.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft3_lo.16b}, v_data_lo.16b
+ tbl v_tmp_hi.16b, {v_gft3_hi.16b}, v_data_hi.16b
+ eor v_tmp_hi.16b, v_tmp_lo.16b, v_tmp_hi.16b
+ and v_tmp_hi.16b, v_tmp_hi.16b, v_tmp.16b
+ eor v_d3_0.16b, v_d3_0.16b, v_tmp_hi.16b
+
+ str q_d1_0, [x_dest1]
+ str q_d2_0, [x_dest2]
+ str q_d3_0, [x_dest3]
+
+ ldr q_d4_0, [x_dest4]
+ ldr q_d5_0, [x_dest5]
+ ldr q_d6_0, [x_dest6]
+ ldr q_gft5_lo, [x_tbl5]
+ ldr q_gft5_hi, [x_tbl5, #16]
+ ldr q_gft6_lo, [x_tbl6]
+ ldr q_gft6_hi, [x_tbl6, #16]
+
+ tbl v_tmp_lo.16b, {v_gft4_lo.16b}, v_data_lo.16b
+ tbl v_tmp_hi.16b, {v_gft4_hi.16b}, v_data_hi.16b
+ eor v_tmp_hi.16b, v_tmp_lo.16b, v_tmp_hi.16b
+ and v_tmp_hi.16b, v_tmp_hi.16b, v_tmp.16b
+ eor v_d4_0.16b, v_d4_0.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft5_lo.16b}, v_data_lo.16b
+ tbl v_tmp_hi.16b, {v_gft5_hi.16b}, v_data_hi.16b
+ eor v_tmp_hi.16b, v_tmp_lo.16b, v_tmp_hi.16b
+ and v_tmp_hi.16b, v_tmp_hi.16b, v_tmp.16b
+ eor v_d5_0.16b, v_d5_0.16b, v_tmp_hi.16b
+
+ tbl v_tmp_lo.16b, {v_gft6_lo.16b}, v_data_lo.16b
+ tbl v_tmp_hi.16b, {v_gft6_hi.16b}, v_data_hi.16b
+ eor v_tmp_hi.16b, v_tmp_lo.16b, v_tmp_hi.16b
+ and v_tmp_hi.16b, v_tmp_hi.16b, v_tmp.16b
+ eor v_d6_0.16b, v_d6_0.16b, v_tmp_hi.16b
+
+ str q_d4_0, [x_dest4]
+ str q_d5_0, [x_dest5]
+ str q_d6_0, [x_dest6]
+
+.return_pass:
+ mov w_ret, #0
+ ret
+
+.return_fail:
+ mov w_ret, #1
+ ret
+
+ASM_DEF_RODATA
+.balign 8
+const_tbl:
+ .dword 0x0000000000000000, 0x0000000000000000
+ .dword 0xffffffffffffffff, 0xffffffffffffffff
diff --git a/contrib/libs/isa-l/erasure_code/aarch64/gf_6vect_mad_sve.S b/contrib/libs/isa-l/erasure_code/aarch64/gf_6vect_mad_sve.S
new file mode 100644
index 0000000000..c4f372cd73
--- /dev/null
+++ b/contrib/libs/isa-l/erasure_code/aarch64/gf_6vect_mad_sve.S
@@ -0,0 +1,237 @@
+/**************************************************************
+ Copyright (c) 2021 Linaro Ltd.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name of Huawei Corporation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+**********************************************************************/
+.text
+.align 6
+.arch armv8-a+sve
+
+#include "../include/aarch64_label.h"
+
+.global cdecl(gf_6vect_mad_sve)
+#ifndef __APPLE__
+.type gf_6vect_mad_sve, %function
+#endif
+
+/* gf_6vect_mad_sve(int len, int vec, int vec_i, unsigned char *gftbls,
+ unsigned char *src, unsigned char **dest);
+ */
+/* arguments */
+x_len .req x0
+x_vec .req x1
+x_vec_i .req x2
+x_tbl .req x3
+x_src .req x4
+x_dest .req x5
+
+/* returns */
+w_ret .req w0
+
+/* local variables */
+x_pos .req x6
+x_dest2 .req x7
+x_dest3 .req x8
+x_dest4 .req x9
+x_dest5 .req x10
+x_dest6 .req x11
+x_dest1 .req x12
+
+/* vectors */
+z_mask0f .req z0
+
+z_src .req z1
+z_src_lo .req z2
+z_src_hi .req z_src
+
+z_dest1 .req z3
+
+z_tmp_lo .req z4
+z_tmp_hi .req z5
+
+z_gft1_lo .req z6
+z_gft1_hi .req z7
+q_gft1_lo .req q6
+q_gft1_hi .req q7
+
+/* bottom 64-bit of v8..v15 must be preserved if used */
+z_gft2_lo .req z17
+z_gft2_hi .req z18
+q_gft2_lo .req q17
+q_gft2_hi .req q18
+
+z_gft3_lo .req z19
+z_gft3_hi .req z20
+q_gft3_lo .req q19
+q_gft3_hi .req q20
+
+z_gft4_lo .req z21
+z_gft4_hi .req z22
+q_gft4_lo .req q21
+q_gft4_hi .req q22
+
+z_gft5_lo .req z23
+z_gft5_hi .req z24
+q_gft5_lo .req q23
+q_gft5_hi .req q24
+
+z_gft6_lo .req z25
+z_gft6_hi .req z26
+q_gft6_lo .req q25
+q_gft6_hi .req q26
+
+z_dest2 .req z27
+z_dest3 .req z28
+z_dest4 .req z29
+z_dest5 .req z30
+z_dest6 .req z31
+
+cdecl(gf_6vect_mad_sve):
+ /* less than 16 bytes, return_fail */
+ cmp x_len, #16
+ blt .return_fail
+
+ mov z_mask0f.b, #0x0f /* z_mask0f = 0x0F0F...0F */
+ /* load table 1 */
+ add x_tbl, x_tbl, x_vec_i, LSL #5 /* x_tbl += x_vec_i * 2^5 */
+
+ /* Load with NEON instruction ldp */
+ ldp q_gft1_lo, q_gft1_hi, [x_tbl]
+ /* load table 2 */
+ add x_tbl, x_tbl, x_vec, LSL #5 /* x_tbl += x_vec * 2^5 */
+ ldp q_gft2_lo, q_gft2_hi, [x_tbl]
+ /* load table 3 */
+ add x_tbl, x_tbl, x_vec, LSL #5 /* x_tbl += x_vec * 2^5 */
+ ldp q_gft3_lo, q_gft3_hi, [x_tbl]
+ /* load table 4 */
+ add x_tbl, x_tbl, x_vec, LSL #5 /* x_tbl += x_vec * 2^5 */
+ ldp q_gft4_lo, q_gft4_hi, [x_tbl]
+ /* load table 5 */
+ add x_tbl, x_tbl, x_vec, LSL #5 /* x_tbl += x_vec * 2^5 */
+ ldp q_gft5_lo, q_gft5_hi, [x_tbl]
+ /* load table 6 */
+ add x_tbl, x_tbl, x_vec, LSL #5 /* x_tbl += x_vec * 2^5 */
+ ldp q_gft6_lo, q_gft6_hi, [x_tbl]
+
+ ldr x_dest1, [x_dest, #8*0] /* pointer to dest1 */
+ ldr x_dest2, [x_dest, #8*1] /* pointer to dest2 */
+ ldr x_dest3, [x_dest, #8*2] /* pointer to dest3 */
+ ldr x_dest4, [x_dest, #8*3] /* pointer to dest4 */
+ ldr x_dest5, [x_dest, #8*4] /* pointer to dest5 */
+ ldr x_dest6, [x_dest, #8*5] /* pointer to dest6 */
+
+ mov x_pos, #0
+
+ /* vector length agnostic */
+.Lloopsve_vl:
+ whilelo p0.b, x_pos, x_len
+ b.none .return_pass
+
+ prfb pldl2strm, p0, [x_dest1, x_pos]
+ prfb pldl2strm, p0, [x_dest2, x_pos]
+
+ /* load src data, governed by p0 */
+ ld1b z_src.b, p0/z, [x_src, x_pos]
+
+ /* split 4-bit lo; 4-bit hi */
+ and z_src_lo.d, z_src.d, z_mask0f.d
+ lsr z_src_hi.b, z_src.b, #4
+
+ /* load dest data, governed by p0 */
+ ld1b z_dest1.b, p0/z, [x_dest1, x_pos]
+ ld1b z_dest2.b, p0/z, [x_dest2, x_pos]
+
+ prfb pldl2strm, p0, [x_dest3, x_pos]
+ prfb pldl2strm, p0, [x_dest4, x_pos]
+
+ /* dest1 */
+ /* table indexing, ie. gf(2^8) multiplication */
+ tbl z_tmp_lo.b, {z_gft1_lo.b}, z_src_lo.b
+ tbl z_tmp_hi.b, {z_gft1_hi.b}, z_src_hi.b
+ /* exclusive or, ie. gf(2^8) add */
+ eor z_dest1.d, z_tmp_lo.d, z_dest1.d
+ eor z_dest1.d, z_tmp_hi.d, z_dest1.d
+
+ ld1b z_dest3.b, p0/z, [x_dest3, x_pos]
+ ld1b z_dest4.b, p0/z, [x_dest4, x_pos]
+
+ prfb pldl2strm, p0, [x_dest5, x_pos]
+ prfb pldl2strm, p0, [x_dest6, x_pos]
+
+ /* dest2 */
+ tbl z_tmp_lo.b, {z_gft2_lo.b}, z_src_lo.b
+ tbl z_tmp_hi.b, {z_gft2_hi.b}, z_src_hi.b
+ eor z_dest2.d, z_tmp_lo.d, z_dest2.d
+ eor z_dest2.d, z_tmp_hi.d, z_dest2.d
+
+ ld1b z_dest5.b, p0/z, [x_dest5, x_pos]
+ ld1b z_dest6.b, p0/z, [x_dest6, x_pos]
+
+ /* dest3 */
+ tbl z_tmp_lo.b, {z_gft3_lo.b}, z_src_lo.b
+ tbl z_tmp_hi.b, {z_gft3_hi.b}, z_src_hi.b
+ eor z_dest3.d, z_tmp_lo.d, z_dest3.d
+ eor z_dest3.d, z_tmp_hi.d, z_dest3.d
+
+ /* store dest data, governed by p0 */
+ st1b z_dest1.b, p0, [x_dest1, x_pos]
+ st1b z_dest2.b, p0, [x_dest2, x_pos]
+
+ /* dest4 */
+ tbl z_tmp_lo.b, {z_gft4_lo.b}, z_src_lo.b
+ tbl z_tmp_hi.b, {z_gft4_hi.b}, z_src_hi.b
+ eor z_dest4.d, z_tmp_lo.d, z_dest4.d
+ eor z_dest4.d, z_tmp_hi.d, z_dest4.d
+
+ /* dest5 */
+ tbl z_tmp_lo.b, {z_gft5_lo.b}, z_src_lo.b
+ tbl z_tmp_hi.b, {z_gft5_hi.b}, z_src_hi.b
+ eor z_dest5.d, z_tmp_lo.d, z_dest5.d
+ eor z_dest5.d, z_tmp_hi.d, z_dest5.d
+
+ st1b z_dest3.b, p0, [x_dest3, x_pos]
+ st1b z_dest4.b, p0, [x_dest4, x_pos]
+
+ /* dest6 */
+ tbl z_tmp_lo.b, {z_gft6_lo.b}, z_src_lo.b
+ tbl z_tmp_hi.b, {z_gft6_hi.b}, z_src_hi.b
+ eor z_dest6.d, z_tmp_lo.d, z_dest6.d
+ eor z_dest6.d, z_tmp_hi.d, z_dest6.d
+
+ st1b z_dest5.b, p0, [x_dest5, x_pos]
+ st1b z_dest6.b, p0, [x_dest6, x_pos]
+ /* increment one vector length */
+ incb x_pos
+
+ b .Lloopsve_vl
+
+.return_pass:
+ mov w_ret, #0
+ ret
+
+.return_fail:
+ mov w_ret, #1
+ ret
diff --git a/contrib/libs/isa-l/erasure_code/aarch64/gf_7vect_dot_prod_sve.S b/contrib/libs/isa-l/erasure_code/aarch64/gf_7vect_dot_prod_sve.S
new file mode 100644
index 0000000000..0f74873de0
--- /dev/null
+++ b/contrib/libs/isa-l/erasure_code/aarch64/gf_7vect_dot_prod_sve.S
@@ -0,0 +1,281 @@
+/*************************************************************
+ Copyright (c) 2021 Linaro Ltd.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name of Huawei Corporation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+**********************************************************************/
+.text
+.align 6
+.arch armv8-a+sve
+
+#include "../include/aarch64_label.h"
+
+.global cdecl(gf_7vect_dot_prod_sve)
+#ifndef __APPLE__
+.type gf_7vect_dot_prod_sve, %function
+#endif
+/* void gf_7vect_dot_prod_sve(int len, int vlen, unsigned char *gftbls,
+ unsigned char **src, unsigned char **dest);
+ */
+
+/* arguments */
+x_len .req x0 /* vector length */
+x_vec .req x1 /* number of source vectors (ie. data blocks) */
+x_tbl .req x2
+x_src .req x3
+x_dest .req x4
+
+/* returns */
+w_ret .req w0
+
+/* local variables */
+x_vec_i .req x5
+x_ptr .req x6
+x_pos .req x7
+
+x_tbl1 .req x8
+x_tbl2 .req x9
+x_tbl3 .req x10
+x_tbl4 .req x11
+x_tbl5 .req x12
+x_tbl6 .req x13
+x_tbl7 .req x14
+
+x_dest1 .req x15
+
+/* r16,r17,r18,r29,r30: special role registers, avoided */
+/* r19..r29 and SP must be preserved */
+x_dest2 .req x19
+x_dest3 .req x20
+x_dest4 .req x21
+x_dest5 .req x22
+x_dest6 .req x23
+x_dest7 .req x_dest /* reused */
+
+/* vectors */
+z_mask0f .req z0
+
+z_src .req z1
+z_src_lo .req z2
+z_src_hi .req z_src
+
+z_dest1 .req z3
+z_gft1_lo .req z4
+z_gft1_hi .req z5
+q_gft1_lo .req q4
+q_gft1_hi .req q5
+
+z_gft7_lo .req z6
+z_gft7_hi .req z7
+q_gft7_lo .req q6
+q_gft7_hi .req q7
+
+/* bottom 64-bit of v8..v15 must be preserved if used */
+z_dest7 .req z16
+
+z_gft2_lo .req z17
+z_gft2_hi .req z18
+q_gft2_lo .req q17
+q_gft2_hi .req q18
+
+z_gft3_lo .req z19
+z_gft3_hi .req z20
+q_gft3_lo .req q19
+q_gft3_hi .req q20
+
+z_gft4_lo .req z21
+z_gft4_hi .req z22
+q_gft4_lo .req q21
+q_gft4_hi .req q22
+
+z_gft5_lo .req z23
+z_gft5_hi .req z24
+q_gft5_lo .req q23
+q_gft5_hi .req q24
+
+z_gft6_lo .req z25
+z_gft6_hi .req z26
+q_gft6_lo .req q25
+q_gft6_hi .req q26
+
+z_dest2 .req z27
+z_dest3 .req z28
+z_dest4 .req z29
+z_dest5 .req z30
+z_dest6 .req z31
+
+cdecl(gf_7vect_dot_prod_sve):
+ /* less than 16 bytes, return_fail */
+ cmp x_len, #16
+ blt .return_fail
+
+ /* save r19..r29 */
+ sub sp, sp, #48 /* alignment */
+ stp x19, x20, [sp]
+ stp x21, x22, [sp, #16]
+ str x23, [sp, #32]
+
+ mov z_mask0f.b, #0x0f /* z_mask0f = 0x0F0F...0F */
+ mov x_pos, #0
+ lsl x_vec, x_vec, #3
+ ldp x_dest1, x_dest2, [x_dest, #8*0]
+ ldp x_dest3, x_dest4, [x_dest, #8*2]
+ ldp x_dest5, x_dest6, [x_dest, #8*4]
+ ldr x_dest7, [x_dest, #8*6] /* x_dest7 reuses x_dest */
+
+/* Loop 1: x_len, vector length */
+.Lloopsve_vl:
+ whilelo p0.b, x_pos, x_len
+ b.none .return_pass
+
+ mov x_vec_i, #0 /* clear x_vec_i */
+ ldr x_ptr, [x_src, x_vec_i] /* x_ptr: src base addr. */
+
+ mov z_dest1.b, #0 /* clear z_dest1 */
+ mov z_dest2.b, #0 /* clear z_dest2 */
+ mov z_dest3.b, #0 /* clear z_dest3 */
+ mov z_dest4.b, #0 /* clear z_dest4 */
+ mov z_dest5.b, #0 /* clear z_dest5 */
+ mov z_dest6.b, #0 /* clear z_dest6 */
+ mov z_dest7.b, #0 /* clear z_dest7 */
+
+ /* gf_tbl base = (x_tbl + dest_idx * x_vec * 32) */
+ mov x_tbl1, x_tbl /* reset x_tbl1 */
+ add x_tbl2, x_tbl1, x_vec, LSL #2 /* reset x_tbl2 */
+ add x_tbl3, x_tbl2, x_vec, LSL #2 /* reset x_tbl3 */
+ add x_tbl4, x_tbl3, x_vec, LSL #2 /* reset x_tbl4 */
+ add x_tbl5, x_tbl4, x_vec, LSL #2 /* reset x_tbl5 */
+ add x_tbl6, x_tbl5, x_vec, LSL #2 /* reset x_tbl6 */
+ add x_tbl7, x_tbl6, x_vec, LSL #2 /* reset x_tbl7 */
+
+/* Loop 2: x_vec, number of source vectors (ie. data blocks) */
+.Lloopsve_vl_vects:
+ /* load src data, governed by p0 */
+ ld1b z_src.b, p0/z, [x_ptr, x_pos] /* load from: src base + pos offset */
+ /* split 4-bit lo; 4-bit hi */
+ and z_src_lo.d, z_src.d, z_mask0f.d
+ lsr z_src_hi.b, z_src.b, #4
+
+ /* gf_tbl addr: (x_tbl + dest_idx * x_vec * 32) + src_vec_idx * 32 */
+ /* load gf_table's */
+ ldp q_gft1_lo, q_gft1_hi, [x_tbl1], #32 /* x_tbl1 is post-added by #32 for each src vect */
+ ldp q_gft2_lo, q_gft2_hi, [x_tbl2], #32
+
+ /* prefetch */
+ prfb pldl2keep, p0, [x_tbl1]
+ prfb pldl2keep, p0, [x_tbl2]
+
+ /* calc for next and prefetch */
+ add x_vec_i, x_vec_i, #8 /* move x_vec_i to next */
+ ldr x_ptr, [x_src, x_vec_i] /* x_ptr: src base addr. */
+
+ /* dest 1 */
+ /* table indexing, ie. gf(2^8) multiplication */
+ tbl z_gft1_lo.b, {z_gft1_lo.b}, z_src_lo.b
+ tbl z_gft1_hi.b, {z_gft1_hi.b}, z_src_hi.b
+ /* exclusive or, ie. gf(2^8) add */
+ eor z_dest1.d, z_gft1_lo.d, z_dest1.d
+ eor z_dest1.d, z_gft1_hi.d, z_dest1.d
+
+ ldp q_gft3_lo, q_gft3_hi, [x_tbl3], #32
+ ldp q_gft4_lo, q_gft4_hi, [x_tbl4], #32
+ prfb pldl2keep, p0, [x_tbl3]
+ prfb pldl2keep, p0, [x_tbl4]
+
+ /* dest 2 */
+ tbl z_gft2_lo.b, {z_gft2_lo.b}, z_src_lo.b
+ tbl z_gft2_hi.b, {z_gft2_hi.b}, z_src_hi.b
+ eor z_dest2.d, z_gft2_lo.d, z_dest2.d
+ eor z_dest2.d, z_gft2_hi.d, z_dest2.d
+
+ /* dest 3 */
+ tbl z_gft3_lo.b, {z_gft3_lo.b}, z_src_lo.b
+ tbl z_gft3_hi.b, {z_gft3_hi.b}, z_src_hi.b
+ eor z_dest3.d, z_gft3_lo.d, z_dest3.d
+ eor z_dest3.d, z_gft3_hi.d, z_dest3.d
+
+ ldp q_gft5_lo, q_gft5_hi, [x_tbl5], #32
+ ldp q_gft6_lo, q_gft6_hi, [x_tbl6], #32
+ prfb pldl2keep, p0, [x_tbl5]
+ prfb pldl2keep, p0, [x_tbl6]
+
+ /* dest 4 */
+ tbl z_gft4_lo.b, {z_gft4_lo.b}, z_src_lo.b
+ tbl z_gft4_hi.b, {z_gft4_hi.b}, z_src_hi.b
+ eor z_dest4.d, z_gft4_lo.d, z_dest4.d
+ eor z_dest4.d, z_gft4_hi.d, z_dest4.d
+
+ /* dest 5 */
+ tbl z_gft5_lo.b, {z_gft5_lo.b}, z_src_lo.b
+ tbl z_gft5_hi.b, {z_gft5_hi.b}, z_src_hi.b
+ eor z_dest5.d, z_gft5_lo.d, z_dest5.d
+ eor z_dest5.d, z_gft5_hi.d, z_dest5.d
+
+ ldp q_gft7_lo, q_gft7_hi, [x_tbl7], #32
+ prfb pldl2keep, p0, [x_tbl7]
+
+ /* dest 6 */
+ tbl z_gft6_lo.b, {z_gft6_lo.b}, z_src_lo.b
+ tbl z_gft6_hi.b, {z_gft6_hi.b}, z_src_hi.b
+ eor z_dest6.d, z_gft6_lo.d, z_dest6.d
+ eor z_dest6.d, z_gft6_hi.d, z_dest6.d
+
+ /* dest 7 */
+ tbl z_gft7_lo.b, {z_gft7_lo.b}, z_src_lo.b
+ tbl z_gft7_hi.b, {z_gft7_hi.b}, z_src_hi.b
+ eor z_dest7.d, z_gft7_lo.d, z_dest7.d
+ eor z_dest7.d, z_gft7_hi.d, z_dest7.d
+
+ cmp x_vec_i, x_vec
+ blt .Lloopsve_vl_vects
+/* end of Loop 2 */
+
+ /* store dest data, governed by p0 */
+ st1b z_dest1.b, p0, [x_dest1, x_pos]
+ st1b z_dest2.b, p0, [x_dest2, x_pos]
+ st1b z_dest3.b, p0, [x_dest3, x_pos]
+ st1b z_dest4.b, p0, [x_dest4, x_pos]
+ st1b z_dest5.b, p0, [x_dest5, x_pos]
+ st1b z_dest6.b, p0, [x_dest6, x_pos]
+ st1b z_dest7.b, p0, [x_dest7, x_pos]
+
+ /* increment one vector length */
+ incb x_pos
+ b .Lloopsve_vl
+/* end of Loop 1 */
+
+.return_pass:
+ /* restore r19..r29 */
+ ldr x23, [sp, #32]
+ ldp x21, x22, [sp, #16]
+ ldp x19, x20, [sp]
+ add sp, sp, #48
+
+ mov w_ret, #0
+ ret
+
+.return_fail:
+ mov w_ret, #1
+ ret
diff --git a/contrib/libs/isa-l/erasure_code/aarch64/gf_8vect_dot_prod_sve.S b/contrib/libs/isa-l/erasure_code/aarch64/gf_8vect_dot_prod_sve.S
new file mode 100644
index 0000000000..20768f4889
--- /dev/null
+++ b/contrib/libs/isa-l/erasure_code/aarch64/gf_8vect_dot_prod_sve.S
@@ -0,0 +1,307 @@
+/*************************************************************
+ Copyright (c) 2021 Linaro Ltd.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name of Huawei Corporation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+**********************************************************************/
+.text
+.align 6
+.arch armv8-a+sve
+
+#include "../include/aarch64_label.h"
+
+.global cdecl(gf_8vect_dot_prod_sve)
+#ifndef __APPLE__
+.type gf_8vect_dot_prod_sve, %function
+#endif
+/* void gf_8vect_dot_prod_sve(int len, int vlen, unsigned char *gftbls,
+ unsigned char **src, unsigned char **dest);
+ */
+
+/* arguments */
+x_len .req x0 /* vector length */
+x_vec .req x1 /* number of source vectors (ie. data blocks) */
+x_tbl .req x2
+x_src .req x3
+x_dest .req x4
+
+/* returns */
+w_ret .req w0
+
+/* local variables */
+x_vec_i .req x5
+x_ptr .req x6
+x_pos .req x7
+
+x_tbl1 .req x8
+x_tbl2 .req x9
+x_tbl3 .req x10
+x_tbl4 .req x11
+x_tbl5 .req x12
+x_tbl6 .req x13
+x_tbl7 .req x14
+
+x_dest1 .req x15
+
+/* r16,r17,r18,r29,r30: special role registers, avoided */
+/* r19..r29 and SP must be preserved */
+x_dest2 .req x19
+x_dest3 .req x20
+x_dest4 .req x21
+x_dest5 .req x22
+x_dest6 .req x23
+x_dest7 .req x24
+x_dest8 .req x_dest /* reused */
+x_tbl8 .req x25
+
+/* vectors */
+z_mask0f .req z0
+
+z_src .req z1
+z_src_lo .req z2
+z_src_hi .req z_src
+
+z_dest1 .req z3
+z_gft1_lo .req z4
+z_gft1_hi .req z5
+q_gft1_lo .req q4
+q_gft1_hi .req q5
+
+z_gft7_lo .req z6
+z_gft7_hi .req z7
+q_gft7_lo .req q6
+q_gft7_hi .req q7
+
+/* bottom 64-bit of v8..v15 must be preserved if used */
+z_dest7 .req z8
+
+z_gft8_lo .req z9
+z_gft8_hi .req z10
+q_gft8_lo .req q9
+q_gft8_hi .req q10
+
+z_dest8 .req z16
+
+z_gft2_lo .req z17
+z_gft2_hi .req z18
+q_gft2_lo .req q17
+q_gft2_hi .req q18
+
+z_gft3_lo .req z19
+z_gft3_hi .req z20
+q_gft3_lo .req q19
+q_gft3_hi .req q20
+
+z_gft4_lo .req z21
+z_gft4_hi .req z22
+q_gft4_lo .req q21
+q_gft4_hi .req q22
+
+z_gft5_lo .req z23
+z_gft5_hi .req z24
+q_gft5_lo .req q23
+q_gft5_hi .req q24
+
+z_gft6_lo .req z25
+z_gft6_hi .req z26
+q_gft6_lo .req q25
+q_gft6_hi .req q26
+
+z_dest2 .req z27
+z_dest3 .req z28
+z_dest4 .req z29
+z_dest5 .req z30
+z_dest6 .req z31
+
+cdecl(gf_8vect_dot_prod_sve):
+ /* less than 16 bytes, return_fail */
+ cmp x_len, #16
+ blt .return_fail
+
+ /* save r19..r29 */
+ sub sp, sp, #80 /* alignment */
+ stp x19, x20, [sp]
+ stp x21, x22, [sp, #16]
+ stp x23, x24, [sp, #32]
+ stp d8, d9, [sp, #48]
+ str d10, [sp, #56]
+ str x25, [sp, #64]
+
+ mov z_mask0f.b, #0x0f /* z_mask0f = 0x0F0F...0F */
+ mov x_pos, #0
+ lsl x_vec, x_vec, #3
+ ldp x_dest1, x_dest2, [x_dest, #8*0]
+ ldp x_dest3, x_dest4, [x_dest, #8*2]
+ ldp x_dest5, x_dest6, [x_dest, #8*4]
+ ldp x_dest7, x_dest8, [x_dest, #8*6] /* x_dest8 reuses x_dest */
+
+/* Loop 1: x_len, vector length */
+.Lloopsve_vl:
+ whilelo p0.b, x_pos, x_len
+ b.none .return_pass
+
+ mov x_vec_i, #0 /* clear x_vec_i */
+ ldr x_ptr, [x_src, x_vec_i] /* x_ptr: src base addr. */
+
+ mov z_dest1.b, #0 /* clear z_dest1 */
+ mov z_dest2.b, #0 /* clear z_dest2 */
+ mov z_dest3.b, #0 /* clear z_dest3 */
+ mov z_dest4.b, #0 /* clear z_dest4 */
+ mov z_dest5.b, #0 /* clear z_dest5 */
+ mov z_dest6.b, #0 /* clear z_dest6 */
+ mov z_dest7.b, #0 /* clear z_dest7 */
+ mov z_dest8.b, #0 /* clear z_dest8 */
+
+ /* gf_tbl base = (x_tbl + dest_idx * x_vec * 32) */
+ mov x_tbl1, x_tbl /* reset x_tbl1 */
+ add x_tbl2, x_tbl1, x_vec, LSL #2 /* reset x_tbl2 */
+ add x_tbl3, x_tbl2, x_vec, LSL #2 /* reset x_tbl3 */
+ add x_tbl4, x_tbl3, x_vec, LSL #2 /* reset x_tbl4 */
+ add x_tbl5, x_tbl4, x_vec, LSL #2 /* reset x_tbl5 */
+ add x_tbl6, x_tbl5, x_vec, LSL #2 /* reset x_tbl6 */
+ add x_tbl7, x_tbl6, x_vec, LSL #2 /* reset x_tbl7 */
+ add x_tbl8, x_tbl7, x_vec, LSL #2 /* reset x_tbl8 */
+
+/* Loop 2: x_vec, number of source vectors (ie. data blocks) */
+.Lloopsve_vl_vects:
+ /* load src data, governed by p0 */
+ ld1b z_src.b, p0/z, [x_ptr, x_pos] /* load from: src base + pos offset */
+ /* split 4-bit lo; 4-bit hi */
+ and z_src_lo.d, z_src.d, z_mask0f.d
+ lsr z_src_hi.b, z_src.b, #4
+
+ /* gf_tbl addr: (x_tbl + dest_idx * x_vec * 32) + src_vec_idx * 32 */
+ /* load gf_table's */
+ ldp q_gft1_lo, q_gft1_hi, [x_tbl1], #32 /* x_tbl1 is post-added by #32 for each src vect */
+ ldp q_gft2_lo, q_gft2_hi, [x_tbl2], #32
+
+ /* prefetch */
+ prfb pldl2keep, p0, [x_tbl1]
+ prfb pldl2keep, p0, [x_tbl2]
+
+ /* calc for next and prefetch */
+ add x_vec_i, x_vec_i, #8 /* move x_vec_i to next */
+ ldr x_ptr, [x_src, x_vec_i] /* x_ptr: src base addr. */
+
+ /* dest 1 */
+ /* table indexing, ie. gf(2^8) multiplication */
+ tbl z_gft1_lo.b, {z_gft1_lo.b}, z_src_lo.b
+ tbl z_gft1_hi.b, {z_gft1_hi.b}, z_src_hi.b
+ /* exclusive or, ie. gf(2^8) add */
+ eor z_dest1.d, z_gft1_lo.d, z_dest1.d
+ eor z_dest1.d, z_gft1_hi.d, z_dest1.d
+
+ ldp q_gft3_lo, q_gft3_hi, [x_tbl3], #32
+ ldp q_gft4_lo, q_gft4_hi, [x_tbl4], #32
+ prfb pldl2keep, p0, [x_tbl3]
+ prfb pldl2keep, p0, [x_tbl4]
+
+ /* dest 2 */
+ tbl z_gft2_lo.b, {z_gft2_lo.b}, z_src_lo.b
+ tbl z_gft2_hi.b, {z_gft2_hi.b}, z_src_hi.b
+ eor z_dest2.d, z_gft2_lo.d, z_dest2.d
+ eor z_dest2.d, z_gft2_hi.d, z_dest2.d
+
+ /* dest 3 */
+ tbl z_gft3_lo.b, {z_gft3_lo.b}, z_src_lo.b
+ tbl z_gft3_hi.b, {z_gft3_hi.b}, z_src_hi.b
+ eor z_dest3.d, z_gft3_lo.d, z_dest3.d
+ eor z_dest3.d, z_gft3_hi.d, z_dest3.d
+
+ ldp q_gft5_lo, q_gft5_hi, [x_tbl5], #32
+ ldp q_gft6_lo, q_gft6_hi, [x_tbl6], #32
+ prfb pldl2keep, p0, [x_tbl5]
+ prfb pldl2keep, p0, [x_tbl6]
+
+ /* dest 4 */
+ tbl z_gft4_lo.b, {z_gft4_lo.b}, z_src_lo.b
+ tbl z_gft4_hi.b, {z_gft4_hi.b}, z_src_hi.b
+ eor z_dest4.d, z_gft4_lo.d, z_dest4.d
+ eor z_dest4.d, z_gft4_hi.d, z_dest4.d
+
+ /* dest 5 */
+ tbl z_gft5_lo.b, {z_gft5_lo.b}, z_src_lo.b
+ tbl z_gft5_hi.b, {z_gft5_hi.b}, z_src_hi.b
+ eor z_dest5.d, z_gft5_lo.d, z_dest5.d
+ eor z_dest5.d, z_gft5_hi.d, z_dest5.d
+
+ ldp q_gft7_lo, q_gft7_hi, [x_tbl7], #32
+ ldp q_gft8_lo, q_gft8_hi, [x_tbl8], #32
+ prfb pldl2keep, p0, [x_tbl7]
+ prfb pldl2keep, p0, [x_tbl8]
+
+ /* dest 6 */
+ tbl z_gft6_lo.b, {z_gft6_lo.b}, z_src_lo.b
+ tbl z_gft6_hi.b, {z_gft6_hi.b}, z_src_hi.b
+ eor z_dest6.d, z_gft6_lo.d, z_dest6.d
+ eor z_dest6.d, z_gft6_hi.d, z_dest6.d
+
+ /* dest 7 */
+ tbl z_gft7_lo.b, {z_gft7_lo.b}, z_src_lo.b
+ tbl z_gft7_hi.b, {z_gft7_hi.b}, z_src_hi.b
+ eor z_dest7.d, z_gft7_lo.d, z_dest7.d
+ eor z_dest7.d, z_gft7_hi.d, z_dest7.d
+
+ /* dest 8 */
+ tbl z_gft8_lo.b, {z_gft8_lo.b}, z_src_lo.b
+ tbl z_gft8_hi.b, {z_gft8_hi.b}, z_src_hi.b
+ eor z_dest8.d, z_gft8_lo.d, z_dest8.d
+ eor z_dest8.d, z_gft8_hi.d, z_dest8.d
+
+ cmp x_vec_i, x_vec
+ blt .Lloopsve_vl_vects
+/* end of Loop 2 */
+
+ /* store dest data, governed by p0 */
+ st1b z_dest1.b, p0, [x_dest1, x_pos]
+ st1b z_dest2.b, p0, [x_dest2, x_pos]
+ st1b z_dest3.b, p0, [x_dest3, x_pos]
+ st1b z_dest4.b, p0, [x_dest4, x_pos]
+ st1b z_dest5.b, p0, [x_dest5, x_pos]
+ st1b z_dest6.b, p0, [x_dest6, x_pos]
+ st1b z_dest7.b, p0, [x_dest7, x_pos]
+ st1b z_dest8.b, p0, [x_dest8, x_pos]
+
+ /* increment one vector length */
+ incb x_pos
+ b .Lloopsve_vl
+/* end of Loop 1 */
+
+.return_pass:
+ /* restore r19..r29 */
+ ldr x25, [sp, #64]
+ ldr d10, [sp, #56]
+ ldp d8, d9, [sp, #48]
+ ldp x23, x24, [sp, #32]
+ ldp x21, x22, [sp, #16]
+ ldp x19, x20, [sp]
+ add sp, sp, #80
+
+ mov w_ret, #0
+ ret
+
+.return_fail:
+ mov w_ret, #1
+ ret
diff --git a/contrib/libs/isa-l/erasure_code/aarch64/gf_vect_dot_prod_neon.S b/contrib/libs/isa-l/erasure_code/aarch64/gf_vect_dot_prod_neon.S
new file mode 100644
index 0000000000..4d17362894
--- /dev/null
+++ b/contrib/libs/isa-l/erasure_code/aarch64/gf_vect_dot_prod_neon.S
@@ -0,0 +1,303 @@
+/**************************************************************
+ Copyright (c) 2019 Huawei Technologies Co., Ltd.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name of Huawei Corporation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+**********************************************************************/
+
+#include "../include/aarch64_label.h"
+
+.text
+
+.global cdecl(gf_vect_dot_prod_neon)
+#ifndef __APPLE__
+.type gf_vect_dot_prod_neon, %function
+#endif
+
+/* arguments */
+x_len .req x0
+x_vec .req x1
+x_tbl .req x2
+x_src .req x3
+x_dest1 .req x4
+
+/* returns */
+w_ret .req w0
+
+/* local variables */
+x_vec_i .req x5
+x_ptr .req x6
+x_pos .req x7
+x_tmp .req x8
+x_tbl1 .req x9
+
+/* vectors */
+v_gft1_lo .req v0
+v_gft1_hi .req v1
+q_gft1_lo .req q0
+q_gft1_hi .req q1
+v_mask0f .req v2
+q_mask0f .req q2
+
+v_data_0 .req v8
+v_data_1 .req v9
+v_data_2 .req v10
+v_data_3 .req v11
+v_data_4 .req v12
+v_data_5 .req v13
+v_data_6 .req v14
+v_data_7 .req v15
+q_data_0 .req q8
+q_data_1 .req q9
+q_data_2 .req q10
+q_data_3 .req q11
+q_data_4 .req q12
+q_data_5 .req q13
+q_data_6 .req q14
+q_data_7 .req q15
+
+v_data_0_lo .req v16
+v_data_1_lo .req v17
+v_data_2_lo .req v18
+v_data_3_lo .req v19
+v_data_4_lo .req v20
+v_data_5_lo .req v21
+v_data_6_lo .req v22
+v_data_7_lo .req v23
+v_data_0_hi .req v_data_0
+v_data_1_hi .req v_data_1
+v_data_2_hi .req v_data_2
+v_data_3_hi .req v_data_3
+v_data_4_hi .req v_data_4
+v_data_5_hi .req v_data_5
+v_data_6_hi .req v_data_6
+v_data_7_hi .req v_data_7
+
+v_p0 .req v24
+v_p1 .req v25
+v_p2 .req v26
+v_p3 .req v27
+v_p4 .req v28
+v_p5 .req v29
+v_p6 .req v30
+v_p7 .req v31
+q_p0 .req q24
+q_p1 .req q25
+q_p2 .req q26
+q_p3 .req q27
+q_p4 .req q28
+q_p5 .req q29
+q_p6 .req q30
+q_p7 .req q31
+
+v_p .req v_p0
+q_p .req q_p0
+v_data .req v_p1
+q_data .req q_p1
+v_data_lo .req v_p2
+v_data_hi .req v_p3
+
+
+cdecl(gf_vect_dot_prod_neon):
+ /* less than 16 bytes, return_fail */
+ cmp x_len, #16
+ blt .return_fail
+
+ movi v_mask0f.16b, #0x0f
+ mov x_pos, #0
+
+ lsl x_vec, x_vec, #3
+
+.Lloop128_init:
+ /* less than 128 bytes, goto Lloop16_init */
+ cmp x_len, #128
+ blt .Lloop16_init
+
+ /* save d8 ~ d15 to stack */
+ sub sp, sp, #64
+ stp d8, d9, [sp]
+ stp d10, d11, [sp, #16]
+ stp d12, d13, [sp, #32]
+ stp d14, d15, [sp, #48]
+
+ sub x_len, x_len, #128
+
+.Lloop128:
+ movi v_p0.16b, #0
+ movi v_p1.16b, #0
+ movi v_p2.16b, #0
+ movi v_p3.16b, #0
+ movi v_p4.16b, #0
+ movi v_p5.16b, #0
+ movi v_p6.16b, #0
+ movi v_p7.16b, #0
+
+ mov x_tbl1, x_tbl
+ mov x_vec_i, #0
+
+.Lloop128_vects:
+ ldr x_ptr, [x_src, x_vec_i]
+ add x_vec_i, x_vec_i, #8
+ add x_ptr, x_ptr, x_pos
+
+ ldp q_gft1_lo, q_gft1_hi, [x_tbl1], #32
+
+ ldp q_data_0, q_data_1, [x_ptr], #32
+ ldp q_data_2, q_data_3, [x_ptr], #32
+ ldp q_data_4, q_data_5, [x_ptr], #32
+ ldp q_data_6, q_data_7, [x_ptr]
+
+ prfm pldl1keep, [x_tbl1]
+ prfm pldl1strm, [x_ptr]
+
+ and v_data_0_lo.16b, v_data_0.16b, v_mask0f.16b
+ and v_data_1_lo.16b, v_data_1.16b, v_mask0f.16b
+ and v_data_2_lo.16b, v_data_2.16b, v_mask0f.16b
+ and v_data_3_lo.16b, v_data_3.16b, v_mask0f.16b
+ and v_data_4_lo.16b, v_data_4.16b, v_mask0f.16b
+ and v_data_5_lo.16b, v_data_5.16b, v_mask0f.16b
+ and v_data_6_lo.16b, v_data_6.16b, v_mask0f.16b
+ and v_data_7_lo.16b, v_data_7.16b, v_mask0f.16b
+
+ ushr v_data_0_hi.16b, v_data_0.16b, #4
+ ushr v_data_1_hi.16b, v_data_1.16b, #4
+ ushr v_data_2_hi.16b, v_data_2.16b, #4
+ ushr v_data_3_hi.16b, v_data_3.16b, #4
+ ushr v_data_4_hi.16b, v_data_4.16b, #4
+ ushr v_data_5_hi.16b, v_data_5.16b, #4
+ ushr v_data_6_hi.16b, v_data_6.16b, #4
+ ushr v_data_7_hi.16b, v_data_7.16b, #4
+
+ tbl v_data_0_lo.16b, {v_gft1_lo.16b}, v_data_0_lo.16b
+ tbl v_data_1_lo.16b, {v_gft1_lo.16b}, v_data_1_lo.16b
+ tbl v_data_2_lo.16b, {v_gft1_lo.16b}, v_data_2_lo.16b
+ tbl v_data_3_lo.16b, {v_gft1_lo.16b}, v_data_3_lo.16b
+ tbl v_data_4_lo.16b, {v_gft1_lo.16b}, v_data_4_lo.16b
+ tbl v_data_5_lo.16b, {v_gft1_lo.16b}, v_data_5_lo.16b
+ tbl v_data_6_lo.16b, {v_gft1_lo.16b}, v_data_6_lo.16b
+ tbl v_data_7_lo.16b, {v_gft1_lo.16b}, v_data_7_lo.16b
+
+ tbl v_data_0_hi.16b, {v_gft1_hi.16b}, v_data_0_hi.16b
+ tbl v_data_1_hi.16b, {v_gft1_hi.16b}, v_data_1_hi.16b
+ tbl v_data_2_hi.16b, {v_gft1_hi.16b}, v_data_2_hi.16b
+ tbl v_data_3_hi.16b, {v_gft1_hi.16b}, v_data_3_hi.16b
+ tbl v_data_4_hi.16b, {v_gft1_hi.16b}, v_data_4_hi.16b
+ tbl v_data_5_hi.16b, {v_gft1_hi.16b}, v_data_5_hi.16b
+ tbl v_data_6_hi.16b, {v_gft1_hi.16b}, v_data_6_hi.16b
+ tbl v_data_7_hi.16b, {v_gft1_hi.16b}, v_data_7_hi.16b
+
+ eor v_p0.16b, v_data_0_lo.16b, v_p0.16b
+ eor v_p0.16b, v_p0.16b, v_data_0_hi.16b
+ eor v_p1.16b, v_data_1_lo.16b, v_p1.16b
+ eor v_p1.16b, v_p1.16b, v_data_1_hi.16b
+ eor v_p2.16b, v_data_2_lo.16b, v_p2.16b
+ eor v_p2.16b, v_p2.16b, v_data_2_hi.16b
+ eor v_p3.16b, v_data_3_lo.16b, v_p3.16b
+ eor v_p3.16b, v_p3.16b, v_data_3_hi.16b
+ eor v_p4.16b, v_data_4_lo.16b, v_p4.16b
+ eor v_p4.16b, v_p4.16b, v_data_4_hi.16b
+ eor v_p5.16b, v_data_5_lo.16b, v_p5.16b
+ eor v_p5.16b, v_p5.16b, v_data_5_hi.16b
+ eor v_p6.16b, v_data_6_lo.16b, v_p6.16b
+ eor v_p6.16b, v_p6.16b, v_data_6_hi.16b
+ eor v_p7.16b, v_data_7_lo.16b, v_p7.16b
+ eor v_p7.16b, v_p7.16b, v_data_7_hi.16b
+
+ cmp x_vec_i, x_vec
+ blt .Lloop128_vects
+
+.Lloop128_vects_end:
+ add x_ptr, x_dest1, x_pos
+ stp q_p0, q_p1, [x_ptr], #32
+ stp q_p2, q_p3, [x_ptr], #32
+ stp q_p4, q_p5, [x_ptr], #32
+ stp q_p6, q_p7, [x_ptr]
+
+ add x_pos, x_pos, #128
+ cmp x_pos, x_len
+ ble .Lloop128
+
+.Lloop128_end:
+ /* restore d8 ~ d15 */
+ ldp d8, d9, [sp]
+ ldp d10, d11, [sp, #16]
+ ldp d12, d13, [sp, #32]
+ ldp d14, d15, [sp, #48]
+ add sp, sp, #64
+
+ add x_len, x_len, #128
+ cmp x_pos, x_len
+ beq .return_pass
+
+.Lloop16_init:
+ sub x_len, x_len, #16
+ cmp x_pos, x_len
+ bgt .lessthan16_init
+
+.Lloop16:
+ movi v_p.16b, #0
+ mov x_tbl1, x_tbl
+ mov x_vec_i, #0
+
+.Lloop16_vects:
+ ldr x_ptr, [x_src, x_vec_i]
+ ldr q_data, [x_ptr, x_pos]
+ add x_vec_i, x_vec_i, #8
+
+ ldp q_gft1_lo, q_gft1_hi, [x_tbl1], #32
+
+ and v_data_lo.16b, v_data.16b, v_mask0f.16b
+ ushr v_data_hi.16b, v_data.16b, #4
+
+ tbl v_data_lo.16b, {v_gft1_lo.16b}, v_data_lo.16b
+ tbl v_data_hi.16b, {v_gft1_hi.16b}, v_data_hi.16b
+ eor v_p.16b, v_data_lo.16b, v_p.16b
+ eor v_p.16b, v_p.16b, v_data_hi.16b
+
+ cmp x_vec_i, x_vec
+ blt .Lloop16_vects
+
+.Lloop16_vects_end:
+ str q_p, [x_dest1, x_pos]
+ add x_pos, x_pos, #16
+ cmp x_pos, x_len
+ ble .Lloop16
+
+.Lloop16_end:
+ sub x_tmp, x_pos, x_len
+ cmp x_tmp, #16
+ beq .return_pass
+
+.lessthan16_init:
+ mov x_pos, x_len
+ b .Lloop16
+
+.return_pass:
+ mov w_ret, #0
+ ret
+
+.return_fail:
+ mov w_ret, #1
+ ret
diff --git a/contrib/libs/isa-l/erasure_code/aarch64/gf_vect_dot_prod_sve.S b/contrib/libs/isa-l/erasure_code/aarch64/gf_vect_dot_prod_sve.S
new file mode 100644
index 0000000000..48ce151fde
--- /dev/null
+++ b/contrib/libs/isa-l/erasure_code/aarch64/gf_vect_dot_prod_sve.S
@@ -0,0 +1,132 @@
+/**************************************************************
+ Copyright (c) 2021 Linaro Ltd.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name of Huawei Corporation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+**********************************************************************/
+.text
+.align 6
+.arch armv8-a+sve
+
+#include "../include/aarch64_label.h"
+
+.global cdecl(gf_vect_dot_prod_sve)
+#ifndef __APPLE__
+.type gf_vect_dot_prod_sve, %function
+#endif
+/* void gf_vect_dot_prod_sve(int len, int vlen, unsigned char *gftbls,
+ unsigned char **src, unsigned char *dest);
+ */
+
+/* arguments */
+x_len .req x0 /* vector length */
+x_vec .req x1 /* number of source vectors (ie. data blocks) */
+x_tbl .req x2
+x_src .req x3
+x_dest1 .req x4
+
+/* returns */
+w_ret .req w0
+
+/* local variables */
+x_vec_i .req x5
+x_ptr .req x6
+x_pos .req x7
+x_tbl1 .req x8
+
+/* vectors */
+z_mask0f .req z0
+
+z_src .req z1
+z_src_lo .req z2
+z_src_hi .req z_src
+
+z_dest .req z3
+
+z_gft1_lo .req z4
+z_gft1_hi .req z5
+q_gft1_lo .req q4
+q_gft1_hi .req q5
+
+cdecl(gf_vect_dot_prod_sve):
+ /* less than 16 bytes, return_fail */
+ cmp x_len, #16
+ blt .return_fail
+
+ mov z_mask0f.b, #0x0f /* z_mask0f = 0x0F0F...0F */
+ mov x_pos, #0
+ lsl x_vec, x_vec, #3
+
+/* Loop 1: x_len, vector length */
+.Lloopsve_vl:
+ whilelo p0.b, x_pos, x_len
+ b.none .return_pass
+
+ mov z_dest.b, #0 /* clear z_dest */
+ mov x_vec_i, #0 /* clear x_vec_i */
+ mov x_tbl1, x_tbl /* reset x_tbl1 */
+
+/* Loop 2: x_vec, number of source vectors (ie. data blocks) */
+.Lloopsve_vl_vects:
+ ldr x_ptr, [x_src, x_vec_i] /* x_ptr: src base addr. */
+ /* load src data, governed by p0 */
+ ld1b z_src.b, p0/z, [x_ptr, x_pos] /* load from: src base + pos offset */
+
+ add x_vec_i, x_vec_i, #8 /* move x_vec_i to next */
+
+ /* load gf_table */
+ ldp q_gft1_lo, q_gft1_hi, [x_tbl1], #32 /* x_tbl1 is added by #32
+ for each src vect */
+
+ /* split 4-bit lo; 4-bit hi */
+ and z_src_lo.d, z_src.d, z_mask0f.d
+ lsr z_src_hi.b, z_src.b, #4
+
+ /* table indexing, ie. gf(2^8) multiplication */
+ tbl z_gft1_lo.b, {z_gft1_lo.b}, z_src_lo.b
+ tbl z_gft1_hi.b, {z_gft1_hi.b}, z_src_hi.b
+
+ /* exclusive or, ie. gf(2^8) add */
+ eor z_dest.d, z_gft1_lo.d, z_dest.d
+ eor z_dest.d, z_gft1_hi.d, z_dest.d
+
+ cmp x_vec_i, x_vec
+ blt .Lloopsve_vl_vects
+
+ /* end of Loop 2 */
+ /* store dest data, governed by p0 */
+ st1b z_dest.b, p0, [x_dest1, x_pos]
+ /* increment one vector length */
+ incb x_pos
+
+ b .Lloopsve_vl
+
+.return_pass:
+ mov w_ret, #0
+ ret
+
+.return_fail:
+ mov w_ret, #1
+ ret
diff --git a/contrib/libs/isa-l/erasure_code/aarch64/gf_vect_mad_neon.S b/contrib/libs/isa-l/erasure_code/aarch64/gf_vect_mad_neon.S
new file mode 100644
index 0000000000..bc2b957820
--- /dev/null
+++ b/contrib/libs/isa-l/erasure_code/aarch64/gf_vect_mad_neon.S
@@ -0,0 +1,324 @@
+/**************************************************************
+ Copyright (c) 2019 Huawei Technologies Co., Ltd.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name of Huawei Corporation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+**********************************************************************/
+
+#include "../include/aarch64_label.h"
+
+.text
+
+.global cdecl(gf_vect_mad_neon)
+#ifndef __APPLE__
+.type gf_vect_mad_neon, %function
+#endif
+
+/* arguments */
+x_len .req x0
+x_vec .req x1
+x_vec_i .req x2
+x_tbl .req x3
+x_src .req x4
+x_dest .req x5
+
+/* returns */
+w_ret .req w0
+
+/* local variables */
+x_src_end .req x6
+x_dest1 .req x_dest
+x_tmp .req x7
+x_const .req x8
+
+/* vectors */
+v_mask0f .req v0
+v_tmp .req v1
+q_tmp .req q1
+
+v_tmp1_lo .req v2
+v_tmp1_hi .req v3
+v_tmp2_lo .req v4
+v_tmp2_hi .req v5
+
+v_gft1_lo .req v6
+v_gft1_hi .req v7
+q_gft1_lo .req q6
+q_gft1_hi .req q7
+
+v_data_0 .req v8
+v_data_1 .req v9
+v_data_2 .req v10
+v_data_3 .req v11
+v_data_4 .req v12
+v_data_5 .req v13
+v_data_6 .req v14
+v_data_7 .req v15
+q_data_0 .req q8
+q_data_1 .req q9
+q_data_2 .req q10
+q_data_3 .req q11
+q_data_4 .req q12
+q_data_5 .req q13
+q_data_6 .req q14
+q_data_7 .req q15
+
+v_data_0_lo .req v16
+v_data_1_lo .req v17
+v_data_2_lo .req v18
+v_data_3_lo .req v19
+v_data_4_lo .req v20
+v_data_5_lo .req v21
+v_data_6_lo .req v22
+v_data_7_lo .req v23
+v_data_0_hi .req v_data_0
+v_data_1_hi .req v_data_1
+v_data_2_hi .req v_data_2
+v_data_3_hi .req v_data_3
+v_data_4_hi .req v_data_4
+v_data_5_hi .req v_data_5
+v_data_6_hi .req v_data_6
+v_data_7_hi .req v_data_7
+
+v_d1_0 .req v24
+v_d1_1 .req v25
+v_d1_2 .req v26
+v_d1_3 .req v27
+v_d1_4 .req v28
+v_d1_5 .req v29
+v_d1_6 .req v30
+v_d1_7 .req v31
+q_d1_0 .req q24
+q_d1_1 .req q25
+q_d1_2 .req q26
+q_d1_3 .req q27
+q_d1_4 .req q28
+q_d1_5 .req q29
+q_d1_6 .req q30
+q_d1_7 .req q31
+
+v_data .req v_d1_1
+q_data .req q_d1_1
+v_data_lo .req v_d1_2
+v_data_hi .req v_d1_3
+
+
+cdecl(gf_vect_mad_neon):
+ /* less than 16 bytes, return_fail */
+ cmp x_len, #16
+ blt .return_fail
+
+ movi v_mask0f.16b, #0x0f
+ lsl x_vec_i, x_vec_i, #5
+ add x_tbl, x_tbl, x_vec_i
+ add x_src_end, x_src, x_len
+
+ ldr q_gft1_lo, [x_tbl]
+ ldr q_gft1_hi, [x_tbl, #16]
+
+.Lloop128_init:
+ /* less than 128 bytes, goto Lloop16_init */
+ cmp x_len, #128
+ blt .Lloop16_init
+
+ /* save d8 ~ d15 to stack */
+ sub sp, sp, #64
+ stp d8, d9, [sp]
+ stp d10, d11, [sp, #16]
+ stp d12, d13, [sp, #32]
+ stp d14, d15, [sp, #48]
+
+ sub x_src_end, x_src_end, #128
+
+.Lloop128:
+ ldr q_data_0, [x_src, #16*0]
+ ldr q_data_1, [x_src, #16*1]
+ ldr q_data_2, [x_src, #16*2]
+ ldr q_data_3, [x_src, #16*3]
+ ldr q_data_4, [x_src, #16*4]
+ ldr q_data_5, [x_src, #16*5]
+ ldr q_data_6, [x_src, #16*6]
+ ldr q_data_7, [x_src, #16*7]
+
+ ldr q_d1_0, [x_dest1, #16*0]
+ ldr q_d1_1, [x_dest1, #16*1]
+ ldr q_d1_2, [x_dest1, #16*2]
+ ldr q_d1_3, [x_dest1, #16*3]
+ ldr q_d1_4, [x_dest1, #16*4]
+ ldr q_d1_5, [x_dest1, #16*5]
+ ldr q_d1_6, [x_dest1, #16*6]
+ ldr q_d1_7, [x_dest1, #16*7]
+
+ and v_data_0_lo.16b, v_data_0.16b, v_mask0f.16b
+ and v_data_1_lo.16b, v_data_1.16b, v_mask0f.16b
+ and v_data_2_lo.16b, v_data_2.16b, v_mask0f.16b
+ and v_data_3_lo.16b, v_data_3.16b, v_mask0f.16b
+ and v_data_4_lo.16b, v_data_4.16b, v_mask0f.16b
+ and v_data_5_lo.16b, v_data_5.16b, v_mask0f.16b
+ and v_data_6_lo.16b, v_data_6.16b, v_mask0f.16b
+ and v_data_7_lo.16b, v_data_7.16b, v_mask0f.16b
+
+ ushr v_data_0_hi.16b, v_data_0.16b, #4
+ ushr v_data_1_hi.16b, v_data_1.16b, #4
+ ushr v_data_2_hi.16b, v_data_2.16b, #4
+ ushr v_data_3_hi.16b, v_data_3.16b, #4
+ ushr v_data_4_hi.16b, v_data_4.16b, #4
+ ushr v_data_5_hi.16b, v_data_5.16b, #4
+ ushr v_data_6_hi.16b, v_data_6.16b, #4
+ ushr v_data_7_hi.16b, v_data_7.16b, #4
+
+ tbl v_tmp1_lo.16b, {v_gft1_lo.16b}, v_data_0_lo.16b
+ tbl v_tmp1_hi.16b, {v_gft1_hi.16b}, v_data_0_hi.16b
+ tbl v_tmp2_lo.16b, {v_gft1_lo.16b}, v_data_1_lo.16b
+ tbl v_tmp2_hi.16b, {v_gft1_hi.16b}, v_data_1_hi.16b
+
+ eor v_d1_0.16b, v_tmp1_lo.16b, v_d1_0.16b
+ eor v_d1_0.16b, v_d1_0.16b, v_tmp1_hi.16b
+ eor v_d1_1.16b, v_tmp2_lo.16b, v_d1_1.16b
+ eor v_d1_1.16b, v_d1_1.16b, v_tmp2_hi.16b
+
+ tbl v_tmp1_lo.16b, {v_gft1_lo.16b}, v_data_2_lo.16b
+ tbl v_tmp1_hi.16b, {v_gft1_hi.16b}, v_data_2_hi.16b
+ tbl v_tmp2_lo.16b, {v_gft1_lo.16b}, v_data_3_lo.16b
+ tbl v_tmp2_hi.16b, {v_gft1_hi.16b}, v_data_3_hi.16b
+
+ eor v_d1_2.16b, v_tmp1_lo.16b, v_d1_2.16b
+ eor v_d1_2.16b, v_d1_2.16b, v_tmp1_hi.16b
+ eor v_d1_3.16b, v_tmp2_lo.16b, v_d1_3.16b
+ eor v_d1_3.16b, v_d1_3.16b, v_tmp2_hi.16b
+
+ tbl v_tmp1_lo.16b, {v_gft1_lo.16b}, v_data_4_lo.16b
+ tbl v_tmp1_hi.16b, {v_gft1_hi.16b}, v_data_4_hi.16b
+ tbl v_tmp2_lo.16b, {v_gft1_lo.16b}, v_data_5_lo.16b
+ tbl v_tmp2_hi.16b, {v_gft1_hi.16b}, v_data_5_hi.16b
+
+ eor v_d1_4.16b, v_tmp1_lo.16b, v_d1_4.16b
+ eor v_d1_4.16b, v_d1_4.16b, v_tmp1_hi.16b
+ eor v_d1_5.16b, v_tmp2_lo.16b, v_d1_5.16b
+ eor v_d1_5.16b, v_d1_5.16b, v_tmp2_hi.16b
+
+ tbl v_tmp1_lo.16b, {v_gft1_lo.16b}, v_data_6_lo.16b
+ tbl v_tmp1_hi.16b, {v_gft1_hi.16b}, v_data_6_hi.16b
+ tbl v_tmp2_lo.16b, {v_gft1_lo.16b}, v_data_7_lo.16b
+ tbl v_tmp2_hi.16b, {v_gft1_hi.16b}, v_data_7_hi.16b
+
+ eor v_d1_6.16b, v_tmp1_lo.16b, v_d1_6.16b
+ eor v_d1_6.16b, v_d1_6.16b, v_tmp1_hi.16b
+ eor v_d1_7.16b, v_tmp2_lo.16b, v_d1_7.16b
+ eor v_d1_7.16b, v_d1_7.16b, v_tmp2_hi.16b
+
+ str q_d1_0, [x_dest1, #16*0]
+ str q_d1_1, [x_dest1, #16*1]
+ str q_d1_2, [x_dest1, #16*2]
+ str q_d1_3, [x_dest1, #16*3]
+ str q_d1_4, [x_dest1, #16*4]
+ str q_d1_5, [x_dest1, #16*5]
+ str q_d1_6, [x_dest1, #16*6]
+ str q_d1_7, [x_dest1, #16*7]
+
+ add x_src, x_src, #128
+ add x_dest1, x_dest1, #128
+ cmp x_src, x_src_end
+ bls .Lloop128
+
+.Lloop128_end:
+ /* restore d8 ~ d15 */
+ ldp d8, d9, [sp]
+ ldp d10, d11, [sp, #16]
+ ldp d12, d13, [sp, #32]
+ ldp d14, d15, [sp, #48]
+ add sp, sp, #64
+ add x_src_end, x_src_end, #128
+
+.Lloop16_init:
+ sub x_src_end, x_src_end, #16
+ cmp x_src, x_src_end
+ bhi .lessthan16_init
+
+.Lloop16:
+ ldr q_data, [x_src]
+ ldr q_d1_0, [x_dest1]
+
+ and v_data_lo.16b, v_data.16b, v_mask0f.16b
+ ushr v_data_hi.16b, v_data.16b, #4
+
+ tbl v_tmp1_lo.16b, {v_gft1_lo.16b}, v_data_lo.16b
+ tbl v_tmp1_hi.16b, {v_gft1_hi.16b}, v_data_hi.16b
+ eor v_d1_0.16b, v_tmp1_lo.16b, v_d1_0.16b
+ eor v_d1_0.16b, v_d1_0.16b, v_tmp1_hi.16b
+
+ str q_d1_0, [x_dest1]
+
+ add x_dest1, x_dest1, #16
+ add x_src, x_src, #16
+ cmp x_src, x_src_end
+ bls .Lloop16
+
+.lessthan16_init:
+ sub x_tmp, x_src, x_src_end
+ cmp x_tmp, #16
+ beq .return_pass
+
+.lessthan16:
+ mov x_src, x_src_end
+ sub x_dest1, x_dest1, x_tmp
+
+#ifndef __APPLE__
+ adrp x_const, const_tbl
+ add x_const, x_const, :lo12:const_tbl
+#else
+ adrp x_const, const_tbl@PAGE
+ add x_const, x_const, const_tbl@PAGEOFF
+#endif
+ sub x_const, x_const, x_tmp
+ ldr q_tmp, [x_const, #16]
+
+ ldr q_data, [x_src]
+ ldr q_d1_0, [x_dest1]
+
+ and v_data_lo.16b, v_data.16b, v_mask0f.16b
+ ushr v_data_hi.16b, v_data.16b, #4
+
+ tbl v_tmp1_lo.16b, {v_gft1_lo.16b}, v_data_lo.16b
+ tbl v_tmp1_hi.16b, {v_gft1_hi.16b}, v_data_hi.16b
+ eor v_tmp1_hi.16b, v_tmp1_lo.16b, v_tmp1_hi.16b
+ and v_tmp1_hi.16b, v_tmp1_hi.16b, v_tmp.16b
+ eor v_d1_0.16b, v_d1_0.16b, v_tmp1_hi.16b
+
+ str q_d1_0, [x_dest1]
+
+.return_pass:
+ mov w_ret, #0
+ ret
+
+.return_fail:
+ mov w_ret, #1
+ ret
+
+ASM_DEF_RODATA
+.balign 8
+const_tbl:
+ .dword 0x0000000000000000, 0x0000000000000000
+ .dword 0xffffffffffffffff, 0xffffffffffffffff
diff --git a/contrib/libs/isa-l/erasure_code/aarch64/gf_vect_mad_sve.S b/contrib/libs/isa-l/erasure_code/aarch64/gf_vect_mad_sve.S
new file mode 100644
index 0000000000..41d6da9d9a
--- /dev/null
+++ b/contrib/libs/isa-l/erasure_code/aarch64/gf_vect_mad_sve.S
@@ -0,0 +1,126 @@
+/**************************************************************
+ Copyright (c) 2021 Linaro Ltd.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name of Huawei Corporation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+**********************************************************************/
+.text
+.align 6
+.arch armv8-a+sve
+
+#include "../include/aarch64_label.h"
+
+.global cdecl(gf_vect_mad_sve)
+#ifndef __APPLE__
+.type gf_vect_mad_sve, %function
+#endif
+
+/* gf_vect_mad_sve(int len, int vec, int vec_i, unsigned char *gftbls,
+ unsigned char *src, unsigned char *dest);
+ */
+/* arguments */
+x_len .req x0
+x_vec .req x1
+x_vec_i .req x2
+x_tbl .req x3
+x_src .req x4
+x_dest .req x5
+
+/* returns */
+w_ret .req w0
+
+/* local variables */
+x_pos .req x6
+
+/* vectors */
+z_mask0f .req z0
+
+z_src .req z1
+z_src_lo .req z2
+z_src_hi .req z_src
+
+z_dest .req z3
+
+z_tmp1_lo .req z4
+z_tmp1_hi .req z5
+
+z_gft1_lo .req z6
+z_gft1_hi .req z7
+q_gft1_lo .req q6
+q_gft1_hi .req q7
+
+cdecl(gf_vect_mad_sve):
+ /* less than 16 bytes, return_fail */
+ cmp x_len, #16
+ blt .return_fail
+
+ mov z_mask0f.b, #0x0f /* z_mask0f = 0x0F0F...0F */
+ add x_tbl, x_tbl, x_vec_i, LSL #5 /* x_tbl += x_vec_i * 2^5 */
+
+ /* Load with NEON instruction ldp */
+ ldp q_gft1_lo, q_gft1_hi, [x_tbl]
+
+ mov x_pos, #0
+
+ /* vector length agnostic */
+.Lloopsve_vl:
+ whilelo p0.b, x_pos, x_len
+ b.none .return_pass
+
+ /* prefetch dest data */
+ prfb pldl2strm, p0, [x_dest, x_pos]
+
+ /* load src data, governed by p0 */
+ ld1b z_src.b, p0/z, [x_src, x_pos]
+
+ /* split 4-bit lo; 4-bit hi */
+ and z_src_lo.d, z_src.d, z_mask0f.d
+ lsr z_src_hi.b, z_src.b, #4
+
+ /* load dest data, governed by p0 */
+ ld1b z_dest.b, p0/z, [x_dest, x_pos]
+
+ /* table indexing, ie. gf(2^8) multiplication */
+ tbl z_tmp1_lo.b, {z_gft1_lo.b}, z_src_lo.b
+ tbl z_tmp1_hi.b, {z_gft1_hi.b}, z_src_hi.b
+
+ /* exclusive or, ie. gf(2^8) add */
+ eor z_dest.d, z_tmp1_lo.d, z_dest.d
+ eor z_dest.d, z_tmp1_hi.d, z_dest.d
+
+ /* store dest data, governed by p0 */
+ st1b z_dest.b, p0, [x_dest, x_pos]
+ /* increment one vector length */
+ incb x_pos
+
+ b .Lloopsve_vl
+
+.return_pass:
+ mov w_ret, #0
+ ret
+
+.return_fail:
+ mov w_ret, #1
+ ret
diff --git a/contrib/libs/isa-l/erasure_code/aarch64/gf_vect_mul_neon.S b/contrib/libs/isa-l/erasure_code/aarch64/gf_vect_mul_neon.S
new file mode 100644
index 0000000000..096b91dd29
--- /dev/null
+++ b/contrib/libs/isa-l/erasure_code/aarch64/gf_vect_mul_neon.S
@@ -0,0 +1,240 @@
+/**************************************************************
+ Copyright (c) 2019 Huawei Technologies Co., Ltd.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name of Huawei Corporation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+**********************************************************************/
+
+#include "../include/aarch64_label.h"
+
+.text
+
+.global cdecl(gf_vect_mul_neon)
+#ifndef __APPLE__
+.type gf_vect_mul_neon, %function
+#endif
+
+/* arguments */
+x_len .req x0
+x_tbl .req x1
+x_src .req x2
+x_dest .req x3
+
+/* returns */
+w_ret .req w0
+
+/* local variables */
+x_dest1 .req x_dest
+x_src_end .req x4
+x_tmp .req x5
+
+/* vectors */
+v_mask0f .req v0
+
+v_gft1_lo .req v2
+v_gft1_hi .req v3
+q_gft1_lo .req q2
+q_gft1_hi .req q3
+
+v_data_0 .req v16
+v_data_1 .req v17
+v_data_2 .req v18
+v_data_3 .req v19
+v_data_4 .req v20
+v_data_5 .req v21
+v_data_6 .req v22
+v_data_7 .req v23
+q_data_0 .req q16
+q_data_1 .req q17
+q_data_2 .req q18
+q_data_3 .req q19
+q_data_4 .req q20
+q_data_5 .req q21
+q_data_6 .req q22
+q_data_7 .req q23
+
+v_data_0_lo .req v24
+v_data_1_lo .req v25
+v_data_2_lo .req v26
+v_data_3_lo .req v27
+v_data_4_lo .req v28
+v_data_5_lo .req v29
+v_data_6_lo .req v30
+v_data_7_lo .req v31
+v_data_0_hi .req v_data_0
+v_data_1_hi .req v_data_1
+v_data_2_hi .req v_data_2
+v_data_3_hi .req v_data_3
+v_data_4_hi .req v_data_4
+v_data_5_hi .req v_data_5
+v_data_6_hi .req v_data_6
+v_data_7_hi .req v_data_7
+
+
+cdecl(gf_vect_mul_neon):
+ /* less than 32 bytes, return_fail */
+ cmp x_len, #32
+ blt .return_fail
+
+ movi v_mask0f.16b, #0x0f
+ add x_src_end, x_src, x_len
+ ldr q_gft1_lo, [x_tbl]
+ ldr q_gft1_hi, [x_tbl, #16]
+
+
+.Lloop128_init:
+ /* less than 128 bytes, goto Lloop16_init */
+ cmp x_len, #128
+ blt .Lloop32_init
+
+ /* save d8 ~ d15 to stack */
+ sub sp, sp, #64
+ stp d8, d9, [sp]
+ stp d10, d11, [sp, #16]
+ stp d12, d13, [sp, #32]
+ stp d14, d15, [sp, #48]
+
+ sub x_src_end, x_src_end, #128
+
+.Lloop128:
+ ldr q_data_0, [x_src, #16*0]
+ ldr q_data_1, [x_src, #16*1]
+ ldr q_data_2, [x_src, #16*2]
+ ldr q_data_3, [x_src, #16*3]
+ ldr q_data_4, [x_src, #16*4]
+ ldr q_data_5, [x_src, #16*5]
+ ldr q_data_6, [x_src, #16*6]
+ ldr q_data_7, [x_src, #16*7]
+
+ and v_data_0_lo.16b, v_data_0.16b, v_mask0f.16b
+ and v_data_1_lo.16b, v_data_1.16b, v_mask0f.16b
+ and v_data_2_lo.16b, v_data_2.16b, v_mask0f.16b
+ and v_data_3_lo.16b, v_data_3.16b, v_mask0f.16b
+ and v_data_4_lo.16b, v_data_4.16b, v_mask0f.16b
+ and v_data_5_lo.16b, v_data_5.16b, v_mask0f.16b
+ and v_data_6_lo.16b, v_data_6.16b, v_mask0f.16b
+ and v_data_7_lo.16b, v_data_7.16b, v_mask0f.16b
+
+ ushr v_data_0_hi.16b, v_data_0.16b, #4
+ ushr v_data_1_hi.16b, v_data_1.16b, #4
+ ushr v_data_2_hi.16b, v_data_2.16b, #4
+ ushr v_data_3_hi.16b, v_data_3.16b, #4
+ ushr v_data_4_hi.16b, v_data_4.16b, #4
+ ushr v_data_5_hi.16b, v_data_5.16b, #4
+ ushr v_data_6_hi.16b, v_data_6.16b, #4
+ ushr v_data_7_hi.16b, v_data_7.16b, #4
+
+ tbl v_data_0_lo.16b, {v_gft1_lo.16b}, v_data_0_lo.16b
+ tbl v_data_1_lo.16b, {v_gft1_lo.16b}, v_data_1_lo.16b
+ tbl v_data_2_lo.16b, {v_gft1_lo.16b}, v_data_2_lo.16b
+ tbl v_data_3_lo.16b, {v_gft1_lo.16b}, v_data_3_lo.16b
+ tbl v_data_4_lo.16b, {v_gft1_lo.16b}, v_data_4_lo.16b
+ tbl v_data_5_lo.16b, {v_gft1_lo.16b}, v_data_5_lo.16b
+ tbl v_data_6_lo.16b, {v_gft1_lo.16b}, v_data_6_lo.16b
+ tbl v_data_7_lo.16b, {v_gft1_lo.16b}, v_data_7_lo.16b
+
+ tbl v_data_0_hi.16b, {v_gft1_hi.16b}, v_data_0_hi.16b
+ tbl v_data_1_hi.16b, {v_gft1_hi.16b}, v_data_1_hi.16b
+ tbl v_data_2_hi.16b, {v_gft1_hi.16b}, v_data_2_hi.16b
+ tbl v_data_3_hi.16b, {v_gft1_hi.16b}, v_data_3_hi.16b
+ tbl v_data_4_hi.16b, {v_gft1_hi.16b}, v_data_4_hi.16b
+ tbl v_data_5_hi.16b, {v_gft1_hi.16b}, v_data_5_hi.16b
+ tbl v_data_6_hi.16b, {v_gft1_hi.16b}, v_data_6_hi.16b
+ tbl v_data_7_hi.16b, {v_gft1_hi.16b}, v_data_7_hi.16b
+
+ eor v_data_0.16b, v_data_0_hi.16b, v_data_0_lo.16b
+ eor v_data_1.16b, v_data_1_hi.16b, v_data_1_lo.16b
+ eor v_data_2.16b, v_data_2_hi.16b, v_data_2_lo.16b
+ eor v_data_3.16b, v_data_3_hi.16b, v_data_3_lo.16b
+ eor v_data_4.16b, v_data_4_hi.16b, v_data_4_lo.16b
+ eor v_data_5.16b, v_data_5_hi.16b, v_data_5_lo.16b
+ eor v_data_6.16b, v_data_6_hi.16b, v_data_6_lo.16b
+ eor v_data_7.16b, v_data_7_hi.16b, v_data_7_lo.16b
+
+ str q_data_0, [x_dest1, #16*0]
+ str q_data_1, [x_dest1, #16*1]
+ str q_data_2, [x_dest1, #16*2]
+ str q_data_3, [x_dest1, #16*3]
+ str q_data_4, [x_dest1, #16*4]
+ str q_data_5, [x_dest1, #16*5]
+ str q_data_6, [x_dest1, #16*6]
+ str q_data_7, [x_dest1, #16*7]
+
+ add x_src, x_src, #128
+ add x_dest1, x_dest1, #128
+ cmp x_src, x_src_end
+ bls .Lloop128
+
+.Lloop128_end:
+ /* restore d8 ~ d15 */
+ ldp d8, d9, [sp]
+ ldp d10, d11, [sp, #16]
+ ldp d12, d13, [sp, #32]
+ ldp d14, d15, [sp, #48]
+ add sp, sp, #64
+ add x_src_end, x_src_end, #128
+ cmp x_src, x_src_end
+ beq .return_pass
+
+.Lloop32_init:
+ sub x_src_end, x_src_end, #32
+ cmp x_src, x_src_end
+ bhi .return_fail
+
+.Lloop32:
+ ldr q_data_0, [x_src, #16*0]
+ ldr q_data_1, [x_src, #16*1]
+
+ and v_data_0_lo.16b, v_data_0.16b, v_mask0f.16b
+ and v_data_1_lo.16b, v_data_1.16b, v_mask0f.16b
+ ushr v_data_0_hi.16b, v_data_0.16b, #4
+ ushr v_data_1_hi.16b, v_data_1.16b, #4
+ tbl v_data_0_lo.16b, {v_gft1_lo.16b}, v_data_0_lo.16b
+ tbl v_data_1_lo.16b, {v_gft1_lo.16b}, v_data_1_lo.16b
+ tbl v_data_0_hi.16b, {v_gft1_hi.16b}, v_data_0_hi.16b
+ tbl v_data_1_hi.16b, {v_gft1_hi.16b}, v_data_1_hi.16b
+ eor v_data_0.16b, v_data_0_hi.16b, v_data_0_lo.16b
+ eor v_data_1.16b, v_data_1_hi.16b, v_data_1_lo.16b
+ str q_data_0, [x_dest1, #16*0]
+ str q_data_1, [x_dest1, #16*1]
+
+ add x_dest1, x_dest1, #32
+ add x_src, x_src, #32
+ cmp x_src, x_src_end
+ bls .Lloop32
+
+.Lloop32_end:
+ sub x_tmp, x_src, x_src_end
+ cmp x_tmp, #32
+ beq .return_pass
+ b .return_fail
+
+.return_pass:
+ mov w_ret, #0
+ ret
+
+.return_fail:
+ mov w_ret, #1
+ ret
diff --git a/contrib/libs/isa-l/erasure_code/aarch64/gf_vect_mul_sve.S b/contrib/libs/isa-l/erasure_code/aarch64/gf_vect_mul_sve.S
new file mode 100644
index 0000000000..d2219bf54c
--- /dev/null
+++ b/contrib/libs/isa-l/erasure_code/aarch64/gf_vect_mul_sve.S
@@ -0,0 +1,123 @@
+/**************************************************************
+ Copyright (c) 2021 Linaro Ltd.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name of Huawei Corporation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+**********************************************************************/
+.text
+.align 6
+.arch armv8-a+sve
+
+#include "../include/aarch64_label.h"
+
+.global cdecl(gf_vect_mul_sve)
+#ifndef __APPLE__
+.type gf_vect_mul_sve, %function
+#endif
+
+/* Refer to include/gf_vect_mul.h
+ *
+ * @param len Length of vector in bytes. Must be aligned to 32B.
+ * @param gftbl Pointer to 32-byte array of pre-calculated constants based on C.
+ * @param src Pointer to src data array. Must be aligned to 32B.
+ * @param dest Pointer to destination data array. Must be aligned to 32B.
+ * @returns 0 pass, other fail
+ *
+ * int gf_vect_mul(int len, unsigned char *gftbl, void *src, void *dest);
+ */
+
+/* arguments */
+x_len .req x0
+x_tbl .req x1
+x_src .req x2
+x_dest .req x3
+x_tmp .req x4
+
+/* returns */
+w_ret .req w0
+
+/* local variables */
+x_pos .req x5
+
+/* vectors */
+z_mask0f .req z0
+
+z_src .req z1
+z_src_lo .req z2
+z_src_hi .req z_src /* reuse */
+
+z_dest .req z3
+z_tmp1_lo .req z4
+z_tmp1_hi .req z_dest /* reuse */
+
+z_gft1_lo .req z6
+z_gft1_hi .req z7
+q_gft1_lo .req q6
+q_gft1_hi .req q7
+
+cdecl(gf_vect_mul_sve):
+ /* len not aligned to 32B, return_fail */
+ and x_tmp, x_len, #0x1f
+ cmp x_tmp, #0
+ bne .return_fail
+
+ mov z_mask0f.b, #0x0f /* z_mask0f = 0x0F0F...0F */
+ mov x_pos, #0
+
+ /* Load with NEON instruction ldp */
+ ldp q_gft1_lo, q_gft1_hi, [x_tbl]
+
+ /* vector length agnostic */
+.Lloopsve_vl:
+ whilelo p0.b, x_pos, x_len
+ b.none .return_pass
+
+ /* load src data, governed by p0 */
+ ld1b z_src.b, p0/z, [x_src, x_pos]
+
+ /* split 4-bit lo; 4-bit hi */
+ and z_src_lo.d, z_src.d, z_mask0f.d
+ lsr z_src_hi.b, z_src.b, #4
+
+ /* table indexing, ie. gf(2^8) multiplication */
+ tbl z_tmp1_lo.b, {z_gft1_lo.b}, z_src_lo.b
+ tbl z_tmp1_hi.b, {z_gft1_hi.b}, z_src_hi.b
+ /* exclusive or, ie. gf(2^8) add */
+ eor z_dest.d, z_tmp1_hi.d, z_tmp1_lo.d
+
+ /* store dest data, governed by p0 */
+ st1b z_dest.b, p0, [x_dest, x_pos]
+ /* increment one vector length */
+ incb x_pos
+
+ b .Lloopsve_vl
+
+.return_pass:
+ mov w_ret, #0
+ ret
+
+.return_fail:
+ mov w_ret, #1
+ ret
diff --git a/contrib/libs/isa-l/erasure_code/aarch64/ya.make b/contrib/libs/isa-l/erasure_code/aarch64/ya.make
new file mode 100644
index 0000000000..ba7f601cfa
--- /dev/null
+++ b/contrib/libs/isa-l/erasure_code/aarch64/ya.make
@@ -0,0 +1,51 @@
+LIBRARY()
+
+LICENSE(BSD-3-Clause)
+
+LICENSE_TEXTS(.yandex_meta/licenses.list.txt)
+
+VERSION(2.31)
+
+NO_UTIL()
+
+NO_COMPILER_WARNINGS()
+
+ADDINCL(
+ contrib/libs/isa-l/include
+)
+
+IF(ARCH_AARCH64)
+CFLAGS(-D__ASSEMBLY__)
+SRCS(
+ ec_multibinary_arm.S
+ gf_2vect_dot_prod_neon.S
+ gf_2vect_dot_prod_sve.S
+ gf_2vect_mad_neon.S
+ gf_2vect_mad_sve.S
+ gf_3vect_dot_prod_neon.S
+ gf_3vect_dot_prod_sve.S
+ gf_3vect_mad_neon.S
+ gf_3vect_mad_sve.S
+ gf_4vect_dot_prod_neon.S
+ gf_4vect_dot_prod_sve.S
+ gf_4vect_mad_neon.S
+ gf_4vect_mad_sve.S
+ gf_5vect_dot_prod_neon.S
+ gf_5vect_dot_prod_sve.S
+ gf_5vect_mad_neon.S
+ gf_5vect_mad_sve.S
+ gf_6vect_dot_prod_sve.S
+ gf_6vect_mad_neon.S
+ gf_6vect_mad_sve.S
+ gf_7vect_dot_prod_sve.S
+ gf_8vect_dot_prod_sve.S
+ gf_vect_dot_prod_neon.S
+ gf_vect_dot_prod_sve.S
+ gf_vect_mad_neon.S
+ gf_vect_mad_sve.S
+ gf_vect_mul_neon.S
+ gf_vect_mul_sve.S
+)
+ENDIF()
+
+END()
diff --git a/contrib/libs/isa-l/erasure_code/ec_base.c b/contrib/libs/isa-l/erasure_code/ec_base.c
index 9a8fbc759e..c076b517bf 100644
--- a/contrib/libs/isa-l/erasure_code/ec_base.c
+++ b/contrib/libs/isa-l/erasure_code/ec_base.c
@@ -29,10 +29,12 @@
#include <limits.h>
#include <string.h> // for memset
+#include <stdint.h>
+
#include "erasure_code.h"
#include "ec_base.h" // for GF tables
-void ec_init_tables(int k, int rows, unsigned char *a, unsigned char *g_tbls)
+void ec_init_tables_base(int k, int rows, unsigned char *a, unsigned char *g_tbls)
{
int i, j;
@@ -171,7 +173,7 @@ void gf_vect_mul_init(unsigned char c, unsigned char *tbl)
unsigned char c4 = (c2 << 1) ^ ((c2 & 0x80) ? 0x1d : 0); //Mult by GF{2}
unsigned char c8 = (c4 << 1) ^ ((c4 & 0x80) ? 0x1d : 0); //Mult by GF{2}
-#if __WORDSIZE == 64 || _WIN64 || __x86_64__
+#if (__WORDSIZE == 64 || _WIN64 || __x86_64__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
unsigned long long v1, v2, v4, v8, *t;
unsigned long long v10, v20, v40, v80;
unsigned char c17, c18, c20, c24;
@@ -331,41 +333,17 @@ void ec_encode_data_update_base(int len, int k, int rows, int vec_i, unsigned ch
}
}
-void gf_vect_mul_base(int len, unsigned char *a, unsigned char *src, unsigned char *dest)
+int gf_vect_mul_base(int len, unsigned char *a, unsigned char *src, unsigned char *dest)
{
//2nd element of table array is ref value used to fill it in
unsigned char c = a[1];
+
+ // Len must be aligned to 32B
+ if ((len % 32) != 0) {
+ return -1;
+ }
+
while (len-- > 0)
*dest++ = gf_mul_erasure(c, *src++);
+ return 0;
}
-
-struct slver {
- unsigned short snum;
- unsigned char ver;
- unsigned char core;
-};
-
-// Version info
-struct slver gf_vect_mul_init_slver_00020035;
-struct slver gf_vect_mul_init_slver = { 0x0035, 0x02, 0x00 };
-
-struct slver ec_encode_data_base_slver_00010135;
-struct slver ec_encode_data_base_slver = { 0x0135, 0x01, 0x00 };
-
-struct slver gf_vect_mul_base_slver_00010136;
-struct slver gf_vect_mul_base_slver = { 0x0136, 0x01, 0x00 };
-
-struct slver gf_vect_dot_prod_base_slver_00010137;
-struct slver gf_vect_dot_prod_base_slver = { 0x0137, 0x01, 0x00 };
-
-struct slver gf_mul_slver_00000214;
-struct slver gf_mul_slver = { 0x0214, 0x00, 0x00 };
-
-struct slver gf_invert_matrix_slver_00000215;
-struct slver gf_invert_matrix_slver = { 0x0215, 0x00, 0x00 };
-
-struct slver gf_gen_rs_matrix_slver_00000216;
-struct slver gf_gen_rs_matrix_slver = { 0x0216, 0x00, 0x00 };
-
-struct slver gf_gen_cauchy1_matrix_slver_00000217;
-struct slver gf_gen_cauchy1_matrix_slver = { 0x0217, 0x00, 0x00 };
diff --git a/contrib/libs/isa-l/erasure_code/ec_base.h b/contrib/libs/isa-l/erasure_code/ec_base.h
index 070b276652..ace384968b 100644
--- a/contrib/libs/isa-l/erasure_code/ec_base.h
+++ b/contrib/libs/isa-l/erasure_code/ec_base.h
@@ -30,6 +30,77 @@
#ifndef _EC_BASE_H_
#define _EC_BASE_H_
+#include <stdint.h>
+
+#define MAX_NUM_OUTPUTS_CALL 6
+
+static const uint64_t gf_table_gfni[256] = {
+ 0x0000000000000000, 0x102040810204080, 0x8001828488102040, 0x8103868c983060c0,
+ 0x408041c2c4881020, 0x418245cad4a850a0, 0xc081c3464c983060, 0xc183c74e5cb870e0,
+ 0x2040a061e2c48810, 0x2142a469f2e4c890, 0xa04122e56ad4a850, 0xa14326ed7af4e8d0,
+ 0x60c0e1a3264c9830, 0x61c2e5ab366cd8b0, 0xe0c16327ae5cb870, 0xe1c3672fbe7cf8f0,
+ 0x102050b071e2c488, 0x112254b861c28408, 0x9021d234f9f2e4c8, 0x9123d63ce9d2a448,
+ 0x50a01172b56ad4a8, 0x51a2157aa54a9428, 0xd0a193f63d7af4e8, 0xd1a397fe2d5ab468,
+ 0x3060f0d193264c98, 0x3162f4d983060c18, 0xb06172551b366cd8, 0xb163765d0b162c58,
+ 0x70e0b11357ae5cb8, 0x71e2b51b478e1c38, 0xf0e13397dfbe7cf8, 0xf1e3379fcf9e3c78,
+ 0x8810a8d83871e2c4, 0x8912acd02851a244, 0x08112a5cb061c284, 0x09132e54a0418204,
+ 0xc890e91afcf9f2e4, 0xc992ed12ecd9b264, 0x48916b9e74e9d2a4, 0x49936f9664c99224,
+ 0xa85008b9dab56ad4, 0xa9520cb1ca952a54, 0x28518a3d52a54a94, 0x29538e3542850a14,
+ 0xe8d0497b1e3d7af4, 0xe9d24d730e1d3a74, 0x68d1cbff962d5ab4, 0x69d3cff7860d1a34,
+ 0x9830f8684993264c, 0x9932fc6059b366cc, 0x18317aecc183060c, 0x19337ee4d1a3468c,
+ 0xd8b0b9aa8d1b366c, 0xd9b2bda29d3b76ec, 0x58b13b2e050b162c, 0x59b33f26152b56ac,
+ 0xb8705809ab57ae5c, 0xb9725c01bb77eedc, 0x3871da8d23478e1c, 0x3973de853367ce9c,
+ 0xf8f019cb6fdfbe7c, 0xf9f21dc37ffffefc, 0x78f19b4fe7cf9e3c, 0x79f39f47f7efdebc,
+ 0xc488d46c1c3871e2, 0xc58ad0640c183162, 0x448956e8942851a2, 0x458b52e084081122,
+ 0x840895aed8b061c2, 0x850a91a6c8902142, 0x0409172a50a04182, 0x050b132240800102,
+ 0xe4c8740dfefcf9f2, 0xe5ca7005eedcb972, 0x64c9f68976ecd9b2, 0x65cbf28166cc9932,
+ 0xa44835cf3a74e9d2, 0xa54a31c72a54a952, 0x2449b74bb264c992, 0x254bb343a2448912,
+ 0xd4a884dc6ddab56a, 0xd5aa80d47dfaf5ea, 0x54a90658e5ca952a, 0x55ab0250f5ead5aa,
+ 0x9428c51ea952a54a, 0x952ac116b972e5ca, 0x1429479a2142850a, 0x152b43923162c58a,
+ 0xf4e824bd8f1e3d7a, 0xf5ea20b59f3e7dfa, 0x74e9a639070e1d3a, 0x75eba231172e5dba,
+ 0xb468657f4b962d5a, 0xb56a61775bb66dda, 0x3469e7fbc3860d1a, 0x356be3f3d3a64d9a,
+ 0x4c987cb424499326, 0x4d9a78bc3469d3a6, 0xcc99fe30ac59b366, 0xcd9bfa38bc79f3e6,
+ 0x0c183d76e0c18306, 0x0d1a397ef0e1c386, 0x8c19bff268d1a346, 0x8d1bbbfa78f1e3c6,
+ 0x6cd8dcd5c68d1b36, 0x6ddad8ddd6ad5bb6, 0xecd95e514e9d3b76, 0xeddb5a595ebd7bf6,
+ 0x2c589d1702050b16, 0x2d5a991f12254b96, 0xac591f938a152b56, 0xad5b1b9b9a356bd6,
+ 0x5cb82c0455ab57ae, 0x5dba280c458b172e, 0xdcb9ae80ddbb77ee, 0xddbbaa88cd9b376e,
+ 0x1c386dc69123478e, 0x1d3a69ce8103070e, 0x9c39ef42193367ce, 0x9d3beb4a0913274e,
+ 0x7cf88c65b76fdfbe, 0x7dfa886da74f9f3e, 0xfcf90ee13f7ffffe, 0xfdfb0ae92f5fbf7e,
+ 0x3c78cda773e7cf9e, 0x3d7ac9af63c78f1e, 0xbc794f23fbf7efde, 0xbd7b4b2bebd7af5e,
+ 0xe2c46a368e1c3871, 0xe3c66e3e9e3c78f1, 0x62c5e8b2060c1831, 0x63c7ecba162c58b1,
+ 0xa2442bf44a942851, 0xa3462ffc5ab468d1, 0x2245a970c2840811, 0x2347ad78d2a44891,
+ 0xc284ca576cd8b061, 0xc386ce5f7cf8f0e1, 0x428548d3e4c89021, 0x43874cdbf4e8d0a1,
+ 0x82048b95a850a041, 0x83068f9db870e0c1, 0x0205091120408001, 0x03070d193060c081,
+ 0xf2e43a86fffefcf9, 0xf3e63e8eefdebc79, 0x72e5b80277eedcb9, 0x73e7bc0a67ce9c39,
+ 0xb2647b443b76ecd9, 0xb3667f4c2b56ac59, 0x3265f9c0b366cc99, 0x3367fdc8a3468c19,
+ 0xd2a49ae71d3a74e9, 0xd3a69eef0d1a3469, 0x52a51863952a54a9, 0x53a71c6b850a1429,
+ 0x9224db25d9b264c9, 0x9326df2dc9922449, 0x122559a151a24489, 0x13275da941820409,
+ 0x6ad4c2eeb66ddab5, 0x6bd6c6e6a64d9a35, 0xead5406a3e7dfaf5, 0xebd744622e5dba75,
+ 0x2a54832c72e5ca95, 0x2b56872462c58a15, 0xaa5501a8faf5ead5, 0xab5705a0ead5aa55,
+ 0x4a94628f54a952a5, 0x4b96668744891225, 0xca95e00bdcb972e5, 0xcb97e403cc993265,
+ 0x0a14234d90214285, 0x0b16274580010205, 0x8a15a1c9183162c5, 0x8b17a5c108112245,
+ 0x7af4925ec78f1e3d, 0x7bf69656d7af5ebd, 0xfaf510da4f9f3e7d, 0xfbf714d25fbf7efd,
+ 0x3a74d39c03070e1d, 0x3b76d79413274e9d, 0xba7551188b172e5d, 0xbb7755109b376edd,
+ 0x5ab4323f254b962d, 0x5bb63637356bd6ad, 0xdab5b0bbad5bb66d, 0xdbb7b4b3bd7bf6ed,
+ 0x1a3473fde1c3860d, 0x1b3677f5f1e3c68d, 0x9a35f17969d3a64d, 0x9b37f57179f3e6cd,
+ 0x264cbe5a92244993, 0x274eba5282040913, 0xa64d3cde1a3469d3, 0xa74f38d60a142953,
+ 0x66ccff9856ac59b3, 0x67cefb90468c1933, 0xe6cd7d1cdebc79f3, 0xe7cf7914ce9c3973,
+ 0x060c1e3b70e0c183, 0x070e1a3360c08103, 0x860d9cbff8f0e1c3, 0x870f98b7e8d0a143,
+ 0x468c5ff9b468d1a3, 0x478e5bf1a4489123, 0xc68ddd7d3c78f1e3, 0xc78fd9752c58b163,
+ 0x366ceeeae3c68d1b, 0x376eeae2f3e6cd9b, 0xb66d6c6e6bd6ad5b, 0xb76f68667bf6eddb,
+ 0x76ecaf28274e9d3b, 0x77eeab20376eddbb, 0xf6ed2dacaf5ebd7b, 0xf7ef29a4bf7efdfb,
+ 0x162c4e8b0102050b, 0x172e4a831122458b, 0x962dcc0f8912254b, 0x972fc807993265cb,
+ 0x56ac0f49c58a152b, 0x57ae0b41d5aa55ab, 0xd6ad8dcd4d9a356b, 0xd7af89c55dba75eb,
+ 0xae5c1682aa55ab57, 0xaf5e128aba75ebd7, 0x2e5d940622458b17, 0x2f5f900e3265cb97,
+ 0xeedc57406eddbb77, 0xefde53487efdfbf7, 0x6eddd5c4e6cd9b37, 0x6fdfd1ccf6eddbb7,
+ 0x8e1cb6e348912347, 0x8f1eb2eb58b163c7, 0x0e1d3467c0810307, 0x0f1f306fd0a14387,
+ 0xce9cf7218c193367, 0xcf9ef3299c3973e7, 0x4e9d75a504091327, 0x4f9f71ad142953a7,
+ 0xbe7c4632dbb76fdf, 0xbf7e423acb972f5f, 0x3e7dc4b653a74f9f, 0x3f7fc0be43870f1f,
+ 0xfefc07f01f3f7fff, 0xfffe03f80f1f3f7f, 0x7efd8574972f5fbf, 0x7fff817c870f1f3f,
+ 0x9e3ce6533973e7cf, 0x9f3ee25b2953a74f, 0x1e3d64d7b163c78f, 0x1f3f60dfa143870f,
+ 0xdebca791fdfbf7ef, 0xdfbea399eddbb76f, 0x5ebd251575ebd7af, 0x5fbf211d65cb972f
+};
+
// Global GF(256) tables
#ifndef GF_LARGE_TABLES
static const unsigned char gff_base[] = {
diff --git a/contrib/libs/isa-l/erasure_code/ec_base.patch b/contrib/libs/isa-l/erasure_code/ec_base.patch
deleted file mode 100644
index 86a927f8c3..0000000000
--- a/contrib/libs/isa-l/erasure_code/ec_base.patch
+++ /dev/null
@@ -1,44 +0,0 @@
-47c47
-< unsigned char gf_mul_erasure(unsigned char a, unsigned char b)
----
-> unsigned char gf_mul(unsigned char a, unsigned char b)
-86c86
-< p = gf_mul_erasure(p, gen);
----
-> p = gf_mul(p, gen);
-88c88
-< gen = gf_mul_erasure(gen, 2);
----
-> gen = gf_mul(gen, 2);
-147,148c147,148
-< in_mat[i * n + j] = gf_mul_erasure(in_mat[i * n + j], temp);
-< out_mat[i * n + j] = gf_mul_erasure(out_mat[i * n + j], temp);
----
-> in_mat[i * n + j] = gf_mul(in_mat[i * n + j], temp);
-> out_mat[i * n + j] = gf_mul(out_mat[i * n + j], temp);
-157,158c157,158
-< out_mat[j * n + k] ^= gf_mul_erasure(temp, out_mat[i * n + k]);
-< in_mat[j * n + k] ^= gf_mul_erasure(temp, in_mat[i * n + k]);
----
-> out_mat[j * n + k] ^= gf_mul(temp, out_mat[i * n + k]);
-> in_mat[j * n + k] ^= gf_mul(temp, in_mat[i * n + k]);
-283c283
-< s ^= gf_mul_erasure(src[j][i], v[j * 32 + 1]);
----
-> s ^= gf_mul(src[j][i], v[j * 32 + 1]);
-296c296
-< s ^= gf_mul_erasure(src[i], v[vec_i * 32 + 1]);
----
-> s ^= gf_mul(src[i], v[vec_i * 32 + 1]);
-311c311
-< s ^= gf_mul_erasure(src[j][i], v[j * 32 + l * srcs * 32 + 1]);
----
-> s ^= gf_mul(src[j][i], v[j * 32 + l * srcs * 32 + 1]);
-327c327
-< s ^= gf_mul_erasure(data[i], v[vec_i * 32 + l * k * 32 + 1]);
----
-> s ^= gf_mul(data[i], v[vec_i * 32 + l * k * 32 + 1]);
-339c339
-< *dest++ = gf_mul_erasure(c, *src++);
----
-> *dest++ = gf_mul(c, *src++);
diff --git a/contrib/libs/isa-l/erasure_code/ec_base_aliases.c b/contrib/libs/isa-l/erasure_code/ec_base_aliases.c
index d046ff61ad..705dfb685c 100644
--- a/contrib/libs/isa-l/erasure_code/ec_base_aliases.c
+++ b/contrib/libs/isa-l/erasure_code/ec_base_aliases.c
@@ -56,6 +56,10 @@ void ec_encode_data_update(int len, int k, int rows, int vec_i, unsigned char *v
int gf_vect_mul(int len, unsigned char *a, void *src, void *dest)
{
- gf_vect_mul_base(len, a, (unsigned char *)src, (unsigned char *)dest);
- return 0;
+ return gf_vect_mul_base(len, a, (unsigned char *)src, (unsigned char *)dest);
+}
+
+void ec_init_tables(int k, int rows, unsigned char *a, unsigned char *g_tbls)
+{
+ return ec_init_tables_base(k, rows, a, g_tbls);
}
diff --git a/contrib/libs/isa-l/erasure_code/ec_highlevel_func.c b/contrib/libs/isa-l/erasure_code/ec_highlevel_func.c
index c57d460a61..373cd33726 100644
--- a/contrib/libs/isa-l/erasure_code/ec_highlevel_func.c
+++ b/contrib/libs/isa-l/erasure_code/ec_highlevel_func.c
@@ -1,5 +1,5 @@
/**********************************************************************
- Copyright(c) 2011-2015 Intel Corporation All rights reserved.
+ Copyright(c) 2011-2019 Intel Corporation All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
@@ -28,6 +28,7 @@
**********************************************************************/
#include <limits.h>
#include "erasure_code.h"
+#include "ec_base.h" /* for GF tables */
#if __x86_64__ || __i386__ || _M_X64 || _M_IX86
void ec_encode_data_sse(int len, int k, int rows, unsigned char *g_tbls, unsigned char **data,
@@ -39,13 +40,19 @@ void ec_encode_data_sse(int len, int k, int rows, unsigned char *g_tbls, unsigne
return;
}
- while (rows >= 4) {
- gf_4vect_dot_prod_sse(len, k, g_tbls, data, coding);
- g_tbls += 4 * k * 32;
- coding += 4;
- rows -= 4;
+ while (rows >= 6) {
+ gf_6vect_dot_prod_sse(len, k, g_tbls, data, coding);
+ g_tbls += 6 * k * 32;
+ coding += 6;
+ rows -= 6;
}
switch (rows) {
+ case 5:
+ gf_5vect_dot_prod_sse(len, k, g_tbls, data, coding);
+ break;
+ case 4:
+ gf_4vect_dot_prod_sse(len, k, g_tbls, data, coding);
+ break;
case 3:
gf_3vect_dot_prod_sse(len, k, g_tbls, data, coding);
break;
@@ -69,13 +76,19 @@ void ec_encode_data_avx(int len, int k, int rows, unsigned char *g_tbls, unsigne
return;
}
- while (rows >= 4) {
- gf_4vect_dot_prod_avx(len, k, g_tbls, data, coding);
- g_tbls += 4 * k * 32;
- coding += 4;
- rows -= 4;
+ while (rows >= 6) {
+ gf_6vect_dot_prod_avx(len, k, g_tbls, data, coding);
+ g_tbls += 6 * k * 32;
+ coding += 6;
+ rows -= 6;
}
switch (rows) {
+ case 5:
+ gf_5vect_dot_prod_avx(len, k, g_tbls, data, coding);
+ break;
+ case 4:
+ gf_4vect_dot_prod_avx(len, k, g_tbls, data, coding);
+ break;
case 3:
gf_3vect_dot_prod_avx(len, k, g_tbls, data, coding);
break;
@@ -100,13 +113,19 @@ void ec_encode_data_avx2(int len, int k, int rows, unsigned char *g_tbls, unsign
return;
}
- while (rows >= 4) {
- gf_4vect_dot_prod_avx2(len, k, g_tbls, data, coding);
- g_tbls += 4 * k * 32;
- coding += 4;
- rows -= 4;
+ while (rows >= 6) {
+ gf_6vect_dot_prod_avx2(len, k, g_tbls, data, coding);
+ g_tbls += 6 * k * 32;
+ coding += 6;
+ rows -= 6;
}
switch (rows) {
+ case 5:
+ gf_5vect_dot_prod_avx2(len, k, g_tbls, data, coding);
+ break;
+ case 4:
+ gf_4vect_dot_prod_avx2(len, k, g_tbls, data, coding);
+ break;
case 3:
gf_3vect_dot_prod_avx2(len, k, g_tbls, data, coding);
break;
@@ -132,6 +151,10 @@ extern int gf_3vect_dot_prod_avx512(int len, int k, unsigned char *g_tbls,
unsigned char **data, unsigned char **coding);
extern int gf_4vect_dot_prod_avx512(int len, int k, unsigned char *g_tbls,
unsigned char **data, unsigned char **coding);
+extern int gf_5vect_dot_prod_avx512(int len, int k, unsigned char *g_tbls,
+ unsigned char **data, unsigned char **coding);
+extern int gf_6vect_dot_prod_avx512(int len, int k, unsigned char *g_tbls,
+ unsigned char **data, unsigned char **coding);
extern void gf_vect_mad_avx512(int len, int vec, int vec_i, unsigned char *gftbls,
unsigned char *src, unsigned char *dest);
extern void gf_2vect_mad_avx512(int len, int vec, int vec_i, unsigned char *gftbls,
@@ -140,6 +163,10 @@ extern void gf_3vect_mad_avx512(int len, int vec, int vec_i, unsigned char *gftb
unsigned char *src, unsigned char **dest);
extern void gf_4vect_mad_avx512(int len, int vec, int vec_i, unsigned char *gftbls,
unsigned char *src, unsigned char **dest);
+extern void gf_5vect_mad_avx512(int len, int vec, int vec_i, unsigned char *gftbls,
+ unsigned char *src, unsigned char **dest);
+extern void gf_6vect_mad_avx512(int len, int vec, int vec_i, unsigned char *gftbls,
+ unsigned char *src, unsigned char **dest);
void ec_encode_data_avx512(int len, int k, int rows, unsigned char *g_tbls,
unsigned char **data, unsigned char **coding)
@@ -150,13 +177,19 @@ void ec_encode_data_avx512(int len, int k, int rows, unsigned char *g_tbls,
return;
}
- while (rows >= 4) {
- gf_4vect_dot_prod_avx512(len, k, g_tbls, data, coding);
- g_tbls += 4 * k * 32;
- coding += 4;
- rows -= 4;
+ while (rows >= 6) {
+ gf_6vect_dot_prod_avx512(len, k, g_tbls, data, coding);
+ g_tbls += 6 * k * 32;
+ coding += 6;
+ rows -= 6;
}
switch (rows) {
+ case 5:
+ gf_5vect_dot_prod_avx512(len, k, g_tbls, data, coding);
+ break;
+ case 4:
+ gf_4vect_dot_prod_avx512(len, k, g_tbls, data, coding);
+ break;
case 3:
gf_3vect_dot_prod_avx512(len, k, g_tbls, data, coding);
break;
@@ -179,13 +212,19 @@ void ec_encode_data_update_avx512(int len, int k, int rows, int vec_i, unsigned
return;
}
- while (rows >= 4) {
- gf_4vect_mad_avx512(len, k, vec_i, g_tbls, data, coding);
- g_tbls += 4 * k * 32;
- coding += 4;
- rows -= 4;
+ while (rows >= 6) {
+ gf_6vect_mad_avx512(len, k, vec_i, g_tbls, data, coding);
+ g_tbls += 6 * k * 32;
+ coding += 6;
+ rows -= 6;
}
switch (rows) {
+ case 5:
+ gf_5vect_mad_avx512(len, k, vec_i, g_tbls, data, coding);
+ break;
+ case 4:
+ gf_4vect_mad_avx512(len, k, vec_i, g_tbls, data, coding);
+ break;
case 3:
gf_3vect_mad_avx512(len, k, vec_i, g_tbls, data, coding);
break;
@@ -200,6 +239,179 @@ void ec_encode_data_update_avx512(int len, int k, int rows, int vec_i, unsigned
}
}
+#if AS_FEATURE_LEVEL >= 10
+
+extern void gf_vect_dot_prod_avx512_gfni(int len, int k, unsigned char *g_tbls,
+ unsigned char **data, unsigned char *dest);
+extern void gf_2vect_dot_prod_avx512_gfni(int len, int k, unsigned char *g_tbls,
+ unsigned char **data, unsigned char **coding);
+extern void gf_3vect_dot_prod_avx512_gfni(int len, int k, unsigned char *g_tbls,
+ unsigned char **data, unsigned char **coding);
+extern void gf_4vect_dot_prod_avx512_gfni(int len, int k, unsigned char *g_tbls,
+ unsigned char **data, unsigned char **coding);
+extern void gf_5vect_dot_prod_avx512_gfni(int len, int k, unsigned char *g_tbls,
+ unsigned char **data, unsigned char **coding);
+extern void gf_6vect_dot_prod_avx512_gfni(int len, int k, unsigned char *g_tbls,
+ unsigned char **data, unsigned char **coding);
+
+extern void gf_vect_mad_avx512_gfni(int len, int vec, int vec_i, unsigned char *gftbls,
+ unsigned char *src, unsigned char *dest);
+extern void gf_2vect_mad_avx512_gfni(int len, int vec, int vec_i, unsigned char *gftbls,
+ unsigned char *src, unsigned char **dest);
+extern void gf_3vect_mad_avx512_gfni(int len, int vec, int vec_i, unsigned char *gftbls,
+ unsigned char *src, unsigned char **dest);
+extern void gf_4vect_mad_avx512_gfni(int len, int vec, int vec_i, unsigned char *gftbls,
+ unsigned char *src, unsigned char **dest);
+extern void gf_5vect_mad_avx512_gfni(int len, int vec, int vec_i, unsigned char *gftbls,
+ unsigned char *src, unsigned char **dest);
+extern void gf_6vect_mad_avx512_gfni(int len, int vec, int vec_i, unsigned char *gftbls,
+ unsigned char *src, unsigned char **dest);
+
+extern void gf_vect_dot_prod_avx2_gfni(int len, int k, unsigned char *g_tbls,
+ unsigned char **data, unsigned char *dest);
+extern void gf_2vect_dot_prod_avx2_gfni(int len, int k, unsigned char *g_tbls,
+ unsigned char **data, unsigned char **coding);
+extern void gf_3vect_dot_prod_avx2_gfni(int len, int k, unsigned char *g_tbls,
+ unsigned char **data, unsigned char **coding);
+extern void gf_vect_mad_avx2_gfni(int len, int vec, int vec_i, unsigned char *gftbls,
+ unsigned char *src, unsigned char *dest);
+extern void gf_2vect_mad_avx2_gfni(int len, int vec, int vec_i, unsigned char *gftbls,
+ unsigned char *src, unsigned char **dest);
+extern void gf_3vect_mad_avx2_gfni(int len, int vec, int vec_i, unsigned char *gftbls,
+ unsigned char *src, unsigned char **dest);
+extern void gf_4vect_mad_avx2_gfni(int len, int vec, int vec_i, unsigned char *gftbls,
+ unsigned char *src, unsigned char **dest);
+extern void gf_5vect_mad_avx2_gfni(int len, int vec, int vec_i, unsigned char *gftbls,
+ unsigned char *src, unsigned char **dest);
+
+void ec_init_tables_gfni(int k, int rows, unsigned char *a, unsigned char *g_tbls)
+{
+ int i, j;
+
+ uint64_t *g64 = (uint64_t *) g_tbls;
+
+ for (i = 0; i < rows; i++)
+ for (j = 0; j < k; j++)
+ *(g64++) = gf_table_gfni[*a++];
+
+}
+
+void ec_encode_data_avx512_gfni(int len, int k, int rows, unsigned char *g_tbls,
+ unsigned char **data, unsigned char **coding)
+{
+
+ while (rows >= 6) {
+ gf_6vect_dot_prod_avx512_gfni(len, k, g_tbls, data, coding);
+ g_tbls += 6 * k * 8;
+ coding += 6;
+ rows -= 6;
+ }
+ switch (rows) {
+ case 5:
+ gf_5vect_dot_prod_avx512_gfni(len, k, g_tbls, data, coding);
+ break;
+ case 4:
+ gf_4vect_dot_prod_avx512_gfni(len, k, g_tbls, data, coding);
+ break;
+ case 3:
+ gf_3vect_dot_prod_avx512_gfni(len, k, g_tbls, data, coding);
+ break;
+ case 2:
+ gf_2vect_dot_prod_avx512_gfni(len, k, g_tbls, data, coding);
+ break;
+ case 1:
+ gf_vect_dot_prod_avx512_gfni(len, k, g_tbls, data, *coding);
+ break;
+ case 0:
+ default:
+ break;
+ }
+}
+
+void ec_encode_data_avx2_gfni(int len, int k, int rows, unsigned char *g_tbls,
+ unsigned char **data, unsigned char **coding)
+{
+ while (rows >= 3) {
+ gf_3vect_dot_prod_avx2_gfni(len, k, g_tbls, data, coding);
+ g_tbls += 3 * k * 8;
+ coding += 3;
+ rows -= 3;
+ }
+ switch (rows) {
+ case 2:
+ gf_2vect_dot_prod_avx2_gfni(len, k, g_tbls, data, coding);
+ break;
+ case 1:
+ gf_vect_dot_prod_avx2_gfni(len, k, g_tbls, data, *coding);
+ break;
+ case 0:
+ default:
+ break;
+ }
+}
+
+void ec_encode_data_update_avx512_gfni(int len, int k, int rows, int vec_i,
+ unsigned char *g_tbls, unsigned char *data,
+ unsigned char **coding)
+{
+ while (rows >= 6) {
+ gf_6vect_mad_avx512_gfni(len, k, vec_i, g_tbls, data, coding);
+ g_tbls += 6 * k * 8;
+ coding += 6;
+ rows -= 6;
+ }
+ switch (rows) {
+ case 5:
+ gf_5vect_mad_avx512_gfni(len, k, vec_i, g_tbls, data, coding);
+ break;
+ case 4:
+ gf_4vect_mad_avx512_gfni(len, k, vec_i, g_tbls, data, coding);
+ break;
+ case 3:
+ gf_3vect_mad_avx512_gfni(len, k, vec_i, g_tbls, data, coding);
+ break;
+ case 2:
+ gf_2vect_mad_avx512_gfni(len, k, vec_i, g_tbls, data, coding);
+ break;
+ case 1:
+ gf_vect_mad_avx512_gfni(len, k, vec_i, g_tbls, data, *coding);
+ break;
+ case 0:
+ default:
+ break;
+ }
+}
+
+void ec_encode_data_update_avx2_gfni(int len, int k, int rows, int vec_i,
+ unsigned char *g_tbls, unsigned char *data,
+ unsigned char **coding)
+{
+ while (rows >= 5) {
+ gf_5vect_mad_avx2_gfni(len, k, vec_i, g_tbls, data, coding);
+ g_tbls += 5 * k * 8;
+ coding += 5;
+ rows -= 5;
+ }
+ switch (rows) {
+ case 4:
+ gf_4vect_mad_avx2_gfni(len, k, vec_i, g_tbls, data, coding);
+ break;
+ case 3:
+ gf_3vect_mad_avx2_gfni(len, k, vec_i, g_tbls, data, coding);
+ break;
+ case 2:
+ gf_2vect_mad_avx2_gfni(len, k, vec_i, g_tbls, data, coding);
+ break;
+ case 1:
+ gf_vect_mad_avx2_gfni(len, k, vec_i, g_tbls, data, *coding);
+ break;
+ case 0:
+ default:
+ break;
+ }
+}
+
+#endif // AS_FEATURE_LEVEL >= 10
#endif // HAVE_AS_KNOWS_AVX512
#if __WORDSIZE == 64 || _WIN64 || __x86_64__
@@ -321,16 +533,3 @@ void ec_encode_data_update_avx2(int len, int k, int rows, int vec_i, unsigned ch
#endif //__WORDSIZE == 64 || _WIN64 || __x86_64__
#endif //__x86_64__ || __i386__ || _M_X64 || _M_IX86
-
-struct slver {
- unsigned short snum;
- unsigned char ver;
- unsigned char core;
-};
-
-// Version info
-struct slver ec_init_tables_slver_00010068;
-struct slver ec_init_tables_slver = { 0x0068, 0x01, 0x00 };
-
-struct slver ec_encode_data_sse_slver_00020069;
-struct slver ec_encode_data_sse_slver = { 0x0069, 0x02, 0x00 };
diff --git a/contrib/libs/isa-l/erasure_code/ec_multibinary.asm b/contrib/libs/isa-l/erasure_code/ec_multibinary.asm
index a07f45d6f8..424687877d 100644
--- a/contrib/libs/isa-l/erasure_code/ec_multibinary.asm
+++ b/contrib/libs/isa-l/erasure_code/ec_multibinary.asm
@@ -53,6 +53,16 @@
extern gf_vect_mad_avx2
%endif
+%if (AS_FEATURE_LEVEL) >= 10
+ extern ec_init_tables_gfni
+ extern ec_encode_data_avx512_gfni
+ extern ec_encode_data_avx2_gfni
+ extern ec_encode_data_update_avx512_gfni
+ extern ec_encode_data_update_avx2_gfni
+%endif
+
+extern ec_init_tables_base
+
extern gf_vect_mul_base
extern ec_encode_data_base
extern ec_encode_data_update_base
@@ -71,6 +81,7 @@ mbin_interface gf_vect_dot_prod
mbin_interface gf_vect_mul
mbin_interface ec_encode_data_update
mbin_interface gf_vect_mad
+mbin_interface ec_init_tables
%ifidn __OUTPUT_FORMAT__, elf32
mbin_dispatch_init5 ec_encode_data, ec_encode_data_base, ec_encode_data_sse, ec_encode_data_avx, ec_encode_data_avx2
@@ -78,18 +89,13 @@ mbin_interface gf_vect_mad
mbin_dispatch_init2 gf_vect_mul, gf_vect_mul_base
mbin_dispatch_init2 ec_encode_data_update, ec_encode_data_update_base
mbin_dispatch_init2 gf_vect_mad, gf_vect_mad_base
+ mbin_dispatch_init2 ec_init_tables, ec_init_tables_base
%else
mbin_dispatch_init5 gf_vect_mul, gf_vect_mul_base, gf_vect_mul_sse, gf_vect_mul_avx, gf_vect_mul_avx
- mbin_dispatch_init6 ec_encode_data, ec_encode_data_base, ec_encode_data_sse, ec_encode_data_avx, ec_encode_data_avx2, ec_encode_data_avx512
- mbin_dispatch_init6 ec_encode_data_update, ec_encode_data_update_base, ec_encode_data_update_sse, ec_encode_data_update_avx, ec_encode_data_update_avx2, ec_encode_data_update_avx512
+ mbin_dispatch_init8 ec_encode_data, ec_encode_data_base, ec_encode_data_sse, ec_encode_data_avx, ec_encode_data_avx2, ec_encode_data_avx512, ec_encode_data_avx2_gfni, ec_encode_data_avx512_gfni
+ mbin_dispatch_init8 ec_encode_data_update, ec_encode_data_update_base, ec_encode_data_update_sse, ec_encode_data_update_avx, ec_encode_data_update_avx2, ec_encode_data_update_avx512, ec_encode_data_update_avx2_gfni, ec_encode_data_update_avx512_gfni
mbin_dispatch_init6 gf_vect_mad, gf_vect_mad_base, gf_vect_mad_sse, gf_vect_mad_avx, gf_vect_mad_avx2, gf_vect_mad_avx512
mbin_dispatch_init6 gf_vect_dot_prod, gf_vect_dot_prod_base, gf_vect_dot_prod_sse, gf_vect_dot_prod_avx, gf_vect_dot_prod_avx2, gf_vect_dot_prod_avx512
+ mbin_dispatch_init8 ec_init_tables, ec_init_tables_base, ec_init_tables_base, ec_init_tables_base, ec_init_tables_base, ec_init_tables_base, ec_init_tables_gfni, ec_init_tables_gfni
%endif
-
-;;; func core, ver, snum
-slversion ec_encode_data, 00, 06, 0133
-slversion gf_vect_mul, 00, 05, 0134
-slversion ec_encode_data_update, 00, 05, 0212
-slversion gf_vect_dot_prod, 00, 05, 0138
-slversion gf_vect_mad, 00, 04, 0213
diff --git a/contrib/libs/isa-l/erasure_code/ec_multibinary_darwin.asm b/contrib/libs/isa-l/erasure_code/ec_multibinary_darwin.asm
index 8c2537f562..c05ff5b720 100644
--- a/contrib/libs/isa-l/erasure_code/ec_multibinary_darwin.asm
+++ b/contrib/libs/isa-l/erasure_code/ec_multibinary_darwin.asm
@@ -53,6 +53,16 @@
extern _gf_vect_mad_avx2
%endif
+%if (AS_FEATURE_LEVEL) >= 10
+ extern _ec_init_tables_gfni
+ extern _ec_encode_data_avx512_gfni
+ extern _ec_encode_data_avx2_gfni
+ extern _ec_encode_data_update_avx512_gfni
+ extern _ec_encode_data_update_avx2_gfni
+%endif
+
+extern _ec_init_tables_base
+
extern _gf_vect_mul_base
extern _ec_encode_data_base
extern _ec_encode_data_update_base
@@ -71,6 +81,7 @@ mbin_interface _gf_vect_dot_prod
mbin_interface _gf_vect_mul
mbin_interface _ec_encode_data_update
mbin_interface _gf_vect_mad
+mbin_interface _ec_init_tables
%ifidn __OUTPUT_FORMAT__, elf32
mbin_dispatch_init5 _ec_encode_data, _ec_encode_data_base, _ec_encode_data_sse, _ec_encode_data_avx, _ec_encode_data_avx2
@@ -78,19 +89,13 @@ mbin_interface _gf_vect_mad
mbin_dispatch_init2 _gf_vect_mul, _gf_vect_mul_base
mbin_dispatch_init2 _ec_encode_data_update, _ec_encode_data_update_base
mbin_dispatch_init2 _gf_vect_mad, _gf_vect_mad_base
+ mbin_dispatch_init2 _ec_init_tables, _ec_init_tables_base
%else
mbin_dispatch_init5 _gf_vect_mul, _gf_vect_mul_base, _gf_vect_mul_sse, _gf_vect_mul_avx, _gf_vect_mul_avx
- mbin_dispatch_init6 _ec_encode_data, _ec_encode_data_base, _ec_encode_data_sse, _ec_encode_data_avx, _ec_encode_data_avx2, _ec_encode_data_avx512
- mbin_dispatch_init6 _ec_encode_data_update, _ec_encode_data_update_base, _ec_encode_data_update_sse, _ec_encode_data_update_avx, _ec_encode_data_update_avx2, _ec_encode_data_update_avx512
+ mbin_dispatch_init8 _ec_encode_data, _ec_encode_data_base, _ec_encode_data_sse, _ec_encode_data_avx, _ec_encode_data_avx2, _ec_encode_data_avx512, _ec_encode_data_avx2_gfni, _ec_encode_data_avx512_gfni
+ mbin_dispatch_init8 _ec_encode_data_update, _ec_encode_data_update_base, _ec_encode_data_update_sse, _ec_encode_data_update_avx, _ec_encode_data_update_avx2, _ec_encode_data_update_avx512, _ec_encode_data_update_avx2_gfni, _ec_encode_data_update_avx512_gfni
mbin_dispatch_init6 _gf_vect_mad, _gf_vect_mad_base, _gf_vect_mad_sse, _gf_vect_mad_avx, _gf_vect_mad_avx2, _gf_vect_mad_avx512
mbin_dispatch_init6 _gf_vect_dot_prod, _gf_vect_dot_prod_base, _gf_vect_dot_prod_sse, _gf_vect_dot_prod_avx, _gf_vect_dot_prod_avx2, _gf_vect_dot_prod_avx512
+ mbin_dispatch_init8 _ec_init_tables, _ec_init_tables_base, _ec_init_tables_base, _ec_init_tables_base, _ec_init_tables_base, _ec_init_tables_base, _ec_init_tables_gfni, _ec_init_tables_gfni
%endif
-
-
-;;; func core, ver, snum
-slversion ec_encode_data, 00, 06, 0133
-slversion gf_vect_mul, 00, 05, 0134
-slversion ec_encode_data_update, 00, 05, 0212
-slversion gf_vect_dot_prod, 00, 05, 0138
-slversion gf_vect_mad, 00, 04, 0213
diff --git a/contrib/libs/isa-l/erasure_code/erasure_code_base_perf.c b/contrib/libs/isa-l/erasure_code/erasure_code_base_perf.c
index 9587788d86..4fca10599d 100644
--- a/contrib/libs/isa-l/erasure_code/erasure_code_base_perf.c
+++ b/contrib/libs/isa-l/erasure_code/erasure_code_base_perf.c
@@ -30,25 +30,26 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h> // for memset, memcmp
+#include <assert.h>
#include "erasure_code.h"
#include "test.h"
-//#define CACHED_TEST
-#ifdef CACHED_TEST
+#ifndef GT_L3_CACHE
+# define GT_L3_CACHE 32*1024*1024 /* some number > last level cache */
+#endif
+
+#if !defined(COLD_TEST) && !defined(TEST_CUSTOM)
// Cached test, loop many times over small dataset
# define TEST_SOURCES 32
# define TEST_LEN(m) ((128*1024 / m) & ~(64-1))
# define TEST_TYPE_STR "_warm"
-#else
-# ifndef TEST_CUSTOM
+#elif defined (COLD_TEST)
// Uncached test. Pull from large mem base.
-# define TEST_SOURCES 32
-# define GT_L3_CACHE 32*1024*1024 /* some number > last level cache */
-# define TEST_LEN(m) ((GT_L3_CACHE / m) & ~(64-1))
-# define TEST_TYPE_STR "_cold"
-# else
-# define TEST_TYPE_STR "_cus"
-# endif
+# define TEST_SOURCES 32
+# define TEST_LEN(m) ((GT_L3_CACHE / m) & ~(64-1))
+# define TEST_TYPE_STR "_cold"
+#elif defined (TEST_CUSTOM)
+# define TEST_TYPE_STR "_cus"
#endif
#define MMAX TEST_SOURCES
@@ -60,7 +61,7 @@ typedef unsigned char u8;
void ec_encode_perf(int m, int k, u8 * a, u8 * g_tbls, u8 ** buffs)
{
- ec_init_tables(k, m - k, &a[k * k], g_tbls);
+ ec_init_tables_base(k, m - k, &a[k * k], g_tbls);
ec_encode_data_base(TEST_LEN(m), k, m - k, g_tbls, buffs, &buffs[k]);
}
@@ -88,7 +89,7 @@ int ec_decode_perf(int m, int k, u8 * a, u8 * g_tbls, u8 ** buffs, u8 * src_in_e
c[k * i + j] = d[k * src_err_list[i] + j];
// Recover data
- ec_init_tables(k, nerrs, c, g_tbls);
+ ec_init_tables_base(k, nerrs, c, g_tbls);
ec_encode_data_base(TEST_LEN(m), k, nerrs, g_tbls, recov, temp_buffs);
return 0;
@@ -112,10 +113,8 @@ int main(int argc, char *argv[])
printf("erasure_code_base_perf: %dx%d %d\n", m, TEST_LEN(m), nerrs);
- if (m > MMAX || k > KMAX || nerrs > (m - k)) {
- printf(" Input test parameter error\n");
- return -1;
- }
+ // check input parameters
+ assert(!(m > MMAX || k > KMAX || nerrs > (m - k)));
memcpy(src_err_list, err_list, nerrs);
memset(src_in_err, 0, TEST_SOURCES);
diff --git a/contrib/libs/isa-l/erasure_code/erasure_code_base_test.c b/contrib/libs/isa-l/erasure_code/erasure_code_base_test.c
index a87f33f9f4..ad48d8e448 100644
--- a/contrib/libs/isa-l/erasure_code/erasure_code_base_test.c
+++ b/contrib/libs/isa-l/erasure_code/erasure_code_base_test.c
@@ -30,10 +30,11 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h> // for memset, memcmp
+#include <assert.h>
#include "erasure_code.h"
-// #include "types.h"
+#include "test.h"
-#define TEST_LEN 512
+#define TEST_LEN 8192
#define TEST_SIZE (TEST_LEN/2)
#ifndef TEST_SOURCES
@@ -264,8 +265,7 @@ int main(int argc, char *argv[])
// Pick a first test
m = 9;
k = 5;
- if (m > MMAX || k > KMAX)
- return -1;
+ assert((m <= MMAX) && (k <= KMAX));
// Make random data
for (i = 0; i < k; i++)
@@ -278,7 +278,7 @@ int main(int argc, char *argv[])
gf_gen_rs_matrix(encode_matrix, m, k);
// Generate g_tbls from encode matrix encode_matrix
- ec_init_tables(k, m - k, &encode_matrix[k * k], g_tbls);
+ ec_init_tables_base(k, m - k, &encode_matrix[k * k], g_tbls);
// Perform matrix dot_prod for EC encoding
// using g_tbls from encode matrix encode_matrix
@@ -304,7 +304,7 @@ int main(int argc, char *argv[])
}
// Recover data
- ec_init_tables(k, nerrs, decode_matrix, g_tbls);
+ ec_init_tables_base(k, nerrs, decode_matrix, g_tbls);
ec_encode_data_base(TEST_LEN, k, nerrs, g_tbls, recov, &temp_buffs[k]);
for (i = 0; i < nerrs; i++) {
@@ -346,7 +346,7 @@ int main(int argc, char *argv[])
gf_gen_cauchy1_matrix(encode_matrix, m, k);
// Generate g_tbls from encode matrix encode_matrix
- ec_init_tables(k, m - k, &encode_matrix[k * k], g_tbls);
+ ec_init_tables_base(k, m - k, &encode_matrix[k * k], g_tbls);
// Perform matrix dot_prod for EC encoding
// using g_tbls from encode matrix encode_matrix
@@ -372,7 +372,7 @@ int main(int argc, char *argv[])
}
// Recover data
- ec_init_tables(k, nerrs, decode_matrix, g_tbls);
+ ec_init_tables_base(k, nerrs, decode_matrix, g_tbls);
ec_encode_data_base(TEST_LEN, k, nerrs, g_tbls, recov, &temp_buffs[k]);
for (i = 0; i < nerrs; i++) {
@@ -417,7 +417,7 @@ int main(int argc, char *argv[])
// Make parity vects
// Generate g_tbls from encode matrix a
- ec_init_tables(k, m - k, &encode_matrix[k * k], g_tbls);
+ ec_init_tables_base(k, m - k, &encode_matrix[k * k], g_tbls);
// Perform matrix dot_prod for EC encoding
// using g_tbls from encode matrix a
ec_encode_data_base(TEST_LEN, k, m - k, g_tbls, buffs, &buffs[k]);
@@ -442,7 +442,7 @@ int main(int argc, char *argv[])
}
// Recover data
- ec_init_tables(k, nerrs, decode_matrix, g_tbls);
+ ec_init_tables_base(k, nerrs, decode_matrix, g_tbls);
ec_encode_data_base(TEST_LEN, k, nerrs, g_tbls, recov, &temp_buffs[k]);
for (i = 0; i < nerrs; i++) {
@@ -470,7 +470,9 @@ int main(int argc, char *argv[])
return -1;
}
}
+#ifdef TEST_VERBOSE
putchar('.');
+#endif
}
// Run tests at end of buffer for Electric Fence
@@ -500,7 +502,7 @@ int main(int argc, char *argv[])
// Make parity vects
// Generate g_tbls from encode matrix a
- ec_init_tables(k, m - k, &encode_matrix[k * k], g_tbls);
+ ec_init_tables_base(k, m - k, &encode_matrix[k * k], g_tbls);
// Perform matrix dot_prod for EC encoding
// using g_tbls from encode matrix a
ec_encode_data_base(size, k, m - k, g_tbls, efence_buffs,
@@ -526,7 +528,7 @@ int main(int argc, char *argv[])
}
// Recover data
- ec_init_tables(k, nerrs, decode_matrix, g_tbls);
+ ec_init_tables_base(k, nerrs, decode_matrix, g_tbls);
ec_encode_data_base(size, k, nerrs, g_tbls, recov, &temp_buffs[k]);
for (i = 0; i < nerrs; i++) {
@@ -593,7 +595,7 @@ int main(int argc, char *argv[])
// Make parity vects
// Generate g_tbls from encode matrix a
- ec_init_tables(k, m - k, &encode_matrix[k * k], g_tbls);
+ ec_init_tables_base(k, m - k, &encode_matrix[k * k], g_tbls);
// Perform matrix dot_prod for EC encoding
// using g_tbls from encode matrix a
ec_encode_data_base(size, k, m - k, g_tbls, ubuffs, &ubuffs[k]);
@@ -618,7 +620,7 @@ int main(int argc, char *argv[])
}
// Recover data
- ec_init_tables(k, nerrs, decode_matrix, g_tbls);
+ ec_init_tables_base(k, nerrs, decode_matrix, g_tbls);
ec_encode_data_base(size, k, nerrs, g_tbls, recov, &temp_ubuffs[k]);
for (i = 0; i < nerrs; i++) {
@@ -681,7 +683,9 @@ int main(int argc, char *argv[])
}
}
+#ifdef TEST_VERBOSE
putchar('.');
+#endif
}
// Test size alignment
@@ -705,7 +709,7 @@ int main(int argc, char *argv[])
// Make parity vects
// Generate g_tbls from encode matrix a
- ec_init_tables(k, m - k, &encode_matrix[k * k], g_tbls);
+ ec_init_tables_base(k, m - k, &encode_matrix[k * k], g_tbls);
// Perform matrix dot_prod for EC encoding
// using g_tbls from encode matrix a
ec_encode_data_base(size, k, m - k, g_tbls, buffs, &buffs[k]);
@@ -729,7 +733,7 @@ int main(int argc, char *argv[])
}
// Recover data
- ec_init_tables(k, nerrs, decode_matrix, g_tbls);
+ ec_init_tables_base(k, nerrs, decode_matrix, g_tbls);
ec_encode_data_base(size, k, nerrs, g_tbls, recov, &temp_buffs[k]);
for (i = 0; i < nerrs; i++) {
diff --git a/contrib/libs/isa-l/erasure_code/erasure_code_base_test.patch b/contrib/libs/isa-l/erasure_code/erasure_code_base_test.patch
deleted file mode 100644
index 0d84217177..0000000000
--- a/contrib/libs/isa-l/erasure_code/erasure_code_base_test.patch
+++ /dev/null
@@ -1,12 +0,0 @@
-34c34
-< // #include "types.h"
----
-> #include "types.h"
-36c36
-< #define TEST_LEN 512
----
-> #define TEST_LEN 8192
-204c204
-< s ^= gf_mul_erasure(invert_matrix[j * k + i],
----
-> s ^= gf_mul(invert_matrix[j * k + i],
diff --git a/contrib/libs/isa-l/erasure_code/erasure_code_perf.c b/contrib/libs/isa-l/erasure_code/erasure_code_perf.c
index c4cad880f1..25c8774507 100644
--- a/contrib/libs/isa-l/erasure_code/erasure_code_perf.c
+++ b/contrib/libs/isa-l/erasure_code/erasure_code_perf.c
@@ -33,22 +33,25 @@
#include "erasure_code.h"
#include "test.h"
-//#define CACHED_TEST
-#ifdef CACHED_TEST
+#ifndef GT_L3_CACHE
+# define GT_L3_CACHE 32*1024*1024 /* some number > last level cache */
+#endif
+
+#if !defined(COLD_TEST) && !defined(TEST_CUSTOM)
// Cached test, loop many times over small dataset
# define TEST_SOURCES 32
# define TEST_LEN(m) ((128*1024 / m) & ~(64-1))
# define TEST_TYPE_STR "_warm"
-#else
-# ifndef TEST_CUSTOM
+#elif defined (COLD_TEST)
// Uncached test. Pull from large mem base.
-# define TEST_SOURCES 32
-# define GT_L3_CACHE 32*1024*1024 /* some number > last level cache */
-# define TEST_LEN(m) ((GT_L3_CACHE / m) & ~(64-1))
-# define TEST_TYPE_STR "_cold"
-# else
-# define TEST_TYPE_STR "_cus"
-# endif
+# define TEST_SOURCES 32
+# define TEST_LEN(m) ((GT_L3_CACHE / m) & ~(64-1))
+# define TEST_TYPE_STR "_cold"
+#elif defined (TEST_CUSTOM)
+# define TEST_TYPE_STR "_cus"
+#endif
+#ifndef TEST_SEED
+# define TEST_SEED 0x1234
#endif
#define MMAX TEST_SOURCES
@@ -58,14 +61,26 @@
typedef unsigned char u8;
-void ec_encode_perf(int m, int k, u8 * a, u8 * g_tbls, u8 ** buffs)
+void usage(const char *app_name)
+{
+ fprintf(stderr,
+ "Usage: %s [options]\n"
+ " -h Help\n"
+ " -k <val> Number of source buffers\n"
+ " -p <val> Number of parity buffers\n"
+ " -e <val> Number of simulated buffers with errors (cannot be higher than p or k)\n",
+ app_name);
+}
+
+void ec_encode_perf(int m, int k, u8 * a, u8 * g_tbls, u8 ** buffs, struct perf *start)
{
ec_init_tables(k, m - k, &a[k * k], g_tbls);
- ec_encode_data(TEST_LEN(m), k, m - k, g_tbls, buffs, &buffs[k]);
+ BENCHMARK(start, BENCHMARK_TIME,
+ ec_encode_data(TEST_LEN(m), k, m - k, g_tbls, buffs, &buffs[k]));
}
int ec_decode_perf(int m, int k, u8 * a, u8 * g_tbls, u8 ** buffs, u8 * src_in_err,
- u8 * src_err_list, int nerrs, u8 ** temp_buffs)
+ u8 * src_err_list, int nerrs, u8 ** temp_buffs, struct perf *start)
{
int i, j, r;
u8 b[MMAX * KMAX], c[MMAX * KMAX], d[MMAX * KMAX];
@@ -89,34 +104,109 @@ int ec_decode_perf(int m, int k, u8 * a, u8 * g_tbls, u8 ** buffs, u8 * src_in_e
// Recover data
ec_init_tables(k, nerrs, c, g_tbls);
- ec_encode_data(TEST_LEN(m), k, nerrs, g_tbls, recov, temp_buffs);
+ BENCHMARK(start, BENCHMARK_TIME,
+ ec_encode_data(TEST_LEN(m), k, nerrs, g_tbls, recov, temp_buffs));
return 0;
}
int main(int argc, char *argv[])
{
- int i, j, m, k, nerrs, check;
+ int i, j, m, k, p, nerrs, check, ret = -1;
void *buf;
- u8 *temp_buffs[TEST_SOURCES], *buffs[TEST_SOURCES];
+ u8 *temp_buffs[TEST_SOURCES] = { NULL };
+ u8 *buffs[TEST_SOURCES] = { NULL };
u8 a[MMAX * KMAX];
u8 g_tbls[KMAX * TEST_SOURCES * 32], src_in_err[TEST_SOURCES];
u8 src_err_list[TEST_SOURCES];
struct perf start;
- // Pick test parameters
- m = 14;
- k = 10;
+ /* Set default parameters */
+ k = 8;
+ p = 6;
nerrs = 4;
- const u8 err_list[] = { 2, 4, 5, 7 };
- printf("erasure_code_perf: %dx%d %d\n", m, TEST_LEN(m), nerrs);
+ /* Parse arguments */
+ for (i = 1; i < argc; i++) {
+ if (strcmp(argv[i], "-k") == 0) {
+ k = atoi(argv[++i]);
+ } else if (strcmp(argv[i], "-p") == 0) {
+ p = atoi(argv[++i]);
+ } else if (strcmp(argv[i], "-e") == 0) {
+ nerrs = atoi(argv[++i]);
+ } else if (strcmp(argv[i], "-h") == 0) {
+ usage(argv[0]);
+ return 0;
+ } else {
+ usage(argv[0]);
+ return -1;
+ }
+ }
+
+ if (nerrs > k) {
+ printf
+ ("Number of errors (%d) cannot be higher than number of data buffers (%d)\n",
+ nerrs, k);
+ return -1;
+ }
+
+ if (k <= 0) {
+ printf("Number of source buffers (%d) must be > 0\n", k);
+ return -1;
+ }
+
+ if (p <= 0) {
+ printf("Number of parity buffers (%d) must be > 0\n", p);
+ return -1;
+ }
+
+ if (nerrs <= 0) {
+ printf("Number of errors (%d) must be > 0\n", nerrs);
+ return -1;
+ }
- if (m > MMAX || k > KMAX || nerrs > (m - k)) {
- printf(" Input test parameter error\n");
+ if (nerrs > p) {
+ printf
+ ("Number of errors (%d) cannot be higher than number of parity buffers (%d)\n",
+ nerrs, p);
return -1;
}
+ m = k + p;
+
+ if (m > MMAX) {
+ printf("Number of total buffers (data and parity) cannot be higher than %d\n",
+ MMAX);
+ return -1;
+ }
+
+ u8 *err_list = malloc((size_t)nerrs);
+ if (err_list == NULL) {
+ printf("Error allocating list of array of error indices\n");
+ return -1;
+ }
+
+ srand(TEST_SEED);
+
+ for (i = 0; i < nerrs;) {
+ u8 next_err = rand() % k;
+ for (j = 0; j < i; j++)
+ if (next_err == err_list[j])
+ break;
+ if (j != i)
+ continue;
+ err_list[i++] = next_err;
+ }
+
+ printf("Testing with %u data buffers and %u parity buffers (num errors = %u, in [ ", k,
+ p, nerrs);
+ for (i = 0; i < nerrs; i++)
+ printf("%d ", (int)err_list[i]);
+
+ printf("])\n");
+
+ printf("erasure_code_perf: %dx%d %d\n", m, TEST_LEN(m), nerrs);
+
memcpy(src_err_list, err_list, nerrs);
memset(src_in_err, 0, TEST_SOURCES);
for (i = 0; i < nerrs; i++)
@@ -125,16 +215,16 @@ int main(int argc, char *argv[])
// Allocate the arrays
for (i = 0; i < m; i++) {
if (posix_memalign(&buf, 64, TEST_LEN(m))) {
- printf("alloc error: Fail\n");
- return -1;
+ printf("Error allocating buffers\n");
+ goto exit;
}
buffs[i] = buf;
}
- for (i = 0; i < (m - k); i++) {
+ for (i = 0; i < p; i++) {
if (posix_memalign(&buf, 64, TEST_LEN(m))) {
- printf("alloc error: Fail\n");
- return -1;
+ printf("Error allocating buffers\n");
+ goto exit;
}
temp_buffs[i] = buf;
}
@@ -147,24 +237,24 @@ int main(int argc, char *argv[])
gf_gen_rs_matrix(a, m, k);
// Start encode test
- BENCHMARK(&start, BENCHMARK_TIME, ec_encode_perf(m, k, a, g_tbls, buffs));
+ ec_encode_perf(m, k, a, g_tbls, buffs, &start);
printf("erasure_code_encode" TEST_TYPE_STR ": ");
perf_print(start, (long long)(TEST_LEN(m)) * (m));
// Start decode test
- BENCHMARK(&start, BENCHMARK_TIME, check =
- ec_decode_perf(m, k, a, g_tbls, buffs, src_in_err, src_err_list, nerrs,
- temp_buffs));
+ check = ec_decode_perf(m, k, a, g_tbls, buffs, src_in_err, src_err_list, nerrs,
+ temp_buffs, &start);
if (check == BAD_MATRIX) {
printf("BAD MATRIX\n");
- return check;
+ ret = check;
+ goto exit;
}
for (i = 0; i < nerrs; i++) {
if (0 != memcmp(temp_buffs[i], buffs[src_err_list[i]], TEST_LEN(m))) {
printf("Fail error recovery (%d, %d, %d) - ", m, k, nerrs);
- return -1;
+ goto exit;
}
}
@@ -172,5 +262,14 @@ int main(int argc, char *argv[])
perf_print(start, (long long)(TEST_LEN(m)) * (k + nerrs));
printf("done all: Pass\n");
- return 0;
+
+ ret = 0;
+
+ exit:
+ free(err_list);
+ for (i = 0; i < TEST_SOURCES; i++) {
+ free(buffs[i]);
+ free(temp_buffs[i]);
+ }
+ return ret;
}
diff --git a/contrib/libs/isa-l/erasure_code/erasure_code_test.c b/contrib/libs/isa-l/erasure_code/erasure_code_test.c
index 16a6457e4e..f45b38a06a 100644
--- a/contrib/libs/isa-l/erasure_code/erasure_code_test.c
+++ b/contrib/libs/isa-l/erasure_code/erasure_code_test.c
@@ -30,8 +30,9 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h> // for memset, memcmp
+#include <assert.h>
#include "erasure_code.h"
-// #include "types.h"
+#include "test.h"
#define TEST_LEN 8192
#define TEST_SIZE (TEST_LEN/2)
@@ -215,13 +216,14 @@ static int gf_gen_decode_matrix(unsigned char *encode_matrix,
int main(int argc, char *argv[])
{
- int re = 0;
+ int re = -1;
int i, j, p, rtest, m, k;
int nerrs, nsrcerrs;
void *buf;
unsigned int decode_index[MMAX];
- unsigned char *temp_buffs[TEST_SOURCES], *buffs[TEST_SOURCES];
- unsigned char *encode_matrix, *decode_matrix, *invert_matrix, *g_tbls;
+ unsigned char *temp_buffs[TEST_SOURCES] = { NULL }, *buffs[TEST_SOURCES] = { NULL };
+ unsigned char *encode_matrix = NULL, *decode_matrix = NULL, *invert_matrix =
+ NULL, *g_tbls = NULL;
unsigned char src_in_err[TEST_SOURCES], src_err_list[TEST_SOURCES];
unsigned char *recov[TEST_SOURCES];
@@ -238,7 +240,7 @@ int main(int argc, char *argv[])
for (i = 0; i < TEST_SOURCES; i++) {
if (posix_memalign(&buf, 64, TEST_LEN)) {
printf("alloc error: Fail");
- return -1;
+ goto exit;
}
buffs[i] = buf;
}
@@ -246,7 +248,7 @@ int main(int argc, char *argv[])
for (i = 0; i < TEST_SOURCES; i++) {
if (posix_memalign(&buf, 64, TEST_LEN)) {
printf("alloc error: Fail");
- return -1;
+ goto exit;
}
temp_buffs[i] = buf;
}
@@ -260,13 +262,12 @@ int main(int argc, char *argv[])
if (encode_matrix == NULL || decode_matrix == NULL
|| invert_matrix == NULL || g_tbls == NULL) {
printf("Test failure! Error with malloc\n");
- return -1;
+ goto exit;
}
// Pick a first test
m = 9;
k = 5;
- if (m > MMAX || k > KMAX)
- return -1;
+ assert((m <= MMAX) && (k <= KMAX));
// Make random data
for (i = 0; i < k; i++)
@@ -295,7 +296,7 @@ int main(int argc, char *argv[])
nerrs, nsrcerrs, k, m);
if (re != 0) {
printf("Fail to gf_gen_decode_matrix\n");
- return -1;
+ goto exit;
}
// Pack recovery array as list of valid sources
// Its order must be the same as the order
@@ -327,15 +328,18 @@ int main(int argc, char *argv[])
dump(temp_buffs[k + i], 25);
printf("orig :");
dump(buffs[src_err_list[i]], 25);
- return -1;
+ re = -1;
+ goto exit;
}
}
// Pick a first test
m = 9;
k = 5;
- if (m > MMAX || k > KMAX)
- return -1;
+ if (m > MMAX || k > KMAX) {
+ re = -1;
+ goto exit;
+ }
// Make random data
for (i = 0; i < k; i++)
@@ -363,7 +367,7 @@ int main(int argc, char *argv[])
nerrs, nsrcerrs, k, m);
if (re != 0) {
printf("Fail to gf_gen_decode_matrix\n");
- return -1;
+ goto exit;
}
// Pack recovery array as list of valid sources
// Its order must be the same as the order
@@ -395,7 +399,8 @@ int main(int argc, char *argv[])
dump(temp_buffs[k + i], 25);
printf("orig :");
dump(buffs[src_err_list[i]], 25);
- return -1;
+ re = -1;
+ goto exit;
}
}
@@ -433,7 +438,7 @@ int main(int argc, char *argv[])
src_in_err, nerrs, nsrcerrs, k, m);
if (re != 0) {
printf("Fail to gf_gen_decode_matrix\n");
- return -1;
+ goto exit;
}
// Pack recovery array as list of valid sources
// Its order must be the same as the order
@@ -468,22 +473,29 @@ int main(int argc, char *argv[])
dump(buffs[src_err_list[i]], 25);
printf("recov %d:", src_err_list[i]);
dump(temp_buffs[k + i], 25);
- return -1;
+ re = -1;
+ goto exit;
}
}
+#ifdef TEST_VERBOSE
putchar('.');
+#endif
}
// Run tests at end of buffer for Electric Fence
k = 16;
align = (LEN_ALIGN_CHK_B != 0) ? 1 : 16;
- if (k > KMAX)
- return -1;
+ if (k > KMAX) {
+ re = -1;
+ goto exit;
+ }
for (rows = 1; rows <= 16; rows++) {
m = k + rows;
- if (m > MMAX)
- return -1;
+ if (m > MMAX) {
+ re = -1;
+ goto exit;
+ }
// Make random data
for (i = 0; i < k; i++)
@@ -516,7 +528,7 @@ int main(int argc, char *argv[])
src_in_err, nerrs, nsrcerrs, k, m);
if (re != 0) {
printf("Fail to gf_gen_decode_matrix\n");
- return -1;
+ goto exit;
}
// Pack recovery array as list of valid sources
// Its order must be the same as the order
@@ -556,7 +568,8 @@ int main(int argc, char *argv[])
dump(temp_buffs[k + i], align);
printf("orig :");
dump(efence_buffs[src_err_list[i]], align);
- return -1;
+ re = -1;
+ goto exit;
}
}
}
@@ -608,7 +621,7 @@ int main(int argc, char *argv[])
src_in_err, nerrs, nsrcerrs, k, m);
if (re != 0) {
printf("Fail to gf_gen_decode_matrix\n");
- return -1;
+ goto exit;
}
// Pack recovery array as list of valid sources
// Its order must be the same as the order
@@ -643,7 +656,8 @@ int main(int argc, char *argv[])
dump(ubuffs[src_err_list[i]], 25);
printf("recov %d:", src_err_list[i]);
dump(temp_ubuffs[k + i], 25);
- return -1;
+ re = -1;
+ goto exit;
}
}
@@ -656,13 +670,15 @@ int main(int argc, char *argv[])
if (memcmp(buffs[i], temp_buffs[0], offset)) {
printf("Fail rand ualign encode pad start\n");
- return -1;
+ re = -1;
+ goto exit;
}
if (memcmp
(buffs[i] + offset + size, temp_buffs[0],
PTR_ALIGN_CHK_B - offset)) {
printf("Fail rand ualign encode pad end\n");
- return -1;
+ re = -1;
+ goto exit;
}
}
@@ -671,17 +687,21 @@ int main(int argc, char *argv[])
offset = temp_ubuffs[k + i] - temp_buffs[k + i];
if (memcmp(temp_buffs[k + i], temp_buffs[0], offset)) {
printf("Fail rand ualign decode pad start\n");
- return -1;
+ re = -1;
+ goto exit;
}
if (memcmp
(temp_buffs[k + i] + offset + size, temp_buffs[0],
PTR_ALIGN_CHK_B - offset)) {
printf("Fail rand ualign decode pad end\n");
- return -1;
+ re = -1;
+ goto exit;
}
}
+#ifdef TEST_VERBOSE
putchar('.');
+#endif
}
// Test size alignment
@@ -719,7 +739,7 @@ int main(int argc, char *argv[])
src_in_err, nerrs, nsrcerrs, k, m);
if (re != 0) {
printf("Fail to gf_gen_decode_matrix\n");
- return -1;
+ goto exit;
}
// Pack recovery array as list of valid sources
// Its order must be the same as the order
@@ -754,11 +774,26 @@ int main(int argc, char *argv[])
dump(buffs[src_err_list[i]], 25);
printf("recov %d:", src_err_list[i]);
dump(temp_buffs[k + i], 25);
- return -1;
+ re = -1;
+ goto exit;
}
}
}
printf("done EC tests: Pass\n");
- return 0;
+ re = 0;
+
+ exit:
+ for (i = 0; i < TEST_SOURCES; i++) {
+ if (buffs[i])
+ aligned_free(buffs[i]);
+ if (temp_buffs[i])
+ aligned_free(temp_buffs[i]);
+ }
+ free(encode_matrix);
+ free(decode_matrix);
+ free(invert_matrix);
+ free(g_tbls);
+
+ return re;
}
diff --git a/contrib/libs/isa-l/erasure_code/erasure_code_test.patch b/contrib/libs/isa-l/erasure_code/erasure_code_test.patch
deleted file mode 100644
index 0bf88ff23b..0000000000
--- a/contrib/libs/isa-l/erasure_code/erasure_code_test.patch
+++ /dev/null
@@ -1,8 +0,0 @@
-34c34
-< // #include "types.h"
----
-> #include "types.h"
-205c205
-< s ^= gf_mul_erasure(invert_matrix[j * k + i],
----
-> s ^= gf_mul(invert_matrix[j * k + i],
diff --git a/contrib/libs/isa-l/erasure_code/erasure_code_update_perf.c b/contrib/libs/isa-l/erasure_code/erasure_code_update_perf.c
index 909e894149..e74a217cb3 100644
--- a/contrib/libs/isa-l/erasure_code/erasure_code_update_perf.c
+++ b/contrib/libs/isa-l/erasure_code/erasure_code_update_perf.c
@@ -31,7 +31,6 @@
#include <stdlib.h>
#include <string.h> // for memset, memcmp
#include "erasure_code.h"
-#include "types.h"
#include "test.h"
//By default, test multibinary version
@@ -48,22 +47,25 @@
#define str(s) #s
#define xstr(s) str(s)
-//#define CACHED_TEST
-#ifdef CACHED_TEST
+#ifndef GT_L3_CACHE
+# define GT_L3_CACHE 32*1024*1024 /* some number > last level cache */
+#endif
+
+#if !defined(COLD_TEST) && !defined(TEST_CUSTOM)
// Cached test, loop many times over small dataset
# define TEST_SOURCES 32
# define TEST_LEN(m) ((128*1024 / m) & ~(64-1))
# define TEST_TYPE_STR "_warm"
-#else
-# ifndef TEST_CUSTOM
+#elif defined (COLD_TEST)
// Uncached test. Pull from large mem base.
-# define TEST_SOURCES 32
-# define GT_L3_CACHE 32*1024*1024 /* some number > last level cache */
-# define TEST_LEN(m) ((GT_L3_CACHE / m) & ~(64-1))
-# define TEST_TYPE_STR "_cold"
-# else
-# define TEST_TYPE_STR "_cus"
-# endif
+# define TEST_SOURCES 32
+# define TEST_LEN(m) ((GT_L3_CACHE / m) & ~(64-1))
+# define TEST_TYPE_STR "_cold"
+#elif defined (TEST_CUSTOM)
+# define TEST_TYPE_STR "_cus"
+#endif
+#ifndef TEST_SEED
+# define TEST_SEED 0x1234
#endif
#define MMAX TEST_SOURCES
@@ -71,6 +73,17 @@
typedef unsigned char u8;
+void usage(const char *app_name)
+{
+ fprintf(stderr,
+ "Usage: %s [options]\n"
+ " -h Help\n"
+ " -k <val> Number of source buffers\n"
+ " -p <val> Number of parity buffers\n"
+ " -e <val> Number of simulated buffers with errors (cannot be higher than p or k)\n",
+ app_name);
+}
+
void dump(unsigned char *buf, int len)
{
int i;
@@ -134,29 +147,103 @@ int decode_test(int m, int k, u8 ** update_buffs, u8 ** recov, u8 * a, u8 * src_
int main(int argc, char *argv[])
{
- int i, j, check, m, k, nerrs;
+ int i, j, check, m, k, p, nerrs, ret = -1;
void *buf;
- u8 *temp_buffs[TEST_SOURCES], *buffs[TEST_SOURCES];
- u8 *update_buffs[TEST_SOURCES];
- u8 *perf_update_buffs[TEST_SOURCES];
+ u8 *temp_buffs[TEST_SOURCES] = { NULL };
+ u8 *buffs[TEST_SOURCES] = { NULL };
+ u8 *update_buffs[TEST_SOURCES] = { NULL };
+ u8 *perf_update_buffs[TEST_SOURCES] = { NULL };
u8 a[MMAX * KMAX];
u8 g_tbls[KMAX * TEST_SOURCES * 32], src_in_err[TEST_SOURCES];
u8 src_err_list[TEST_SOURCES], *recov[TEST_SOURCES];
struct perf start;
- // Pick test parameters
+ /* Set default parameters */
k = 10;
- m = k + VECT;
+ p = VECT;
nerrs = VECT;
- const u8 err_list[] = { 0, 2, 4, 5, 7, 8 };
- printf(xstr(FUNCTION_UNDER_TEST) "_perf: %dx%d %d\n", m, TEST_LEN(m), nerrs);
+ /* Parse arguments */
+ for (i = 1; i < argc; i++) {
+ if (strcmp(argv[i], "-k") == 0) {
+ k = atoi(argv[++i]);
+ } else if (strcmp(argv[i], "-p") == 0) {
+ p = atoi(argv[++i]);
+ } else if (strcmp(argv[i], "-e") == 0) {
+ nerrs = atoi(argv[++i]);
+ } else if (strcmp(argv[i], "-h") == 0) {
+ usage(argv[0]);
+ return 0;
+ } else {
+ usage(argv[0]);
+ return -1;
+ }
+ }
+
+ if (nerrs > k) {
+ printf
+ ("Number of errors (%d) cannot be higher than number of data buffers (%d)\n",
+ nerrs, k);
+ return -1;
+ }
+
+ if (k <= 0) {
+ printf("Number of source buffers (%d) must be > 0\n", k);
+ return -1;
+ }
+
+ if (p <= 0) {
+ printf("Number of parity buffers (%d) must be > 0\n", p);
+ return -1;
+ }
+
+ if (nerrs > p) {
+ printf
+ ("Number of errors (%d) cannot be higher than number of parity buffers (%d)\n",
+ nerrs, p);
+ return -1;
+ }
+
+ if (nerrs <= 0) {
+ printf("Number of errors (%d) must be > 0\n", nerrs);
+ return -1;
+ }
+
+ m = k + p;
- if (m > MMAX || k > KMAX || nerrs > (m - k)) {
- printf(" Input test parameter error\n");
+ if (m > MMAX) {
+ printf("Number of total buffers (data and parity) cannot be higher than %d\n",
+ MMAX);
return -1;
}
+ u8 *err_list = malloc((size_t)nerrs);
+ if (err_list == NULL) {
+ printf("Error allocating list of array of error indices\n");
+ return -1;
+ }
+
+ srand(TEST_SEED);
+
+ for (i = 0; i < nerrs;) {
+ u8 next_err = rand() % k;
+ for (j = 0; j < i; j++)
+ if (next_err == err_list[j])
+ break;
+ if (j != i)
+ continue;
+ err_list[i++] = next_err;
+ }
+
+ printf("Testing with %u data buffers and %u parity buffers (num errors = %u, in [ ", k,
+ p, nerrs);
+ for (i = 0; i < nerrs; i++)
+ printf("%d ", err_list[i]);
+
+ printf("])\n");
+
+ printf(xstr(FUNCTION_UNDER_TEST) "_perf: %dx%d %d\n", m, TEST_LEN(m), nerrs);
+
memcpy(src_err_list, err_list, nerrs);
memset(src_in_err, 0, TEST_SOURCES);
for (i = 0; i < nerrs; i++)
@@ -165,16 +252,16 @@ int main(int argc, char *argv[])
// Allocate the arrays
for (i = 0; i < m; i++) {
if (posix_memalign(&buf, 64, TEST_LEN(m))) {
- printf("alloc error: Fail\n");
- return -1;
+ printf("Error allocating buffers\n");
+ goto exit;
}
buffs[i] = buf;
}
for (i = 0; i < (m - k); i++) {
if (posix_memalign(&buf, 64, TEST_LEN(m))) {
- printf("alloc error: Fail\n");
- return -1;
+ printf("Error allocating buffers\n");
+ goto exit;
}
temp_buffs[i] = buf;
memset(temp_buffs[i], 0, TEST_LEN(m)); // initialize the destination buffer to be zero for update function
@@ -182,16 +269,16 @@ int main(int argc, char *argv[])
for (i = 0; i < TEST_SOURCES; i++) {
if (posix_memalign(&buf, 64, TEST_LEN(m))) {
- printf("alloc error: Fail");
- return -1;
+ printf("Error allocating buffers\n");
+ goto exit;
}
update_buffs[i] = buf;
memset(update_buffs[i], 0, TEST_LEN(m)); // initialize the destination buffer to be zero for update function
}
for (i = 0; i < TEST_SOURCES; i++) {
if (posix_memalign(&buf, 64, TEST_LEN(m))) {
- printf("alloc error: Fail");
- return -1;
+ printf("Error allocating buffers\n");
+ goto exit;
}
perf_update_buffs[i] = buf;
memset(perf_update_buffs[i], 0, TEST_LEN(m)); // initialize the destination buffer to be zero for update function
@@ -214,7 +301,7 @@ int main(int argc, char *argv[])
dump(update_buffs[k + i], 25);
printf("buffs%d :", i);
dump(buffs[k + i], 25);
- return -1;
+ goto exit;
}
}
@@ -263,13 +350,14 @@ int main(int argc, char *argv[])
nerrs, g_tbls, perf_update_buffs));
if (check) {
printf("BAD_MATRIX\n");
- return -1;
+ ret = check;
+ goto exit;
}
for (i = 0; i < nerrs; i++) {
if (0 != memcmp(temp_buffs[i], update_buffs[src_err_list[i]], TEST_LEN(m))) {
printf("Fail error recovery (%d, %d, %d) - \n", m, k, nerrs);
- return -1;
+ goto exit;
}
}
@@ -277,5 +365,16 @@ int main(int argc, char *argv[])
perf_print(start, (long long)(TEST_LEN(m)) * (k + nerrs));
printf("done all: Pass\n");
- return 0;
+
+ ret = 0;
+
+ exit:
+ free(err_list);
+ for (i = 0; i < TEST_SOURCES; i++) {
+ free(buffs[i]);
+ free(temp_buffs[i]);
+ free(update_buffs[i]);
+ free(perf_update_buffs[i]);
+ }
+ return ret;
}
diff --git a/contrib/libs/isa-l/erasure_code/erasure_code_update_test.c b/contrib/libs/isa-l/erasure_code/erasure_code_update_test.c
index 9014da7890..b13485cd72 100644
--- a/contrib/libs/isa-l/erasure_code/erasure_code_update_test.c
+++ b/contrib/libs/isa-l/erasure_code/erasure_code_update_test.c
@@ -30,8 +30,9 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h> // for memset, memcmp
+#include <assert.h>
#include "erasure_code.h"
-// #include "types.h"
+#include "test.h"
#ifndef ALIGN_SIZE
# define ALIGN_SIZE 16
@@ -227,14 +228,15 @@ static int gf_gen_decode_matrix(unsigned char *encode_matrix,
int main(int argc, char *argv[])
{
- int re = 0;
+ int re = -1;
int i, j, p, rtest, m, k;
int nerrs, nsrcerrs;
void *buf;
unsigned int decode_index[MMAX];
- unsigned char *temp_buffs[TEST_SOURCES], *buffs[TEST_SOURCES];
- unsigned char *update_buffs[TEST_SOURCES];
- unsigned char *encode_matrix, *decode_matrix, *invert_matrix, *g_tbls;
+ unsigned char *temp_buffs[TEST_SOURCES] = { NULL }, *buffs[TEST_SOURCES] = { NULL };
+ unsigned char *update_buffs[TEST_SOURCES] = { NULL };
+ unsigned char *encode_matrix = NULL, *decode_matrix = NULL, *invert_matrix =
+ NULL, *g_tbls = NULL;
unsigned char src_in_err[TEST_SOURCES], src_err_list[TEST_SOURCES];
unsigned char *recov[TEST_SOURCES];
@@ -253,7 +255,7 @@ int main(int argc, char *argv[])
for (i = 0; i < TEST_SOURCES; i++) {
if (posix_memalign(&buf, 64, TEST_LEN)) {
printf("alloc error: Fail");
- return -1;
+ goto exit;
}
buffs[i] = buf;
}
@@ -261,7 +263,7 @@ int main(int argc, char *argv[])
for (i = 0; i < TEST_SOURCES; i++) {
if (posix_memalign(&buf, 64, TEST_LEN)) {
printf("alloc error: Fail");
- return -1;
+ goto exit;
}
temp_buffs[i] = buf;
memset(temp_buffs[i], 0, TEST_LEN); // initialize the destination buffer to be zero for update function
@@ -270,7 +272,7 @@ int main(int argc, char *argv[])
for (i = 0; i < TEST_SOURCES; i++) {
if (posix_memalign(&buf, 64, TEST_LEN)) {
printf("alloc error: Fail");
- return -1;
+ goto exit;
}
update_buffs[i] = buf;
memset(update_buffs[i], 0, TEST_LEN); // initialize the destination buffer to be zero for update function
@@ -284,13 +286,12 @@ int main(int argc, char *argv[])
if (encode_matrix == NULL || decode_matrix == NULL
|| invert_matrix == NULL || g_tbls == NULL) {
printf("Test failure! Error with malloc\n");
- return -1;
+ goto exit;
}
// Pick a first test
m = 14;
k = 10;
- if (m > MMAX || k > KMAX)
- return -1;
+ assert(!(m > MMAX || k > KMAX));
// Make random data
for (i = 0; i < k; i++) {
@@ -321,7 +322,7 @@ int main(int argc, char *argv[])
dump(update_buffs[k + i], 25);
printf("buffs%d :", i);
dump(buffs[k + i], 25);
- return -1;
+ goto exit;
}
}
@@ -335,7 +336,7 @@ int main(int argc, char *argv[])
nerrs, nsrcerrs, k, m);
if (re != 0) {
printf("Fail to gf_gen_decode_matrix\n");
- return -1;
+ goto exit;
}
// Pack recovery array as list of valid sources
// Its order must be the same as the order
@@ -367,16 +368,21 @@ int main(int argc, char *argv[])
dump(temp_buffs[k + i], 25);
printf("orig :");
dump(update_buffs[src_err_list[i]], 25);
- return -1;
+ re = -1;
+ goto exit;
}
}
+#ifdef TEST_VERBOSE
putchar('.');
+#endif
// Pick a first test
m = 7;
k = 5;
- if (m > MMAX || k > KMAX)
- return -1;
+ if (m > MMAX || k > KMAX) {
+ re = -1;
+ goto exit;
+ }
// Zero the destination buffer for update function
for (i = k; i < TEST_SOURCES; i++) {
@@ -411,7 +417,8 @@ int main(int argc, char *argv[])
dump(update_buffs[k + i], 25);
printf("buffs%d :", i);
dump(buffs[k + i], 25);
- return -1;
+ re = -1;
+ goto exit;
}
}
@@ -425,7 +432,7 @@ int main(int argc, char *argv[])
nerrs, nsrcerrs, k, m);
if (re != 0) {
printf("Fail to gf_gen_decode_matrix\n");
- return -1;
+ goto exit;
}
// Pack recovery array as list of valid sources
// Its order must be the same as the order
@@ -462,10 +469,13 @@ int main(int argc, char *argv[])
dump(temp_buffs[k + i], 25);
printf("orig :");
dump(update_buffs[src_err_list[i]], 25);
- return -1;
+ re = -1;
+ goto exit;
}
}
+#ifdef TEST_VERBOSE
putchar('.');
+#endif
// Do more random tests
for (rtest = 0; rtest < RANDOMS; rtest++) {
@@ -508,7 +518,8 @@ int main(int argc, char *argv[])
dump(update_buffs[k + i], 25);
printf("buffs%d :", i);
dump(buffs[k + i], 25);
- return -1;
+ re = -1;
+ goto exit;
}
}
@@ -522,7 +533,7 @@ int main(int argc, char *argv[])
src_in_err, nerrs, nsrcerrs, k, m);
if (re != 0) {
printf("Fail to gf_gen_decode_matrix\n");
- return -1;
+ goto exit;
}
// Pack recovery array as list of valid sources
// Its order must be the same as the order
@@ -565,22 +576,29 @@ int main(int argc, char *argv[])
dump(update_buffs[src_err_list[i]], 25);
printf("recov %d:", src_err_list[i]);
dump(temp_buffs[k + i], 25);
- return -1;
+ re = -1;
+ goto exit;
}
}
+#ifdef TEST_VERBOSE
putchar('.');
+#endif
}
// Run tests at end of buffer for Electric Fence
k = 16;
align = (LEN_ALIGN_CHK_B != 0) ? 1 : ALIGN_SIZE;
- if (k > KMAX)
- return -1;
+ if (k > KMAX) {
+ re = -1;
+ goto exit;
+ }
for (rows = 1; rows <= 16; rows++) {
m = k + rows;
- if (m > MMAX)
- return -1;
+ if (m > MMAX) {
+ re = -1;
+ goto exit;
+ }
for (i = k; i < TEST_SOURCES; i++) {
memset(buffs[i], 0, TEST_LEN);
@@ -628,7 +646,8 @@ int main(int argc, char *argv[])
dump(efence_update_buffs[k + i], 25);
printf("efence_buffs%d :", i);
dump(efence_buffs[k + i], 25);
- return -1;
+ re = -1;
+ goto exit;
}
}
@@ -642,7 +661,7 @@ int main(int argc, char *argv[])
src_in_err, nerrs, nsrcerrs, k, m);
if (re != 0) {
printf("Fail to gf_gen_decode_matrix\n");
- return -1;
+ goto exit;
}
// Pack recovery array as list of valid sources
// Its order must be the same as the order
@@ -688,11 +707,14 @@ int main(int argc, char *argv[])
dump(temp_buffs[k + i], align);
printf("orig :");
dump(efence_update_buffs[src_err_list[i]], align);
- return -1;
+ re = 1;
+ goto exit;
}
}
}
+#ifdef TEST_VERBOSE
putchar('.');
+#endif
}
@@ -752,7 +774,8 @@ int main(int argc, char *argv[])
dump(update_ubuffs[k + i], 25);
printf("ubuffs%d :", i);
dump(ubuffs[k + i], 25);
- return -1;
+ re = -1;
+ goto exit;
}
}
@@ -766,7 +789,7 @@ int main(int argc, char *argv[])
src_in_err, nerrs, nsrcerrs, k, m);
if (re != 0) {
printf("Fail to gf_gen_decode_matrix\n");
- return -1;
+ goto exit;
}
// Pack recovery array as list of valid sources
// Its order must be the same as the order
@@ -808,7 +831,8 @@ int main(int argc, char *argv[])
dump(update_ubuffs[src_err_list[i]], 25);
printf("recov %d:", src_err_list[i]);
dump(temp_ubuffs[k + i], 25);
- return -1;
+ re = -1;
+ goto exit;
}
}
@@ -821,13 +845,15 @@ int main(int argc, char *argv[])
if (memcmp(update_buffs[i], temp_buffs[0], offset)) {
printf("Fail rand ualign encode pad start\n");
- return -1;
+ re = -1;
+ goto exit;
}
if (memcmp
(update_buffs[i] + offset + size, temp_buffs[0],
PTR_ALIGN_CHK_B - offset)) {
printf("Fail rand ualign encode pad end\n");
- return -1;
+ re = -1;
+ goto exit;
}
}
@@ -836,17 +862,21 @@ int main(int argc, char *argv[])
offset = temp_ubuffs[k + i] - temp_buffs[k + i];
if (memcmp(temp_buffs[k + i], temp_buffs[0], offset)) {
printf("Fail rand ualign decode pad start\n");
- return -1;
+ re = -1;
+ goto exit;
}
if (memcmp
(temp_buffs[k + i] + offset + size, temp_buffs[0],
PTR_ALIGN_CHK_B - offset)) {
printf("Fail rand ualign decode pad end\n");
- return -1;
+ re = -1;
+ goto exit;
}
}
+#ifdef TEST_VERBOSE
putchar('.');
+#endif
}
// Test size alignment
@@ -893,7 +923,8 @@ int main(int argc, char *argv[])
dump(update_buffs[k + i], 25);
printf("buffs%d (size=%d) :", i, size);
dump(buffs[k + i], 25);
- return -1;
+ re = -1;
+ goto exit;
}
}
@@ -906,7 +937,7 @@ int main(int argc, char *argv[])
src_in_err, nerrs, nsrcerrs, k, m);
if (re != 0) {
printf("Fail to gf_gen_decode_matrix\n");
- return -1;
+ goto exit;
}
// Pack recovery array as list of valid sources
// Its order must be the same as the order
@@ -948,12 +979,30 @@ int main(int argc, char *argv[])
dump(update_buffs[src_err_list[i]], 25);
printf("recov %d:", src_err_list[i]);
dump(temp_buffs[k + i], 25);
- return -1;
+ re = -1;
+ goto exit;
}
}
+#ifdef TEST_VERBOSE
putchar('.');
+#endif
}
printf("done EC tests: Pass\n");
+ re = 0;
+
+ exit:
+ for (i = 0; i < TEST_SOURCES; i++) {
+ if (buffs[i])
+ aligned_free(buffs[i]);
+ if (temp_buffs[i])
+ aligned_free(temp_buffs[i]);
+ if (update_buffs[i])
+ aligned_free(update_buffs[i]);
+ }
+ free(encode_matrix);
+ free(decode_matrix);
+ free(invert_matrix);
+ free(g_tbls);
return 0;
}
diff --git a/contrib/libs/isa-l/erasure_code/erasure_code_update_test.patch b/contrib/libs/isa-l/erasure_code/erasure_code_update_test.patch
deleted file mode 100644
index 3726f2d805..0000000000
--- a/contrib/libs/isa-l/erasure_code/erasure_code_update_test.patch
+++ /dev/null
@@ -1,8 +0,0 @@
-34c34
-< // #include "types.h"
----
-> #include "types.h"
-217c217
-< s ^= gf_mul_erasure(invert_matrix[j * k + i],
----
-> s ^= gf_mul(invert_matrix[j * k + i],
diff --git a/contrib/libs/isa-l/erasure_code/gen_rs_matrix_limits.c b/contrib/libs/isa-l/erasure_code/gen_rs_matrix_limits.c
index 85061484bc..18a559088d 100644
--- a/contrib/libs/isa-l/erasure_code/gen_rs_matrix_limits.c
+++ b/contrib/libs/isa-l/erasure_code/gen_rs_matrix_limits.c
@@ -9,7 +9,7 @@
#define ROWS M_MAX
#define COLS K_MAX
-static inline int min(int a, int b)
+static inline uint64_t min(const uint64_t a, const uint64_t b)
{
if (a <= b)
return a;
@@ -17,10 +17,11 @@ static inline int min(int a, int b)
return b;
}
-void gen_sub_matrix(unsigned char *out_matrix, int dim, unsigned char *in_matrix, int rows,
- int cols, uint64_t row_indicator, uint64_t col_indicator)
+void gen_sub_matrix(unsigned char *out_matrix, const uint64_t dim, unsigned char *in_matrix,
+ const uint64_t rows, const uint64_t cols, const uint64_t row_indicator,
+ const uint64_t col_indicator)
{
- int i, j, r, s;
+ uint64_t i, j, r, s;
for (i = 0, r = 0; i < rows; i++) {
if (!(row_indicator & ((uint64_t) 1 << i)))
@@ -51,23 +52,23 @@ uint64_t next_subset(uint64_t * subset, uint64_t element_count, uint64_t subsize
return 0;
}
-int are_submatrices_singular(unsigned char *vmatrix, int rows, int cols)
+int are_submatrices_singular(unsigned char *vmatrix, const uint64_t rows, const uint64_t cols)
{
unsigned char matrix[COLS * COLS];
unsigned char invert_matrix[COLS * COLS];
- uint64_t row_indicator, col_indicator, subset_init, subsize;
+ uint64_t subsize;
/* Check all square subsize x subsize submatrices of the rows x cols
* vmatrix for singularity*/
for (subsize = 1; subsize <= min(rows, cols); subsize++) {
- subset_init = (1 << subsize) - 1;
- col_indicator = subset_init;
+ const uint64_t subset_init = (1ULL << subsize) - 1ULL;
+ uint64_t col_indicator = subset_init;
do {
- row_indicator = subset_init;
+ uint64_t row_indicator = subset_init;
do {
gen_sub_matrix(matrix, subsize, vmatrix, rows,
cols, row_indicator, col_indicator);
- if (gf_invert_matrix(matrix, invert_matrix, subsize))
+ if (gf_invert_matrix(matrix, invert_matrix, (int)subsize))
return 1;
} while (next_subset(&row_indicator, rows, subsize) == 0);
@@ -80,7 +81,7 @@ int are_submatrices_singular(unsigned char *vmatrix, int rows, int cols)
int main(int argc, char **argv)
{
unsigned char vmatrix[(ROWS + COLS) * COLS];
- int rows, cols;
+ uint64_t rows, cols;
if (K_MAX > MAX_CHECK) {
printf("K_MAX too large for this test\n");
@@ -108,7 +109,7 @@ int main(int argc, char **argv)
break;
}
- printf(" k = %2d, m <= %2d \n", cols, rows + cols - 1);
+ printf(" k = %2u, m <= %2u \n", (unsigned)cols, (unsigned)(rows + cols - 1));
}
return 0;
diff --git a/contrib/libs/isa-l/erasure_code/gf_2vect_dot_prod_avx.asm b/contrib/libs/isa-l/erasure_code/gf_2vect_dot_prod_avx.asm
index 6233d42e5d..b5dcb0e112 100644
--- a/contrib/libs/isa-l/erasure_code/gf_2vect_dot_prod_avx.asm
+++ b/contrib/libs/isa-l/erasure_code/gf_2vect_dot_prod_avx.asm
@@ -52,7 +52,7 @@
%define PS 8
%define LOG_PS 3
- %define func(x) x:
+ %define func(x) x: endbranch
%macro FUNC_SAVE 0
push r12
%endmacro
@@ -84,9 +84,9 @@
%define func(x) proc_frame x
%macro FUNC_SAVE 0
alloc_stack stack_size
- save_xmm128 xmm6, 0*16
- save_xmm128 xmm7, 1*16
- save_xmm128 xmm8, 2*16
+ vmovdqa [rsp + 0*16], xmm6
+ vmovdqa [rsp + 1*16], xmm7
+ vmovdqa [rsp + 2*16], xmm8
save_reg r12, 3*16 + 0*8
save_reg r13, 3*16 + 1*8
save_reg r14, 3*16 + 2*8
@@ -127,7 +127,7 @@
%define PS 4
%define LOG_PS 2
- %define func(x) x:
+ %define func(x) x: endbranch
%define arg(x) [ebp + PS*2 + PS*x]
%define var(x) [ebp - PS - PS*x]
@@ -238,13 +238,9 @@ section .text
%endif
align 16
-global gf_2vect_dot_prod_avx:ISAL_SYM_TYPE_FUNCTION
-func(gf_2vect_dot_prod_avx)
-%ifidn __OUTPUT_FORMAT__, macho64
-global _gf_2vect_dot_prod_avx:ISAL_SYM_TYPE_FUNCTION
-func(_gf_2vect_dot_prod_avx)
-%endif
+global gf_2vect_dot_prod_avx, function
+func(gf_2vect_dot_prod_avx)
FUNC_SAVE
SLDR len, len_m
sub len, 16
@@ -336,6 +332,3 @@ section .data
align 16
mask0f: dq 0x0f0f0f0f0f0f0f0f, 0x0f0f0f0f0f0f0f0f
-
-;;; func core, ver, snum
-slversion gf_2vect_dot_prod_avx, 02, 05, 0191
diff --git a/contrib/libs/isa-l/erasure_code/gf_2vect_dot_prod_avx.patch b/contrib/libs/isa-l/erasure_code/gf_2vect_dot_prod_avx.patch
deleted file mode 100644
index bca96af58e..0000000000
--- a/contrib/libs/isa-l/erasure_code/gf_2vect_dot_prod_avx.patch
+++ /dev/null
@@ -1,8 +0,0 @@
-242,246d241
-< func(gf_2vect_dot_prod_avx)
-< %ifidn __OUTPUT_FORMAT__, macho64
-< global _gf_2vect_dot_prod_avx:ISAL_SYM_TYPE_FUNCTION
-< func(_gf_2vect_dot_prod_avx)
-< %endif
-247a243
-> func(gf_2vect_dot_prod_avx)
diff --git a/contrib/libs/isa-l/erasure_code/gf_2vect_dot_prod_avx2.asm b/contrib/libs/isa-l/erasure_code/gf_2vect_dot_prod_avx2.asm
index 53052d56e0..3d13300528 100644
--- a/contrib/libs/isa-l/erasure_code/gf_2vect_dot_prod_avx2.asm
+++ b/contrib/libs/isa-l/erasure_code/gf_2vect_dot_prod_avx2.asm
@@ -54,7 +54,7 @@
%define PS 8
%define LOG_PS 3
- %define func(x) x:
+ %define func(x) x: endbranch
%macro FUNC_SAVE 0
push r12
%endmacro
@@ -131,7 +131,7 @@
%define PS 4
%define LOG_PS 2
- %define func(x) x:
+ %define func(x) x: endbranch
%define arg(x) [ebp + PS*2 + PS*x]
%define var(x) [ebp - PS - PS*x]
@@ -248,13 +248,9 @@ section .text
%endif
align 16
-global gf_2vect_dot_prod_avx2:ISAL_SYM_TYPE_FUNCTION
-func(gf_2vect_dot_prod_avx2)
-%ifidn __OUTPUT_FORMAT__, macho64
-global _gf_2vect_dot_prod_avx2:ISAL_SYM_TYPE_FUNCTION
-func(_gf_2vect_dot_prod_avx2)
-%endif
+global gf_2vect_dot_prod_avx2, function
+func(gf_2vect_dot_prod_avx2)
FUNC_SAVE
SLDR len, len_m
sub len, 32
@@ -353,8 +349,3 @@ func(_gf_2vect_dot_prod_avx2)
ret
endproc_frame
-
-section .data
-
-;;; func core, ver, snum
-slversion gf_2vect_dot_prod_avx2, 04, 05, 0196
diff --git a/contrib/libs/isa-l/erasure_code/gf_2vect_dot_prod_avx2.patch b/contrib/libs/isa-l/erasure_code/gf_2vect_dot_prod_avx2.patch
deleted file mode 100644
index cee2de5a58..0000000000
--- a/contrib/libs/isa-l/erasure_code/gf_2vect_dot_prod_avx2.patch
+++ /dev/null
@@ -1,8 +0,0 @@
-252,256d251
-< func(gf_2vect_dot_prod_avx2)
-< %ifidn __OUTPUT_FORMAT__, macho64
-< global _gf_2vect_dot_prod_avx2:ISAL_SYM_TYPE_FUNCTION
-< func(_gf_2vect_dot_prod_avx2)
-< %endif
-257a253
-> func(gf_2vect_dot_prod_avx2)
diff --git a/contrib/libs/isa-l/erasure_code/gf_2vect_dot_prod_avx2_gfni.asm b/contrib/libs/isa-l/erasure_code/gf_2vect_dot_prod_avx2_gfni.asm
new file mode 100644
index 0000000000..bdf03442e0
--- /dev/null
+++ b/contrib/libs/isa-l/erasure_code/gf_2vect_dot_prod_avx2_gfni.asm
@@ -0,0 +1,362 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; Copyright(c) 2023 Intel Corporation All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions
+; are met:
+; * Redistributions of source code must retain the above copyright
+; notice, this list of conditions and the following disclaimer.
+; * Redistributions in binary form must reproduce the above copyright
+; notice, this list of conditions and the following disclaimer in
+; the documentation and/or other materials provided with the
+; distribution.
+; * Neither the name of Intel Corporation nor the names of its
+; contributors may be used to endorse or promote products derived
+; from this software without specific prior written permission.
+;
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+; "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+; A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+; OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+; SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+; LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+; OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;;;
+;;; gf_2vect_dot_prod_avx2_gfni(len, vec, *g_tbls, **buffs, **dests);
+;;;
+
+%include "reg_sizes.asm"
+%include "gf_vect_gfni.inc"
+%include "memcpy.asm"
+
+%if AS_FEATURE_LEVEL >= 10
+
+%ifidn __OUTPUT_FORMAT__, elf64
+ %define arg0 rdi
+ %define arg1 rsi
+ %define arg2 rdx
+ %define arg3 rcx
+ %define arg4 r8
+ %define arg5 r9
+
+ %define tmp r11
+ %define tmp2 r10
+ %define tmp3 r13 ; must be saved and restored
+ %define tmp4 r12 ; must be saved and restored
+ %define tmp5 r14 ; must be saved and restored
+
+ %define stack_size 3*8
+ %define func(x) x: endbranch
+ %macro FUNC_SAVE 0
+ sub rsp, stack_size
+ mov [rsp + 0*8], r12
+ mov [rsp + 1*8], r13
+ mov [rsp + 2*8], r14
+ %endmacro
+ %macro FUNC_RESTORE 0
+ mov r12, [rsp + 0*8]
+ mov r13, [rsp + 1*8]
+ mov r14, [rsp + 2*8]
+ add rsp, stack_size
+ %endmacro
+%endif
+
+%ifidn __OUTPUT_FORMAT__, win64
+ %define arg0 rcx
+ %define arg1 rdx
+ %define arg2 r8
+ %define arg3 r9
+
+ %define arg4 r12 ; must be saved, loaded and restored
+ %define arg5 r15 ; must be saved and restored
+ %define tmp r11
+ %define tmp2 r10
+ %define tmp3 r13 ; must be saved and restored
+ %define tmp4 r14 ; must be saved and restored
+ %define tmp5 rdi ; must be saved and restored
+ %define stack_size 7*16 + 5*8 ; must be an odd multiple of 8
+ %define arg(x) [rsp + stack_size + 8 + 8*x]
+
+ %define func(x) proc_frame x
+ %macro FUNC_SAVE 0
+ alloc_stack stack_size
+ vmovdqa [rsp + 0*16], xmm6
+ vmovdqa [rsp + 1*16], xmm7
+ vmovdqa [rsp + 2*16], xmm8
+ vmovdqa [rsp + 3*16], xmm9
+ vmovdqa [rsp + 4*16], xmm10
+ vmovdqa [rsp + 5*16], xmm11
+ vmovdqa [rsp + 6*16], xmm12
+ mov [rsp + 7*16 + 0*8], r12
+ mov [rsp + 7*16 + 1*8], r13
+ mov [rsp + 7*16 + 2*8], r14
+ mov [rsp + 7*16 + 3*8], r15
+ mov [rsp + 7*16 + 4*8], rdi
+ end_prolog
+ mov arg4, arg(4)
+ %endmacro
+
+ %macro FUNC_RESTORE 0
+ vmovdqa xmm6, [rsp + 0*16]
+ vmovdqa xmm7, [rsp + 1*16]
+ vmovdqa xmm8, [rsp + 2*16]
+ vmovdqa xmm9, [rsp + 3*16]
+ vmovdqa xmm10, [rsp + 4*16]
+ vmovdqa xmm11, [rsp + 5*16]
+ vmovdqa xmm12, [rsp + 6*16]
+ mov r12, [rsp + 7*16 + 0*8]
+ mov r13, [rsp + 7*16 + 1*8]
+ mov r14, [rsp + 7*16 + 2*8]
+ mov r15, [rsp + 7*16 + 3*8]
+ mov rdi, [rsp + 7*16 + 4*8]
+ add rsp, stack_size
+ %endmacro
+%endif
+
+
+%define len arg0
+%define vec arg1
+%define mul_array arg2
+%define src arg3
+%define dest arg4
+%define ptr arg5
+%define vec_i tmp2
+%define dest2 tmp3
+%define dest1 tmp5
+%define pos rax
+
+%ifndef EC_ALIGNED_ADDR
+;;; Use Un-aligned load/store
+ %define XLDR vmovdqu
+ %define XSTR vmovdqu
+%else
+;;; Use Non-temporal load/stor
+ %ifdef NO_NT_LDST
+ %define XLDR vmovdqa
+ %define XSTR vmovdqa
+ %else
+ %define XLDR vmovntdqa
+ %define XSTR vmovntdq
+ %endif
+%endif
+
+%define x0l ymm0
+%define x0h ymm1
+%define x0x ymm2
+
+%define xgft1 ymm3
+%define xgft2 ymm4
+
+%define xtmp1 ymm5
+%define xtmp2 ymm6
+
+%define xp1l ymm7
+%define xp2l ymm8
+
+%define xp1h ymm9
+%define xp2h ymm10
+
+%define xp1x ymm11
+%define xp2x ymm12
+
+%define x0 x0l
+%define xp1 xp1l
+%define xp2 xp2l
+
+default rel
+[bits 64]
+
+section .text
+
+;;
+;; Encodes 96 bytes of all "k" sources into 2x 96 bytes (parity disk)
+;;
+%macro ENCODE_96B_2 0
+ vpxor xp1l, xp1l, xp1l
+ vpxor xp1h, xp1h, xp1h
+ vpxor xp1x, xp1x, xp1x
+
+ vpxor xp2l, xp2l, xp2l
+ vpxor xp2h, xp2h, xp2h
+ vpxor xp2x, xp2x, xp2x
+ mov tmp, mul_array
+ xor vec_i, vec_i
+
+%%next_vect:
+ ;; load next source vector
+ mov ptr, [src + vec_i]
+ XLDR x0l, [ptr + pos]
+ XLDR x0h, [ptr + pos + 32]
+ XLDR x0x, [ptr + pos + 64]
+ add vec_i, 8
+
+ vbroadcastsd xgft1, [tmp]
+ vbroadcastsd xgft2, [tmp + vec]
+
+ GF_MUL_XOR VEX, x0l, xgft1, xtmp1, xp1l, xgft2, xtmp2, xp2l
+ GF_MUL_XOR VEX, x0h, xgft1, xtmp1, xp1h, xgft2, xtmp2, xp2h
+ GF_MUL_XOR VEX, x0x, xgft1, xtmp1, xp1x, xgft2, xtmp2, xp2x
+ add tmp, 8
+
+ cmp vec_i, vec
+ jl %%next_vect
+
+ XSTR [dest1 + pos], xp1l
+ XSTR [dest1 + pos + 32], xp1h
+ XSTR [dest1 + pos + 64], xp1x
+ XSTR [dest2 + pos], xp2l
+ XSTR [dest2 + pos + 32], xp2h
+ XSTR [dest2 + pos + 64], xp2x
+%endmacro
+
+;;
+;; Encodes 64 bytes of all "k" sources into 2x 64 bytes (parity disks)
+;;
+%macro ENCODE_64B_2 0
+ vpxor xp1l, xp1l, xp1l
+ vpxor xp1h, xp1h, xp1h
+ vpxor xp2l, xp2l, xp2l
+ vpxor xp2h, xp2h, xp2h
+ mov tmp, mul_array
+ xor vec_i, vec_i
+
+%%next_vect:
+ mov ptr, [src + vec_i]
+ XLDR x0l, [ptr + pos] ;; Get next source vector low 32 bytes
+ XLDR x0h, [ptr + pos + 32] ;; Get next source vector high 32 bytes
+ add vec_i, 8
+
+ vbroadcastsd xgft1, [tmp]
+ vbroadcastsd xgft2, [tmp + vec]
+ add tmp, 8
+
+ GF_MUL_XOR VEX, x0l, xgft1, xtmp1, xp1l, xgft2, xtmp2, xp2l
+ GF_MUL_XOR VEX, x0h, xgft1, xgft1, xp1h, xgft2, xgft2, xp2h
+
+ cmp vec_i, vec
+ jl %%next_vect
+
+ XSTR [dest1 + pos], xp1l
+ XSTR [dest1 + pos + 32], xp1h
+ XSTR [dest2 + pos], xp2l
+ XSTR [dest2 + pos + 32], xp2h
+%endmacro
+
+;;
+;; Encodes 32 bytes of all "k" sources into 2x 32 bytes (parity disks)
+;;
+%macro ENCODE_32B_2 0
+ vpxor xp1, xp1, xp1
+ vpxor xp2, xp2, xp2
+ mov tmp, mul_array
+ xor vec_i, vec_i
+
+%%next_vect:
+ mov ptr, [src + vec_i]
+ XLDR x0, [ptr + pos] ;Get next source vector (32 bytes)
+ add vec_i, 8
+
+ vbroadcastsd xgft1, [tmp]
+ vbroadcastsd xgft2, [tmp + vec]
+ add tmp, 8
+
+ GF_MUL_XOR VEX, x0, xgft1, xgft1, xp1, xgft2, xgft2, xp2
+
+ cmp vec_i, vec
+ jl %%next_vect
+
+ XSTR [dest1 + pos], xp1
+ XSTR [dest2 + pos], xp2
+%endmacro
+
+;;
+;; Encodes less than 32 bytes of all "k" sources into 2 parity disks
+;;
+%macro ENCODE_LT_32B_2 1
+%define %%LEN %1
+
+ vpxor xp1, xp1, xp1
+ vpxor xp2, xp2, xp2
+ xor vec_i, vec_i
+
+%%next_vect:
+ mov ptr, [src + vec_i]
+ simd_load_avx2 x0, ptr + pos, %%LEN, tmp, tmp4 ;Get next source vector
+ add vec_i, 8
+
+ vbroadcastsd xgft1, [mul_array]
+ vbroadcastsd xgft2, [mul_array + vec]
+ add mul_array, 8
+
+ GF_MUL_XOR VEX, x0, xgft1, xgft1, xp1, xgft2, xgft2, xp2
+
+ cmp vec_i, vec
+ jl %%next_vect
+
+ ;Store updated encoded data
+ lea ptr, [dest1 + pos]
+ simd_store_avx2 ptr, xp1, %%LEN, tmp, tmp4
+
+ lea ptr, [dest2 + pos]
+ simd_store_avx2 ptr, xp2, %%LEN, tmp, tmp4
+%endmacro
+
+align 16
+global gf_2vect_dot_prod_avx2_gfni, function
+func(gf_2vect_dot_prod_avx2_gfni)
+ FUNC_SAVE
+
+ xor pos, pos
+ shl vec, 3 ;; vec *= 8. Make vec_i count by 8
+ mov dest1, [dest]
+ mov dest2, [dest + 8]
+
+ cmp len, 96
+ jl .len_lt_96
+
+.loop96:
+ ENCODE_96B_2
+
+ add pos, 96 ;; Loop on 96 bytes at a time first
+ sub len, 96
+ cmp len, 96
+ jge .loop96
+
+.len_lt_96:
+ cmp len, 64
+ jl .len_lt_64
+
+ ENCODE_64B_2
+
+ add pos, 64 ;; encode next 64 bytes
+ sub len, 64
+
+.len_lt_64:
+ cmp len, 32
+ jl .len_lt_32
+
+ ENCODE_32B_2
+
+ add pos, 32 ;; encode next 32 bytes
+ sub len, 32
+
+.len_lt_32:
+ cmp len, 0
+ jle .exit
+
+ ENCODE_LT_32B_2 len ;; encode remaining bytes
+
+.exit:
+ vzeroupper
+
+ FUNC_RESTORE
+ ret
+
+endproc_frame
+%endif ; if AS_FEATURE_LEVEL >= 10
diff --git a/contrib/libs/isa-l/erasure_code/gf_2vect_dot_prod_avx512.asm b/contrib/libs/isa-l/erasure_code/gf_2vect_dot_prod_avx512.asm
index 0fe2f434a1..1593c963a3 100644
--- a/contrib/libs/isa-l/erasure_code/gf_2vect_dot_prod_avx512.asm
+++ b/contrib/libs/isa-l/erasure_code/gf_2vect_dot_prod_avx512.asm
@@ -50,7 +50,7 @@
%define PS 8
%define LOG_PS 3
- %define func(x) x:
+ %define func(x) x: endbranch
%macro FUNC_SAVE 0
push r12
%endmacro
@@ -73,7 +73,7 @@
%define return rax
%define PS 8
%define LOG_PS 3
- %define stack_size 9*16 + 5*8 ; must be an odd multiple of 8
+ %define stack_size 3*16 + 3*8 ; must be an odd multiple of 8
%define arg(x) [rsp + stack_size + PS + PS*x]
%define func(x) proc_frame x
@@ -82,16 +82,9 @@
vmovdqa [rsp + 0*16], xmm6
vmovdqa [rsp + 1*16], xmm7
vmovdqa [rsp + 2*16], xmm8
- vmovdqa [rsp + 3*16], xmm9
- vmovdqa [rsp + 4*16], xmm10
- vmovdqa [rsp + 5*16], xmm11
- vmovdqa [rsp + 6*16], xmm12
- vmovdqa [rsp + 7*16], xmm13
- vmovdqa [rsp + 8*16], xmm14
- save_reg r12, 9*16 + 0*8
- save_reg r13, 9*16 + 1*8
- save_reg r14, 9*16 + 2*8
- save_reg r15, 9*16 + 3*8
+ save_reg r12, 3*16 + 0*8
+ save_reg r13, 3*16 + 1*8
+ save_reg r15, 3*16 + 2*8
end_prolog
mov arg4, arg(4)
%endmacro
@@ -100,16 +93,9 @@
vmovdqa xmm6, [rsp + 0*16]
vmovdqa xmm7, [rsp + 1*16]
vmovdqa xmm8, [rsp + 2*16]
- vmovdqa xmm9, [rsp + 3*16]
- vmovdqa xmm10, [rsp + 4*16]
- vmovdqa xmm11, [rsp + 5*16]
- vmovdqa xmm12, [rsp + 6*16]
- vmovdqa xmm13, [rsp + 7*16]
- vmovdqa xmm14, [rsp + 8*16]
- mov r12, [rsp + 9*16 + 0*8]
- mov r13, [rsp + 9*16 + 1*8]
- mov r14, [rsp + 9*16 + 2*8]
- mov r15, [rsp + 9*16 + 3*8]
+ mov r12, [rsp + 3*16 + 0*8]
+ mov r13, [rsp + 3*16 + 1*8]
+ mov r15, [rsp + 3*16 + 2*8]
add rsp, stack_size
%endmacro
%endif
@@ -133,8 +119,8 @@
%else
;;; Use Non-temporal load/stor
%ifdef NO_NT_LDST
- %define XLDR vmovdqa
- %define XSTR vmovdqa
+ %define XLDR vmovdqa64
+ %define XSTR vmovdqa64
%else
%define XLDR vmovntdqa
%define XSTR vmovntdq
@@ -160,13 +146,8 @@ default rel
section .text
align 16
-global gf_2vect_dot_prod_avx512:ISAL_SYM_TYPE_FUNCTION
+global gf_2vect_dot_prod_avx512, function
func(gf_2vect_dot_prod_avx512)
-%ifidn __OUTPUT_FORMAT__, macho64
-global _gf_2vect_dot_prod_avx512:ISAL_SYM_TYPE_FUNCTION
-func(_gf_2vect_dot_prod_avx512)
-%endif
-
FUNC_SAVE
sub len, 64
jl .return_fail
diff --git a/contrib/libs/isa-l/erasure_code/gf_2vect_dot_prod_avx512.patch b/contrib/libs/isa-l/erasure_code/gf_2vect_dot_prod_avx512.patch
deleted file mode 100644
index b00998d4b6..0000000000
--- a/contrib/libs/isa-l/erasure_code/gf_2vect_dot_prod_avx512.patch
+++ /dev/null
@@ -1,6 +0,0 @@
-165,169d164
-< %ifidn __OUTPUT_FORMAT__, macho64
-< global _gf_2vect_dot_prod_avx512:ISAL_SYM_TYPE_FUNCTION
-< func(_gf_2vect_dot_prod_avx512)
-< %endif
-<
diff --git a/contrib/libs/isa-l/erasure_code/gf_2vect_dot_prod_avx512_gfni.asm b/contrib/libs/isa-l/erasure_code/gf_2vect_dot_prod_avx512_gfni.asm
new file mode 100644
index 0000000000..33967b2928
--- /dev/null
+++ b/contrib/libs/isa-l/erasure_code/gf_2vect_dot_prod_avx512_gfni.asm
@@ -0,0 +1,209 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; Copyright(c) 2023 Intel Corporation All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions
+; are met:
+; * Redistributions of source code must retain the above copyright
+; notice, this list of conditions and the following disclaimer.
+; * Redistributions in binary form must reproduce the above copyright
+; notice, this list of conditions and the following disclaimer in
+; the documentation and/or other materials provided with the
+; distribution.
+; * Neither the name of Intel Corporation nor the names of its
+; contributors may be used to endorse or promote products derived
+; from this software without specific prior written permission.
+;
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+; "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+; A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+; OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+; SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+; LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+; OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;;;
+;;; gf_2vect_dot_prod_avx512_gfni(len, vec, *g_tbls, **buffs, **dests);
+;;;
+
+%include "reg_sizes.asm"
+%include "gf_vect_gfni.inc"
+
+%if AS_FEATURE_LEVEL >= 10
+
+%ifidn __OUTPUT_FORMAT__, elf64
+ %define arg0 rdi
+ %define arg1 rsi
+ %define arg2 rdx
+ %define arg3 rcx
+ %define arg4 r8
+ %define arg5 r9
+
+ %define tmp r11
+ %define tmp2 r10
+ %define tmp3 r12 ; must be saved and restored
+
+ %define func(x) x: endbranch
+ %macro FUNC_SAVE 0
+ push r12
+ %endmacro
+ %macro FUNC_RESTORE 0
+ pop r12
+ %endmacro
+%endif
+
+%ifidn __OUTPUT_FORMAT__, win64
+ %define arg0 rcx
+ %define arg1 rdx
+ %define arg2 r8
+ %define arg3 r9
+
+ %define arg4 r12 ; must be saved, loaded and restored
+ %define arg5 r14 ; must be saved and restored
+ %define tmp r11
+ %define tmp2 r10
+ %define tmp3 r13 ; must be saved and restored
+ %define stack_size 3*8 ; must be an odd multiple of 8
+ %define arg(x) [rsp + stack_size + 8 + 8*x]
+
+ %define func(x) proc_frame x
+ %macro FUNC_SAVE 0
+ alloc_stack stack_size
+ mov [rsp + 0*8], r12
+ mov [rsp + 1*8], r13
+ mov [rsp + 2*8], r14
+ end_prolog
+ mov arg4, arg(4)
+ %endmacro
+
+ %macro FUNC_RESTORE 0
+ mov r12, [rsp + 0*8]
+ mov r13, [rsp + 1*8]
+ mov r14, [rsp + 2*8]
+ add rsp, stack_size
+ %endmacro
+%endif
+
+
+%define len arg0
+%define vec arg1
+%define mul_array arg2
+%define src arg3
+%define dest1 arg4
+%define ptr arg5
+%define vec_i tmp2
+%define dest2 tmp3
+%define pos rax
+
+
+%ifndef EC_ALIGNED_ADDR
+;;; Use Un-aligned load/store
+ %define XLDR vmovdqu8
+ %define XSTR vmovdqu8
+%else
+;;; Use Non-temporal load/stor
+ %ifdef NO_NT_LDST
+ %define XLDR vmovdqa64
+ %define XSTR vmovdqa64
+ %else
+ %define XLDR vmovntdqa
+ %define XSTR vmovntdq
+ %endif
+%endif
+
+%define xgft1 zmm3
+%define xgft2 zmm4
+
+%define x0 zmm0
+%define xp1 zmm1
+%define xp2 zmm2
+
+default rel
+[bits 64]
+
+section .text
+
+;;
+;; Encodes 64 bytes of all "k" sources into 2x 64 bytes (parity disks)
+;;
+%macro ENCODE_64B_2 0-1
+%define %%KMASK %1
+
+ vpxorq xp1, xp1, xp1
+ vpxorq xp2, xp2, xp2
+ mov tmp, mul_array
+ xor vec_i, vec_i
+
+%%next_vect:
+ mov ptr, [src + vec_i]
+%if %0 == 1
+ vmovdqu8 x0{%%KMASK}, [ptr + pos] ;Get next source vector (less than 64 bytes)
+%else
+ XLDR x0, [ptr + pos] ;Get next source vector (64 bytes)
+%endif
+ add vec_i, 8
+
+ vbroadcastf32x2 xgft1, [tmp]
+ vbroadcastf32x2 xgft2, [tmp + vec]
+ add tmp, 8
+
+ GF_MUL_XOR EVEX, x0, xgft1, xgft1, xp1, xgft2, xgft2, xp2
+
+ cmp vec_i, vec
+ jl %%next_vect
+
+%if %0 == 1
+ vmovdqu8 [dest1 + pos]{%%KMASK}, xp1
+ vmovdqu8 [dest2 + pos]{%%KMASK}, xp2
+%else
+ XSTR [dest1 + pos], xp1
+ XSTR [dest2 + pos], xp2
+%endif
+%endmacro
+
+align 16
+global gf_2vect_dot_prod_avx512_gfni, function
+func(gf_2vect_dot_prod_avx512_gfni)
+ FUNC_SAVE
+
+ xor pos, pos
+ shl vec, 3 ;vec *= 8. Make vec_i count by 8
+ mov dest2, [dest1 + 8]
+ mov dest1, [dest1]
+
+ cmp len, 64
+ jl .len_lt_64
+
+.loop64:
+
+ ENCODE_64B_2
+
+ add pos, 64 ;Loop on 64 bytes at a time
+ sub len, 64
+ cmp len, 64
+ jge .loop64
+
+.len_lt_64:
+ cmp len, 0
+ jle .exit
+
+ xor tmp, tmp
+ bts tmp, len
+ dec tmp
+ kmovq k1, tmp
+
+ ENCODE_64B_2 k1
+
+.exit:
+ vzeroupper
+
+ FUNC_RESTORE
+ ret
+
+endproc_frame
+%endif ; if AS_FEATURE_LEVEL >= 10
diff --git a/contrib/libs/isa-l/erasure_code/gf_2vect_dot_prod_sse.asm b/contrib/libs/isa-l/erasure_code/gf_2vect_dot_prod_sse.asm
index ad61093471..986160204d 100644
--- a/contrib/libs/isa-l/erasure_code/gf_2vect_dot_prod_sse.asm
+++ b/contrib/libs/isa-l/erasure_code/gf_2vect_dot_prod_sse.asm
@@ -52,7 +52,7 @@
%define PS 8
%define LOG_PS 3
- %define func(x) x:
+ %define func(x) x: endbranch
%macro FUNC_SAVE 0
push r12
%endmacro
@@ -127,7 +127,7 @@
%define PS 4
%define LOG_PS 2
- %define func(x) x:
+ %define func(x) x: endbranch
%define arg(x) [ebp + PS*2 + PS*x]
%define var(x) [ebp - PS - PS*x]
@@ -238,13 +238,9 @@ section .text
%endif
align 16
-global gf_2vect_dot_prod_sse:ISAL_SYM_TYPE_FUNCTION
-func(gf_2vect_dot_prod_sse)
-%ifidn __OUTPUT_FORMAT__, macho64
-global _gf_2vect_dot_prod_sse:ISAL_SYM_TYPE_FUNCTION
-func(_gf_2vect_dot_prod_sse)
-%endif
+global gf_2vect_dot_prod_sse, function
+func(gf_2vect_dot_prod_sse)
FUNC_SAVE
SLDR len, len_m
sub len, 16
@@ -338,6 +334,3 @@ section .data
align 16
mask0f: dq 0x0f0f0f0f0f0f0f0f, 0x0f0f0f0f0f0f0f0f
-
-;;; func core, ver, snum
-slversion gf_2vect_dot_prod_sse, 00, 04, 0062
diff --git a/contrib/libs/isa-l/erasure_code/gf_2vect_dot_prod_sse.patch b/contrib/libs/isa-l/erasure_code/gf_2vect_dot_prod_sse.patch
deleted file mode 100644
index 439a2b1ac9..0000000000
--- a/contrib/libs/isa-l/erasure_code/gf_2vect_dot_prod_sse.patch
+++ /dev/null
@@ -1,8 +0,0 @@
-242,246d241
-< func(gf_2vect_dot_prod_sse)
-< %ifidn __OUTPUT_FORMAT__, macho64
-< global _gf_2vect_dot_prod_sse:ISAL_SYM_TYPE_FUNCTION
-< func(_gf_2vect_dot_prod_sse)
-< %endif
-247a243
-> func(gf_2vect_dot_prod_sse)
diff --git a/contrib/libs/isa-l/erasure_code/gf_2vect_dot_prod_sse_test.c b/contrib/libs/isa-l/erasure_code/gf_2vect_dot_prod_sse_test.c
deleted file mode 100644
index 406183bc30..0000000000
--- a/contrib/libs/isa-l/erasure_code/gf_2vect_dot_prod_sse_test.c
+++ /dev/null
@@ -1,480 +0,0 @@
-/**********************************************************************
- Copyright(c) 2011-2015 Intel Corporation All rights reserved.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions
- are met:
- * Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in
- the documentation and/or other materials provided with the
- distribution.
- * Neither the name of Intel Corporation nor the names of its
- contributors may be used to endorse or promote products derived
- from this software without specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-**********************************************************************/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h> // for memset, memcmp
-#include "erasure_code.h"
-// #include "types.h"
-
-#ifndef FUNCTION_UNDER_TEST
-# define FUNCTION_UNDER_TEST gf_2vect_dot_prod_sse
-#endif
-#ifndef TEST_MIN_SIZE
-# define TEST_MIN_SIZE 16
-#endif
-
-#define str(s) #s
-#define xstr(s) str(s)
-
-#define TEST_LEN 2048
-#define TEST_SIZE (TEST_LEN/2)
-#define TEST_MEM TEST_SIZE
-#define TEST_LOOPS 1000
-#define TEST_TYPE_STR ""
-
-#ifndef TEST_SOURCES
-# define TEST_SOURCES 16
-#endif
-#ifndef RANDOMS
-# define RANDOMS 20
-#endif
-
-#ifdef EC_ALIGNED_ADDR
-// Define power of 2 range to check ptr, len alignment
-# define PTR_ALIGN_CHK_B 0
-# define LEN_ALIGN_CHK_B 0 // 0 for aligned only
-#else
-// Define power of 2 range to check ptr, len alignment
-# define PTR_ALIGN_CHK_B 32
-# define LEN_ALIGN_CHK_B 32 // 0 for aligned only
-#endif
-
-typedef unsigned char u8;
-
-extern void FUNCTION_UNDER_TEST(int len, int vlen, unsigned char *gftbls,
- unsigned char **src, unsigned char **dest);
-
-void dump(unsigned char *buf, int len)
-{
- int i;
- for (i = 0; i < len;) {
- printf(" %2x", 0xff & buf[i++]);
- if (i % 32 == 0)
- printf("\n");
- }
- printf("\n");
-}
-
-void dump_matrix(unsigned char **s, int k, int m)
-{
- int i, j;
- for (i = 0; i < k; i++) {
- for (j = 0; j < m; j++) {
- printf(" %2x", s[i][j]);
- }
- printf("\n");
- }
- printf("\n");
-}
-
-void dump_u8xu8(unsigned char *s, int k, int m)
-{
- int i, j;
- for (i = 0; i < k; i++) {
- for (j = 0; j < m; j++) {
- printf(" %2x", 0xff & s[j + (i * m)]);
- }
- printf("\n");
- }
- printf("\n");
-}
-
-int main(int argc, char *argv[])
-{
- int i, j, rtest, srcs;
- void *buf;
- u8 g1[TEST_SOURCES], g2[TEST_SOURCES], g_tbls[2 * TEST_SOURCES * 32];
- u8 *dest1, *dest2, *dest_ref1, *dest_ref2, *dest_ptrs[2];
- u8 *buffs[TEST_SOURCES];
-
- int align, size;
- unsigned char *efence_buffs[TEST_SOURCES];
- unsigned int offset;
- u8 *ubuffs[TEST_SOURCES];
- u8 *udest_ptrs[2];
-
- printf(xstr(FUNCTION_UNDER_TEST) ": %dx%d ", TEST_SOURCES, TEST_LEN);
-
- // Allocate the arrays
- for (i = 0; i < TEST_SOURCES; i++) {
- if (posix_memalign(&buf, 64, TEST_LEN)) {
- printf("alloc error: Fail");
- return -1;
- }
- buffs[i] = buf;
- }
-
- if (posix_memalign(&buf, 64, TEST_LEN)) {
- printf("alloc error: Fail");
- return -1;
- }
- dest1 = buf;
-
- if (posix_memalign(&buf, 64, TEST_LEN)) {
- printf("alloc error: Fail");
- return -1;
- }
- dest2 = buf;
-
- if (posix_memalign(&buf, 64, TEST_LEN)) {
- printf("alloc error: Fail");
- return -1;
- }
- dest_ref1 = buf;
-
- if (posix_memalign(&buf, 64, TEST_LEN)) {
- printf("alloc error: Fail");
- return -1;
- }
- dest_ref2 = buf;
-
- dest_ptrs[0] = dest1;
- dest_ptrs[1] = dest2;
-
- // Test of all zeros
- for (i = 0; i < TEST_SOURCES; i++)
- memset(buffs[i], 0, TEST_LEN);
-
- memset(dest1, 0, TEST_LEN);
- memset(dest2, 0, TEST_LEN);
- memset(dest_ref1, 0, TEST_LEN);
- memset(dest_ref2, 0, TEST_LEN);
- memset(g1, 2, TEST_SOURCES);
- memset(g2, 1, TEST_SOURCES);
-
- for (i = 0; i < TEST_SOURCES; i++) {
- gf_vect_mul_init(g1[i], &g_tbls[i * 32]);
- gf_vect_mul_init(g2[i], &g_tbls[32 * TEST_SOURCES + i * 32]);
- }
-
- gf_vect_dot_prod_base(TEST_LEN, TEST_SOURCES, &g_tbls[0], buffs, dest_ref1);
- gf_vect_dot_prod_base(TEST_LEN, TEST_SOURCES, &g_tbls[32 * TEST_SOURCES], buffs,
- dest_ref2);
-
- FUNCTION_UNDER_TEST(TEST_LEN, TEST_SOURCES, g_tbls, buffs, dest_ptrs);
-
- if (0 != memcmp(dest_ref1, dest1, TEST_LEN)) {
- printf("Fail zero " xstr(FUNCTION_UNDER_TEST) " test1\n");
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref1, 25);
- printf("dprod_dut:");
- dump(dest1, 25);
- return -1;
- }
- if (0 != memcmp(dest_ref2, dest2, TEST_LEN)) {
- printf("Fail zero " xstr(FUNCTION_UNDER_TEST) " test2\n");
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref2, 25);
- printf("dprod_dut:");
- dump(dest2, 25);
- return -1;
- }
-
- putchar('.');
-
- // Rand data test
-
- for (rtest = 0; rtest < RANDOMS; rtest++) {
- for (i = 0; i < TEST_SOURCES; i++)
- for (j = 0; j < TEST_LEN; j++)
- buffs[i][j] = rand();
-
- for (i = 0; i < TEST_SOURCES; i++) {
- g1[i] = rand();
- g2[i] = rand();
- }
-
- for (i = 0; i < TEST_SOURCES; i++) {
- gf_vect_mul_init(g1[i], &g_tbls[i * 32]);
- gf_vect_mul_init(g2[i], &g_tbls[(32 * TEST_SOURCES) + (i * 32)]);
- }
-
- gf_vect_dot_prod_base(TEST_LEN, TEST_SOURCES, &g_tbls[0], buffs, dest_ref1);
- gf_vect_dot_prod_base(TEST_LEN, TEST_SOURCES, &g_tbls[32 * TEST_SOURCES],
- buffs, dest_ref2);
-
- FUNCTION_UNDER_TEST(TEST_LEN, TEST_SOURCES, g_tbls, buffs, dest_ptrs);
-
- if (0 != memcmp(dest_ref1, dest1, TEST_LEN)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test1 %d\n", rtest);
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref1, 25);
- printf("dprod_dut:");
- dump(dest1, 25);
- return -1;
- }
- if (0 != memcmp(dest_ref2, dest2, TEST_LEN)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test2 %d\n", rtest);
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref2, 25);
- printf("dprod_dut:");
- dump(dest2, 25);
- return -1;
- }
-
- putchar('.');
- }
-
- // Rand data test with varied parameters
- for (rtest = 0; rtest < RANDOMS; rtest++) {
- for (srcs = TEST_SOURCES; srcs > 0; srcs--) {
- for (i = 0; i < srcs; i++)
- for (j = 0; j < TEST_LEN; j++)
- buffs[i][j] = rand();
-
- for (i = 0; i < srcs; i++) {
- g1[i] = rand();
- g2[i] = rand();
- }
-
- for (i = 0; i < srcs; i++) {
- gf_vect_mul_init(g1[i], &g_tbls[i * 32]);
- gf_vect_mul_init(g2[i], &g_tbls[(32 * srcs) + (i * 32)]);
- }
-
- gf_vect_dot_prod_base(TEST_LEN, srcs, &g_tbls[0], buffs, dest_ref1);
- gf_vect_dot_prod_base(TEST_LEN, srcs, &g_tbls[32 * srcs], buffs,
- dest_ref2);
-
- FUNCTION_UNDER_TEST(TEST_LEN, srcs, g_tbls, buffs, dest_ptrs);
-
- if (0 != memcmp(dest_ref1, dest1, TEST_LEN)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST)
- " test1 srcs=%d\n", srcs);
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref1, 25);
- printf("dprod_dut:");
- dump(dest1, 25);
- return -1;
- }
- if (0 != memcmp(dest_ref2, dest2, TEST_LEN)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST)
- " test2 srcs=%d\n", srcs);
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref2, 25);
- printf("dprod_dut:");
- dump(dest2, 25);
- return -1;
- }
-
- putchar('.');
- }
- }
-
- // Run tests at end of buffer for Electric Fence
- align = (LEN_ALIGN_CHK_B != 0) ? 1 : 16;
- for (size = TEST_MIN_SIZE; size <= TEST_SIZE; size += align) {
- for (i = 0; i < TEST_SOURCES; i++)
- for (j = 0; j < TEST_LEN; j++)
- buffs[i][j] = rand();
-
- for (i = 0; i < TEST_SOURCES; i++) // Line up TEST_SIZE from end
- efence_buffs[i] = buffs[i] + TEST_LEN - size;
-
- for (i = 0; i < TEST_SOURCES; i++) {
- g1[i] = rand();
- g2[i] = rand();
- }
-
- for (i = 0; i < TEST_SOURCES; i++) {
- gf_vect_mul_init(g1[i], &g_tbls[i * 32]);
- gf_vect_mul_init(g2[i], &g_tbls[(32 * TEST_SOURCES) + (i * 32)]);
- }
-
- gf_vect_dot_prod_base(size, TEST_SOURCES, &g_tbls[0], efence_buffs, dest_ref1);
- gf_vect_dot_prod_base(size, TEST_SOURCES, &g_tbls[32 * TEST_SOURCES],
- efence_buffs, dest_ref2);
-
- FUNCTION_UNDER_TEST(size, TEST_SOURCES, g_tbls, efence_buffs, dest_ptrs);
-
- if (0 != memcmp(dest_ref1, dest1, size)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test1 %d\n", rtest);
- dump_matrix(efence_buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref1, align);
- printf("dprod_dut:");
- dump(dest1, align);
- return -1;
- }
-
- if (0 != memcmp(dest_ref2, dest2, size)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test2 %d\n", rtest);
- dump_matrix(efence_buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref2, align);
- printf("dprod_dut:");
- dump(dest2, align);
- return -1;
- }
-
- putchar('.');
- }
-
- // Test rand ptr alignment if available
-
- for (rtest = 0; rtest < RANDOMS; rtest++) {
- size = (TEST_LEN - PTR_ALIGN_CHK_B) & ~(TEST_MIN_SIZE - 1);
- srcs = rand() % TEST_SOURCES;
- if (srcs == 0)
- continue;
-
- offset = (PTR_ALIGN_CHK_B != 0) ? 1 : PTR_ALIGN_CHK_B;
- // Add random offsets
- for (i = 0; i < srcs; i++)
- ubuffs[i] = buffs[i] + (rand() & (PTR_ALIGN_CHK_B - offset));
-
- udest_ptrs[0] = dest1 + (rand() & (PTR_ALIGN_CHK_B - offset));
- udest_ptrs[1] = dest2 + (rand() & (PTR_ALIGN_CHK_B - offset));
-
- memset(dest1, 0, TEST_LEN); // zero pad to check write-over
- memset(dest2, 0, TEST_LEN);
-
- for (i = 0; i < srcs; i++)
- for (j = 0; j < size; j++)
- ubuffs[i][j] = rand();
-
- for (i = 0; i < srcs; i++) {
- g1[i] = rand();
- g2[i] = rand();
- }
-
- for (i = 0; i < srcs; i++) {
- gf_vect_mul_init(g1[i], &g_tbls[i * 32]);
- gf_vect_mul_init(g2[i], &g_tbls[(32 * srcs) + (i * 32)]);
- }
-
- gf_vect_dot_prod_base(size, srcs, &g_tbls[0], ubuffs, dest_ref1);
- gf_vect_dot_prod_base(size, srcs, &g_tbls[32 * srcs], ubuffs, dest_ref2);
-
- FUNCTION_UNDER_TEST(size, srcs, g_tbls, ubuffs, udest_ptrs);
-
- if (memcmp(dest_ref1, udest_ptrs[0], size)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test ualign srcs=%d\n",
- srcs);
- dump_matrix(ubuffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref1, 25);
- printf("dprod_dut:");
- dump(udest_ptrs[0], 25);
- return -1;
- }
- if (memcmp(dest_ref2, udest_ptrs[1], size)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test ualign srcs=%d\n",
- srcs);
- dump_matrix(ubuffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref2, 25);
- printf("dprod_dut:");
- dump(udest_ptrs[1], 25);
- return -1;
- }
- // Confirm that padding around dests is unchanged
- memset(dest_ref1, 0, PTR_ALIGN_CHK_B); // Make reference zero buff
- offset = udest_ptrs[0] - dest1;
-
- if (memcmp(dest1, dest_ref1, offset)) {
- printf("Fail rand ualign pad1 start\n");
- return -1;
- }
- if (memcmp(dest1 + offset + size, dest_ref1, PTR_ALIGN_CHK_B - offset)) {
- printf("Fail rand ualign pad1 end\n");
- return -1;
- }
-
- offset = udest_ptrs[1] - dest2;
- if (memcmp(dest2, dest_ref1, offset)) {
- printf("Fail rand ualign pad2 start\n");
- return -1;
- }
- if (memcmp(dest2 + offset + size, dest_ref1, PTR_ALIGN_CHK_B - offset)) {
- printf("Fail rand ualign pad2 end\n");
- return -1;
- }
-
- putchar('.');
- }
-
- // Test all size alignment
- align = (LEN_ALIGN_CHK_B != 0) ? 1 : 16;
-
- for (size = TEST_LEN; size >= TEST_MIN_SIZE; size -= align) {
- srcs = TEST_SOURCES;
-
- for (i = 0; i < srcs; i++)
- for (j = 0; j < size; j++)
- buffs[i][j] = rand();
-
- for (i = 0; i < srcs; i++) {
- g1[i] = rand();
- g2[i] = rand();
- }
-
- for (i = 0; i < srcs; i++) {
- gf_vect_mul_init(g1[i], &g_tbls[i * 32]);
- gf_vect_mul_init(g2[i], &g_tbls[(32 * srcs) + (i * 32)]);
- }
-
- gf_vect_dot_prod_base(size, srcs, &g_tbls[0], buffs, dest_ref1);
- gf_vect_dot_prod_base(size, srcs, &g_tbls[32 * srcs], buffs, dest_ref2);
-
- FUNCTION_UNDER_TEST(size, srcs, g_tbls, buffs, dest_ptrs);
-
- if (memcmp(dest_ref1, dest_ptrs[0], size)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test ualign len=%d\n",
- size);
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref1, 25);
- printf("dprod_dut:");
- dump(dest_ptrs[0], 25);
- return -1;
- }
- if (memcmp(dest_ref2, dest_ptrs[1], size)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test ualign len=%d\n",
- size);
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref2, 25);
- printf("dprod_dut:");
- dump(dest_ptrs[1], 25);
- return -1;
- }
- }
-
- printf("Pass\n");
- return 0;
-
-}
diff --git a/contrib/libs/isa-l/erasure_code/gf_2vect_dot_prod_sse_test.patch b/contrib/libs/isa-l/erasure_code/gf_2vect_dot_prod_sse_test.patch
deleted file mode 100644
index 21bbfaa667..0000000000
--- a/contrib/libs/isa-l/erasure_code/gf_2vect_dot_prod_sse_test.patch
+++ /dev/null
@@ -1,4 +0,0 @@
-34c34
-< // #include "types.h"
----
-> #include "types.h"
diff --git a/contrib/libs/isa-l/erasure_code/gf_2vect_mad_avx.asm b/contrib/libs/isa-l/erasure_code/gf_2vect_mad_avx.asm
index 2d51dad33f..08e9a7f040 100644
--- a/contrib/libs/isa-l/erasure_code/gf_2vect_mad_avx.asm
+++ b/contrib/libs/isa-l/erasure_code/gf_2vect_mad_avx.asm
@@ -97,7 +97,7 @@
%define return rax
%define return.w eax
- %define func(x) x:
+ %define func(x) x: endbranch
%define FUNC_SAVE
%define FUNC_RESTORE
%endif
@@ -155,13 +155,9 @@ section .text
align 16
-global gf_2vect_mad_avx:ISAL_SYM_TYPE_FUNCTION
-func(gf_2vect_mad_avx)
-%ifidn __OUTPUT_FORMAT__, macho64
-global _gf_2vect_mad_avx:ISAL_SYM_TYPE_FUNCTION
-func(_gf_2vect_mad_avx)
-%endif
+global gf_2vect_mad_avx, function
+func(gf_2vect_mad_avx)
FUNC_SAVE
sub len, 16
jl .return_fail
@@ -235,6 +231,3 @@ section .data
align 16
mask0f: dq 0x0f0f0f0f0f0f0f0f, 0x0f0f0f0f0f0f0f0f
-
-;;; func core, ver, snum
-slversion gf_2vect_mad_avx, 02, 01, 0204
diff --git a/contrib/libs/isa-l/erasure_code/gf_2vect_mad_avx.patch b/contrib/libs/isa-l/erasure_code/gf_2vect_mad_avx.patch
deleted file mode 100644
index b2bb2f2c3d..0000000000
--- a/contrib/libs/isa-l/erasure_code/gf_2vect_mad_avx.patch
+++ /dev/null
@@ -1,8 +0,0 @@
-159,163d158
-< func(gf_2vect_mad_avx)
-< %ifidn __OUTPUT_FORMAT__, macho64
-< global _gf_2vect_mad_avx:ISAL_SYM_TYPE_FUNCTION
-< func(_gf_2vect_mad_avx)
-< %endif
-164a160
-> func(gf_2vect_mad_avx)
diff --git a/contrib/libs/isa-l/erasure_code/gf_2vect_mad_avx2.asm b/contrib/libs/isa-l/erasure_code/gf_2vect_mad_avx2.asm
index 2b0fd8ea2d..aa6a61c949 100644
--- a/contrib/libs/isa-l/erasure_code/gf_2vect_mad_avx2.asm
+++ b/contrib/libs/isa-l/erasure_code/gf_2vect_mad_avx2.asm
@@ -104,7 +104,7 @@
%define return rax
%define return.w eax
- %define func(x) x:
+ %define func(x) x: endbranch
%define FUNC_SAVE
%define FUNC_RESTORE
%endif
@@ -163,13 +163,9 @@ section .text
%define xtmpd2 ymm9
align 16
-global gf_2vect_mad_avx2:ISAL_SYM_TYPE_FUNCTION
-func(gf_2vect_mad_avx2)
-%ifidn __OUTPUT_FORMAT__, macho64
-global _gf_2vect_mad_avx2:ISAL_SYM_TYPE_FUNCTION
-func(_gf_2vect_mad_avx2)
-%endif
+global gf_2vect_mad_avx2, function
+func(gf_2vect_mad_avx2)
FUNC_SAVE
sub len, 32
jl .return_fail
@@ -244,8 +240,3 @@ func(_gf_2vect_mad_avx2)
ret
endproc_frame
-
-section .data
-
-;;; func core, ver, snum
-slversion gf_2vect_mad_avx2, 04, 01, 0205
diff --git a/contrib/libs/isa-l/erasure_code/gf_2vect_mad_avx2.patch b/contrib/libs/isa-l/erasure_code/gf_2vect_mad_avx2.patch
deleted file mode 100644
index 6f00af6393..0000000000
--- a/contrib/libs/isa-l/erasure_code/gf_2vect_mad_avx2.patch
+++ /dev/null
@@ -1,8 +0,0 @@
-167,171d166
-< func(gf_2vect_mad_avx2)
-< %ifidn __OUTPUT_FORMAT__, macho64
-< global _gf_2vect_mad_avx2:ISAL_SYM_TYPE_FUNCTION
-< func(_gf_2vect_mad_avx2)
-< %endif
-172a168
-> func(gf_2vect_mad_avx2)
diff --git a/contrib/libs/isa-l/erasure_code/gf_2vect_mad_avx2_gfni.asm b/contrib/libs/isa-l/erasure_code/gf_2vect_mad_avx2_gfni.asm
new file mode 100644
index 0000000000..0445555419
--- /dev/null
+++ b/contrib/libs/isa-l/erasure_code/gf_2vect_mad_avx2_gfni.asm
@@ -0,0 +1,298 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; Copyright(c) 2023 Intel Corporation All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions
+; are met:
+; * Redistributions of source code must retain the above copyright
+; notice, this list of conditions and the following disclaimer.
+; * Redistributions in binary form must reproduce the above copyright
+; notice, this list of conditions and the following disclaimer in
+; the documentation and/or other materials provided with the
+; distribution.
+; * Neither the name of Intel Corporation nor the names of its
+; contributors may be used to endorse or promote products derived
+; from this software without specific prior written permission.
+;
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+; "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+; A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+; OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+; SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+; LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+; OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;;;
+;;; gf_2vect_mad_avx2_gfni(len, vec, vec_i, mul_array, src, dest);
+;;;
+
+%include "reg_sizes.asm"
+%include "gf_vect_gfni.inc"
+%include "memcpy.asm"
+
+%if AS_FEATURE_LEVEL >= 10
+
+%ifidn __OUTPUT_FORMAT__, elf64
+ %define arg0 rdi
+ %define arg1 rsi
+ %define arg2 rdx
+ %define arg3 rcx
+ %define arg4 r8
+ %define arg5 r9
+ %define tmp r11
+ %define tmp2 r10
+ %define func(x) x: endbranch
+ %define FUNC_SAVE
+ %define FUNC_RESTORE
+%endif
+
+%ifidn __OUTPUT_FORMAT__, win64
+ %define arg0 rcx
+ %define arg1 rdx
+ %define arg2 r8
+ %define arg3 r9
+ %define arg4 r12 ; must be saved, loaded and restored
+ %define arg5 r13 ; must be saved and restored
+ %define tmp r11
+ %define tmp2 r10
+ %define stack_size 16*9 + 3*8
+ %define arg(x) [rsp + stack_size + 8 + 8*x]
+ %define func(x) proc_frame x
+
+ %macro FUNC_SAVE 0
+ sub rsp, stack_size
+ vmovdqa [rsp + 0*16], xmm6
+ vmovdqa [rsp + 1*16], xmm7
+ vmovdqa [rsp + 2*16], xmm8
+ vmovdqa [rsp + 3*16], xmm9
+ vmovdqa [rsp + 4*16], xmm10
+ vmovdqa [rsp + 5*16], xmm11
+ vmovdqa [rsp + 6*16], xmm12
+ vmovdqa [rsp + 7*16], xmm13
+ vmovdqa [rsp + 8*16], xmm14
+ mov [rsp + 9*16 + 0*8], r12
+ mov [rsp + 9*16 + 1*8], r13
+ end_prolog
+ mov arg4, arg(4)
+ mov arg5, arg(5)
+ %endmacro
+
+ %macro FUNC_RESTORE 0
+ vmovdqa xmm6, [rsp + 0*16]
+ vmovdqa xmm7, [rsp + 1*16]
+ vmovdqa xmm8, [rsp + 2*16]
+ vmovdqa xmm9, [rsp + 3*16]
+ vmovdqa xmm10, [rsp + 4*16]
+ vmovdqa xmm11, [rsp + 5*16]
+ vmovdqa xmm12, [rsp + 6*16]
+ vmovdqa xmm13, [rsp + 7*16]
+ vmovdqa xmm14, [rsp + 8*16]
+ mov r12, [rsp + 9*16 + 0*8]
+ mov r13, [rsp + 9*16 + 1*8]
+ add rsp, stack_size
+ %endmacro
+%endif
+
+%define len arg0
+%define vec arg1
+%define vec_i arg2
+%define mul_array arg3
+%define src arg4
+%define dest1 arg5
+%define pos rax
+%define dest2 mul_array
+%define dest3 vec_i
+
+%ifndef EC_ALIGNED_ADDR
+;;; Use Un-aligned load/store
+ %define XLDR vmovdqu
+ %define XSTR vmovdqu
+%else
+;;; Use Non-temporal load/stor
+ %ifdef NO_NT_LDST
+ %define XLDR vmovdqa
+ %define XSTR vmovdqa
+ %else
+ %define XLDR vmovntdqa
+ %define XSTR vmovntdq
+ %endif
+%endif
+
+default rel
+[bits 64]
+section .text
+
+%define x0l ymm0
+%define x0h ymm1
+%define x0x ymm2
+
+%define xgft1 ymm3
+%define xgft2 ymm4
+%define xd1l ymm5
+%define xd1h ymm6
+%define xd1x ymm7
+
+%define xd2l ymm8
+%define xd2h ymm9
+%define xd2x ymm10
+
+%define xret1l ymm11
+%define xret1h ymm12
+%define xret2l ymm13
+%define xret2h ymm14
+
+%define x0 x0l
+%define xd1 xd1l
+%define xd2 xd2l
+%define xret1 xret1l
+%define xret2 xret2l
+
+;;
+;; Encodes 96 bytes of a single source into 2x 96 bytes (parity disks)
+;;
+%macro ENCODE_96B_2 0
+
+ ;Get next source vector
+ XLDR x0l, [src + pos]
+ XLDR x0h, [src + pos + 32]
+ XLDR x0x, [src + pos + 64]
+ ;Get next dest vectors
+ XLDR xd1l, [dest1 + pos]
+ XLDR xd1h, [dest1 + pos + 32]
+ XLDR xd1x, [dest1 + pos + 64]
+ XLDR xd2l, [dest2 + pos]
+ XLDR xd2h, [dest2 + pos + 32]
+ XLDR xd2x, [dest2 + pos + 64]
+
+ GF_MUL_XOR VEX, x0l, xgft1, xret1l, xd1l, xgft2, xret2l, xd2l
+ GF_MUL_XOR VEX, x0h, xgft1, xret1h, xd1h, xgft2, xret2h, xd2h
+ GF_MUL_XOR VEX, x0x, xgft1, xret1l, xd1x, xgft2, xret2l, xd2x
+
+ XSTR [dest1 + pos], xd1l
+ XSTR [dest1 + pos + 32], xd1h
+ XSTR [dest1 + pos + 64], xd1x
+ XSTR [dest2 + pos], xd2l
+ XSTR [dest2 + pos + 32], xd2h
+ XSTR [dest2 + pos + 64], xd2x
+%endmacro
+
+;;
+;; Encodes 64 bytes of a single source into 2x 64 bytes (parity disks)
+;;
+%macro ENCODE_64B_2 0
+
+ ;Get next source vector
+ XLDR x0l, [src + pos]
+ XLDR x0h, [src + pos + 32]
+ ;Get next dest vectors
+ XLDR xd1l, [dest1 + pos]
+ XLDR xd1h, [dest1 + pos + 32]
+ XLDR xd2l, [dest2 + pos]
+ XLDR xd2h, [dest2 + pos + 32]
+
+ GF_MUL_XOR VEX, x0l, xgft1, xret1l, xd1l, xgft2, xret2l, xd2l
+ GF_MUL_XOR VEX, x0h, xgft1, xret1h, xd1h, xgft2, xret2h, xd2h
+
+ XSTR [dest1 + pos], xd1l
+ XSTR [dest1 + pos + 32], xd1h
+ XSTR [dest2 + pos], xd2l
+ XSTR [dest2 + pos + 32], xd2h
+%endmacro
+
+;;
+;; Encodes 32 bytes of a single source into 2x 32 bytes (parity disks)
+;;
+%macro ENCODE_32B_2 0
+
+ ;Get next source vector
+ XLDR x0, [src + pos]
+ ;Get next dest vectors
+ XLDR xd1, [dest1 + pos]
+ XLDR xd2, [dest2 + pos]
+
+ GF_MUL_XOR VEX, x0, xgft1, xret1, xd1, xgft2, xret2, xd2
+
+ XSTR [dest1 + pos], xd1
+ XSTR [dest2 + pos], xd2
+%endmacro
+
+;;
+;; Encodes less than 32 bytes of a single source into 2x parity disks
+;;
+%macro ENCODE_LT_32B_2 1
+%define %%LEN %1
+
+ ;Get next source vector
+ simd_load_avx2 x0, src + pos, %%LEN, tmp, tmp2
+ ;Get next dest vectors
+ simd_load_avx2 xd1, dest1 + pos, %%LEN, tmp, tmp2
+ simd_load_avx2 xd2, dest2 + pos, %%LEN, tmp, tmp2
+
+ GF_MUL_XOR VEX, x0, xgft1, xret1, xd1, xgft2, xret2, xd2
+
+ lea dest1, [dest1 + pos]
+ simd_store_avx2 dest1, xd1, %%LEN, tmp, tmp2
+ lea dest2, [dest2 + pos]
+ simd_store_avx2 dest2, xd2, %%LEN, tmp, tmp2
+%endmacro
+
+align 16
+global gf_2vect_mad_avx2_gfni, function
+func(gf_2vect_mad_avx2_gfni)
+ FUNC_SAVE
+
+ xor pos, pos
+ shl vec_i, 3 ;Multiply by 8
+ shl vec, 3 ;Multiply by 8
+ lea tmp, [mul_array + vec_i]
+ vbroadcastsd xgft1, [tmp]
+ vbroadcastsd xgft2, [tmp + vec]
+ mov dest2, [dest1 + 8] ; reuse mul_array
+ mov dest1, [dest1]
+
+ cmp len, 96
+ jl .len_lt_96
+
+.loop96:
+ ENCODE_96B_2
+ add pos, 96 ;; loop on 96 bytes at a time
+ sub len, 96
+ cmp len, 96
+ jge .loop96
+
+.len_lt_96:
+ cmp len, 64
+ jl .len_lt_64
+ ENCODE_64B_2 ;; encode next 64 bytes
+
+ add pos, 64
+ sub len, 64
+
+.len_lt_64:
+ cmp len, 32
+ jl .len_lt_32
+
+ ENCODE_32B_2 ;; encode next 32 bytes
+
+ add pos, 32
+ sub len, 32
+
+.len_lt_32:
+ cmp len, 0
+ jle .exit
+
+ ENCODE_LT_32B_2 len ;; encode final bytes
+
+.exit:
+ vzeroupper
+
+ FUNC_RESTORE
+ ret
+
+endproc_frame
+%endif ; if AS_FEATURE_LEVEL >= 10
diff --git a/contrib/libs/isa-l/erasure_code/gf_2vect_mad_avx512.asm b/contrib/libs/isa-l/erasure_code/gf_2vect_mad_avx512.asm
index acb67e4334..1b76432eb7 100644
--- a/contrib/libs/isa-l/erasure_code/gf_2vect_mad_avx512.asm
+++ b/contrib/libs/isa-l/erasure_code/gf_2vect_mad_avx512.asm
@@ -45,7 +45,7 @@
%define tmp r11
%define tmp2 r10
%define return rax
- %define func(x) x:
+ %define func(x) x: endbranch
%define FUNC_SAVE
%define FUNC_RESTORE
%endif
@@ -118,8 +118,8 @@
%else
;;; Use Non-temporal load/stor
%ifdef NO_NT_LDST
- %define XLDR vmovdqa
- %define XSTR vmovdqa
+ %define XLDR vmovdqa64
+ %define XSTR vmovdqa64
%else
%define XLDR vmovntdqa
%define XSTR vmovntdq
@@ -149,13 +149,8 @@ section .text
%define xmask0f zmm14
align 16
-global gf_2vect_mad_avx512:ISAL_SYM_TYPE_FUNCTION
+global gf_2vect_mad_avx512, function
func(gf_2vect_mad_avx512)
-%ifidn __OUTPUT_FORMAT__, macho64
-global _gf_2vect_mad_avx512:ISAL_SYM_TYPE_FUNCTION
-func(_gf_2vect_mad_avx512)
-%endif
-
FUNC_SAVE
sub len, 64
jl .return_fail
diff --git a/contrib/libs/isa-l/erasure_code/gf_2vect_mad_avx512.patch b/contrib/libs/isa-l/erasure_code/gf_2vect_mad_avx512.patch
deleted file mode 100644
index 6b3d2e6d23..0000000000
--- a/contrib/libs/isa-l/erasure_code/gf_2vect_mad_avx512.patch
+++ /dev/null
@@ -1,6 +0,0 @@
-154,158d153
-< %ifidn __OUTPUT_FORMAT__, macho64
-< global _gf_2vect_mad_avx512:ISAL_SYM_TYPE_FUNCTION
-< func(_gf_2vect_mad_avx512)
-< %endif
-<
diff --git a/contrib/libs/isa-l/erasure_code/gf_2vect_mad_avx512_gfni.asm b/contrib/libs/isa-l/erasure_code/gf_2vect_mad_avx512_gfni.asm
new file mode 100644
index 0000000000..41343305b1
--- /dev/null
+++ b/contrib/libs/isa-l/erasure_code/gf_2vect_mad_avx512_gfni.asm
@@ -0,0 +1,189 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; Copyright(c) 2023 Intel Corporation All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions
+; are met:
+; * Redistributions of source code must retain the above copyright
+; notice, this list of conditions and the following disclaimer.
+; * Redistributions in binary form must reproduce the above copyright
+; notice, this list of conditions and the following disclaimer in
+; the documentation and/or other materials provided with the
+; distribution.
+; * Neither the name of Intel Corporation nor the names of its
+; contributors may be used to endorse or promote products derived
+; from this software without specific prior written permission.
+;
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+; "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+; A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+; OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+; SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+; LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+; OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;;;
+;;; gf_2vect_mad_avx512_gfni(len, vec, vec_i, mul_array, src, dest);
+;;;
+
+%include "reg_sizes.asm"
+%include "gf_vect_gfni.inc"
+
+%if AS_FEATURE_LEVEL >= 10
+
+%ifidn __OUTPUT_FORMAT__, elf64
+ %define arg0 rdi
+ %define arg1 rsi
+ %define arg2 rdx
+ %define arg3 rcx
+ %define arg4 r8
+ %define arg5 r9
+ %define tmp r11
+ %define tmp2 r10
+ %define func(x) x: endbranch
+ %define FUNC_SAVE
+ %define FUNC_RESTORE
+%endif
+
+%ifidn __OUTPUT_FORMAT__, win64
+ %define arg0 rcx
+ %define arg1 rdx
+ %define arg2 r8
+ %define arg3 r9
+ %define arg4 r12
+ %define arg5 r13
+ %define tmp r11
+ %define tmp2 r10
+ %define stack_size 16 + 3*8 ; must be an odd multiple of 8
+ %define arg(x) [rsp + stack_size + 8 + 8*x]
+
+ %define func(x) proc_frame x
+ %macro FUNC_SAVE 0
+ sub rsp, stack_size
+ vmovdqa [rsp + 16*0], xmm6
+ mov [rsp + 16 + 0*8], r12
+ mov [rsp + 16 + 1*8], r13
+ end_prolog
+ mov arg4, arg(4)
+ mov arg5, arg(5)
+ %endmacro
+
+ %macro FUNC_RESTORE 0
+ vmovdqa xmm6, [rsp + 16*0]
+ mov r12, [rsp + 16 + 0*8]
+ mov r13, [rsp + 16 + 1*8]
+ add rsp, stack_size
+ %endmacro
+%endif
+
+%define len arg0
+%define vec arg1
+%define vec_i arg2
+%define mul_array arg3
+%define src arg4
+%define dest1 arg5
+%define pos rax
+%define dest2 tmp2
+
+%ifndef EC_ALIGNED_ADDR
+;;; Use Un-aligned load/store
+ %define XLDR vmovdqu8
+ %define XSTR vmovdqu8
+%else
+;;; Use Non-temporal load/stor
+ %ifdef NO_NT_LDST
+ %define XLDR vmovdqa64
+ %define XSTR vmovdqa64
+ %else
+ %define XLDR vmovntdqa
+ %define XSTR vmovntdq
+ %endif
+%endif
+
+default rel
+[bits 64]
+section .text
+
+%define x0 zmm0
+%define xd1 zmm1
+%define xd2 zmm2
+%define xgft1 zmm3
+%define xgft2 zmm4
+%define xret1 zmm5
+%define xret2 zmm6
+
+;;
+;; Encodes 64 bytes of a single source into 2x 64 bytes (parity disks)
+;;
+%macro ENCODE_64B_2 0-1
+%define %%KMASK %1
+
+%if %0 == 1
+ vmovdqu8 x0{%%KMASK}, [src + pos] ;Get next source vector
+ vmovdqu8 xd1{%%KMASK}, [dest1 + pos] ;Get next dest vector
+ vmovdqu8 xd2{%%KMASK}, [dest2 + pos] ;Get next dest vector
+%else
+ XLDR x0, [src + pos] ;Get next source vector
+ XLDR xd1, [dest1 + pos] ;Get next dest vector
+ XLDR xd2, [dest2 + pos] ;Get next dest vector
+%endif
+
+ GF_MUL_XOR EVEX, x0, xgft1, xret1, xd1, xgft2, xret2, xd2
+
+%if %0 == 1
+ vmovdqu8 [dest1 + pos]{%%KMASK}, xd1
+ vmovdqu8 [dest2 + pos]{%%KMASK}, xd2
+%else
+ XSTR [dest1 + pos], xd1
+ XSTR [dest2 + pos], xd2
+%endif
+%endmacro
+
+align 16
+global gf_2vect_mad_avx512_gfni, function
+func(gf_2vect_mad_avx512_gfni)
+ FUNC_SAVE
+
+ xor pos, pos
+ shl vec_i, 3 ;Multiply by 8
+ shl vec, 3
+ lea tmp, [mul_array + vec_i]
+ vbroadcastf32x2 xgft1, [tmp]
+ vbroadcastf32x2 xgft2, [tmp + vec]
+ mov dest2, [dest1 + 8] ; reuse mul_array
+ mov dest1, [dest1]
+
+ cmp len, 64
+ jl .len_lt_64
+.loop64:
+ ENCODE_64B_2
+
+ add pos, 64 ;Loop on 64 bytes at a time
+ sub len, 64
+ cmp len, 64
+ jge .loop64
+
+.len_lt_64:
+ cmp len, 0
+ jle .exit
+
+ xor tmp, tmp
+ bts tmp, len
+ dec tmp
+ kmovq k1, tmp
+
+ ENCODE_64B_2 k1
+
+.exit:
+ vzeroupper
+
+ FUNC_RESTORE
+ ret
+
+endproc_frame
+%endif ; if AS_FEATURE_LEVEL >= 10
diff --git a/contrib/libs/isa-l/erasure_code/gf_2vect_mad_sse.asm b/contrib/libs/isa-l/erasure_code/gf_2vect_mad_sse.asm
index 5bf380df14..1fa6729a6c 100644
--- a/contrib/libs/isa-l/erasure_code/gf_2vect_mad_sse.asm
+++ b/contrib/libs/isa-l/erasure_code/gf_2vect_mad_sse.asm
@@ -97,7 +97,7 @@
%define return rax
%define return.w eax
- %define func(x) x:
+ %define func(x) x: endbranch
%define FUNC_SAVE
%define FUNC_RESTORE
%endif
@@ -154,13 +154,8 @@ section .text
align 16
-global gf_2vect_mad_sse:ISAL_SYM_TYPE_FUNCTION
+global gf_2vect_mad_sse, function
func(gf_2vect_mad_sse)
-%ifidn __OUTPUT_FORMAT__, macho64
-global _gf_2vect_mad_sse:ISAL_SYM_TYPE_FUNCTION
-func(_gf_2vect_mad_sse)
-%endif
-
FUNC_SAVE
sub len, 16
jl .return_fail
@@ -239,6 +234,3 @@ align 16
mask0f:
dq 0x0f0f0f0f0f0f0f0f, 0x0f0f0f0f0f0f0f0f
-
-;;; func core, ver, snum
-slversion gf_2vect_mad_sse, 00, 01, 0203
diff --git a/contrib/libs/isa-l/erasure_code/gf_2vect_mad_sse.patch b/contrib/libs/isa-l/erasure_code/gf_2vect_mad_sse.patch
deleted file mode 100644
index 1d9e040742..0000000000
--- a/contrib/libs/isa-l/erasure_code/gf_2vect_mad_sse.patch
+++ /dev/null
@@ -1,6 +0,0 @@
-159,163d158
-< %ifidn __OUTPUT_FORMAT__, macho64
-< global _gf_2vect_mad_sse:ISAL_SYM_TYPE_FUNCTION
-< func(_gf_2vect_mad_sse)
-< %endif
-<
diff --git a/contrib/libs/isa-l/erasure_code/gf_3vect_dot_prod_avx.asm b/contrib/libs/isa-l/erasure_code/gf_3vect_dot_prod_avx.asm
index a2619507b7..7676c56229 100644
--- a/contrib/libs/isa-l/erasure_code/gf_3vect_dot_prod_avx.asm
+++ b/contrib/libs/isa-l/erasure_code/gf_3vect_dot_prod_avx.asm
@@ -52,7 +52,7 @@
%define PS 8
%define LOG_PS 3
- %define func(x) x:
+ %define func(x) x: endbranch
%macro FUNC_SAVE 0
push r12
push r13
@@ -87,12 +87,12 @@
%define func(x) proc_frame x
%macro FUNC_SAVE 0
alloc_stack stack_size
- save_xmm128 xmm6, 0*16
- save_xmm128 xmm7, 1*16
- save_xmm128 xmm8, 2*16
- save_xmm128 xmm9, 3*16
- save_xmm128 xmm10, 4*16
- save_xmm128 xmm11, 5*16
+ vmovdqa [rsp + 0*16], xmm6
+ vmovdqa [rsp + 1*16], xmm7
+ vmovdqa [rsp + 2*16], xmm8
+ vmovdqa [rsp + 3*16], xmm9
+ vmovdqa [rsp + 4*16], xmm10
+ vmovdqa [rsp + 5*16], xmm11
save_reg r12, 6*16 + 0*8
save_reg r13, 6*16 + 1*8
save_reg r14, 6*16 + 2*8
@@ -139,7 +139,7 @@
%define PS 4
%define LOG_PS 2
- %define func(x) x:
+ %define func(x) x: endbranch
%define arg(x) [ebp + PS*2 + PS*x]
%define var(x) [ebp - PS - PS*x]
@@ -261,13 +261,8 @@ section .text
%endif
align 16
-global gf_3vect_dot_prod_avx:ISAL_SYM_TYPE_FUNCTION
+global gf_3vect_dot_prod_avx, function
func(gf_3vect_dot_prod_avx)
-%ifidn __OUTPUT_FORMAT__, macho64
-global _gf_3vect_dot_prod_avx:ISAL_SYM_TYPE_FUNCTION
-func(_gf_3vect_dot_prod_avx)
-%endif
-
FUNC_SAVE
SLDR len, len_m
sub len, 16
@@ -377,6 +372,3 @@ section .data
align 16
mask0f: dq 0x0f0f0f0f0f0f0f0f, 0x0f0f0f0f0f0f0f0f
-
-;;; func core, ver, snum
-slversion gf_3vect_dot_prod_avx, 02, 05, 0192
diff --git a/contrib/libs/isa-l/erasure_code/gf_3vect_dot_prod_avx.patch b/contrib/libs/isa-l/erasure_code/gf_3vect_dot_prod_avx.patch
deleted file mode 100644
index 8689356763..0000000000
--- a/contrib/libs/isa-l/erasure_code/gf_3vect_dot_prod_avx.patch
+++ /dev/null
@@ -1,6 +0,0 @@
-266,270d265
-< %ifidn __OUTPUT_FORMAT__, macho64
-< global _gf_3vect_dot_prod_avx:ISAL_SYM_TYPE_FUNCTION
-< func(_gf_3vect_dot_prod_avx)
-< %endif
-<
diff --git a/contrib/libs/isa-l/erasure_code/gf_3vect_dot_prod_avx2.asm b/contrib/libs/isa-l/erasure_code/gf_3vect_dot_prod_avx2.asm
index 26b6b82e21..d06ccc30d2 100644
--- a/contrib/libs/isa-l/erasure_code/gf_3vect_dot_prod_avx2.asm
+++ b/contrib/libs/isa-l/erasure_code/gf_3vect_dot_prod_avx2.asm
@@ -54,7 +54,7 @@
%define PS 8
%define LOG_PS 3
- %define func(x) x:
+ %define func(x) x: endbranch
%macro FUNC_SAVE 0
push r12
push r13
@@ -143,7 +143,7 @@
%define PS 4
%define LOG_PS 2
- %define func(x) x:
+ %define func(x) x: endbranch
%define arg(x) [ebp + PS*2 + PS*x]
%define var(x) [ebp - PS - PS*x]
@@ -269,13 +269,8 @@ section .text
%endif
align 16
-global gf_3vect_dot_prod_avx2:ISAL_SYM_TYPE_FUNCTION
+global gf_3vect_dot_prod_avx2, function
func(gf_3vect_dot_prod_avx2)
-%ifidn __OUTPUT_FORMAT__, macho64
-global _gf_3vect_dot_prod_avx2:ISAL_SYM_TYPE_FUNCTION
-func(_gf_3vect_dot_prod_avx2)
-%endif
-
FUNC_SAVE
SLDR len, len_m
sub len, 32
@@ -395,8 +390,3 @@ func(_gf_3vect_dot_prod_avx2)
ret
endproc_frame
-
-section .data
-
-;;; func core, ver, snum
-slversion gf_3vect_dot_prod_avx2, 04, 05, 0197
diff --git a/contrib/libs/isa-l/erasure_code/gf_3vect_dot_prod_avx2.patch b/contrib/libs/isa-l/erasure_code/gf_3vect_dot_prod_avx2.patch
deleted file mode 100644
index 9c59162877..0000000000
--- a/contrib/libs/isa-l/erasure_code/gf_3vect_dot_prod_avx2.patch
+++ /dev/null
@@ -1,6 +0,0 @@
-274,278d273
-< %ifidn __OUTPUT_FORMAT__, macho64
-< global _gf_3vect_dot_prod_avx2:ISAL_SYM_TYPE_FUNCTION
-< func(_gf_3vect_dot_prod_avx2)
-< %endif
-<
diff --git a/contrib/libs/isa-l/erasure_code/gf_3vect_dot_prod_avx2_gfni.asm b/contrib/libs/isa-l/erasure_code/gf_3vect_dot_prod_avx2_gfni.asm
new file mode 100644
index 0000000000..76a19763a3
--- /dev/null
+++ b/contrib/libs/isa-l/erasure_code/gf_3vect_dot_prod_avx2_gfni.asm
@@ -0,0 +1,335 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; Copyright(c) 2023 Intel Corporation All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions
+; are met:
+; * Redistributions of source code must retain the above copyright
+; notice, this list of conditions and the following disclaimer.
+; * Redistributions in binary form must reproduce the above copyright
+; notice, this list of conditions and the following disclaimer in
+; the documentation and/or other materials provided with the
+; distribution.
+; * Neither the name of Intel Corporation nor the names of its
+; contributors may be used to endorse or promote products derived
+; from this software without specific prior written permission.
+;
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+; "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+; A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+; OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+; SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+; LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+; OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;;;
+;;; gf_3vect_dot_prod_avx2_gfni(len, vec, *g_tbls, **buffs, **dests);
+;;;
+
+%include "reg_sizes.asm"
+%include "gf_vect_gfni.inc"
+%include "memcpy.asm"
+
+%if AS_FEATURE_LEVEL >= 10
+
+%ifidn __OUTPUT_FORMAT__, elf64
+ %define arg0 rdi
+ %define arg1 rsi
+ %define arg2 rdx
+ %define arg3 rcx
+ %define arg4 r8
+ %define arg5 r9
+
+ %define tmp r11
+ %define tmp2 r10
+ %define tmp3 r13 ; must be saved and restored
+ %define tmp4 r12 ; must be saved and restored
+ %define tmp5 r14 ; must be saved and restored
+ %define tmp6 r15 ; must be saved and restored
+
+ %define stack_size 4*8
+ %define func(x) x: endbranch
+ %macro FUNC_SAVE 0
+ sub rsp, stack_size
+ mov [rsp + 0*8], r12
+ mov [rsp + 1*8], r13
+ mov [rsp + 2*8], r14
+ mov [rsp + 3*8], r15
+ %endmacro
+ %macro FUNC_RESTORE 0
+ mov r12, [rsp + 0*8]
+ mov r13, [rsp + 1*8]
+ mov r14, [rsp + 2*8]
+ mov r15, [rsp + 3*8]
+ add rsp, stack_size
+ %endmacro
+%endif
+
+%ifidn __OUTPUT_FORMAT__, win64
+ %define arg0 rcx
+ %define arg1 rdx
+ %define arg2 r8
+ %define arg3 r9
+
+ %define arg4 r12 ; must be saved, loaded and restored
+ %define arg5 r15 ; must be saved and restored
+ %define tmp r11
+ %define tmp2 r10
+ %define tmp3 r13 ; must be saved and restored
+ %define tmp4 r14 ; must be saved and restored
+ %define tmp5 rdi ; must be saved and restored
+ %define tmp6 rsi ; must be saved and restored
+ %define stack_size 8*16 + 7*8 ; must be an odd multiple of 8
+ %define arg(x) [rsp + stack_size + 8 + 8*x]
+
+ %define func(x) proc_frame x
+ %macro FUNC_SAVE 0
+ alloc_stack stack_size
+ vmovdqa [rsp + 0*16], xmm6
+ vmovdqa [rsp + 1*16], xmm7
+ vmovdqa [rsp + 2*16], xmm8
+ vmovdqa [rsp + 3*16], xmm9
+ vmovdqa [rsp + 4*16], xmm10
+ vmovdqa [rsp + 5*16], xmm11
+ vmovdqa [rsp + 6*16], xmm12
+ vmovdqa [rsp + 7*16], xmm13
+ mov [rsp + 8*16 + 0*8], r12
+ mov [rsp + 8*16 + 1*8], r13
+ mov [rsp + 8*16 + 2*8], r14
+ mov [rsp + 8*16 + 3*8], r15
+ mov [rsp + 8*16 + 4*8], rdi
+ mov [rsp + 8*16 + 5*8], rsi
+ end_prolog
+ mov arg4, arg(4)
+ %endmacro
+
+ %macro FUNC_RESTORE 0
+ vmovdqa xmm6, [rsp + 0*16]
+ vmovdqa xmm7, [rsp + 1*16]
+ vmovdqa xmm8, [rsp + 2*16]
+ vmovdqa xmm9, [rsp + 3*16]
+ vmovdqa xmm10, [rsp + 4*16]
+ vmovdqa xmm11, [rsp + 5*16]
+ vmovdqa xmm12, [rsp + 6*16]
+ vmovdqa xmm13, [rsp + 7*16]
+ mov r12, [rsp + 8*16 + 0*8]
+ mov r13, [rsp + 8*16 + 1*8]
+ mov r14, [rsp + 8*16 + 2*8]
+ mov r15, [rsp + 8*16 + 3*8]
+ mov rdi, [rsp + 8*16 + 4*8]
+ mov rsi, [rsp + 8*16 + 5*8]
+ add rsp, stack_size
+ %endmacro
+%endif
+
+
+%define len arg0
+%define vec arg1
+%define mul_array arg2
+%define src arg3
+%define dest arg4
+%define ptr arg5
+%define vec_i tmp2
+%define dest2 tmp3
+%define dest3 tmp4
+%define dest1 tmp5
+%define pos rax
+
+%ifndef EC_ALIGNED_ADDR
+;;; Use Un-aligned load/store
+ %define XLDR vmovdqu
+ %define XSTR vmovdqu
+%else
+;;; Use Non-temporal load/stor
+ %ifdef NO_NT_LDST
+ %define XLDR vmovdqa
+ %define XSTR vmovdqa
+ %else
+ %define XLDR vmovntdqa
+ %define XSTR vmovntdq
+ %endif
+%endif
+
+%define x0l ymm0
+%define x0h ymm1
+
+%define xgft1 ymm8
+%define xgft2 ymm9
+%define xgft3 ymm10
+
+%define xtmp1 ymm11
+%define xtmp2 ymm12
+%define xtmp3 ymm13
+
+%define xp1l ymm2
+%define xp2l ymm3
+%define xp3l ymm4
+%define xp1h ymm5
+%define xp2h ymm6
+%define xp3h ymm7
+
+%define x0 x0l
+%define xp1 xp1l
+%define xp2 xp2l
+%define xp3 xp3l
+
+default rel
+[bits 64]
+
+section .text
+
+;;
+;; Encodes 64 bytes of all "k" sources into 3x 64 bytes (parity disks)
+;;
+%macro ENCODE_64B_3 0
+ vpxor xp1l, xp1l, xp1l
+ vpxor xp1h, xp1h, xp1h
+ vpxor xp2l, xp2l, xp2l
+ vpxor xp2h, xp2h, xp2h
+ vpxor xp3l, xp3l, xp3l
+ vpxor xp3h, xp3h, xp3h
+ mov tmp, mul_array
+ xor vec_i, vec_i
+
+%%next_vect:
+ mov ptr, [src + vec_i]
+ XLDR x0l, [ptr + pos] ;; Get next source vector low 32 bytes
+ XLDR x0h, [ptr + pos + 32] ;; Get next source vector high 32 bytes
+ add vec_i, 8
+
+ vbroadcastsd xgft1, [tmp]
+ vbroadcastsd xgft2, [tmp + vec]
+ vbroadcastsd xgft3, [tmp + vec*2]
+ add tmp, 8
+
+ GF_MUL_XOR VEX, x0l, xgft1, xtmp1, xp1l, xgft2, xtmp2, xp2l, xgft3, xtmp3, xp3l
+ GF_MUL_XOR VEX, x0h, xgft1, xgft1, xp1h, xgft2, xgft2, xp2h, xgft3, xgft3, xp3h
+
+ cmp vec_i, vec
+ jl %%next_vect
+
+ XSTR [dest1 + pos], xp1l
+ XSTR [dest1 + pos + 32], xp1h
+ XSTR [dest2 + pos], xp2l
+ XSTR [dest2 + pos + 32], xp2h
+ XSTR [dest3 + pos], xp3l
+ XSTR [dest3 + pos + 32], xp3h
+%endmacro
+
+;;
+;; Encodes 32 bytes of all "k" sources into 3x 32 bytes (parity disks)
+;;
+%macro ENCODE_32B_3 0
+ vpxor xp1, xp1, xp1
+ vpxor xp2, xp2, xp2
+ vpxor xp3, xp3, xp3
+ mov tmp, mul_array
+ xor vec_i, vec_i
+
+%%next_vect:
+ mov ptr, [src + vec_i]
+ XLDR x0, [ptr + pos] ;Get next source vector (32 bytes)
+ add vec_i, 8
+
+ vbroadcastsd xgft1, [tmp]
+ vbroadcastsd xgft2, [tmp + vec]
+ vbroadcastsd xgft3, [tmp + vec*2]
+ add tmp, 8
+
+ GF_MUL_XOR VEX, x0, xgft1, xgft1, xp1, xgft2, xgft2, xp2, xgft3, xgft3, xp3
+
+ cmp vec_i, vec
+ jl %%next_vect
+
+ XSTR [dest1 + pos], xp1
+ XSTR [dest2 + pos], xp2
+ XSTR [dest3 + pos], xp3
+%endmacro
+
+;;
+;; Encodes less than 32 bytes of all "k" sources into 3 parity disks
+;;
+%macro ENCODE_LT_32B_3 1
+%define %%LEN %1
+
+ vpxor xp1, xp1, xp1
+ vpxor xp2, xp2, xp2
+ vpxor xp3, xp3, xp3
+ xor vec_i, vec_i
+
+%%next_vect:
+ mov ptr, [src + vec_i]
+ simd_load_avx2 x0, ptr + pos, %%LEN, tmp, tmp6 ;Get next source vector
+ add vec_i, 8
+
+ vbroadcastsd xgft1, [mul_array]
+ vbroadcastsd xgft2, [mul_array + vec]
+ vbroadcastsd xgft3, [mul_array + vec*2]
+ add mul_array, 8
+
+ GF_MUL_XOR VEX, x0, xgft1, xgft1, xp1, xgft2, xgft2, xp2, xgft3, xgft3, xp3
+
+ cmp vec_i, vec
+ jl %%next_vect
+
+ ;Store updated encoded data
+ lea ptr, [dest1 + pos]
+ simd_store_avx2 ptr, xp1, %%LEN, tmp, vec_i
+
+ lea ptr, [dest2 + pos]
+ simd_store_avx2 ptr, xp2, %%LEN, tmp, vec_i
+
+ lea ptr, [dest3 + pos]
+ simd_store_avx2 ptr, xp3, %%LEN, tmp, vec_i
+%endmacro
+
+align 16
+global gf_3vect_dot_prod_avx2_gfni, function
+func(gf_3vect_dot_prod_avx2_gfni)
+ FUNC_SAVE
+
+ xor pos, pos
+ shl vec, 3 ;; vec *= 8. Make vec_i count by 8
+ mov dest1, [dest]
+ mov dest2, [dest + 8]
+ mov dest3, [dest + 2*8]
+
+ cmp len, 64
+ jl .len_lt_64
+
+.loop64:
+ ENCODE_64B_3
+
+ add pos, 64 ;; Loop on 64 bytes at a time first
+ sub len, 64
+ cmp len, 64
+ jge .loop64
+
+.len_lt_64:
+ cmp len, 32
+ jl .len_lt_32
+
+ ENCODE_32B_3
+
+ add pos, 32 ;; encode next 32 bytes
+ sub len, 32
+
+.len_lt_32:
+ cmp len, 0
+ jle .exit
+
+ ENCODE_LT_32B_3 len
+
+.exit:
+ vzeroupper
+
+ FUNC_RESTORE
+ ret
+
+endproc_frame
+%endif ; if AS_FEATURE_LEVEL >= 10
diff --git a/contrib/libs/isa-l/erasure_code/gf_3vect_dot_prod_avx512.asm b/contrib/libs/isa-l/erasure_code/gf_3vect_dot_prod_avx512.asm
index 16a90eb2af..fcd919367d 100644
--- a/contrib/libs/isa-l/erasure_code/gf_3vect_dot_prod_avx512.asm
+++ b/contrib/libs/isa-l/erasure_code/gf_3vect_dot_prod_avx512.asm
@@ -44,8 +44,6 @@
%define arg5 r9
%define tmp r11
- %define tmp.w r11d
- %define tmp.b r11b
%define tmp2 r10
%define tmp3 r13 ; must be saved and restored
%define tmp4 r12 ; must be saved and restored
@@ -53,7 +51,7 @@
%define PS 8
%define LOG_PS 3
- %define func(x) x:
+ %define func(x) x: endbranch
%macro FUNC_SAVE 0
push r12
push r13
@@ -73,15 +71,13 @@
%define arg4 r12 ; must be saved, loaded and restored
%define arg5 r15 ; must be saved and restored
%define tmp r11
- %define tmp.w r11d
- %define tmp.b r11b
%define tmp2 r10
%define tmp3 r13 ; must be saved and restored
%define tmp4 r14 ; must be saved and restored
%define return rax
%define PS 8
%define LOG_PS 3
- %define stack_size 9*16 + 5*8 ; must be an odd multiple of 8
+ %define stack_size 6*16 + 5*8 ; must be an odd multiple of 8
%define arg(x) [rsp + stack_size + PS + PS*x]
%define func(x) proc_frame x
@@ -93,13 +89,10 @@
vmovdqa [rsp + 3*16], xmm9
vmovdqa [rsp + 4*16], xmm10
vmovdqa [rsp + 5*16], xmm11
- vmovdqa [rsp + 6*16], xmm12
- vmovdqa [rsp + 7*16], xmm13
- vmovdqa [rsp + 8*16], xmm14
- save_reg r12, 9*16 + 0*8
- save_reg r13, 9*16 + 1*8
- save_reg r14, 9*16 + 2*8
- save_reg r15, 9*16 + 3*8
+ save_reg r12, 6*16 + 0*8
+ save_reg r13, 6*16 + 1*8
+ save_reg r14, 6*16 + 2*8
+ save_reg r15, 6*16 + 3*8
end_prolog
mov arg4, arg(4)
%endmacro
@@ -111,13 +104,10 @@
vmovdqa xmm9, [rsp + 3*16]
vmovdqa xmm10, [rsp + 4*16]
vmovdqa xmm11, [rsp + 5*16]
- vmovdqa xmm12, [rsp + 6*16]
- vmovdqa xmm13, [rsp + 7*16]
- vmovdqa xmm14, [rsp + 8*16]
- mov r12, [rsp + 9*16 + 0*8]
- mov r13, [rsp + 9*16 + 1*8]
- mov r14, [rsp + 9*16 + 2*8]
- mov r15, [rsp + 9*16 + 3*8]
+ mov r12, [rsp + 6*16 + 0*8]
+ mov r13, [rsp + 6*16 + 1*8]
+ mov r14, [rsp + 6*16 + 2*8]
+ mov r15, [rsp + 6*16 + 3*8]
add rsp, stack_size
%endmacro
%endif
@@ -142,8 +132,8 @@
%else
;;; Use Non-temporal load/stor
%ifdef NO_NT_LDST
- %define XLDR vmovdqa
- %define XSTR vmovdqa
+ %define XLDR vmovdqa64
+ %define XSTR vmovdqa64
%else
%define XLDR vmovntdqa
%define XSTR vmovntdq
@@ -173,13 +163,8 @@ default rel
section .text
align 16
-global gf_3vect_dot_prod_avx512:ISAL_SYM_TYPE_FUNCTION
+global gf_3vect_dot_prod_avx512, function
func(gf_3vect_dot_prod_avx512)
-%ifidn __OUTPUT_FORMAT__, macho64
-global _gf_3vect_dot_prod_avx512:ISAL_SYM_TYPE_FUNCTION
-func(_gf_3vect_dot_prod_avx512)
-%endif
-
FUNC_SAVE
sub len, 64
jl .return_fail
diff --git a/contrib/libs/isa-l/erasure_code/gf_3vect_dot_prod_avx512.patch b/contrib/libs/isa-l/erasure_code/gf_3vect_dot_prod_avx512.patch
deleted file mode 100644
index 8397eb6861..0000000000
--- a/contrib/libs/isa-l/erasure_code/gf_3vect_dot_prod_avx512.patch
+++ /dev/null
@@ -1,6 +0,0 @@
-178,182d177
-< %ifidn __OUTPUT_FORMAT__, macho64
-< global _gf_3vect_dot_prod_avx512:ISAL_SYM_TYPE_FUNCTION
-< func(_gf_3vect_dot_prod_avx512)
-< %endif
-<
diff --git a/contrib/libs/isa-l/erasure_code/gf_3vect_dot_prod_avx512_gfni.asm b/contrib/libs/isa-l/erasure_code/gf_3vect_dot_prod_avx512_gfni.asm
new file mode 100644
index 0000000000..39ee6382a2
--- /dev/null
+++ b/contrib/libs/isa-l/erasure_code/gf_3vect_dot_prod_avx512_gfni.asm
@@ -0,0 +1,225 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; Copyright(c) 2023 Intel Corporation All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions
+; are met:
+; * Redistributions of source code must retain the above copyright
+; notice, this list of conditions and the following disclaimer.
+; * Redistributions in binary form must reproduce the above copyright
+; notice, this list of conditions and the following disclaimer in
+; the documentation and/or other materials provided with the
+; distribution.
+; * Neither the name of Intel Corporation nor the names of its
+; contributors may be used to endorse or promote products derived
+; from this software without specific prior written permission.
+;
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+; "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+; A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+; OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+; SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+; LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+; OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;;;
+;;; gf_3vect_dot_prod_avx512_gfni(len, vec, *g_tbls, **buffs, **dests);
+;;;
+
+%include "reg_sizes.asm"
+%include "gf_vect_gfni.inc"
+
+%if AS_FEATURE_LEVEL >= 10
+
+%ifidn __OUTPUT_FORMAT__, elf64
+ %define arg0 rdi
+ %define arg1 rsi
+ %define arg2 rdx
+ %define arg3 rcx
+ %define arg4 r8
+ %define arg5 r9
+
+ %define tmp r11
+ %define tmp2 r10
+ %define tmp3 r13 ; must be saved and restored
+ %define tmp4 r12 ; must be saved and restored
+
+ %define func(x) x: endbranch
+ %macro FUNC_SAVE 0
+ push r12
+ push r13
+ %endmacro
+ %macro FUNC_RESTORE 0
+ pop r13
+ pop r12
+ %endmacro
+%endif
+
+%ifidn __OUTPUT_FORMAT__, win64
+ %define arg0 rcx
+ %define arg1 rdx
+ %define arg2 r8
+ %define arg3 r9
+
+ %define arg4 r12 ; must be saved, loaded and restored
+ %define arg5 r15 ; must be saved and restored
+ %define tmp r11
+ %define tmp2 r10
+ %define tmp3 r13 ; must be saved and restored
+ %define tmp4 r14 ; must be saved and restored
+ %define stack_size 1*16 + 5*8 ; must be an odd multiple of 8
+ %define arg(x) [rsp + stack_size + 8 + 8*x]
+
+ %define func(x) proc_frame x
+ %macro FUNC_SAVE 0
+ alloc_stack stack_size
+ vmovdqa [rsp + 0*16], xmm6
+ mov [rsp + 1*16 + 0*8], r12
+ mov [rsp + 1*16 + 1*8], r13
+ mov [rsp + 1*16 + 2*8], r14
+ mov [rsp + 1*16 + 3*8], r15
+ end_prolog
+ mov arg4, arg(4)
+ %endmacro
+
+ %macro FUNC_RESTORE 0
+ vmovdqa xmm6, [rsp + 0*16]
+ mov r12, [rsp + 1*16 + 0*8]
+ mov r13, [rsp + 1*16 + 1*8]
+ mov r14, [rsp + 1*16 + 2*8]
+ mov r15, [rsp + 1*16 + 3*8]
+ add rsp, stack_size
+ %endmacro
+%endif
+
+
+%define len arg0
+%define vec arg1
+%define mul_array arg2
+%define src arg3
+%define dest1 arg4
+%define ptr arg5
+%define vec_i tmp2
+%define dest2 tmp3
+%define dest3 tmp4
+%define pos rax
+
+
+%ifndef EC_ALIGNED_ADDR
+;;; Use Un-aligned load/store
+ %define XLDR vmovdqu8
+ %define XSTR vmovdqu8
+%else
+;;; Use Non-temporal load/stor
+ %ifdef NO_NT_LDST
+ %define XLDR vmovdqa64
+ %define XSTR vmovdqa64
+ %else
+ %define XLDR vmovntdqa
+ %define XSTR vmovntdq
+ %endif
+%endif
+
+%define xgft1 zmm4
+%define xgft2 zmm5
+%define xgft3 zmm6
+
+%define x0 zmm0
+%define xp1 zmm1
+%define xp2 zmm2
+%define xp3 zmm3
+
+default rel
+[bits 64]
+
+section .text
+
+;;
+;; Encodes 64 bytes of all "k" sources into 3x 64 bytes (parity disks)
+;;
+%macro ENCODE_64B_3 0-1
+%define %%KMASK %1
+
+ vpxorq xp1, xp1, xp1
+ vpxorq xp2, xp2, xp2
+ vpxorq xp3, xp3, xp3
+ mov tmp, mul_array
+ xor vec_i, vec_i
+
+%%next_vect:
+ mov ptr, [src + vec_i]
+%if %0 == 1
+ vmovdqu8 x0{%%KMASK}, [ptr + pos] ;Get next source vector (less than 64 bytes)
+%else
+ XLDR x0, [ptr + pos] ;Get next source vector (64 bytes)
+%endif
+ add vec_i, 8
+
+ vbroadcastf32x2 xgft1, [tmp]
+ vbroadcastf32x2 xgft2, [tmp + vec]
+ vbroadcastf32x2 xgft3, [tmp + vec*2]
+ add tmp, 8
+
+ GF_MUL_XOR EVEX, x0, xgft1, xgft1, xp1, xgft2, xgft2, xp2, xgft3, xgft3, xp3
+
+ cmp vec_i, vec
+ jl %%next_vect
+
+%if %0 == 1
+ vmovdqu8 [dest1 + pos]{%%KMASK}, xp1
+ vmovdqu8 [dest2 + pos]{%%KMASK}, xp2
+ vmovdqu8 [dest3 + pos]{%%KMASK}, xp3
+%else
+ XSTR [dest1 + pos], xp1
+ XSTR [dest2 + pos], xp2
+ XSTR [dest3 + pos], xp3
+%endif
+%endmacro
+
+align 16
+global gf_3vect_dot_prod_avx512_gfni, function
+func(gf_3vect_dot_prod_avx512_gfni)
+ FUNC_SAVE
+
+ xor pos, pos
+ shl vec, 3 ;vec *= 8. Make vec_i count by 8
+ mov dest2, [dest1 + 8]
+ mov dest3, [dest1 + 2*8]
+ mov dest1, [dest1]
+
+ cmp len, 64
+ jl .len_lt_64
+
+.loop64:
+
+ ENCODE_64B_3
+
+ add pos, 64 ;Loop on 64 bytes at a time
+ sub len, 64
+ cmp len, 64
+ jge .loop64
+
+.len_lt_64:
+ cmp len, 0
+ jle .exit
+
+ xor tmp, tmp
+ bts tmp, len
+ dec tmp
+ kmovq k1, tmp
+
+ ENCODE_64B_3 k1
+
+.exit:
+ vzeroupper
+
+ FUNC_RESTORE
+ ret
+
+endproc_frame
+%endif ; if AS_FEATURE_LEVEL >= 10
diff --git a/contrib/libs/isa-l/erasure_code/gf_3vect_dot_prod_sse.asm b/contrib/libs/isa-l/erasure_code/gf_3vect_dot_prod_sse.asm
index 582fac8481..af0875016c 100644
--- a/contrib/libs/isa-l/erasure_code/gf_3vect_dot_prod_sse.asm
+++ b/contrib/libs/isa-l/erasure_code/gf_3vect_dot_prod_sse.asm
@@ -52,7 +52,7 @@
%define PS 8
%define LOG_PS 3
- %define func(x) x:
+ %define func(x) x: endbranch
%macro FUNC_SAVE 0
push r12
push r13
@@ -139,7 +139,7 @@
%define PS 4
%define LOG_PS 2
- %define func(x) x:
+ %define func(x) x: endbranch
%define arg(x) [ebp + PS*2 + PS*x]
%define var(x) [ebp - PS - PS*x]
@@ -261,13 +261,8 @@ section .text
%endif
align 16
-global gf_3vect_dot_prod_sse:ISAL_SYM_TYPE_FUNCTION
+global gf_3vect_dot_prod_sse, function
func(gf_3vect_dot_prod_sse)
-%ifidn __OUTPUT_FORMAT__, macho64
-global _gf_3vect_dot_prod_sse:ISAL_SYM_TYPE_FUNCTION
-func(_gf_3vect_dot_prod_sse)
-%endif
-
FUNC_SAVE
SLDR len, len_m
sub len, 16
@@ -378,6 +373,3 @@ section .data
align 16
mask0f: dq 0x0f0f0f0f0f0f0f0f, 0x0f0f0f0f0f0f0f0f
-
-;;; func core, ver, snum
-slversion gf_3vect_dot_prod_sse, 00, 06, 0063
diff --git a/contrib/libs/isa-l/erasure_code/gf_3vect_dot_prod_sse.patch b/contrib/libs/isa-l/erasure_code/gf_3vect_dot_prod_sse.patch
deleted file mode 100644
index f21ce0ff9c..0000000000
--- a/contrib/libs/isa-l/erasure_code/gf_3vect_dot_prod_sse.patch
+++ /dev/null
@@ -1,6 +0,0 @@
-266,270d265
-< %ifidn __OUTPUT_FORMAT__, macho64
-< global _gf_3vect_dot_prod_sse:ISAL_SYM_TYPE_FUNCTION
-< func(_gf_3vect_dot_prod_sse)
-< %endif
-<
diff --git a/contrib/libs/isa-l/erasure_code/gf_3vect_dot_prod_sse_test.c b/contrib/libs/isa-l/erasure_code/gf_3vect_dot_prod_sse_test.c
deleted file mode 100644
index b2c19382ff..0000000000
--- a/contrib/libs/isa-l/erasure_code/gf_3vect_dot_prod_sse_test.c
+++ /dev/null
@@ -1,586 +0,0 @@
-/**********************************************************************
- Copyright(c) 2011-2015 Intel Corporation All rights reserved.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions
- are met:
- * Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in
- the documentation and/or other materials provided with the
- distribution.
- * Neither the name of Intel Corporation nor the names of its
- contributors may be used to endorse or promote products derived
- from this software without specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-**********************************************************************/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h> // for memset, memcmp
-#include "erasure_code.h"
-// #include "types.h"
-
-#ifndef FUNCTION_UNDER_TEST
-# define FUNCTION_UNDER_TEST gf_3vect_dot_prod_sse
-#endif
-#ifndef TEST_MIN_SIZE
-# define TEST_MIN_SIZE 16
-#endif
-
-#define str(s) #s
-#define xstr(s) str(s)
-
-#define TEST_LEN 2048
-#define TEST_SIZE (TEST_LEN/2)
-#define TEST_MEM TEST_SIZE
-#define TEST_LOOPS 1000
-#define TEST_TYPE_STR ""
-
-#ifndef TEST_SOURCES
-# define TEST_SOURCES 16
-#endif
-#ifndef RANDOMS
-# define RANDOMS 20
-#endif
-
-#ifdef EC_ALIGNED_ADDR
-// Define power of 2 range to check ptr, len alignment
-# define PTR_ALIGN_CHK_B 0
-# define LEN_ALIGN_CHK_B 0 // 0 for aligned only
-#else
-// Define power of 2 range to check ptr, len alignment
-# define PTR_ALIGN_CHK_B 32
-# define LEN_ALIGN_CHK_B 32 // 0 for aligned only
-#endif
-
-typedef unsigned char u8;
-
-extern void FUNCTION_UNDER_TEST(int len, int vlen, unsigned char *gftbls,
- unsigned char **src, unsigned char **dest);
-
-void dump(unsigned char *buf, int len)
-{
- int i;
- for (i = 0; i < len;) {
- printf(" %2x", 0xff & buf[i++]);
- if (i % 32 == 0)
- printf("\n");
- }
- printf("\n");
-}
-
-void dump_matrix(unsigned char **s, int k, int m)
-{
- int i, j;
- for (i = 0; i < k; i++) {
- for (j = 0; j < m; j++) {
- printf(" %2x", s[i][j]);
- }
- printf("\n");
- }
- printf("\n");
-}
-
-void dump_u8xu8(unsigned char *s, int k, int m)
-{
- int i, j;
- for (i = 0; i < k; i++) {
- for (j = 0; j < m; j++) {
- printf(" %2x", 0xff & s[j + (i * m)]);
- }
- printf("\n");
- }
- printf("\n");
-}
-
-int main(int argc, char *argv[])
-{
- int i, j, rtest, srcs;
- void *buf;
- u8 g1[TEST_SOURCES], g2[TEST_SOURCES], g3[TEST_SOURCES];
- u8 g_tbls[3 * TEST_SOURCES * 32], *dest_ptrs[3], *buffs[TEST_SOURCES];
- u8 *dest1, *dest2, *dest3, *dest_ref1, *dest_ref2, *dest_ref3;
-
- int align, size;
- unsigned char *efence_buffs[TEST_SOURCES];
- unsigned int offset;
- u8 *ubuffs[TEST_SOURCES];
- u8 *udest_ptrs[3];
- printf(xstr(FUNCTION_UNDER_TEST) "_test: %dx%d ", TEST_SOURCES, TEST_LEN);
-
- // Allocate the arrays
- for (i = 0; i < TEST_SOURCES; i++) {
- if (posix_memalign(&buf, 64, TEST_LEN)) {
- printf("alloc error: Fail");
- return -1;
- }
- buffs[i] = buf;
- }
-
- if (posix_memalign(&buf, 64, TEST_LEN)) {
- printf("alloc error: Fail");
- return -1;
- }
- dest1 = buf;
-
- if (posix_memalign(&buf, 64, TEST_LEN)) {
- printf("alloc error: Fail");
- return -1;
- }
- dest2 = buf;
-
- if (posix_memalign(&buf, 64, TEST_LEN)) {
- printf("alloc error: Fail");
- return -1;
- }
- dest3 = buf;
-
- if (posix_memalign(&buf, 64, TEST_LEN)) {
- printf("alloc error: Fail");
- return -1;
- }
- dest_ref1 = buf;
-
- if (posix_memalign(&buf, 64, TEST_LEN)) {
- printf("alloc error: Fail");;
- return -1;
- }
- dest_ref2 = buf;
-
- if (posix_memalign(&buf, 64, TEST_LEN)) {
- printf("alloc error: Fail");
- return -1;
- }
- dest_ref3 = buf;
-
- dest_ptrs[0] = dest1;
- dest_ptrs[1] = dest2;
- dest_ptrs[2] = dest3;
-
- // Test of all zeros
- for (i = 0; i < TEST_SOURCES; i++)
- memset(buffs[i], 0, TEST_LEN);
-
- memset(dest1, 0, TEST_LEN);
- memset(dest2, 0, TEST_LEN);
- memset(dest3, 0, TEST_LEN);
- memset(dest_ref1, 0, TEST_LEN);
- memset(dest_ref2, 0, TEST_LEN);
- memset(dest_ref3, 0, TEST_LEN);
- memset(g1, 2, TEST_SOURCES);
- memset(g2, 1, TEST_SOURCES);
- memset(g3, 7, TEST_SOURCES);
-
- for (i = 0; i < TEST_SOURCES; i++) {
- gf_vect_mul_init(g1[i], &g_tbls[i * 32]);
- gf_vect_mul_init(g2[i], &g_tbls[32 * TEST_SOURCES + i * 32]);
- gf_vect_mul_init(g3[i], &g_tbls[64 * TEST_SOURCES + i * 32]);
- }
-
- gf_vect_dot_prod_base(TEST_LEN, TEST_SOURCES, &g_tbls[0], buffs, dest_ref1);
- gf_vect_dot_prod_base(TEST_LEN, TEST_SOURCES, &g_tbls[32 * TEST_SOURCES], buffs,
- dest_ref2);
- gf_vect_dot_prod_base(TEST_LEN, TEST_SOURCES, &g_tbls[64 * TEST_SOURCES], buffs,
- dest_ref3);
-
- FUNCTION_UNDER_TEST(TEST_LEN, TEST_SOURCES, g_tbls, buffs, dest_ptrs);
-
- if (0 != memcmp(dest_ref1, dest1, TEST_LEN)) {
- printf("Fail zero" xstr(FUNCTION_UNDER_TEST) " test1\n");
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref1, 25);
- printf("dprod_dut:");
- dump(dest1, 25);
- return -1;
- }
- if (0 != memcmp(dest_ref2, dest2, TEST_LEN)) {
- printf("Fail zero " xstr(FUNCTION_UNDER_TEST) " test2\n");
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref2, 25);
- printf("dprod_dut:");
- dump(dest2, 25);
- return -1;
- }
- if (0 != memcmp(dest_ref3, dest3, TEST_LEN)) {
- printf("Fail zero " xstr(FUNCTION_UNDER_TEST) " test3\n");
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref3, 25);
- printf("dprod_dut:");
- dump(dest3, 25);
- return -1;
- }
-
- putchar('.');
-
- // Rand data test
-
- for (rtest = 0; rtest < RANDOMS; rtest++) {
- for (i = 0; i < TEST_SOURCES; i++)
- for (j = 0; j < TEST_LEN; j++)
- buffs[i][j] = rand();
-
- for (i = 0; i < TEST_SOURCES; i++) {
- g1[i] = rand();
- g2[i] = rand();
- g3[i] = rand();
- }
-
- for (i = 0; i < TEST_SOURCES; i++) {
- gf_vect_mul_init(g1[i], &g_tbls[i * 32]);
- gf_vect_mul_init(g2[i], &g_tbls[(32 * TEST_SOURCES) + (i * 32)]);
- gf_vect_mul_init(g3[i], &g_tbls[(64 * TEST_SOURCES) + (i * 32)]);
- }
-
- gf_vect_dot_prod_base(TEST_LEN, TEST_SOURCES, &g_tbls[0], buffs, dest_ref1);
- gf_vect_dot_prod_base(TEST_LEN, TEST_SOURCES, &g_tbls[32 * TEST_SOURCES],
- buffs, dest_ref2);
- gf_vect_dot_prod_base(TEST_LEN, TEST_SOURCES, &g_tbls[64 * TEST_SOURCES],
- buffs, dest_ref3);
-
- FUNCTION_UNDER_TEST(TEST_LEN, TEST_SOURCES, g_tbls, buffs, dest_ptrs);
-
- if (0 != memcmp(dest_ref1, dest1, TEST_LEN)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test1 %d\n", rtest);
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref1, 25);
- printf("dprod_dut:");
- dump(dest1, 25);
- return -1;
- }
- if (0 != memcmp(dest_ref2, dest2, TEST_LEN)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test2 %d\n", rtest);
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref2, 25);
- printf("dprod_dut:");
- dump(dest2, 25);
- return -1;
- }
- if (0 != memcmp(dest_ref3, dest3, TEST_LEN)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test3 %d\n", rtest);
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref3, 25);
- printf("dprod_dut:");
- dump(dest3, 25);
- return -1;
- }
-
- putchar('.');
- }
-
- // Rand data test with varied parameters
- for (rtest = 0; rtest < RANDOMS; rtest++) {
- for (srcs = TEST_SOURCES; srcs > 0; srcs--) {
- for (i = 0; i < srcs; i++)
- for (j = 0; j < TEST_LEN; j++)
- buffs[i][j] = rand();
-
- for (i = 0; i < srcs; i++) {
- g1[i] = rand();
- g2[i] = rand();
- g3[i] = rand();
- }
-
- for (i = 0; i < srcs; i++) {
- gf_vect_mul_init(g1[i], &g_tbls[i * 32]);
- gf_vect_mul_init(g2[i], &g_tbls[(32 * srcs) + (i * 32)]);
- gf_vect_mul_init(g3[i], &g_tbls[(64 * srcs) + (i * 32)]);
- }
-
- gf_vect_dot_prod_base(TEST_LEN, srcs, &g_tbls[0], buffs, dest_ref1);
- gf_vect_dot_prod_base(TEST_LEN, srcs, &g_tbls[32 * srcs], buffs,
- dest_ref2);
- gf_vect_dot_prod_base(TEST_LEN, srcs, &g_tbls[64 * srcs], buffs,
- dest_ref3);
-
- FUNCTION_UNDER_TEST(TEST_LEN, srcs, g_tbls, buffs, dest_ptrs);
-
- if (0 != memcmp(dest_ref1, dest1, TEST_LEN)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST)
- " test1 srcs=%d\n", srcs);
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref1, 25);
- printf("dprod_dut:");
- dump(dest1, 25);
- return -1;
- }
- if (0 != memcmp(dest_ref2, dest2, TEST_LEN)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST)
- " test2 srcs=%d\n", srcs);
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref2, 25);
- printf("dprod_dut:");
- dump(dest2, 25);
- return -1;
- }
- if (0 != memcmp(dest_ref3, dest3, TEST_LEN)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST)
- " test3 srcs=%d\n", srcs);
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref3, 25);
- printf("dprod_dut:");
- dump(dest3, 25);
- return -1;
- }
-
- putchar('.');
- }
- }
-
- // Run tests at end of buffer for Electric Fence
- align = (LEN_ALIGN_CHK_B != 0) ? 1 : 16;
- for (size = TEST_MIN_SIZE; size <= TEST_SIZE; size += align) {
- for (i = 0; i < TEST_SOURCES; i++)
- for (j = 0; j < TEST_LEN; j++)
- buffs[i][j] = rand();
-
- for (i = 0; i < TEST_SOURCES; i++) // Line up TEST_SIZE from end
- efence_buffs[i] = buffs[i] + TEST_LEN - size;
-
- for (i = 0; i < TEST_SOURCES; i++) {
- g1[i] = rand();
- g2[i] = rand();
- g3[i] = rand();
- }
-
- for (i = 0; i < TEST_SOURCES; i++) {
- gf_vect_mul_init(g1[i], &g_tbls[i * 32]);
- gf_vect_mul_init(g2[i], &g_tbls[(32 * TEST_SOURCES) + (i * 32)]);
- gf_vect_mul_init(g3[i], &g_tbls[(64 * TEST_SOURCES) + (i * 32)]);
- }
-
- gf_vect_dot_prod_base(size, TEST_SOURCES, &g_tbls[0], efence_buffs, dest_ref1);
- gf_vect_dot_prod_base(size, TEST_SOURCES, &g_tbls[32 * TEST_SOURCES],
- efence_buffs, dest_ref2);
- gf_vect_dot_prod_base(size, TEST_SOURCES, &g_tbls[64 * TEST_SOURCES],
- efence_buffs, dest_ref3);
-
- FUNCTION_UNDER_TEST(size, TEST_SOURCES, g_tbls, efence_buffs, dest_ptrs);
-
- if (0 != memcmp(dest_ref1, dest1, size)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test1 %d\n", rtest);
- dump_matrix(efence_buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref1, align);
- printf("dprod_dut:");
- dump(dest1, align);
- return -1;
- }
-
- if (0 != memcmp(dest_ref2, dest2, size)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test2 %d\n", rtest);
- dump_matrix(efence_buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref2, align);
- printf("dprod_dut:");
- dump(dest2, align);
- return -1;
- }
-
- if (0 != memcmp(dest_ref3, dest3, size)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test3 %d\n", rtest);
- dump_matrix(efence_buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref3, align);
- printf("dprod_dut:");
- dump(dest3, align);
- return -1;
- }
-
- putchar('.');
- }
-
- // Test rand ptr alignment if available
-
- for (rtest = 0; rtest < RANDOMS; rtest++) {
- size = (TEST_LEN - PTR_ALIGN_CHK_B) & ~(TEST_MIN_SIZE - 1);
- srcs = rand() % TEST_SOURCES;
- if (srcs == 0)
- continue;
-
- offset = (PTR_ALIGN_CHK_B != 0) ? 1 : PTR_ALIGN_CHK_B;
- // Add random offsets
- for (i = 0; i < srcs; i++)
- ubuffs[i] = buffs[i] + (rand() & (PTR_ALIGN_CHK_B - offset));
-
- udest_ptrs[0] = dest1 + (rand() & (PTR_ALIGN_CHK_B - offset));
- udest_ptrs[1] = dest2 + (rand() & (PTR_ALIGN_CHK_B - offset));
- udest_ptrs[2] = dest3 + (rand() & (PTR_ALIGN_CHK_B - offset));
-
- memset(dest1, 0, TEST_LEN); // zero pad to check write-over
- memset(dest2, 0, TEST_LEN);
- memset(dest3, 0, TEST_LEN);
-
- for (i = 0; i < srcs; i++)
- for (j = 0; j < size; j++)
- ubuffs[i][j] = rand();
-
- for (i = 0; i < srcs; i++) {
- g1[i] = rand();
- g2[i] = rand();
- g3[i] = rand();
- }
-
- for (i = 0; i < srcs; i++) {
- gf_vect_mul_init(g1[i], &g_tbls[i * 32]);
- gf_vect_mul_init(g2[i], &g_tbls[(32 * srcs) + (i * 32)]);
- gf_vect_mul_init(g3[i], &g_tbls[(64 * srcs) + (i * 32)]);
- }
-
- gf_vect_dot_prod_base(size, srcs, &g_tbls[0], ubuffs, dest_ref1);
- gf_vect_dot_prod_base(size, srcs, &g_tbls[32 * srcs], ubuffs, dest_ref2);
- gf_vect_dot_prod_base(size, srcs, &g_tbls[64 * srcs], ubuffs, dest_ref3);
-
- FUNCTION_UNDER_TEST(size, srcs, g_tbls, ubuffs, udest_ptrs);
-
- if (memcmp(dest_ref1, udest_ptrs[0], size)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test ualign srcs=%d\n",
- srcs);
- dump_matrix(ubuffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref1, 25);
- printf("dprod_dut:");
- dump(udest_ptrs[0], 25);
- return -1;
- }
- if (memcmp(dest_ref2, udest_ptrs[1], size)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test ualign srcs=%d\n",
- srcs);
- dump_matrix(ubuffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref2, 25);
- printf("dprod_dut:");
- dump(udest_ptrs[1], 25);
- return -1;
- }
- if (memcmp(dest_ref3, udest_ptrs[2], size)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test ualign srcs=%d\n",
- srcs);
- dump_matrix(ubuffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref3, 25);
- printf("dprod_dut:");
- dump(udest_ptrs[2], 25);
- return -1;
- }
- // Confirm that padding around dests is unchanged
- memset(dest_ref1, 0, PTR_ALIGN_CHK_B); // Make reference zero buff
- offset = udest_ptrs[0] - dest1;
-
- if (memcmp(dest1, dest_ref1, offset)) {
- printf("Fail rand ualign pad1 start\n");
- return -1;
- }
- if (memcmp(dest1 + offset + size, dest_ref1, PTR_ALIGN_CHK_B - offset)) {
- printf("Fail rand ualign pad1 end\n");
- return -1;
- }
-
- offset = udest_ptrs[1] - dest2;
- if (memcmp(dest2, dest_ref1, offset)) {
- printf("Fail rand ualign pad2 start\n");
- return -1;
- }
- if (memcmp(dest2 + offset + size, dest_ref1, PTR_ALIGN_CHK_B - offset)) {
- printf("Fail rand ualign pad2 end\n");
- return -1;
- }
-
- offset = udest_ptrs[2] - dest3;
- if (memcmp(dest3, dest_ref1, offset)) {
- printf("Fail rand ualign pad3 start\n");
- return -1;
- }
- if (memcmp(dest3 + offset + size, dest_ref1, PTR_ALIGN_CHK_B - offset)) {
- printf("Fail rand ualign pad3 end\n");;
- return -1;
- }
-
- putchar('.');
- }
-
- // Test all size alignment
- align = (LEN_ALIGN_CHK_B != 0) ? 1 : 16;
-
- for (size = TEST_LEN; size >= TEST_MIN_SIZE; size -= align) {
- srcs = TEST_SOURCES;
-
- for (i = 0; i < srcs; i++)
- for (j = 0; j < size; j++)
- buffs[i][j] = rand();
-
- for (i = 0; i < srcs; i++) {
- g1[i] = rand();
- g2[i] = rand();
- g3[i] = rand();
- }
-
- for (i = 0; i < srcs; i++) {
- gf_vect_mul_init(g1[i], &g_tbls[i * 32]);
- gf_vect_mul_init(g2[i], &g_tbls[(32 * srcs) + (i * 32)]);
- gf_vect_mul_init(g3[i], &g_tbls[(64 * srcs) + (i * 32)]);
- }
-
- gf_vect_dot_prod_base(size, srcs, &g_tbls[0], buffs, dest_ref1);
- gf_vect_dot_prod_base(size, srcs, &g_tbls[32 * srcs], buffs, dest_ref2);
- gf_vect_dot_prod_base(size, srcs, &g_tbls[64 * srcs], buffs, dest_ref3);
-
- FUNCTION_UNDER_TEST(size, srcs, g_tbls, buffs, dest_ptrs);
-
- if (memcmp(dest_ref1, dest_ptrs[0], size)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test ualign len=%d\n",
- size);
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref1, 25);
- printf("dprod_dut:");
- dump(dest_ptrs[0], 25);
- return -1;
- }
- if (memcmp(dest_ref2, dest_ptrs[1], size)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test ualign len=%d\n",
- size);
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref2, 25);
- printf("dprod_dut:");
- dump(dest_ptrs[1], 25);
- return -1;
- }
- if (memcmp(dest_ref3, dest_ptrs[2], size)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test ualign len=%d\n",
- size);
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref3, 25);
- printf("dprod_dut:");
- dump(dest_ptrs[2], 25);
- return -1;
- }
- }
-
- printf("Pass\n");
- return 0;
-
-}
diff --git a/contrib/libs/isa-l/erasure_code/gf_3vect_dot_prod_sse_test.patch b/contrib/libs/isa-l/erasure_code/gf_3vect_dot_prod_sse_test.patch
deleted file mode 100644
index 21bbfaa667..0000000000
--- a/contrib/libs/isa-l/erasure_code/gf_3vect_dot_prod_sse_test.patch
+++ /dev/null
@@ -1,4 +0,0 @@
-34c34
-< // #include "types.h"
----
-> #include "types.h"
diff --git a/contrib/libs/isa-l/erasure_code/gf_3vect_mad_avx.asm b/contrib/libs/isa-l/erasure_code/gf_3vect_mad_avx.asm
index 7cf630558c..4e30d1764e 100644
--- a/contrib/libs/isa-l/erasure_code/gf_3vect_mad_avx.asm
+++ b/contrib/libs/isa-l/erasure_code/gf_3vect_mad_avx.asm
@@ -97,7 +97,7 @@
%define return rax
%define return.w eax
- %define func(x) x:
+ %define func(x) x: endbranch
%define FUNC_SAVE
%define FUNC_RESTORE
%endif
@@ -158,12 +158,8 @@ section .text
%define xd3 xtmph1
align 16
-global gf_3vect_mad_avx:ISAL_SYM_TYPE_FUNCTION
+global gf_3vect_mad_avx, function
func(gf_3vect_mad_avx)
-%ifidn __OUTPUT_FORMAT__, macho64
-global _gf_3vect_mad_avx:ISAL_SYM_TYPE_FUNCTION
-func(_gf_3vect_mad_avx)
-%endif
FUNC_SAVE
sub len, 16
jl .return_fail
@@ -287,6 +283,3 @@ align 16
mask0f: dq 0x0f0f0f0f0f0f0f0f, 0x0f0f0f0f0f0f0f0f
constip16:
dq 0xf8f9fafbfcfdfeff, 0xf0f1f2f3f4f5f6f7
-
-;;; func core, ver, snum
-slversion gf_3vect_mad_avx, 02, 01, 0207
diff --git a/contrib/libs/isa-l/erasure_code/gf_3vect_mad_avx.patch b/contrib/libs/isa-l/erasure_code/gf_3vect_mad_avx.patch
deleted file mode 100644
index 983b4fc414..0000000000
--- a/contrib/libs/isa-l/erasure_code/gf_3vect_mad_avx.patch
+++ /dev/null
@@ -1,5 +0,0 @@
-163,166d162
-< %ifidn __OUTPUT_FORMAT__, macho64
-< global _gf_3vect_mad_avx:ISAL_SYM_TYPE_FUNCTION
-< func(_gf_3vect_mad_avx)
-< %endif
diff --git a/contrib/libs/isa-l/erasure_code/gf_3vect_mad_avx2.asm b/contrib/libs/isa-l/erasure_code/gf_3vect_mad_avx2.asm
index c218b4db28..069c5103bc 100644
--- a/contrib/libs/isa-l/erasure_code/gf_3vect_mad_avx2.asm
+++ b/contrib/libs/isa-l/erasure_code/gf_3vect_mad_avx2.asm
@@ -103,7 +103,7 @@
%define return rax
%define return.w eax
- %define func(x) x:
+ %define func(x) x: endbranch
%define FUNC_SAVE
%define FUNC_RESTORE
%endif
@@ -165,13 +165,8 @@ section .text
%define xd3 ymm10
align 16
-global gf_3vect_mad_avx2:ISAL_SYM_TYPE_FUNCTION
+global gf_3vect_mad_avx2, function
func(gf_3vect_mad_avx2)
-%ifidn __OUTPUT_FORMAT__, macho64
-global _gf_3vect_mad_avx2:ISAL_SYM_TYPE_FUNCTION
-func(_gf_3vect_mad_avx2)
-%endif
-
FUNC_SAVE
sub len, 32
jl .return_fail
@@ -317,6 +312,3 @@ align 32
constip32:
dq 0xf8f9fafbfcfdfeff, 0xf0f1f2f3f4f5f6f7
dq 0xe8e9eaebecedeeef, 0xe0e1e2e3e4e5e6e7
-
-;;; func core, ver, snum
-slversion gf_3vect_mad_avx2, 04, 01, 0208
diff --git a/contrib/libs/isa-l/erasure_code/gf_3vect_mad_avx2.patch b/contrib/libs/isa-l/erasure_code/gf_3vect_mad_avx2.patch
deleted file mode 100644
index 058f09b3c4..0000000000
--- a/contrib/libs/isa-l/erasure_code/gf_3vect_mad_avx2.patch
+++ /dev/null
@@ -1,6 +0,0 @@
-170,174d169
-< %ifidn __OUTPUT_FORMAT__, macho64
-< global _gf_3vect_mad_avx2:ISAL_SYM_TYPE_FUNCTION
-< func(_gf_3vect_mad_avx2)
-< %endif
-<
diff --git a/contrib/libs/isa-l/erasure_code/gf_3vect_mad_avx2_gfni.asm b/contrib/libs/isa-l/erasure_code/gf_3vect_mad_avx2_gfni.asm
new file mode 100644
index 0000000000..8a04577acd
--- /dev/null
+++ b/contrib/libs/isa-l/erasure_code/gf_3vect_mad_avx2_gfni.asm
@@ -0,0 +1,276 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; Copyright(c) 2023 Intel Corporation All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions
+; are met:
+; * Redistributions of source code must retain the above copyright
+; notice, this list of conditions and the following disclaimer.
+; * Redistributions in binary form must reproduce the above copyright
+; notice, this list of conditions and the following disclaimer in
+; the documentation and/or other materials provided with the
+; distribution.
+; * Neither the name of Intel Corporation nor the names of its
+; contributors may be used to endorse or promote products derived
+; from this software without specific prior written permission.
+;
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+; "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+; A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+; OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+; SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+; LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+; OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;;;
+;;; gf_3vect_mad_avx2_gfni(len, vec, vec_i, mul_array, src, dest);
+;;;
+
+%include "reg_sizes.asm"
+%include "gf_vect_gfni.inc"
+%include "memcpy.asm"
+
+%if AS_FEATURE_LEVEL >= 10
+
+%ifidn __OUTPUT_FORMAT__, elf64
+ %define arg0 rdi
+ %define arg1 rsi
+ %define arg2 rdx
+ %define arg3 rcx
+ %define arg4 r8
+ %define arg5 r9
+ %define tmp r11
+ %define tmp2 r10
+ %define func(x) x: endbranch
+ %define FUNC_SAVE
+ %define FUNC_RESTORE
+%endif
+
+%ifidn __OUTPUT_FORMAT__, win64
+ %define arg0 rcx
+ %define arg1 rdx
+ %define arg2 r8
+ %define arg3 r9
+ %define arg4 r12 ; must be saved, loaded and restored
+ %define arg5 r13 ; must be saved and restored
+ %define tmp r11
+ %define tmp2 r10
+ %define stack_size 16*10 + 3*8
+ %define arg(x) [rsp + stack_size + 8 + 8*x]
+ %define func(x) proc_frame x
+
+ %macro FUNC_SAVE 0
+ sub rsp, stack_size
+ vmovdqa [rsp + 0*16], xmm6
+ vmovdqa [rsp + 1*16], xmm7
+ vmovdqa [rsp + 2*16], xmm8
+ vmovdqa [rsp + 3*16], xmm9
+ vmovdqa [rsp + 4*16], xmm10
+ vmovdqa [rsp + 5*16], xmm11
+ vmovdqa [rsp + 6*16], xmm12
+ vmovdqa [rsp + 7*16], xmm13
+ vmovdqa [rsp + 8*16], xmm14
+ vmovdqa [rsp + 9*16], xmm15
+ mov [rsp + 10*16 + 0*8], r12
+ mov [rsp + 10*16 + 1*8], r13
+ end_prolog
+ mov arg4, arg(4)
+ mov arg5, arg(5)
+ %endmacro
+
+ %macro FUNC_RESTORE 0
+ vmovdqa xmm6, [rsp + 0*16]
+ vmovdqa xmm7, [rsp + 1*16]
+ vmovdqa xmm8, [rsp + 2*16]
+ vmovdqa xmm9, [rsp + 3*16]
+ vmovdqa xmm10, [rsp + 4*16]
+ vmovdqa xmm11, [rsp + 5*16]
+ vmovdqa xmm12, [rsp + 6*16]
+ vmovdqa xmm13, [rsp + 7*16]
+ vmovdqa xmm14, [rsp + 8*16]
+ vmovdqa xmm15, [rsp + 9*16]
+ mov r12, [rsp + 10*16 + 0*8]
+ mov r13, [rsp + 10*16 + 1*8]
+ add rsp, stack_size
+ %endmacro
+%endif
+
+%define len arg0
+%define vec arg1
+%define vec_i arg2
+%define mul_array arg3
+%define src arg4
+%define dest1 arg5
+%define pos rax
+%define dest2 mul_array
+%define dest3 vec_i
+
+%ifndef EC_ALIGNED_ADDR
+;;; Use Un-aligned load/store
+ %define XLDR vmovdqu
+ %define XSTR vmovdqu
+%else
+;;; Use Non-temporal load/stor
+ %ifdef NO_NT_LDST
+ %define XLDR vmovdqa
+ %define XSTR vmovdqa
+ %else
+ %define XLDR vmovntdqa
+ %define XSTR vmovntdq
+ %endif
+%endif
+
+default rel
+[bits 64]
+section .text
+
+%define x0l ymm0
+%define x0h ymm0 ; reuse ymm0
+%define xgft1 ymm1
+%define xgft2 ymm2
+%define xgft3 ymm3
+%define xd1l ymm4
+%define xd1h ymm5
+%define xd2l ymm6
+%define xd2h ymm7
+%define xd3l ymm8
+%define xd3h ymm9
+
+%define xret1l ymm10
+%define xret1h ymm11
+%define xret2l ymm12
+%define xret2h ymm13
+%define xret3l ymm14
+%define xret3h ymm15
+
+%define x0 x0l
+%define xd1 xd1l
+%define xd2 xd2l
+%define xd3 xd3l
+%define xret1 xret1l
+%define xret2 xret2l
+%define xret3 xret3l
+
+;;
+;; Encodes 64 bytes of a single source into 3x 64 bytes (parity disks)
+;;
+%macro ENCODE_64B_3 0
+ ; get next source vector
+ XLDR x0l, [src + pos] ;; read low 32 bytes
+ ; get next dest vectors
+ XLDR xd1l, [dest1 + pos]
+ XLDR xd1h, [dest1 + pos + 32]
+ XLDR xd2l, [dest2 + pos]
+ XLDR xd2h, [dest2 + pos + 32]
+ XLDR xd3l, [dest3 + pos]
+ XLDR xd3h, [dest3 + pos + 32]
+
+ GF_MUL_XOR VEX, x0l, xgft1, xret1l, xd1l, xgft2, xret2l, xd2l, xgft3, xret3l, xd3l
+
+ XLDR x0h, [src + pos + 32] ;; read high 32 bytes
+
+ GF_MUL_XOR VEX, x0h, xgft1, xret1h, xd1h, xgft2, xret2h, xd2h, xgft3, xret3h, xd3h
+
+ XSTR [dest1 + pos], xd1l
+ XSTR [dest1 + pos + 32], xd1h
+ XSTR [dest2 + pos], xd2l
+ XSTR [dest2 + pos + 32], xd2h
+ XSTR [dest3 + pos], xd3l
+ XSTR [dest3 + pos + 32], xd3h
+%endmacro
+
+;;
+;; Encodes 32 bytes of a single source into 3x 32 bytes (parity disks)
+;;
+%macro ENCODE_32B_3 0
+ ; get next source vector
+ XLDR x0, [src + pos]
+ ; get next dest vectors
+ XLDR xd1, [dest1 + pos]
+ XLDR xd2, [dest2 + pos]
+ XLDR xd3, [dest3 + pos]
+
+ GF_MUL_XOR VEX, x0, xgft1, xret1, xd1, xgft2, xret2, xd2, xgft3, xret3, xd3
+
+ XSTR [dest1 + pos], xd1
+ XSTR [dest2 + pos], xd2
+ XSTR [dest3 + pos], xd3
+%endmacro
+
+;;
+;; Encodes less than 32 bytes of a single source into 3x parity disks
+;;
+%macro ENCODE_LT_32B_3 1
+%define %%LEN %1
+ ; get next source vector
+ simd_load_avx2 x0, src + pos, %%LEN, tmp, tmp2
+ ; get next dest vectors
+ simd_load_avx2 xd1, dest1 + pos, %%LEN, tmp, tmp2
+ simd_load_avx2 xd2, dest2 + pos, %%LEN, tmp, tmp2
+ simd_load_avx2 xd3, dest3 + pos, %%LEN, tmp, tmp2
+
+ GF_MUL_XOR VEX, x0, xgft1, xret1, xd1, xgft2, xret2, xd2, xgft3, xret3, xd3
+
+ lea dest1, [dest1 + pos]
+ simd_store_avx2 dest1, xd1, %%LEN, tmp, tmp2
+ lea dest2, [dest2 + pos]
+ simd_store_avx2 dest2, xd2, %%LEN, tmp, tmp2
+ lea dest3, [dest3 + pos]
+ simd_store_avx2 dest3, xd3, %%LEN, tmp, tmp2
+%endmacro
+
+align 16
+global gf_3vect_mad_avx2_gfni, function
+func(gf_3vect_mad_avx2_gfni)
+ FUNC_SAVE
+
+ xor pos, pos
+ shl vec_i, 3 ;Multiply by 8
+ shl vec, 3 ;Multiply by 8
+ lea tmp, [mul_array + vec_i]
+ vbroadcastsd xgft1, [tmp]
+ vbroadcastsd xgft2, [tmp + vec]
+ vbroadcastsd xgft3, [tmp + vec*2]
+ mov dest2, [dest1 + 8] ; reuse mul_array
+ mov dest3, [dest1 + 2*8] ; reuse vec_i
+ mov dest1, [dest1]
+
+ cmp len, 64
+ jl .len_lt_64
+
+.loop64:
+ ENCODE_64B_3 ;; loop on 64 bytes at a time
+
+ add pos, 64
+ sub len, 64
+ cmp len, 64
+ jge .loop64
+
+.len_lt_64:
+ cmp len, 32
+ jl .len_lt_32
+
+ ENCODE_32B_3 ;; encode next 32 bytes
+
+ add pos, 32
+ sub len, 32
+
+.len_lt_32:
+ cmp len, 0
+ jle .exit
+
+ ENCODE_LT_32B_3 len ;; encode final bytes
+
+.exit:
+ vzeroupper
+
+ FUNC_RESTORE
+ ret
+
+endproc_frame
+%endif ; if AS_FEATURE_LEVEL >= 10
diff --git a/contrib/libs/isa-l/erasure_code/gf_3vect_mad_avx512.asm b/contrib/libs/isa-l/erasure_code/gf_3vect_mad_avx512.asm
index 53b3eb5afa..567624d273 100644
--- a/contrib/libs/isa-l/erasure_code/gf_3vect_mad_avx512.asm
+++ b/contrib/libs/isa-l/erasure_code/gf_3vect_mad_avx512.asm
@@ -44,7 +44,7 @@
%define arg5 r9
%define tmp r11
%define return rax
- %define func(x) x:
+ %define func(x) x: endbranch
%define FUNC_SAVE
%define FUNC_RESTORE
%endif
@@ -117,8 +117,8 @@
%else
;;; Use Non-temporal load/stor
%ifdef NO_NT_LDST
- %define XLDR vmovdqa
- %define XSTR vmovdqa
+ %define XLDR vmovdqa64
+ %define XSTR vmovdqa64
%else
%define XLDR vmovntdqa
%define XSTR vmovntdq
@@ -152,13 +152,8 @@ section .text
%define xmask0f zmm17
align 16
-global gf_3vect_mad_avx512:ISAL_SYM_TYPE_FUNCTION
+global gf_3vect_mad_avx512, function
func(gf_3vect_mad_avx512)
-%ifidn __OUTPUT_FORMAT__, macho64
-global _gf_3vect_mad_avx512:ISAL_SYM_TYPE_FUNCTION
-func(_gf_3vect_mad_avx512)
-%endif
-
FUNC_SAVE
sub len, 64
jl .return_fail
@@ -209,7 +204,7 @@ func(_gf_3vect_mad_avx512)
vpshufb xtmph3 {k1}{z}, xgft3_hi, x0 ;Lookup mul table of high nibble
vpshufb xtmpl3 {k1}{z}, xgft3_lo, xtmpa ;Lookup mul table of low nibble
vpxorq xtmph3, xtmph3, xtmpl3 ;GF add high and low partials
- vpxorq xd3, xd3, xtmph3 ;xd2 += partial
+ vpxorq xd3, xd3, xtmph3 ;xd3 += partial
XSTR [dest1+pos], xd1
XSTR [dest2+pos], xd2
diff --git a/contrib/libs/isa-l/erasure_code/gf_3vect_mad_avx512.patch b/contrib/libs/isa-l/erasure_code/gf_3vect_mad_avx512.patch
deleted file mode 100644
index d8b12fac96..0000000000
--- a/contrib/libs/isa-l/erasure_code/gf_3vect_mad_avx512.patch
+++ /dev/null
@@ -1,6 +0,0 @@
-157,161d156
-< %ifidn __OUTPUT_FORMAT__, macho64
-< global _gf_3vect_mad_avx512:ISAL_SYM_TYPE_FUNCTION
-< func(_gf_3vect_mad_avx512)
-< %endif
-<
diff --git a/contrib/libs/isa-l/erasure_code/gf_3vect_mad_avx512_gfni.asm b/contrib/libs/isa-l/erasure_code/gf_3vect_mad_avx512_gfni.asm
new file mode 100644
index 0000000000..53cc812595
--- /dev/null
+++ b/contrib/libs/isa-l/erasure_code/gf_3vect_mad_avx512_gfni.asm
@@ -0,0 +1,204 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; Copyright(c) 2023 Intel Corporation All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions
+; are met:
+; * Redistributions of source code must retain the above copyright
+; notice, this list of conditions and the following disclaimer.
+; * Redistributions in binary form must reproduce the above copyright
+; notice, this list of conditions and the following disclaimer in
+; the documentation and/or other materials provided with the
+; distribution.
+; * Neither the name of Intel Corporation nor the names of its
+; contributors may be used to endorse or promote products derived
+; from this software without specific prior written permission.
+;
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+; "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+; A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+; OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+; SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+; LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+; OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;;;
+;;; gf_3vect_mad_avx512_gfni(len, vec, vec_i, mul_array, src, dest);
+;;;
+
+%include "reg_sizes.asm"
+%include "gf_vect_gfni.inc"
+
+%if AS_FEATURE_LEVEL >= 10
+
+%ifidn __OUTPUT_FORMAT__, elf64
+ %define arg0 rdi
+ %define arg1 rsi
+ %define arg2 rdx
+ %define arg3 rcx
+ %define arg4 r8
+ %define arg5 r9
+ %define tmp r11
+ %define func(x) x: endbranch
+ %define FUNC_SAVE
+ %define FUNC_RESTORE
+%endif
+
+%ifidn __OUTPUT_FORMAT__, win64
+ %define arg0 rcx
+ %define arg1 rdx
+ %define arg2 r8
+ %define arg3 r9
+ %define arg4 r12 ; must be saved, loaded and restored
+ %define arg5 r13 ; must be saved and restored
+ %define tmp r11
+ %define stack_size 16*4 + 3*8
+ %define arg(x) [rsp + stack_size + 8 + 8*x]
+ %define func(x) proc_frame x
+
+ %macro FUNC_SAVE 0
+ sub rsp, stack_size
+ vmovdqa [rsp + 16*0], xmm6
+ vmovdqa [rsp + 16*1], xmm7
+ vmovdqa [rsp + 16*2], xmm8
+ vmovdqa [rsp + 16*3], xmm9
+ mov [rsp + 4*16 + 0*8], r12
+ mov [rsp + 4*16 + 1*8], r13
+ end_prolog
+ mov arg4, arg(4)
+ mov arg5, arg(5)
+ %endmacro
+
+ %macro FUNC_RESTORE 0
+ vmovdqa xmm6, [rsp + 16*0]
+ vmovdqa xmm7, [rsp + 16*1]
+ vmovdqa xmm8, [rsp + 16*2]
+ vmovdqa xmm9, [rsp + 16*3]
+ mov r12, [rsp + 4*16 + 0*8]
+ mov r13, [rsp + 4*16 + 1*8]
+ add rsp, stack_size
+ %endmacro
+%endif
+
+%define len arg0
+%define vec arg1
+%define vec_i arg2
+%define mul_array arg3
+%define src arg4
+%define dest1 arg5
+%define pos rax
+%define dest2 mul_array
+%define dest3 vec_i
+
+%ifndef EC_ALIGNED_ADDR
+;;; Use Un-aligned load/store
+ %define XLDR vmovdqu8
+ %define XSTR vmovdqu8
+%else
+;;; Use Non-temporal load/stor
+ %ifdef NO_NT_LDST
+ %define XLDR vmovdqa64
+ %define XSTR vmovdqa64
+ %else
+ %define XLDR vmovntdqa
+ %define XSTR vmovntdq
+ %endif
+%endif
+
+default rel
+[bits 64]
+section .text
+
+%define x0 zmm0
+%define xgft1 zmm1
+%define xgft2 zmm2
+%define xgft3 zmm3
+%define xd1 zmm4
+%define xd2 zmm5
+%define xd3 zmm6
+
+%define xret1 zmm7
+%define xret2 zmm8
+%define xret3 zmm9
+
+;;
+;; Encodes 64 bytes of a single source into 3x 64 bytes (parity disks)
+;;
+%macro ENCODE_64B_3 0-1
+%define %%KMASK %1
+
+%if %0 == 1
+ vmovdqu8 x0{%%KMASK}, [src + pos] ;Get next source vector
+ vmovdqu8 xd1{%%KMASK}, [dest1 + pos] ;Get next dest vector
+ vmovdqu8 xd2{%%KMASK}, [dest2 + pos] ;Get next dest vector
+ vmovdqu8 xd3{%%KMASK}, [dest3 + pos] ;Get next dest vector
+%else
+ XLDR x0, [src + pos] ;Get next source vector
+ XLDR xd1, [dest1 + pos] ;Get next dest vector
+ XLDR xd2, [dest2 + pos] ;Get next dest vector
+ XLDR xd3, [dest3 + pos] ;Get next dest vector
+%endif
+
+ GF_MUL_XOR EVEX, x0, xgft1, xret1, xd1, xgft2, xret2, xd2, xgft3, xret3, xd3
+
+%if %0 == 1
+ vmovdqu8 [dest1 + pos]{%%KMASK}, xd1
+ vmovdqu8 [dest2 + pos]{%%KMASK}, xd2
+ vmovdqu8 [dest3 + pos]{%%KMASK}, xd3
+%else
+ XSTR [dest1 + pos], xd1
+ XSTR [dest2 + pos], xd2
+ XSTR [dest3 + pos], xd3
+%endif
+%endmacro
+
+align 16
+global gf_3vect_mad_avx512_gfni, function
+func(gf_3vect_mad_avx512_gfni)
+ FUNC_SAVE
+
+ xor pos, pos
+ shl vec_i, 3 ;Multiply by 8
+ shl vec, 3 ;Multiply by 8
+ lea tmp, [mul_array + vec_i]
+ vbroadcastf32x2 xgft1, [tmp]
+ vbroadcastf32x2 xgft2, [tmp + vec]
+ vbroadcastf32x2 xgft3, [tmp + vec*2]
+ mov dest2, [dest1 + 8] ; reuse mul_array
+ mov dest3, [dest1 + 2*8] ; reuse vec
+ mov dest1, [dest1]
+
+ cmp len, 64
+ jl .len_lt_64
+.loop64:
+ ENCODE_64B_3
+
+ add pos, 64 ;Loop on 64 bytes at a time
+ sub len, 64
+ cmp len, 64
+ jge .loop64
+
+.len_lt_64:
+ cmp len, 0
+ jle .exit
+
+ xor tmp, tmp
+ bts tmp, len
+ dec tmp
+ kmovq k1, tmp
+
+ ENCODE_64B_3 k1
+
+.exit:
+ vzeroupper
+
+ FUNC_RESTORE
+ ret
+
+endproc_frame
+%endif ; if AS_FEATURE_LEVEL >= 10
diff --git a/contrib/libs/isa-l/erasure_code/gf_3vect_mad_sse.asm b/contrib/libs/isa-l/erasure_code/gf_3vect_mad_sse.asm
index d6dbe8f200..0a4284d53e 100644
--- a/contrib/libs/isa-l/erasure_code/gf_3vect_mad_sse.asm
+++ b/contrib/libs/isa-l/erasure_code/gf_3vect_mad_sse.asm
@@ -96,7 +96,7 @@
%define return rax
%define return.w eax
- %define func(x) x:
+ %define func(x) x: endbranch
%define FUNC_SAVE
%define FUNC_RESTORE
%endif
@@ -156,13 +156,8 @@ section .text
%define xd3 xtmph1
align 16
-global gf_3vect_mad_sse:ISAL_SYM_TYPE_FUNCTION
+global gf_3vect_mad_sse, function
func(gf_3vect_mad_sse)
-%ifidn __OUTPUT_FORMAT__, macho64
-global _gf_3vect_mad_sse:ISAL_SYM_TYPE_FUNCTION
-func(_gf_3vect_mad_sse)
-%endif
-
FUNC_SAVE
sub len, 16
jl .return_fail
@@ -298,6 +293,3 @@ mask0f:
dq 0x0f0f0f0f0f0f0f0f, 0x0f0f0f0f0f0f0f0f
constip16:
dq 0xf8f9fafbfcfdfeff, 0xf0f1f2f3f4f5f6f7
-
-;;; func core, ver, snum
-slversion gf_3vect_mad_sse, 00, 01, 0206
diff --git a/contrib/libs/isa-l/erasure_code/gf_3vect_mad_sse.patch b/contrib/libs/isa-l/erasure_code/gf_3vect_mad_sse.patch
deleted file mode 100644
index 83363c45cf..0000000000
--- a/contrib/libs/isa-l/erasure_code/gf_3vect_mad_sse.patch
+++ /dev/null
@@ -1,6 +0,0 @@
-161,165d160
-< %ifidn __OUTPUT_FORMAT__, macho64
-< global _gf_3vect_mad_sse:ISAL_SYM_TYPE_FUNCTION
-< func(_gf_3vect_mad_sse)
-< %endif
-<
diff --git a/contrib/libs/isa-l/erasure_code/gf_4vect_dot_prod_avx.asm b/contrib/libs/isa-l/erasure_code/gf_4vect_dot_prod_avx.asm
index 30f1e81f6b..077018eefd 100644
--- a/contrib/libs/isa-l/erasure_code/gf_4vect_dot_prod_avx.asm
+++ b/contrib/libs/isa-l/erasure_code/gf_4vect_dot_prod_avx.asm
@@ -54,7 +54,7 @@
%define PS 8
%define LOG_PS 3
- %define func(x) x:
+ %define func(x) x: endbranch
%macro FUNC_SAVE 0
push r12
push r13
@@ -95,15 +95,15 @@
%define func(x) proc_frame x
%macro FUNC_SAVE 0
alloc_stack stack_size
- save_xmm128 xmm6, 0*16
- save_xmm128 xmm7, 1*16
- save_xmm128 xmm8, 2*16
- save_xmm128 xmm9, 3*16
- save_xmm128 xmm10, 4*16
- save_xmm128 xmm11, 5*16
- save_xmm128 xmm12, 6*16
- save_xmm128 xmm13, 7*16
- save_xmm128 xmm14, 8*16
+ vmovdqa [rsp + 0*16], xmm6
+ vmovdqa [rsp + 1*16], xmm7
+ vmovdqa [rsp + 2*16], xmm8
+ vmovdqa [rsp + 3*16], xmm9
+ vmovdqa [rsp + 4*16], xmm10
+ vmovdqa [rsp + 5*16], xmm11
+ vmovdqa [rsp + 6*16], xmm12
+ vmovdqa [rsp + 7*16], xmm13
+ vmovdqa [rsp + 8*16], xmm14
save_reg r12, 9*16 + 0*8
save_reg r13, 9*16 + 1*8
save_reg r14, 9*16 + 2*8
@@ -159,7 +159,7 @@
%define PS 4
%define LOG_PS 2
- %define func(x) x:
+ %define func(x) x: endbranch
%define arg(x) [ebp + PS*2 + PS*x]
%define var(x) [ebp - PS - PS*x]
@@ -294,13 +294,8 @@ section .text
%define xp4 xmm5
%endif
align 16
-global gf_4vect_dot_prod_avx:ISAL_SYM_TYPE_FUNCTION
+global gf_4vect_dot_prod_avx, function
func(gf_4vect_dot_prod_avx)
-%ifidn __OUTPUT_FORMAT__, macho64
-global _gf_4vect_dot_prod_avx:ISAL_SYM_TYPE_FUNCTION
-func(_gf_4vect_dot_prod_avx)
-%endif
-
FUNC_SAVE
SLDR len, len_m
sub len, 16
@@ -441,6 +436,3 @@ section .data
align 16
mask0f: dq 0x0f0f0f0f0f0f0f0f, 0x0f0f0f0f0f0f0f0f
-
-;;; func core, ver, snum
-slversion gf_4vect_dot_prod_avx, 02, 05, 0193
diff --git a/contrib/libs/isa-l/erasure_code/gf_4vect_dot_prod_avx.patch b/contrib/libs/isa-l/erasure_code/gf_4vect_dot_prod_avx.patch
deleted file mode 100644
index aa908028bb..0000000000
--- a/contrib/libs/isa-l/erasure_code/gf_4vect_dot_prod_avx.patch
+++ /dev/null
@@ -1,6 +0,0 @@
-299,303d298
-< %ifidn __OUTPUT_FORMAT__, macho64
-< global _gf_4vect_dot_prod_avx:ISAL_SYM_TYPE_FUNCTION
-< func(_gf_4vect_dot_prod_avx)
-< %endif
-<
diff --git a/contrib/libs/isa-l/erasure_code/gf_4vect_dot_prod_avx2.asm b/contrib/libs/isa-l/erasure_code/gf_4vect_dot_prod_avx2.asm
index efe2f76de9..8d5febe0fa 100644
--- a/contrib/libs/isa-l/erasure_code/gf_4vect_dot_prod_avx2.asm
+++ b/contrib/libs/isa-l/erasure_code/gf_4vect_dot_prod_avx2.asm
@@ -56,7 +56,7 @@
%define PS 8
%define LOG_PS 3
- %define func(x) x:
+ %define func(x) x: endbranch
%macro FUNC_SAVE 0
push r12
push r13
@@ -163,7 +163,7 @@
%define PS 4
%define LOG_PS 2
- %define func(x) x:
+ %define func(x) x: endbranch
%define arg(x) [ebp + PS*2 + PS*x]
%define var(x) [ebp - PS - PS*x]
@@ -301,15 +301,9 @@ section .text
%define xp3 ymm4
%define xp4 ymm5
%endif
-
align 16
-global gf_4vect_dot_prod_avx2:ISAL_SYM_TYPE_FUNCTION
+global gf_4vect_dot_prod_avx2, function
func(gf_4vect_dot_prod_avx2)
-%ifidn __OUTPUT_FORMAT__, macho64
-global _gf_4vect_dot_prod_avx2:ISAL_SYM_TYPE_FUNCTION
-func(_gf_4vect_dot_prod_avx2)
-%endif
-
FUNC_SAVE
SLDR len, len_m
sub len, 32
@@ -459,8 +453,3 @@ func(_gf_4vect_dot_prod_avx2)
ret
endproc_frame
-
-section .data
-
-;;; func core, ver, snum
-slversion gf_4vect_dot_prod_avx2, 04, 05, 0198
diff --git a/contrib/libs/isa-l/erasure_code/gf_4vect_dot_prod_avx2.patch b/contrib/libs/isa-l/erasure_code/gf_4vect_dot_prod_avx2.patch
deleted file mode 100644
index 39cdd548a7..0000000000
--- a/contrib/libs/isa-l/erasure_code/gf_4vect_dot_prod_avx2.patch
+++ /dev/null
@@ -1,8 +0,0 @@
-304d303
-<
-308,312d306
-< %ifidn __OUTPUT_FORMAT__, macho64
-< global _gf_4vect_dot_prod_avx2:ISAL_SYM_TYPE_FUNCTION
-< func(_gf_4vect_dot_prod_avx2)
-< %endif
-<
diff --git a/contrib/libs/isa-l/erasure_code/gf_4vect_dot_prod_avx512.asm b/contrib/libs/isa-l/erasure_code/gf_4vect_dot_prod_avx512.asm
index c810008c85..9bdc1a5670 100644
--- a/contrib/libs/isa-l/erasure_code/gf_4vect_dot_prod_avx512.asm
+++ b/contrib/libs/isa-l/erasure_code/gf_4vect_dot_prod_avx512.asm
@@ -44,8 +44,6 @@
%define arg5 r9
%define tmp r11
- %define tmp.w r11d
- %define tmp.b r11b
%define tmp2 r10
%define tmp3 r13 ; must be saved and restored
%define tmp4 r12 ; must be saved and restored
@@ -54,19 +52,22 @@
%define return rax
%define PS 8
%define LOG_PS 3
+ %define stack_size 4*8
- %define func(x) x:
+ %define func(x) x: endbranch
%macro FUNC_SAVE 0
- push r12
- push r13
- push r14
- push r15
+ sub rsp, stack_size
+ mov [rsp + 0*8], r12
+ mov [rsp + 1*8], r13
+ mov [rsp + 2*8], r14
+ mov [rsp + 3*8], r15
%endmacro
%macro FUNC_RESTORE 0
- pop r15
- pop r14
- pop r13
- pop r12
+ mov r12, [rsp + 0*8]
+ mov r13, [rsp + 1*8]
+ mov r14, [rsp + 2*8]
+ mov r15, [rsp + 3*8]
+ add rsp, stack_size
%endmacro
%endif
@@ -79,8 +80,6 @@
%define arg4 r12 ; must be saved, loaded and restored
%define arg5 r15 ; must be saved and restored
%define tmp r11
- %define tmp.w r11d
- %define tmp.b r11b
%define tmp2 r10
%define tmp3 r13 ; must be saved and restored
%define tmp4 r14 ; must be saved and restored
@@ -156,8 +155,8 @@
%else
;;; Use Non-temporal load/stor
%ifdef NO_NT_LDST
- %define XLDR vmovdqa
- %define XSTR vmovdqa
+ %define XLDR vmovdqa64
+ %define XSTR vmovdqa64
%else
%define XLDR vmovntdqa
%define XSTR vmovntdq
@@ -191,13 +190,8 @@ default rel
section .text
align 16
-global gf_4vect_dot_prod_avx512:ISAL_SYM_TYPE_FUNCTION
+global gf_4vect_dot_prod_avx512, function
func(gf_4vect_dot_prod_avx512)
-%ifidn __OUTPUT_FORMAT__, macho64
-global _gf_4vect_dot_prod_avx512:ISAL_SYM_TYPE_FUNCTION
-func(_gf_4vect_dot_prod_avx512)
-%endif
-
FUNC_SAVE
sub len, 64
jl .return_fail
diff --git a/contrib/libs/isa-l/erasure_code/gf_4vect_dot_prod_avx512.patch b/contrib/libs/isa-l/erasure_code/gf_4vect_dot_prod_avx512.patch
deleted file mode 100644
index 6ca011bcc3..0000000000
--- a/contrib/libs/isa-l/erasure_code/gf_4vect_dot_prod_avx512.patch
+++ /dev/null
@@ -1,6 +0,0 @@
-196,200d195
-< %ifidn __OUTPUT_FORMAT__, macho64
-< global _gf_4vect_dot_prod_avx512:ISAL_SYM_TYPE_FUNCTION
-< func(_gf_4vect_dot_prod_avx512)
-< %endif
-<
diff --git a/contrib/libs/isa-l/erasure_code/gf_4vect_dot_prod_avx512_gfni.asm b/contrib/libs/isa-l/erasure_code/gf_4vect_dot_prod_avx512_gfni.asm
new file mode 100644
index 0000000000..9adb83f196
--- /dev/null
+++ b/contrib/libs/isa-l/erasure_code/gf_4vect_dot_prod_avx512_gfni.asm
@@ -0,0 +1,253 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; Copyright(c) 2023 Intel Corporation All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions
+; are met:
+; * Redistributions of source code must retain the above copyright
+; notice, this list of conditions and the following disclaimer.
+; * Redistributions in binary form must reproduce the above copyright
+; notice, this list of conditions and the following disclaimer in
+; the documentation and/or other materials provided with the
+; distribution.
+; * Neither the name of Intel Corporation nor the names of its
+; contributors may be used to endorse or promote products derived
+; from this software without specific prior written permission.
+;
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+; "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+; A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+; OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+; SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+; LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+; OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;;;
+;;; gf_4vect_dot_prod_avx512_gfni(len, vec, *g_tbls, **buffs, **dests);
+;;;
+
+%include "reg_sizes.asm"
+%include "gf_vect_gfni.inc"
+
+%if AS_FEATURE_LEVEL >= 10
+
+%ifidn __OUTPUT_FORMAT__, elf64
+ %define arg0 rdi
+ %define arg1 rsi
+ %define arg2 rdx
+ %define arg3 rcx
+ %define arg4 r8
+ %define arg5 r9
+
+ %define tmp r11
+ %define tmp2 r10
+ %define tmp3 r13 ; must be saved and restored
+ %define tmp4 r12 ; must be saved and restored
+ %define tmp5 r14 ; must be saved and restored
+ %define tmp6 r15 ; must be saved and restored
+
+ %define func(x) x: endbranch
+ %macro FUNC_SAVE 0
+ push r12
+ push r13
+ push r14
+ push r15
+ %endmacro
+ %macro FUNC_RESTORE 0
+ pop r15
+ pop r14
+ pop r13
+ pop r12
+ %endmacro
+%endif
+
+%ifidn __OUTPUT_FORMAT__, win64
+ %define arg0 rcx
+ %define arg1 rdx
+ %define arg2 r8
+ %define arg3 r9
+
+ %define arg4 r12 ; must be saved, loaded and restored
+ %define arg5 r15 ; must be saved and restored
+ %define tmp r11
+ %define tmp2 r10
+ %define tmp3 r13 ; must be saved and restored
+ %define tmp4 r14 ; must be saved and restored
+ %define tmp5 rdi ; must be saved and restored
+ %define tmp6 rsi ; must be saved and restored
+ %define stack_size 3*16 + 7*8 ; must be an odd multiple of 8
+ %define arg(x) [rsp + stack_size + 8 + 8*x]
+
+ %define func(x) proc_frame x
+ %macro FUNC_SAVE 0
+ alloc_stack stack_size
+ vmovdqa [rsp + 0*16], xmm6
+ vmovdqa [rsp + 1*16], xmm7
+ vmovdqa [rsp + 2*16], xmm8
+ mov [rsp + 3*16 + 0*8], r12
+ mov [rsp + 3*16 + 1*8], r13
+ mov [rsp + 3*16 + 2*8], r14
+ mov [rsp + 3*16 + 3*8], r15
+ mov [rsp + 3*16 + 4*8], rdi
+ mov [rsp + 3*16 + 5*8], rsi
+ end_prolog
+ mov arg4, arg(4)
+ %endmacro
+
+ %macro FUNC_RESTORE 0
+ vmovdqa xmm6, [rsp + 0*16]
+ vmovdqa xmm7, [rsp + 1*16]
+ vmovdqa xmm8, [rsp + 2*16]
+ mov r12, [rsp + 3*16 + 0*8]
+ mov r13, [rsp + 3*16 + 1*8]
+ mov r14, [rsp + 3*16 + 2*8]
+ mov r15, [rsp + 3*16 + 3*8]
+ mov rdi, [rsp + 3*16 + 4*8]
+ mov rsi, [rsp + 3*16 + 5*8]
+ add rsp, stack_size
+ %endmacro
+%endif
+
+
+%define len arg0
+%define vec arg1
+%define mul_array arg2
+%define src arg3
+%define dest1 arg4
+%define ptr arg5
+%define vec_i tmp2
+%define dest2 tmp3
+%define dest3 tmp4
+%define dest4 tmp5
+%define vskip3 tmp6
+%define pos rax
+
+
+%ifndef EC_ALIGNED_ADDR
+;;; Use Un-aligned load/store
+ %define XLDR vmovdqu8
+ %define XSTR vmovdqu8
+%else
+;;; Use Non-temporal load/stor
+ %ifdef NO_NT_LDST
+ %define XLDR vmovdqa64
+ %define XSTR vmovdqa64
+ %else
+ %define XLDR vmovntdqa
+ %define XSTR vmovntdq
+ %endif
+%endif
+
+%define xgft1 zmm5
+%define xgft2 zmm6
+%define xgft3 zmm7
+%define xgft4 zmm8
+
+%define x0 zmm0
+%define xp1 zmm1
+%define xp2 zmm2
+%define xp3 zmm3
+%define xp4 zmm4
+
+default rel
+[bits 64]
+
+section .text
+
+;;
+;; Encodes 64 bytes of all "k" sources into 4x 64 bytes (parity disks)
+;;
+%macro ENCODE_64B_4 0-1
+%define %%KMASK %1
+
+ vpxorq xp1, xp1, xp1
+ vpxorq xp2, xp2, xp2
+ vpxorq xp3, xp3, xp3
+ vpxorq xp4, xp4, xp4
+ mov tmp, mul_array
+ xor vec_i, vec_i
+
+%%next_vect:
+ mov ptr, [src + vec_i]
+%if %0 == 1
+ vmovdqu8 x0{%%KMASK}, [ptr + pos] ;Get next source vector (less than 64 bytes)
+%else
+ XLDR x0, [ptr + pos] ;Get next source vector (64 bytes)
+%endif
+ add vec_i, 8
+
+ vbroadcastf32x2 xgft1, [tmp]
+ vbroadcastf32x2 xgft2, [tmp + vec]
+ vbroadcastf32x2 xgft3, [tmp + vec*2]
+ vbroadcastf32x2 xgft4, [tmp + vskip3]
+ add tmp, 8
+
+ GF_MUL_XOR EVEX, x0, xgft1, xgft1, xp1, xgft2, xgft2, xp2, xgft3, xgft3, xp3, \
+ xgft4, xgft4, xp4
+
+ cmp vec_i, vec
+ jl %%next_vect
+
+%if %0 == 1
+ vmovdqu8 [dest1 + pos]{%%KMASK}, xp1
+ vmovdqu8 [dest2 + pos]{%%KMASK}, xp2
+ vmovdqu8 [dest3 + pos]{%%KMASK}, xp3
+ vmovdqu8 [dest4 + pos]{%%KMASK}, xp4
+%else
+ XSTR [dest1 + pos], xp1
+ XSTR [dest2 + pos], xp2
+ XSTR [dest3 + pos], xp3
+ XSTR [dest4 + pos], xp4
+%endif
+%endmacro
+
+align 16
+global gf_4vect_dot_prod_avx512_gfni, function
+func(gf_4vect_dot_prod_avx512_gfni)
+ FUNC_SAVE
+
+ xor pos, pos
+ mov vskip3, vec
+ imul vskip3, 8*3
+ shl vec, 3 ;vec *= 8. Make vec_i count by 8
+ mov dest2, [dest1 + 8]
+ mov dest3, [dest1 + 2*8]
+ mov dest4, [dest1 + 3*8]
+ mov dest1, [dest1]
+
+ cmp len, 64
+ jl .len_lt_64
+
+.loop64:
+
+ ENCODE_64B_4
+
+ add pos, 64 ;Loop on 64 bytes at a time
+ sub len, 64
+ cmp len, 64
+ jge .loop64
+
+.len_lt_64:
+ cmp len, 0
+ jle .exit
+
+ xor tmp, tmp
+ bts tmp, len
+ dec tmp
+ kmovq k1, tmp
+
+ ENCODE_64B_4 k1
+
+.exit:
+ vzeroupper
+
+ FUNC_RESTORE
+ ret
+
+endproc_frame
+%endif ; if AS_FEATURE_LEVEL >= 10
diff --git a/contrib/libs/isa-l/erasure_code/gf_4vect_dot_prod_sse.asm b/contrib/libs/isa-l/erasure_code/gf_4vect_dot_prod_sse.asm
index 8a486bf7b5..aadab4b1e4 100644
--- a/contrib/libs/isa-l/erasure_code/gf_4vect_dot_prod_sse.asm
+++ b/contrib/libs/isa-l/erasure_code/gf_4vect_dot_prod_sse.asm
@@ -54,7 +54,7 @@
%define PS 8
%define LOG_PS 3
- %define func(x) x:
+ %define func(x) x: endbranch
%macro FUNC_SAVE 0
push r12
push r13
@@ -159,7 +159,7 @@
%define PS 4
%define LOG_PS 2
- %define func(x) x:
+ %define func(x) x: endbranch
%define arg(x) [ebp + PS*2 + PS*x]
%define var(x) [ebp - PS - PS*x]
@@ -294,13 +294,8 @@ section .text
%define xp4 xmm5
%endif
align 16
-global gf_4vect_dot_prod_sse:ISAL_SYM_TYPE_FUNCTION
+global gf_4vect_dot_prod_sse, function
func(gf_4vect_dot_prod_sse)
-%ifidn __OUTPUT_FORMAT__, macho64
-global _gf_4vect_dot_prod_sse:ISAL_SYM_TYPE_FUNCTION
-func(_gf_4vect_dot_prod_sse)
-%endif
-
FUNC_SAVE
SLDR len, len_m
sub len, 16
@@ -443,6 +438,3 @@ section .data
align 16
mask0f: dq 0x0f0f0f0f0f0f0f0f, 0x0f0f0f0f0f0f0f0f
-
-;;; func core, ver, snum
-slversion gf_4vect_dot_prod_sse, 00, 06, 0064
diff --git a/contrib/libs/isa-l/erasure_code/gf_4vect_dot_prod_sse.patch b/contrib/libs/isa-l/erasure_code/gf_4vect_dot_prod_sse.patch
deleted file mode 100644
index 78b6abbe4b..0000000000
--- a/contrib/libs/isa-l/erasure_code/gf_4vect_dot_prod_sse.patch
+++ /dev/null
@@ -1,6 +0,0 @@
-299,303d298
-< %ifidn __OUTPUT_FORMAT__, macho64
-< global _gf_4vect_dot_prod_sse:ISAL_SYM_TYPE_FUNCTION
-< func(_gf_4vect_dot_prod_sse)
-< %endif
-<
diff --git a/contrib/libs/isa-l/erasure_code/gf_4vect_dot_prod_sse_test.c b/contrib/libs/isa-l/erasure_code/gf_4vect_dot_prod_sse_test.c
deleted file mode 100644
index eb6bc986ab..0000000000
--- a/contrib/libs/isa-l/erasure_code/gf_4vect_dot_prod_sse_test.c
+++ /dev/null
@@ -1,695 +0,0 @@
-/**********************************************************************
- Copyright(c) 2011-2015 Intel Corporation All rights reserved.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions
- are met:
- * Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in
- the documentation and/or other materials provided with the
- distribution.
- * Neither the name of Intel Corporation nor the names of its
- contributors may be used to endorse or promote products derived
- from this software without specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-**********************************************************************/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h> // for memset, memcmp
-#include "erasure_code.h"
-// #include "types.h"
-
-#ifndef FUNCTION_UNDER_TEST
-# define FUNCTION_UNDER_TEST gf_4vect_dot_prod_sse
-#endif
-#ifndef TEST_MIN_SIZE
-# define TEST_MIN_SIZE 16
-#endif
-
-#define str(s) #s
-#define xstr(s) str(s)
-
-#define TEST_LEN 2048
-#define TEST_SIZE (TEST_LEN/2)
-#define TEST_MEM TEST_SIZE
-#define TEST_LOOPS 1000
-#define TEST_TYPE_STR ""
-
-#ifndef TEST_SOURCES
-# define TEST_SOURCES 16
-#endif
-#ifndef RANDOMS
-# define RANDOMS 20
-#endif
-
-#ifdef EC_ALIGNED_ADDR
-// Define power of 2 range to check ptr, len alignment
-# define PTR_ALIGN_CHK_B 0
-# define LEN_ALIGN_CHK_B 0 // 0 for aligned only
-#else
-// Define power of 2 range to check ptr, len alignment
-# define PTR_ALIGN_CHK_B 32
-# define LEN_ALIGN_CHK_B 32 // 0 for aligned only
-#endif
-
-typedef unsigned char u8;
-
-extern void FUNCTION_UNDER_TEST(int len, int vlen, unsigned char *gftbls,
- unsigned char **src, unsigned char **dest);
-
-void dump(unsigned char *buf, int len)
-{
- int i;
- for (i = 0; i < len;) {
- printf(" %2x", 0xff & buf[i++]);
- if (i % 32 == 0)
- printf("\n");
- }
- printf("\n");
-}
-
-void dump_matrix(unsigned char **s, int k, int m)
-{
- int i, j;
- for (i = 0; i < k; i++) {
- for (j = 0; j < m; j++) {
- printf(" %2x", s[i][j]);
- }
- printf("\n");
- }
- printf("\n");
-}
-
-void dump_u8xu8(unsigned char *s, int k, int m)
-{
- int i, j;
- for (i = 0; i < k; i++) {
- for (j = 0; j < m; j++) {
- printf(" %2x", 0xff & s[j + (i * m)]);
- }
- printf("\n");
- }
- printf("\n");
-}
-
-int main(int argc, char *argv[])
-{
- int i, j, rtest, srcs;
- void *buf;
- u8 g1[TEST_SOURCES], g2[TEST_SOURCES], g3[TEST_SOURCES];
- u8 g4[TEST_SOURCES], g_tbls[4 * TEST_SOURCES * 32], *buffs[TEST_SOURCES];
- u8 *dest1, *dest2, *dest3, *dest4, *dest_ref1, *dest_ref2, *dest_ref3;
- u8 *dest_ref4, *dest_ptrs[4];
-
- int align, size;
- unsigned char *efence_buffs[TEST_SOURCES];
- unsigned int offset;
- u8 *ubuffs[TEST_SOURCES];
- u8 *udest_ptrs[4];
- printf(xstr(FUNCTION_UNDER_TEST) ": %dx%d ", TEST_SOURCES, TEST_LEN);
-
- // Allocate the arrays
- for (i = 0; i < TEST_SOURCES; i++) {
- if (posix_memalign(&buf, 64, TEST_LEN)) {
- printf("alloc error: Fail");
- return -1;
- }
- buffs[i] = buf;
- }
-
- if (posix_memalign(&buf, 64, TEST_LEN)) {
- printf("alloc error: Fail");
- return -1;
- }
- dest1 = buf;
-
- if (posix_memalign(&buf, 64, TEST_LEN)) {
- printf("alloc error: Fail");
- return -1;
- }
- dest2 = buf;
-
- if (posix_memalign(&buf, 64, TEST_LEN)) {
- printf("alloc error: Fail");
- return -1;
- }
- dest3 = buf;
-
- if (posix_memalign(&buf, 64, TEST_LEN)) {
- printf("alloc error: Fail");
- return -1;
- }
- dest4 = buf;
-
- if (posix_memalign(&buf, 64, TEST_LEN)) {
- printf("alloc error: Fail");
- return -1;
- }
- dest_ref1 = buf;
-
- if (posix_memalign(&buf, 64, TEST_LEN)) {
- printf("alloc error: Fail");
- return -1;
- }
- dest_ref2 = buf;
-
- if (posix_memalign(&buf, 64, TEST_LEN)) {
- printf("alloc error: Fail");
- return -1;
- }
- dest_ref3 = buf;
-
- if (posix_memalign(&buf, 64, TEST_LEN)) {
- printf("alloc error: Fail");
- return -1;
- }
- dest_ref4 = buf;
-
- dest_ptrs[0] = dest1;
- dest_ptrs[1] = dest2;
- dest_ptrs[2] = dest3;
- dest_ptrs[3] = dest4;
-
- // Test of all zeros
- for (i = 0; i < TEST_SOURCES; i++)
- memset(buffs[i], 0, TEST_LEN);
-
- memset(dest1, 0, TEST_LEN);
- memset(dest2, 0, TEST_LEN);
- memset(dest3, 0, TEST_LEN);
- memset(dest4, 0, TEST_LEN);
- memset(dest_ref1, 0, TEST_LEN);
- memset(dest_ref2, 0, TEST_LEN);
- memset(dest_ref3, 0, TEST_LEN);
- memset(dest_ref4, 0, TEST_LEN);
- memset(g1, 2, TEST_SOURCES);
- memset(g2, 1, TEST_SOURCES);
- memset(g3, 7, TEST_SOURCES);
- memset(g4, 3, TEST_SOURCES);
-
- for (i = 0; i < TEST_SOURCES; i++) {
- gf_vect_mul_init(g1[i], &g_tbls[i * 32]);
- gf_vect_mul_init(g2[i], &g_tbls[32 * TEST_SOURCES + i * 32]);
- gf_vect_mul_init(g3[i], &g_tbls[64 * TEST_SOURCES + i * 32]);
- gf_vect_mul_init(g4[i], &g_tbls[96 * TEST_SOURCES + i * 32]);
- }
-
- gf_vect_dot_prod_base(TEST_LEN, TEST_SOURCES, &g_tbls[0], buffs, dest_ref1);
- gf_vect_dot_prod_base(TEST_LEN, TEST_SOURCES, &g_tbls[32 * TEST_SOURCES], buffs,
- dest_ref2);
- gf_vect_dot_prod_base(TEST_LEN, TEST_SOURCES, &g_tbls[64 * TEST_SOURCES], buffs,
- dest_ref3);
- gf_vect_dot_prod_base(TEST_LEN, TEST_SOURCES, &g_tbls[96 * TEST_SOURCES], buffs,
- dest_ref4);
-
- FUNCTION_UNDER_TEST(TEST_LEN, TEST_SOURCES, g_tbls, buffs, dest_ptrs);
-
- if (0 != memcmp(dest_ref1, dest1, TEST_LEN)) {
- printf("Fail zero " xstr(FUNCTION_UNDER_TEST) " test1\n");
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref1, 25);
- printf("dprod_dut:");
- dump(dest1, 25);
- return -1;
- }
- if (0 != memcmp(dest_ref2, dest2, TEST_LEN)) {
- printf("Fail zero " xstr(FUNCTION_UNDER_TEST) " test2\n");
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref2, 25);
- printf("dprod_dut:");
- dump(dest2, 25);
- return -1;
- }
- if (0 != memcmp(dest_ref3, dest3, TEST_LEN)) {
- printf("Fail zero " xstr(FUNCTION_UNDER_TEST) " test3\n");
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref3, 25);
- printf("dprod_dut:");
- dump(dest3, 25);
- return -1;
- }
- if (0 != memcmp(dest_ref4, dest4, TEST_LEN)) {
- printf("Fail zero " xstr(FUNCTION_UNDER_TEST) " test4\n");
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref4, 25);
- printf("dprod_dut:");
- dump(dest4, 25);
- return -1;
- }
-
- putchar('.');
-
- // Rand data test
-
- for (rtest = 0; rtest < RANDOMS; rtest++) {
- for (i = 0; i < TEST_SOURCES; i++)
- for (j = 0; j < TEST_LEN; j++)
- buffs[i][j] = rand();
-
- for (i = 0; i < TEST_SOURCES; i++) {
- g1[i] = rand();
- g2[i] = rand();
- g3[i] = rand();
- g4[i] = rand();
- }
-
- for (i = 0; i < TEST_SOURCES; i++) {
- gf_vect_mul_init(g1[i], &g_tbls[i * 32]);
- gf_vect_mul_init(g2[i], &g_tbls[(32 * TEST_SOURCES) + (i * 32)]);
- gf_vect_mul_init(g3[i], &g_tbls[(64 * TEST_SOURCES) + (i * 32)]);
- gf_vect_mul_init(g4[i], &g_tbls[(96 * TEST_SOURCES) + (i * 32)]);
- }
-
- gf_vect_dot_prod_base(TEST_LEN, TEST_SOURCES, &g_tbls[0], buffs, dest_ref1);
- gf_vect_dot_prod_base(TEST_LEN, TEST_SOURCES, &g_tbls[32 * TEST_SOURCES],
- buffs, dest_ref2);
- gf_vect_dot_prod_base(TEST_LEN, TEST_SOURCES, &g_tbls[64 * TEST_SOURCES],
- buffs, dest_ref3);
- gf_vect_dot_prod_base(TEST_LEN, TEST_SOURCES, &g_tbls[96 * TEST_SOURCES],
- buffs, dest_ref4);
-
- FUNCTION_UNDER_TEST(TEST_LEN, TEST_SOURCES, g_tbls, buffs, dest_ptrs);
-
- if (0 != memcmp(dest_ref1, dest1, TEST_LEN)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test1 %d\n", rtest);
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref1, 25);
- printf("dprod_dut:");
- dump(dest1, 25);
- return -1;
- }
- if (0 != memcmp(dest_ref2, dest2, TEST_LEN)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test2 %d\n", rtest);
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref2, 25);
- printf("dprod_dut:");
- dump(dest2, 25);
- return -1;
- }
- if (0 != memcmp(dest_ref3, dest3, TEST_LEN)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test3 %d\n", rtest);
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref3, 25);
- printf("dprod_dut:");
- dump(dest3, 25);
- return -1;
- }
- if (0 != memcmp(dest_ref4, dest4, TEST_LEN)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test4 %d\n", rtest);
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref4, 25);
- printf("dprod_dut:");
- dump(dest4, 25);
- return -1;
- }
-
- putchar('.');
- }
-
- // Rand data test with varied parameters
- for (rtest = 0; rtest < RANDOMS; rtest++) {
- for (srcs = TEST_SOURCES; srcs > 0; srcs--) {
- for (i = 0; i < srcs; i++)
- for (j = 0; j < TEST_LEN; j++)
- buffs[i][j] = rand();
-
- for (i = 0; i < srcs; i++) {
- g1[i] = rand();
- g2[i] = rand();
- g3[i] = rand();
- g4[i] = rand();
- }
-
- for (i = 0; i < srcs; i++) {
- gf_vect_mul_init(g1[i], &g_tbls[i * 32]);
- gf_vect_mul_init(g2[i], &g_tbls[(32 * srcs) + (i * 32)]);
- gf_vect_mul_init(g3[i], &g_tbls[(64 * srcs) + (i * 32)]);
- gf_vect_mul_init(g4[i], &g_tbls[(96 * srcs) + (i * 32)]);
- }
-
- gf_vect_dot_prod_base(TEST_LEN, srcs, &g_tbls[0], buffs, dest_ref1);
- gf_vect_dot_prod_base(TEST_LEN, srcs, &g_tbls[32 * srcs], buffs,
- dest_ref2);
- gf_vect_dot_prod_base(TEST_LEN, srcs, &g_tbls[64 * srcs], buffs,
- dest_ref3);
- gf_vect_dot_prod_base(TEST_LEN, srcs, &g_tbls[96 * srcs], buffs,
- dest_ref4);
-
- FUNCTION_UNDER_TEST(TEST_LEN, srcs, g_tbls, buffs, dest_ptrs);
-
- if (0 != memcmp(dest_ref1, dest1, TEST_LEN)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST)
- " test1 srcs=%d\n", srcs);
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref1, 25);
- printf("dprod_dut:");
- dump(dest1, 25);
- return -1;
- }
- if (0 != memcmp(dest_ref2, dest2, TEST_LEN)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST)
- " test2 srcs=%d\n", srcs);
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref2, 25);
- printf("dprod_dut:");
- dump(dest2, 25);
- return -1;
- }
- if (0 != memcmp(dest_ref3, dest3, TEST_LEN)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST)
- " test3 srcs=%d\n", srcs);
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref3, 25);
- printf("dprod_dut:");
- dump(dest3, 25);
- return -1;
- }
- if (0 != memcmp(dest_ref4, dest4, TEST_LEN)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST)
- " test4 srcs=%d\n", srcs);
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref4, 25);
- printf("dprod_dut:");
- dump(dest4, 25);
- return -1;
- }
-
- putchar('.');
- }
- }
-
- // Run tests at end of buffer for Electric Fence
- align = (LEN_ALIGN_CHK_B != 0) ? 1 : 32;
- for (size = TEST_MIN_SIZE; size <= TEST_SIZE; size += align) {
- for (i = 0; i < TEST_SOURCES; i++)
- for (j = 0; j < TEST_LEN; j++)
- buffs[i][j] = rand();
-
- for (i = 0; i < TEST_SOURCES; i++) // Line up TEST_SIZE from end
- efence_buffs[i] = buffs[i] + TEST_LEN - size;
-
- for (i = 0; i < TEST_SOURCES; i++) {
- g1[i] = rand();
- g2[i] = rand();
- g3[i] = rand();
- g4[i] = rand();
- }
-
- for (i = 0; i < TEST_SOURCES; i++) {
- gf_vect_mul_init(g1[i], &g_tbls[i * 32]);
- gf_vect_mul_init(g2[i], &g_tbls[(32 * TEST_SOURCES) + (i * 32)]);
- gf_vect_mul_init(g3[i], &g_tbls[(64 * TEST_SOURCES) + (i * 32)]);
- gf_vect_mul_init(g4[i], &g_tbls[(96 * TEST_SOURCES) + (i * 32)]);
- }
-
- gf_vect_dot_prod_base(size, TEST_SOURCES, &g_tbls[0], efence_buffs, dest_ref1);
- gf_vect_dot_prod_base(size, TEST_SOURCES, &g_tbls[32 * TEST_SOURCES],
- efence_buffs, dest_ref2);
- gf_vect_dot_prod_base(size, TEST_SOURCES, &g_tbls[64 * TEST_SOURCES],
- efence_buffs, dest_ref3);
- gf_vect_dot_prod_base(size, TEST_SOURCES, &g_tbls[96 * TEST_SOURCES],
- efence_buffs, dest_ref4);
-
- FUNCTION_UNDER_TEST(size, TEST_SOURCES, g_tbls, efence_buffs, dest_ptrs);
-
- if (0 != memcmp(dest_ref1, dest1, size)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test1 %d\n", rtest);
- dump_matrix(efence_buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref1, align);
- printf("dprod_dut:");
- dump(dest1, align);
- return -1;
- }
-
- if (0 != memcmp(dest_ref2, dest2, size)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test2 %d\n", rtest);
- dump_matrix(efence_buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref2, align);
- printf("dprod_dut:");
- dump(dest2, align);
- return -1;
- }
-
- if (0 != memcmp(dest_ref3, dest3, size)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test3 %d\n", rtest);
- dump_matrix(efence_buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref3, align);
- printf("dprod_dut:");
- dump(dest3, align);
- return -1;
- }
-
- if (0 != memcmp(dest_ref4, dest4, size)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test4 %d\n", rtest);
- dump_matrix(efence_buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref4, align);
- printf("dprod_dut:");
- dump(dest4, align);
- return -1;
- }
-
- putchar('.');
- }
-
- // Test rand ptr alignment if available
-
- for (rtest = 0; rtest < RANDOMS; rtest++) {
- size = (TEST_LEN - PTR_ALIGN_CHK_B) & ~(TEST_MIN_SIZE - 1);
- srcs = rand() % TEST_SOURCES;
- if (srcs == 0)
- continue;
-
- offset = (PTR_ALIGN_CHK_B != 0) ? 1 : PTR_ALIGN_CHK_B;
- // Add random offsets
- for (i = 0; i < srcs; i++)
- ubuffs[i] = buffs[i] + (rand() & (PTR_ALIGN_CHK_B - offset));
-
- udest_ptrs[0] = dest1 + (rand() & (PTR_ALIGN_CHK_B - offset));
- udest_ptrs[1] = dest2 + (rand() & (PTR_ALIGN_CHK_B - offset));
- udest_ptrs[2] = dest3 + (rand() & (PTR_ALIGN_CHK_B - offset));
- udest_ptrs[3] = dest4 + (rand() & (PTR_ALIGN_CHK_B - offset));
-
- memset(dest1, 0, TEST_LEN); // zero pad to check write-over
- memset(dest2, 0, TEST_LEN);
- memset(dest3, 0, TEST_LEN);
- memset(dest4, 0, TEST_LEN);
-
- for (i = 0; i < srcs; i++)
- for (j = 0; j < size; j++)
- ubuffs[i][j] = rand();
-
- for (i = 0; i < srcs; i++) {
- g1[i] = rand();
- g2[i] = rand();
- g3[i] = rand();
- g4[i] = rand();
- }
-
- for (i = 0; i < srcs; i++) {
- gf_vect_mul_init(g1[i], &g_tbls[i * 32]);
- gf_vect_mul_init(g2[i], &g_tbls[(32 * srcs) + (i * 32)]);
- gf_vect_mul_init(g3[i], &g_tbls[(64 * srcs) + (i * 32)]);
- gf_vect_mul_init(g4[i], &g_tbls[(96 * srcs) + (i * 32)]);
- }
-
- gf_vect_dot_prod_base(size, srcs, &g_tbls[0], ubuffs, dest_ref1);
- gf_vect_dot_prod_base(size, srcs, &g_tbls[32 * srcs], ubuffs, dest_ref2);
- gf_vect_dot_prod_base(size, srcs, &g_tbls[64 * srcs], ubuffs, dest_ref3);
- gf_vect_dot_prod_base(size, srcs, &g_tbls[96 * srcs], ubuffs, dest_ref4);
-
- FUNCTION_UNDER_TEST(size, srcs, g_tbls, ubuffs, udest_ptrs);
-
- if (memcmp(dest_ref1, udest_ptrs[0], size)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test ualign srcs=%d\n",
- srcs);
- dump_matrix(ubuffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref1, 25);
- printf("dprod_dut:");
- dump(udest_ptrs[0], 25);
- return -1;
- }
- if (memcmp(dest_ref2, udest_ptrs[1], size)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test ualign srcs=%d\n",
- srcs);
- dump_matrix(ubuffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref2, 25);
- printf("dprod_dut:");
- dump(udest_ptrs[1], 25);
- return -1;
- }
- if (memcmp(dest_ref3, udest_ptrs[2], size)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test ualign srcs=%d\n",
- srcs);
- dump_matrix(ubuffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref3, 25);
- printf("dprod_dut:");
- dump(udest_ptrs[2], 25);
- return -1;
- }
- if (memcmp(dest_ref4, udest_ptrs[3], size)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test ualign srcs=%d\n",
- srcs);
- dump_matrix(ubuffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref4, 25);
- printf("dprod_dut:");
- dump(udest_ptrs[3], 25);
- return -1;
- }
- // Confirm that padding around dests is unchanged
- memset(dest_ref1, 0, PTR_ALIGN_CHK_B); // Make reference zero buff
- offset = udest_ptrs[0] - dest1;
-
- if (memcmp(dest1, dest_ref1, offset)) {
- printf("Fail rand ualign pad1 start\n");
- return -1;
- }
- if (memcmp(dest1 + offset + size, dest_ref1, PTR_ALIGN_CHK_B - offset)) {
- printf("Fail rand ualign pad1 end\n");
- printf("size=%d offset=%d srcs=%d\n", size, offset, srcs);
- return -1;
- }
-
- offset = udest_ptrs[1] - dest2;
- if (memcmp(dest2, dest_ref1, offset)) {
- printf("Fail rand ualign pad2 start\n");
- return -1;
- }
- if (memcmp(dest2 + offset + size, dest_ref1, PTR_ALIGN_CHK_B - offset)) {
- printf("Fail rand ualign pad2 end\n");
- return -1;
- }
-
- offset = udest_ptrs[2] - dest3;
- if (memcmp(dest3, dest_ref1, offset)) {
- printf("Fail rand ualign pad3 start\n");
- return -1;
- }
- if (memcmp(dest3 + offset + size, dest_ref1, PTR_ALIGN_CHK_B - offset)) {
- printf("Fail rand ualign pad3 end\n");
- return -1;
- }
-
- offset = udest_ptrs[3] - dest4;
- if (memcmp(dest4, dest_ref1, offset)) {
- printf("Fail rand ualign pad4 start\n");
- return -1;
- }
- if (memcmp(dest4 + offset + size, dest_ref1, PTR_ALIGN_CHK_B - offset)) {
- printf("Fail rand ualign pad4 end\n");
- return -1;
- }
-
- putchar('.');
- }
-
- // Test all size alignment
- align = (LEN_ALIGN_CHK_B != 0) ? 1 : 32;
-
- for (size = TEST_LEN; size >= TEST_MIN_SIZE; size -= align) {
- srcs = TEST_SOURCES;
-
- for (i = 0; i < srcs; i++)
- for (j = 0; j < size; j++)
- buffs[i][j] = rand();
-
- for (i = 0; i < srcs; i++) {
- g1[i] = rand();
- g2[i] = rand();
- g3[i] = rand();
- g4[i] = rand();
- }
-
- for (i = 0; i < srcs; i++) {
- gf_vect_mul_init(g1[i], &g_tbls[i * 32]);
- gf_vect_mul_init(g2[i], &g_tbls[(32 * srcs) + (i * 32)]);
- gf_vect_mul_init(g3[i], &g_tbls[(64 * srcs) + (i * 32)]);
- gf_vect_mul_init(g4[i], &g_tbls[(96 * srcs) + (i * 32)]);
- }
-
- gf_vect_dot_prod_base(size, srcs, &g_tbls[0], buffs, dest_ref1);
- gf_vect_dot_prod_base(size, srcs, &g_tbls[32 * srcs], buffs, dest_ref2);
- gf_vect_dot_prod_base(size, srcs, &g_tbls[64 * srcs], buffs, dest_ref3);
- gf_vect_dot_prod_base(size, srcs, &g_tbls[96 * srcs], buffs, dest_ref4);
-
- FUNCTION_UNDER_TEST(size, srcs, g_tbls, buffs, dest_ptrs);
-
- if (memcmp(dest_ref1, dest_ptrs[0], size)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test ualign len=%d\n",
- size);
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref1, 25);
- printf("dprod_dut:");
- dump(dest_ptrs[0], 25);
- return -1;
- }
- if (memcmp(dest_ref2, dest_ptrs[1], size)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test ualign len=%d\n",
- size);
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref2, 25);
- printf("dprod_dut:");
- dump(dest_ptrs[1], 25);
- return -1;
- }
- if (memcmp(dest_ref3, dest_ptrs[2], size)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test ualign len=%d\n",
- size);
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref3, 25);
- printf("dprod_dut:");
- dump(dest_ptrs[2], 25);
- return -1;
- }
- if (memcmp(dest_ref4, dest_ptrs[3], size)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test ualign len=%d\n",
- size);
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref4, 25);
- printf("dprod_dut:");
- dump(dest_ptrs[3], 25);
- return -1;
- }
- }
-
- printf("Pass\n");
- return 0;
-
-}
diff --git a/contrib/libs/isa-l/erasure_code/gf_4vect_dot_prod_sse_test.patch b/contrib/libs/isa-l/erasure_code/gf_4vect_dot_prod_sse_test.patch
deleted file mode 100644
index 21bbfaa667..0000000000
--- a/contrib/libs/isa-l/erasure_code/gf_4vect_dot_prod_sse_test.patch
+++ /dev/null
@@ -1,4 +0,0 @@
-34c34
-< // #include "types.h"
----
-> #include "types.h"
diff --git a/contrib/libs/isa-l/erasure_code/gf_4vect_mad_avx.asm b/contrib/libs/isa-l/erasure_code/gf_4vect_mad_avx.asm
index 2d351663c3..870bc1cdaf 100644
--- a/contrib/libs/isa-l/erasure_code/gf_4vect_mad_avx.asm
+++ b/contrib/libs/isa-l/erasure_code/gf_4vect_mad_avx.asm
@@ -103,7 +103,7 @@
%define return rax
%define return.w eax
- %define func(x) x:
+ %define func(x) x: endbranch
%macro FUNC_SAVE 0
push r12
%endmacro
@@ -169,13 +169,8 @@ section .text
%define xd4 xtmpl1
align 16
-global gf_4vect_mad_avx:ISAL_SYM_TYPE_FUNCTION
+global gf_4vect_mad_avx, function
func(gf_4vect_mad_avx)
-%ifidn __OUTPUT_FORMAT__, macho64
-global _gf_4vect_mad_avx:ISAL_SYM_TYPE_FUNCTION
-func(_gf_4vect_mad_avx)
-%endif
-
FUNC_SAVE
sub len, 16
jl .return_fail
@@ -336,6 +331,3 @@ align 16
mask0f: dq 0x0f0f0f0f0f0f0f0f, 0x0f0f0f0f0f0f0f0f
constip16:
dq 0xf8f9fafbfcfdfeff, 0xf0f1f2f3f4f5f6f7
-
-;;; func core, ver, snum
-slversion gf_4vect_mad_avx, 02, 01, 020a
diff --git a/contrib/libs/isa-l/erasure_code/gf_4vect_mad_avx.patch b/contrib/libs/isa-l/erasure_code/gf_4vect_mad_avx.patch
deleted file mode 100644
index 5b3ad1f1a9..0000000000
--- a/contrib/libs/isa-l/erasure_code/gf_4vect_mad_avx.patch
+++ /dev/null
@@ -1,6 +0,0 @@
-174,178d173
-< %ifidn __OUTPUT_FORMAT__, macho64
-< global _gf_4vect_mad_avx:ISAL_SYM_TYPE_FUNCTION
-< func(_gf_4vect_mad_avx)
-< %endif
-<
diff --git a/contrib/libs/isa-l/erasure_code/gf_4vect_mad_avx2.asm b/contrib/libs/isa-l/erasure_code/gf_4vect_mad_avx2.asm
index 9ec431ff27..4ec710ddac 100644
--- a/contrib/libs/isa-l/erasure_code/gf_4vect_mad_avx2.asm
+++ b/contrib/libs/isa-l/erasure_code/gf_4vect_mad_avx2.asm
@@ -101,7 +101,7 @@
%define return rax
%define return.w eax
- %define func(x) x:
+ %define func(x) x: endbranch
%define FUNC_SAVE
%define FUNC_RESTORE
%endif
@@ -165,13 +165,8 @@ section .text
%define xd4 ymm10
align 16
-global gf_4vect_mad_avx2:ISAL_SYM_TYPE_FUNCTION
+global gf_4vect_mad_avx2, function
func(gf_4vect_mad_avx2)
-%ifidn __OUTPUT_FORMAT__, macho64
-global _gf_4vect_mad_avx2:ISAL_SYM_TYPE_FUNCTION
-func(_gf_4vect_mad_avx2)
-%endif
-
FUNC_SAVE
sub len, 32
jl .return_fail
@@ -342,6 +337,3 @@ align 32
constip32:
dq 0xf8f9fafbfcfdfeff, 0xf0f1f2f3f4f5f6f7
dq 0xe8e9eaebecedeeef, 0xe0e1e2e3e4e5e6e7
-
-;;; func core, ver, snum
-slversion gf_4vect_mad_avx2, 04, 01, 020b
diff --git a/contrib/libs/isa-l/erasure_code/gf_4vect_mad_avx2.patch b/contrib/libs/isa-l/erasure_code/gf_4vect_mad_avx2.patch
deleted file mode 100644
index e0518326ce..0000000000
--- a/contrib/libs/isa-l/erasure_code/gf_4vect_mad_avx2.patch
+++ /dev/null
@@ -1,6 +0,0 @@
-170,174d169
-< %ifidn __OUTPUT_FORMAT__, macho64
-< global _gf_4vect_mad_avx2:ISAL_SYM_TYPE_FUNCTION
-< func(_gf_4vect_mad_avx2)
-< %endif
-<
diff --git a/contrib/libs/isa-l/erasure_code/gf_4vect_mad_avx2_gfni.asm b/contrib/libs/isa-l/erasure_code/gf_4vect_mad_avx2_gfni.asm
new file mode 100644
index 0000000000..63efd4decc
--- /dev/null
+++ b/contrib/libs/isa-l/erasure_code/gf_4vect_mad_avx2_gfni.asm
@@ -0,0 +1,239 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; Copyright(c) 2023 Intel Corporation All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions
+; are met:
+; * Redistributions of source code must retain the above copyright
+; notice, this list of conditions and the following disclaimer.
+; * Redistributions in binary form must reproduce the above copyright
+; notice, this list of conditions and the following disclaimer in
+; the documentation and/or other materials provided with the
+; distribution.
+; * Neither the name of Intel Corporation nor the names of its
+; contributors may be used to endorse or promote products derived
+; from this software without specific prior written permission.
+;
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+; "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+; A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+; OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+; SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+; LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+; OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;;;
+;;; gf_4vect_mad_avx2_gfni(len, vec, vec_i, mul_array, src, dest);
+;;;
+
+%include "reg_sizes.asm"
+%include "gf_vect_gfni.inc"
+%include "memcpy.asm"
+
+%if AS_FEATURE_LEVEL >= 10
+
+%ifidn __OUTPUT_FORMAT__, elf64
+ %define arg0 rdi
+ %define arg1 rsi
+ %define arg2 rdx
+ %define arg3 rcx
+ %define arg4 r8
+ %define arg5 r9
+ %define tmp r11
+ %define tmp2 r10
+ %define tmp3 r12
+ %define func(x) x: endbranch
+ %macro FUNC_SAVE 0
+ push r12
+ %endmacro
+ %macro FUNC_RESTORE 0
+ pop r12
+ %endmacro
+%endif
+
+%ifidn __OUTPUT_FORMAT__, win64
+ %define arg0 rcx
+ %define arg1 rdx
+ %define arg2 r8
+ %define arg3 r9
+ %define arg4 r12 ; must be saved, loaded and restored
+ %define arg5 r13 ; must be saved and restored
+ %define tmp r11
+ %define tmp2 r10
+ %define tmp3 r14
+ %define stack_size 16*7 + 3*8
+ %define arg(x) [rsp + stack_size + 8 + 8*x]
+ %define func(x) proc_frame x
+
+ %macro FUNC_SAVE 0
+ sub rsp, stack_size
+ vmovdqa [rsp + 0*16], xmm6
+ vmovdqa [rsp + 1*16], xmm7
+ vmovdqa [rsp + 2*16], xmm8
+ vmovdqa [rsp + 3*16], xmm9
+ vmovdqa [rsp + 4*16], xmm10
+ vmovdqa [rsp + 5*16], xmm11
+ vmovdqa [rsp + 6*16], xmm12
+ mov [rsp + 7*16 + 0*8], r12
+ mov [rsp + 7*16 + 1*8], r13
+ mov [rsp + 7*16 + 2*8], r14
+ end_prolog
+ mov arg4, arg(4)
+ mov arg5, arg(5)
+ %endmacro
+
+ %macro FUNC_RESTORE 0
+ vmovdqa xmm6, [rsp + 0*16]
+ vmovdqa xmm7, [rsp + 1*16]
+ vmovdqa xmm8, [rsp + 2*16]
+ vmovdqa xmm9, [rsp + 3*16]
+ vmovdqa xmm10, [rsp + 4*16]
+ vmovdqa xmm11, [rsp + 5*16]
+ vmovdqa xmm12, [rsp + 6*16]
+ mov r12, [rsp + 7*16 + 0*8]
+ mov r13, [rsp + 7*16 + 1*8]
+ mov r14, [rsp + 7*16 + 2*8]
+ add rsp, stack_size
+ %endmacro
+%endif
+
+%define len arg0
+%define vec arg1
+%define vec_i arg2
+%define mul_array arg3
+%define src arg4
+%define dest1 arg5
+%define pos rax
+%define dest2 mul_array
+%define dest3 vec_i
+%define dest4 tmp3
+
+%ifndef EC_ALIGNED_ADDR
+;;; Use Un-aligned load/store
+ %define XLDR vmovdqu
+ %define XSTR vmovdqu
+%else
+;;; Use Non-temporal load/stor
+ %ifdef NO_NT_LDST
+ %define XLDR vmovdqa
+ %define XSTR vmovdqa
+ %else
+ %define XLDR vmovntdqa
+ %define XSTR vmovntdq
+ %endif
+%endif
+
+default rel
+[bits 64]
+section .text
+
+%define x0 ymm0
+%define xd1 ymm1
+%define xd2 ymm2
+%define xd3 ymm3
+%define xd4 ymm4
+%define xgft1 ymm5
+%define xgft2 ymm6
+%define xgft3 ymm7
+%define xgft4 ymm8
+%define xret1 ymm9
+%define xret2 ymm10
+%define xret3 ymm11
+%define xret4 ymm12
+
+;;
+;; Encodes 32 bytes of a single source into 4x 32 bytes (parity disks)
+;;
+%macro ENCODE_32B_4 0
+ ;; get next source vector
+ XLDR x0, [src + pos]
+ ;; get next dest vectors
+ XLDR xd1, [dest1 + pos]
+ XLDR xd2, [dest2 + pos]
+ XLDR xd3, [dest3 + pos]
+ XLDR xd4, [dest4 + pos]
+
+ GF_MUL_XOR VEX, x0, xgft1, xret1, xd1, xgft2, xret2, xd2, \
+ xgft3, xret3, xd3, xgft4, xret4, xd4
+
+ XSTR [dest1 + pos], xd1
+ XSTR [dest2 + pos], xd2
+ XSTR [dest3 + pos], xd3
+ XSTR [dest4 + pos], xd4
+%endmacro
+
+;;
+;; Encodes less than 32 bytes of a single source into 4x parity disks
+;;
+%macro ENCODE_LT_32B_4 1
+%define %%LEN %1
+ ;; get next source vector
+ simd_load_avx2 x0, src + pos, %%LEN, tmp, tmp2
+ ;; get next dest vectors
+ simd_load_avx2 xd1, dest1 + pos, %%LEN, tmp, tmp2
+ simd_load_avx2 xd2, dest2 + pos, %%LEN, tmp, tmp2
+ simd_load_avx2 xd3, dest3 + pos, %%LEN, tmp, tmp2
+ simd_load_avx2 xd4, dest4 + pos, %%LEN, tmp, tmp2
+
+ GF_MUL_XOR VEX, x0, xgft1, xret1, xd1, xgft2, xret2, xd2, \
+ xgft3, xret3, xd3, xgft4, xret4, xd4
+
+ lea dest1, [dest1 + pos]
+ simd_store_avx2 dest1, xd1, %%LEN, tmp, tmp2
+ lea dest2, [dest2 + pos]
+ simd_store_avx2 dest2, xd2, %%LEN, tmp, tmp2
+ lea dest3, [dest3 + pos]
+ simd_store_avx2 dest3, xd3, %%LEN, tmp, tmp2
+ lea dest4, [dest4 + pos]
+ simd_store_avx2 dest4, xd4, %%LEN, tmp, tmp2
+%endmacro
+
+align 16
+global gf_4vect_mad_avx2_gfni, function
+func(gf_4vect_mad_avx2_gfni)
+ FUNC_SAVE
+
+ xor pos, pos
+ shl vec_i, 3 ;Multiply by 8
+ shl vec, 3 ;Multiply by 8
+ lea tmp, [mul_array + vec_i]
+ lea tmp2,[vec*3]
+ vbroadcastsd xgft1, [tmp]
+ vbroadcastsd xgft2, [tmp + vec]
+ vbroadcastsd xgft3, [tmp + vec*2]
+ vbroadcastsd xgft4, [tmp + tmp2]
+ mov dest2, [dest1 + 8] ; reuse mul_array
+ mov dest3, [dest1 + 2*8] ; reuse vec_i
+ mov dest4, [dest1 + 3*8]
+ mov dest1, [dest1]
+
+ cmp len, 32
+ jl .len_lt_32
+
+.loop32:
+ ENCODE_32B_4 ;; loop on 32 bytes at a time
+
+ add pos, 32
+ sub len, 32
+ cmp len, 32
+ jge .loop32
+
+.len_lt_32:
+ cmp len, 0
+ jle .exit
+
+ ENCODE_LT_32B_4 len ;; encode final bytes
+
+.exit:
+ vzeroupper
+
+ FUNC_RESTORE
+ ret
+
+endproc_frame
+%endif ; if AS_FEATURE_LEVEL >= 10
diff --git a/contrib/libs/isa-l/erasure_code/gf_4vect_mad_avx512.asm b/contrib/libs/isa-l/erasure_code/gf_4vect_mad_avx512.asm
index 7a5866fdf0..c09ec387e7 100644
--- a/contrib/libs/isa-l/erasure_code/gf_4vect_mad_avx512.asm
+++ b/contrib/libs/isa-l/erasure_code/gf_4vect_mad_avx512.asm
@@ -44,7 +44,7 @@
%define arg5 r9
%define tmp r11
%define return rax
- %define func(x) x:
+ %define func(x) x: endbranch
%define FUNC_SAVE
%define FUNC_RESTORE
%endif
@@ -64,16 +64,16 @@
%macro FUNC_SAVE 0
sub rsp, stack_size
- movdqa [rsp+16*0],xmm6
- movdqa [rsp+16*1],xmm7
- movdqa [rsp+16*2],xmm8
- movdqa [rsp+16*3],xmm9
- movdqa [rsp+16*4],xmm10
- movdqa [rsp+16*5],xmm11
- movdqa [rsp+16*6],xmm12
- movdqa [rsp+16*7],xmm13
- movdqa [rsp+16*8],xmm14
- movdqa [rsp+16*9],xmm15
+ vmovdqa [rsp+16*0],xmm6
+ vmovdqa [rsp+16*1],xmm7
+ vmovdqa [rsp+16*2],xmm8
+ vmovdqa [rsp+16*3],xmm9
+ vmovdqa [rsp+16*4],xmm10
+ vmovdqa [rsp+16*5],xmm11
+ vmovdqa [rsp+16*6],xmm12
+ vmovdqa [rsp+16*7],xmm13
+ vmovdqa [rsp+16*8],xmm14
+ vmovdqa [rsp+16*9],xmm15
save_reg r12, 10*16 + 0*8
save_reg r15, 10*16 + 1*8
end_prolog
@@ -82,16 +82,16 @@
%endmacro
%macro FUNC_RESTORE 0
- movdqa xmm6, [rsp+16*0]
- movdqa xmm7, [rsp+16*1]
- movdqa xmm8, [rsp+16*2]
- movdqa xmm9, [rsp+16*3]
- movdqa xmm10, [rsp+16*4]
- movdqa xmm11, [rsp+16*5]
- movdqa xmm12, [rsp+16*6]
- movdqa xmm13, [rsp+16*7]
- movdqa xmm14, [rsp+16*8]
- movdqa xmm15, [rsp+16*9]
+ vmovdqa xmm6, [rsp+16*0]
+ vmovdqa xmm7, [rsp+16*1]
+ vmovdqa xmm8, [rsp+16*2]
+ vmovdqa xmm9, [rsp+16*3]
+ vmovdqa xmm10, [rsp+16*4]
+ vmovdqa xmm11, [rsp+16*5]
+ vmovdqa xmm12, [rsp+16*6]
+ vmovdqa xmm13, [rsp+16*7]
+ vmovdqa xmm14, [rsp+16*8]
+ vmovdqa xmm15, [rsp+16*9]
mov r12, [rsp + 10*16 + 0*8]
mov r15, [rsp + 10*16 + 1*8]
add rsp, stack_size
@@ -117,8 +117,8 @@
%else
;;; Use Non-temporal load/stor
%ifdef NO_NT_LDST
- %define XLDR vmovdqa
- %define XSTR vmovdqa
+ %define XLDR vmovdqa64
+ %define XSTR vmovdqa64
%else
%define XLDR vmovntdqa
%define XSTR vmovntdq
@@ -159,13 +159,8 @@ section .text
%define xtmpl5 zmm23
align 16
-global gf_4vect_mad_avx512:ISAL_SYM_TYPE_FUNCTION
+global gf_4vect_mad_avx512, function
func(gf_4vect_mad_avx512)
-%ifidn __OUTPUT_FORMAT__, macho64
-global _gf_4vect_mad_avx512:ISAL_SYM_TYPE_FUNCTION
-func(_gf_4vect_mad_avx512)
-%endif
-
FUNC_SAVE
sub len, 64
jl .return_fail
diff --git a/contrib/libs/isa-l/erasure_code/gf_4vect_mad_avx512.patch b/contrib/libs/isa-l/erasure_code/gf_4vect_mad_avx512.patch
deleted file mode 100644
index 4c2a0d08c0..0000000000
--- a/contrib/libs/isa-l/erasure_code/gf_4vect_mad_avx512.patch
+++ /dev/null
@@ -1,6 +0,0 @@
-164,168d163
-< %ifidn __OUTPUT_FORMAT__, macho64
-< global _gf_4vect_mad_avx512:ISAL_SYM_TYPE_FUNCTION
-< func(_gf_4vect_mad_avx512)
-< %endif
-<
diff --git a/contrib/libs/isa-l/erasure_code/gf_4vect_mad_avx512_gfni.asm b/contrib/libs/isa-l/erasure_code/gf_4vect_mad_avx512_gfni.asm
new file mode 100644
index 0000000000..1a5c4d9804
--- /dev/null
+++ b/contrib/libs/isa-l/erasure_code/gf_4vect_mad_avx512_gfni.asm
@@ -0,0 +1,223 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; Copyright(c) 2023 Intel Corporation All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions
+; are met:
+; * Redistributions of source code must retain the above copyright
+; notice, this list of conditions and the following disclaimer.
+; * Redistributions in binary form must reproduce the above copyright
+; notice, this list of conditions and the following disclaimer in
+; the documentation and/or other materials provided with the
+; distribution.
+; * Neither the name of Intel Corporation nor the names of its
+; contributors may be used to endorse or promote products derived
+; from this software without specific prior written permission.
+;
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+; "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+; A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+; OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+; SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+; LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+; OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;;;
+;;; gf_4vect_mad_avx512_gfni(len, vec, vec_i, mul_array, src, dest);
+;;;
+
+%include "reg_sizes.asm"
+%include "gf_vect_gfni.inc"
+
+%if AS_FEATURE_LEVEL >= 10
+
+%ifidn __OUTPUT_FORMAT__, elf64
+ %define arg0 rdi
+ %define arg1 rsi
+ %define arg2 rdx
+ %define arg3 rcx
+ %define arg4 r8
+ %define arg5 r9
+ %define tmp r11
+ %define func(x) x: endbranch
+ %define FUNC_SAVE
+ %define FUNC_RESTORE
+%endif
+
+%ifidn __OUTPUT_FORMAT__, win64
+ %define arg0 rcx
+ %define arg1 rdx
+ %define arg2 r8
+ %define arg3 r9
+ %define arg4 r12
+ %define arg5 r13
+ %define tmp r11
+ %define stack_size 7*16 + 3*8
+ %define arg(x) [rsp + stack_size + 8 + 8*x]
+ %define func(x) proc_frame x
+
+%macro FUNC_SAVE 0
+ sub rsp, stack_size
+ vmovdqa [rsp + 16*0], xmm6
+ vmovdqa [rsp + 16*1], xmm7
+ vmovdqa [rsp + 16*2], xmm8
+ vmovdqa [rsp + 16*3], xmm9
+ vmovdqa [rsp + 16*4], xmm10
+ vmovdqa [rsp + 16*5], xmm11
+ vmovdqa [rsp + 16*6], xmm12
+ mov [rsp + 7*16 + 0*8], r12
+ mov [rsp + 7*16 + 1*8], r13
+ end_prolog
+ mov arg4, arg(4)
+ mov arg5, arg(5)
+%endmacro
+
+%macro FUNC_RESTORE 0
+ vmovdqa xmm6, [rsp + 16*0]
+ vmovdqa xmm7, [rsp + 16*1]
+ vmovdqa xmm8, [rsp + 16*2]
+ vmovdqa xmm9, [rsp + 16*3]
+ vmovdqa xmm10, [rsp + 16*4]
+ vmovdqa xmm11, [rsp + 16*5]
+ vmovdqa xmm12, [rsp + 16*6]
+ mov r12, [rsp + 7*16 + 0*8]
+ mov r13, [rsp + 7*16 + 1*8]
+ add rsp, stack_size
+%endmacro
+%endif
+
+%define len arg0
+%define vec arg1
+%define vec_i arg2
+%define mul_array arg3
+%define src arg4
+%define dest1 arg5
+%define pos rax
+%define dest2 mul_array
+%define dest3 vec
+%define dest4 vec_i
+
+%ifndef EC_ALIGNED_ADDR
+;;; Use Un-aligned load/store
+ %define XLDR vmovdqu8
+ %define XSTR vmovdqu8
+%else
+;;; Use Non-temporal load/stor
+ %ifdef NO_NT_LDST
+ %define XLDR vmovdqa64
+ %define XSTR vmovdqa64
+ %else
+ %define XLDR vmovntdqa
+ %define XSTR vmovntdq
+ %endif
+%endif
+
+default rel
+[bits 64]
+section .text
+
+%define x0 zmm0
+%define xd1 zmm1
+%define xd2 zmm2
+%define xd3 zmm3
+%define xd4 zmm4
+
+%define xgft1 zmm5
+%define xgft2 zmm6
+%define xgft3 zmm7
+%define xgft4 zmm8
+
+%define xret1 zmm9
+%define xret2 zmm10
+%define xret3 zmm11
+%define xret4 zmm12
+
+;;
+;; Encodes 64 bytes of a single source into 4x 64 bytes (parity disks)
+;;
+%macro ENCODE_64B_4 0-1
+%define %%KMASK %1
+
+%if %0 == 1
+ vmovdqu8 x0{%%KMASK}, [src + pos] ;Get next source vector
+ vmovdqu8 xd1{%%KMASK}, [dest1 + pos] ;Get next dest vector
+ vmovdqu8 xd2{%%KMASK}, [dest2 + pos] ;Get next dest vector
+ vmovdqu8 xd3{%%KMASK}, [dest3 + pos] ;Get next dest vector
+ vmovdqu8 xd4{%%KMASK}, [dest4 + pos] ;Get next dest vector
+%else
+ XLDR x0, [src + pos] ;Get next source vector
+ XLDR xd1, [dest1 + pos] ;Get next dest vector
+ XLDR xd2, [dest2 + pos] ;Get next dest vector
+ XLDR xd3, [dest3 + pos] ;Get next dest vector
+ XLDR xd4, [dest4 + pos] ;Get next dest vector
+%endif
+
+ GF_MUL_XOR EVEX, x0, xgft1, xret1, xd1, xgft2, xret2, xd2, xgft3, xret3, xd3, \
+ xgft4, xret4, xd4
+
+%if %0 == 1
+ vmovdqu8 [dest1 + pos]{%%KMASK}, xd1
+ vmovdqu8 [dest2 + pos]{%%KMASK}, xd2
+ vmovdqu8 [dest3 + pos]{%%KMASK}, xd3
+ vmovdqu8 [dest4 + pos]{%%KMASK}, xd4
+%else
+ XSTR [dest1 + pos], xd1
+ XSTR [dest2 + pos], xd2
+ XSTR [dest3 + pos], xd3
+ XSTR [dest4 + pos], xd4
+%endif
+%endmacro
+
+align 16
+global gf_4vect_mad_avx512_gfni, function
+func(gf_4vect_mad_avx512_gfni)
+ FUNC_SAVE
+
+ xor pos, pos
+ shl vec_i, 3 ;Multiply by 8
+ shl vec, 3 ;Multiply by 8
+ lea tmp, [mul_array + vec_i]
+ vbroadcastf32x2 xgft1, [tmp]
+ vbroadcastf32x2 xgft2, [tmp + vec]
+ vbroadcastf32x2 xgft3, [tmp + vec*2]
+ add tmp, vec
+ vbroadcastf32x2 xgft4, [tmp + vec*2]
+ mov dest2, [dest1 + 8] ; reuse mul_array
+ mov dest3, [dest1 + 2*8] ; reuse vec
+ mov dest4, [dest1 + 3*8] ; reuse vec_i
+ mov dest1, [dest1]
+
+ cmp len, 64
+ jl .len_lt_64
+.loop64:
+ ENCODE_64B_4
+
+ add pos, 64 ;Loop on 64 bytes at a time
+ sub len, 64
+ cmp len, 64
+ jge .loop64
+
+.len_lt_64:
+ cmp len, 0
+ jle .exit
+
+ xor tmp, tmp
+ bts tmp, len
+ dec tmp
+ kmovq k1, tmp
+
+ ENCODE_64B_4 k1
+
+.exit:
+ vzeroupper
+
+ FUNC_RESTORE
+ ret
+
+endproc_frame
+%endif ; if AS_FEATURE_LEVEL >= 10
diff --git a/contrib/libs/isa-l/erasure_code/gf_4vect_mad_sse.asm b/contrib/libs/isa-l/erasure_code/gf_4vect_mad_sse.asm
index 32b6cda183..efbe3836a8 100644
--- a/contrib/libs/isa-l/erasure_code/gf_4vect_mad_sse.asm
+++ b/contrib/libs/isa-l/erasure_code/gf_4vect_mad_sse.asm
@@ -103,7 +103,7 @@
%define return rax
%define return.w eax
- %define func(x) x:
+ %define func(x) x: endbranch
%macro FUNC_SAVE 0
push r12
%endmacro
@@ -168,13 +168,8 @@ section .text
%define xd4 xtmpl1
align 16
-global gf_4vect_mad_sse:ISAL_SYM_TYPE_FUNCTION
+global gf_4vect_mad_sse, function
func(gf_4vect_mad_sse)
-%ifidn __OUTPUT_FORMAT__, macho64
-global _gf_4vect_mad_sse:ISAL_SYM_TYPE_FUNCTION
-func(_gf_4vect_mad_sse)
-%endif
-
FUNC_SAVE
sub len, 16
jl .return_fail
@@ -342,6 +337,3 @@ mask0f:
dq 0x0f0f0f0f0f0f0f0f, 0x0f0f0f0f0f0f0f0f
constip16:
dq 0xf8f9fafbfcfdfeff, 0xf0f1f2f3f4f5f6f7
-
-;;; func core, ver, snum
-slversion gf_4vect_mad_sse, 00, 01, 0209
diff --git a/contrib/libs/isa-l/erasure_code/gf_4vect_mad_sse.patch b/contrib/libs/isa-l/erasure_code/gf_4vect_mad_sse.patch
deleted file mode 100644
index d8610712d2..0000000000
--- a/contrib/libs/isa-l/erasure_code/gf_4vect_mad_sse.patch
+++ /dev/null
@@ -1,6 +0,0 @@
-173,177d172
-< %ifidn __OUTPUT_FORMAT__, macho64
-< global _gf_4vect_mad_sse:ISAL_SYM_TYPE_FUNCTION
-< func(_gf_4vect_mad_sse)
-< %endif
-<
diff --git a/contrib/libs/isa-l/erasure_code/gf_5vect_dot_prod_avx.asm b/contrib/libs/isa-l/erasure_code/gf_5vect_dot_prod_avx.asm
index 1d8cccf70b..978b4d2720 100644
--- a/contrib/libs/isa-l/erasure_code/gf_5vect_dot_prod_avx.asm
+++ b/contrib/libs/isa-l/erasure_code/gf_5vect_dot_prod_avx.asm
@@ -51,7 +51,7 @@
%define PS 8
%define LOG_PS 3
- %define func(x) x:
+ %define func(x) x: endbranch
%macro FUNC_SAVE 0
push r12
push r13
@@ -89,16 +89,16 @@
%define func(x) proc_frame x
%macro FUNC_SAVE 0
alloc_stack stack_size
- save_xmm128 xmm6, 0*16
- save_xmm128 xmm7, 1*16
- save_xmm128 xmm8, 2*16
- save_xmm128 xmm9, 3*16
- save_xmm128 xmm10, 4*16
- save_xmm128 xmm11, 5*16
- save_xmm128 xmm12, 6*16
- save_xmm128 xmm13, 7*16
- save_xmm128 xmm14, 8*16
- save_xmm128 xmm15, 9*16
+ vmovdqa [rsp + 0*16], xmm6
+ vmovdqa [rsp + 1*16], xmm7
+ vmovdqa [rsp + 2*16], xmm8
+ vmovdqa [rsp + 3*16], xmm9
+ vmovdqa [rsp + 4*16], xmm10
+ vmovdqa [rsp + 5*16], xmm11
+ vmovdqa [rsp + 6*16], xmm12
+ vmovdqa [rsp + 7*16], xmm13
+ vmovdqa [rsp + 8*16], xmm14
+ vmovdqa [rsp + 9*16], xmm15
save_reg r12, 10*16 + 0*8
save_reg r13, 10*16 + 1*8
save_reg r14, 10*16 + 2*8
@@ -184,13 +184,8 @@ section .text
%define xp5 xmm6
align 16
-global gf_5vect_dot_prod_avx:ISAL_SYM_TYPE_FUNCTION
+global gf_5vect_dot_prod_avx, function
func(gf_5vect_dot_prod_avx)
-%ifidn __OUTPUT_FORMAT__, macho64
-global _gf_5vect_dot_prod_avx:ISAL_SYM_TYPE_FUNCTION
-func(_gf_5vect_dot_prod_avx)
-%endif
-
FUNC_SAVE
sub len, 16
jl .return_fail
@@ -303,6 +298,3 @@ section .data
align 16
mask0f: dq 0x0f0f0f0f0f0f0f0f, 0x0f0f0f0f0f0f0f0f
-
-;;; func core, ver, snum
-slversion gf_5vect_dot_prod_avx, 02, 04, 0194
diff --git a/contrib/libs/isa-l/erasure_code/gf_5vect_dot_prod_avx.patch b/contrib/libs/isa-l/erasure_code/gf_5vect_dot_prod_avx.patch
deleted file mode 100644
index e72a2b4857..0000000000
--- a/contrib/libs/isa-l/erasure_code/gf_5vect_dot_prod_avx.patch
+++ /dev/null
@@ -1,6 +0,0 @@
-189,193d188
-< %ifidn __OUTPUT_FORMAT__, macho64
-< global _gf_5vect_dot_prod_avx:ISAL_SYM_TYPE_FUNCTION
-< func(_gf_5vect_dot_prod_avx)
-< %endif
-<
diff --git a/contrib/libs/isa-l/erasure_code/gf_5vect_dot_prod_avx2.asm b/contrib/libs/isa-l/erasure_code/gf_5vect_dot_prod_avx2.asm
index 0cdfee906e..11fb36b687 100644
--- a/contrib/libs/isa-l/erasure_code/gf_5vect_dot_prod_avx2.asm
+++ b/contrib/libs/isa-l/erasure_code/gf_5vect_dot_prod_avx2.asm
@@ -53,7 +53,7 @@
%define PS 8
%define LOG_PS 3
- %define func(x) x:
+ %define func(x) x: endbranch
%macro FUNC_SAVE 0
push r12
push r13
@@ -189,13 +189,8 @@ section .text
%define xp5 ymm6
align 16
-global gf_5vect_dot_prod_avx2:ISAL_SYM_TYPE_FUNCTION
+global gf_5vect_dot_prod_avx2, function
func(gf_5vect_dot_prod_avx2)
-%ifidn __OUTPUT_FORMAT__, macho64
-global _gf_5vect_dot_prod_avx2:ISAL_SYM_TYPE_FUNCTION
-func(_gf_5vect_dot_prod_avx2)
-%endif
-
FUNC_SAVE
sub len, 32
jl .return_fail
@@ -313,8 +308,3 @@ func(_gf_5vect_dot_prod_avx2)
ret
endproc_frame
-
-section .data
-
-;;; func core, ver, snum
-slversion gf_5vect_dot_prod_avx2, 04, 04, 0199
diff --git a/contrib/libs/isa-l/erasure_code/gf_5vect_dot_prod_avx2.patch b/contrib/libs/isa-l/erasure_code/gf_5vect_dot_prod_avx2.patch
deleted file mode 100644
index a898e05522..0000000000
--- a/contrib/libs/isa-l/erasure_code/gf_5vect_dot_prod_avx2.patch
+++ /dev/null
@@ -1,6 +0,0 @@
-194,198d193
-< %ifidn __OUTPUT_FORMAT__, macho64
-< global _gf_5vect_dot_prod_avx2:ISAL_SYM_TYPE_FUNCTION
-< func(_gf_5vect_dot_prod_avx2)
-< %endif
-<
diff --git a/contrib/libs/isa-l/erasure_code/gf_5vect_dot_prod_avx512.asm b/contrib/libs/isa-l/erasure_code/gf_5vect_dot_prod_avx512.asm
new file mode 100644
index 0000000000..e790cb69eb
--- /dev/null
+++ b/contrib/libs/isa-l/erasure_code/gf_5vect_dot_prod_avx512.asm
@@ -0,0 +1,334 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; Copyright(c) 2011-2019 Intel Corporation All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions
+; are met:
+; * Redistributions of source code must retain the above copyright
+; notice, this list of conditions and the following disclaimer.
+; * Redistributions in binary form must reproduce the above copyright
+; notice, this list of conditions and the following disclaimer in
+; the documentation and/or other materials provided with the
+; distribution.
+; * Neither the name of Intel Corporation nor the names of its
+; contributors may be used to endorse or promote products derived
+; from this software without specific prior written permission.
+;
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+; "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+; A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+; OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+; SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+; LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+; OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;;;
+;;; gf_5vect_dot_prod_avx512(len, vec, *g_tbls, **buffs, **dests);
+;;;
+
+%include "reg_sizes.asm"
+
+%ifdef HAVE_AS_KNOWS_AVX512
+
+%ifidn __OUTPUT_FORMAT__, elf64
+ %define arg0 rdi
+ %define arg1 rsi
+ %define arg2 rdx
+ %define arg3 rcx
+ %define arg4 r8
+ %define arg5 r9
+
+ %define tmp r11
+ %define tmp2 r10
+ %define tmp3 r13 ; must be saved and restored
+ %define tmp4 r12 ; must be saved and restored
+ %define tmp5 r14 ; must be saved and restored
+ %define tmp6 r15 ; must be saved and restored
+ %define tmp7 rbp ; must be saved and restored
+ %define tmp8 rbx ; must be saved and restored
+ %define return rax
+ %define PS 8
+ %define LOG_PS 3
+ %define stack_size 6*8
+
+ %define func(x) x: endbranch
+ %macro FUNC_SAVE 0
+ sub rsp, stack_size
+ mov [rsp + 0*8], r12
+ mov [rsp + 1*8], r13
+ mov [rsp + 2*8], r14
+ mov [rsp + 3*8], r15
+ mov [rsp + 4*8], rbp
+ mov [rsp + 5*8], rbx
+ %endmacro
+ %macro FUNC_RESTORE 0
+ mov r12, [rsp + 0*8]
+ mov r13, [rsp + 1*8]
+ mov r14, [rsp + 2*8]
+ mov r15, [rsp + 3*8]
+ mov rbp, [rsp + 4*8]
+ mov rbx, [rsp + 5*8]
+ add rsp, stack_size
+ %endmacro
+%endif
+
+%ifidn __OUTPUT_FORMAT__, win64
+ %define arg0 rcx
+ %define arg1 rdx
+ %define arg2 r8
+ %define arg3 r9
+
+ %define arg4 r12 ; must be saved, loaded and restored
+ %define arg5 r15 ; must be saved and restored
+ %define tmp r11
+ %define tmp2 r10
+ %define tmp3 r13 ; must be saved and restored
+ %define tmp4 r14 ; must be saved and restored
+ %define tmp5 rdi ; must be saved and restored
+ %define tmp6 rsi ; must be saved and restored
+ %define tmp7 rbp ; must be saved and restored
+ %define tmp8 rbx ; must be saved and restored
+ %define return rax
+ %define PS 8
+ %define LOG_PS 3
+ %define stack_size 10*16 + 9*8 ; must be an odd multiple of 8
+ %define arg(x) [rsp + stack_size + PS + PS*x]
+
+ %define func(x) proc_frame x
+ %macro FUNC_SAVE 0
+ alloc_stack stack_size
+ vmovdqa [rsp + 0*16], xmm6
+ vmovdqa [rsp + 1*16], xmm7
+ vmovdqa [rsp + 2*16], xmm8
+ vmovdqa [rsp + 3*16], xmm9
+ vmovdqa [rsp + 4*16], xmm10
+ vmovdqa [rsp + 5*16], xmm11
+ vmovdqa [rsp + 6*16], xmm12
+ vmovdqa [rsp + 7*16], xmm13
+ vmovdqa [rsp + 8*16], xmm14
+ vmovdqa [rsp + 9*16], xmm15
+ save_reg r12, 10*16 + 0*8
+ save_reg r13, 10*16 + 1*8
+ save_reg r14, 10*16 + 2*8
+ save_reg r15, 10*16 + 3*8
+ save_reg rdi, 10*16 + 4*8
+ save_reg rsi, 10*16 + 5*8
+ save_reg rbp, 10*16 + 6*8
+ save_reg rbx, 10*16 + 7*8
+ end_prolog
+ mov arg4, arg(4)
+ %endmacro
+
+ %macro FUNC_RESTORE 0
+ vmovdqa xmm6, [rsp + 0*16]
+ vmovdqa xmm7, [rsp + 1*16]
+ vmovdqa xmm8, [rsp + 2*16]
+ vmovdqa xmm9, [rsp + 3*16]
+ vmovdqa xmm10, [rsp + 4*16]
+ vmovdqa xmm11, [rsp + 5*16]
+ vmovdqa xmm12, [rsp + 6*16]
+ vmovdqa xmm13, [rsp + 7*16]
+ vmovdqa xmm14, [rsp + 8*16]
+ vmovdqa xmm15, [rsp + 9*16]
+ mov r12, [rsp + 10*16 + 0*8]
+ mov r13, [rsp + 10*16 + 1*8]
+ mov r14, [rsp + 10*16 + 2*8]
+ mov r15, [rsp + 10*16 + 3*8]
+ mov rdi, [rsp + 10*16 + 4*8]
+ mov rsi, [rsp + 10*16 + 5*8]
+ mov rbp, [rsp + 10*16 + 6*8]
+ mov rbx, [rsp + 10*16 + 7*8]
+ add rsp, stack_size
+ %endmacro
+%endif
+
+
+%define len arg0
+%define vec arg1
+%define mul_array arg2
+%define src arg3
+%define dest1 arg4
+%define ptr arg5
+%define vec_i tmp2
+%define dest2 tmp3
+%define dest3 tmp4
+%define dest4 tmp5
+%define vskip3 tmp6
+%define dest5 tmp7
+%define vskip1 tmp8
+%define pos return
+
+
+%ifndef EC_ALIGNED_ADDR
+;;; Use Un-aligned load/store
+ %define XLDR vmovdqu8
+ %define XSTR vmovdqu8
+%else
+;;; Use Non-temporal load/stor
+ %ifdef NO_NT_LDST
+ %define XLDR vmovdqa64
+ %define XSTR vmovdqa64
+ %else
+ %define XLDR vmovntdqa
+ %define XSTR vmovntdq
+ %endif
+%endif
+
+%define xmask0f zmm17
+%define xgft1_lo zmm16
+%define xgft1_loy ymm16
+%define xgft1_hi zmm15
+%define xgft2_lo zmm14
+%define xgft2_loy ymm14
+%define xgft2_hi zmm13
+%define xgft3_lo zmm12
+%define xgft3_loy ymm12
+%define xgft3_hi zmm11
+%define xgft4_lo zmm10
+%define xgft4_loy ymm10
+%define xgft4_hi zmm9
+%define xgft5_lo zmm8
+%define xgft5_loy ymm8
+%define xgft5_hi zmm7
+
+%define x0 zmm0
+%define xtmpa zmm1
+%define xp1 zmm2
+%define xp2 zmm3
+%define xp3 zmm4
+%define xp4 zmm5
+%define xp5 zmm6
+
+default rel
+[bits 64]
+
+section .text
+
+align 16
+global gf_5vect_dot_prod_avx512, function
+func(gf_5vect_dot_prod_avx512)
+ FUNC_SAVE
+ sub len, 64
+ jl .return_fail
+
+ xor pos, pos
+ mov tmp, 0x0f
+ vpbroadcastb xmask0f, tmp ;Construct mask 0x0f0f0f...
+ mov vskip1, vec
+ imul vskip1, 32
+ mov vskip3, vec
+ imul vskip3, 96
+ sal vec, LOG_PS ;vec *= PS. Make vec_i count by PS
+ mov dest2, [dest1+PS]
+ mov dest3, [dest1+2*PS]
+ mov dest4, [dest1+3*PS]
+ mov dest5, [dest1+4*PS]
+ mov dest1, [dest1]
+
+.loop64:
+ vpxorq xp1, xp1, xp1
+ vpxorq xp2, xp2, xp2
+ vpxorq xp3, xp3, xp3
+ vpxorq xp4, xp4, xp4
+ vpxorq xp5, xp5, xp5
+ mov tmp, mul_array
+ xor vec_i, vec_i
+
+.next_vect:
+ mov ptr, [src+vec_i]
+ XLDR x0, [ptr+pos] ;Get next source vector
+ add vec_i, PS
+
+ vpandq xtmpa, x0, xmask0f ;Mask low src nibble in bits 4-0
+ vpsraw x0, x0, 4 ;Shift to put high nibble into bits 4-0
+ vpandq x0, x0, xmask0f ;Mask high src nibble in bits 4-0
+
+ vmovdqu8 xgft1_loy, [tmp] ;Load array Ax{00}..{0f}, Ax{00}..{f0}
+ vmovdqu8 xgft2_loy, [tmp+vec*(32/PS)] ;Load array Bx{00}..{0f}, Bx{00}..{f0}
+ vmovdqu8 xgft3_loy, [tmp+vec*(64/PS)] ;Load array Cx{00}..{0f}, Cx{00}..{f0}
+ vmovdqu8 xgft4_loy, [tmp+vskip3] ;Load array Dx{00}..{0f}, Dx{00}..{f0}
+ vmovdqu8 xgft5_loy, [tmp+vskip1*4] ;Load array Ex{00}..{0f}, Ex{00}..{f0}
+ add tmp, 32
+
+ vshufi64x2 xgft1_hi, xgft1_lo, xgft1_lo, 0x55
+ vshufi64x2 xgft1_lo, xgft1_lo, xgft1_lo, 0x00
+ vshufi64x2 xgft2_hi, xgft2_lo, xgft2_lo, 0x55
+ vshufi64x2 xgft2_lo, xgft2_lo, xgft2_lo, 0x00
+
+ vpshufb xgft1_hi, xgft1_hi, x0 ;Lookup mul table of high nibble
+ vpshufb xgft1_lo, xgft1_lo, xtmpa ;Lookup mul table of low nibble
+ vpxorq xgft1_hi, xgft1_hi, xgft1_lo ;GF add high and low partials
+ vpxorq xp1, xp1, xgft1_hi ;xp1 += partial
+
+ vpshufb xgft2_hi, xgft2_hi, x0 ;Lookup mul table of high nibble
+ vpshufb xgft2_lo, xgft2_lo, xtmpa ;Lookup mul table of low nibble
+ vpxorq xgft2_hi, xgft2_hi, xgft2_lo ;GF add high and low partials
+ vpxorq xp2, xp2, xgft2_hi ;xp2 += partial
+
+ vshufi64x2 xgft3_hi, xgft3_lo, xgft3_lo, 0x55
+ vshufi64x2 xgft3_lo, xgft3_lo, xgft3_lo, 0x00
+ vshufi64x2 xgft4_hi, xgft4_lo, xgft4_lo, 0x55
+ vshufi64x2 xgft4_lo, xgft4_lo, xgft4_lo, 0x00
+
+ vpshufb xgft3_hi, xgft3_hi, x0 ;Lookup mul table of high nibble
+ vpshufb xgft3_lo, xgft3_lo, xtmpa ;Lookup mul table of low nibble
+ vpxorq xgft3_hi, xgft3_hi, xgft3_lo ;GF add high and low partials
+ vpxorq xp3, xp3, xgft3_hi ;xp3 += partial
+
+ vpshufb xgft4_hi, xgft4_hi, x0 ;Lookup mul table of high nibble
+ vpshufb xgft4_lo, xgft4_lo, xtmpa ;Lookup mul table of low nibble
+ vpxorq xgft4_hi, xgft4_hi, xgft4_lo ;GF add high and low partials
+ vpxorq xp4, xp4, xgft4_hi ;xp4 += partial
+
+ vshufi64x2 xgft5_hi, xgft5_lo, xgft5_lo, 0x55
+ vshufi64x2 xgft5_lo, xgft5_lo, xgft5_lo, 0x00
+
+ vpshufb xgft5_hi, xgft5_hi, x0 ;Lookup mul table of high nibble
+ vpshufb xgft5_lo, xgft5_lo, xtmpa ;Lookup mul table of low nibble
+ vpxorq xgft5_hi, xgft5_hi, xgft5_lo ;GF add high and low partials
+ vpxorq xp5, xp5, xgft5_hi ;xp5 += partial
+
+ cmp vec_i, vec
+ jl .next_vect
+
+ XSTR [dest1+pos], xp1
+ XSTR [dest2+pos], xp2
+ XSTR [dest3+pos], xp3
+ XSTR [dest4+pos], xp4
+ XSTR [dest5+pos], xp5
+
+ add pos, 64 ;Loop on 64 bytes at a time
+ cmp pos, len
+ jle .loop64
+
+ lea tmp, [len + 64]
+ cmp pos, tmp
+ je .return_pass
+
+ ;; Tail len
+ mov pos, len ;Overlapped offset length-64
+ jmp .loop64 ;Do one more overlap pass
+
+.return_pass:
+ mov return, 0
+ FUNC_RESTORE
+ ret
+
+.return_fail:
+ mov return, 1
+ FUNC_RESTORE
+ ret
+
+endproc_frame
+
+%else
+%ifidn __OUTPUT_FORMAT__, win64
+global no_gf_5vect_dot_prod_avx512
+no_gf_5vect_dot_prod_avx512:
+%endif
+%endif ; ifdef HAVE_AS_KNOWS_AVX512
diff --git a/contrib/libs/isa-l/erasure_code/gf_5vect_dot_prod_avx512_gfni.asm b/contrib/libs/isa-l/erasure_code/gf_5vect_dot_prod_avx512_gfni.asm
new file mode 100644
index 0000000000..ebb9052368
--- /dev/null
+++ b/contrib/libs/isa-l/erasure_code/gf_5vect_dot_prod_avx512_gfni.asm
@@ -0,0 +1,275 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; Copyright(c) 2023 Intel Corporation All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions
+; are met:
+; * Redistributions of source code must retain the above copyright
+; notice, this list of conditions and the following disclaimer.
+; * Redistributions in binary form must reproduce the above copyright
+; notice, this list of conditions and the following disclaimer in
+; the documentation and/or other materials provided with the
+; distribution.
+; * Neither the name of Intel Corporation nor the names of its
+; contributors may be used to endorse or promote products derived
+; from this software without specific prior written permission.
+;
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+; "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+; A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+; OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+; SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+; LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+; OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;;;
+;;; gf_5vect_dot_prod_avx512_gfni(len, vec, *g_tbls, **buffs, **dests);
+;;;
+
+%include "reg_sizes.asm"
+%include "gf_vect_gfni.inc"
+
+%if AS_FEATURE_LEVEL >= 10
+
+%ifidn __OUTPUT_FORMAT__, elf64
+ %define arg0 rdi
+ %define arg1 rsi
+ %define arg2 rdx
+ %define arg3 rcx
+ %define arg4 r8
+ %define arg5 r9
+
+ %define tmp r11
+ %define tmp2 r10
+ %define tmp3 r13 ; must be saved and restored
+ %define tmp4 r12 ; must be saved and restored
+ %define tmp5 r14 ; must be saved and restored
+ %define tmp6 r15 ; must be saved and restored
+ %define tmp7 rbp ; must be saved and restored
+
+ %define func(x) x: endbranch
+ %macro FUNC_SAVE 0
+ push r12
+ push r13
+ push r14
+ push r15
+ push rbp
+ %endmacro
+ %macro FUNC_RESTORE 0
+ pop rbp
+ pop r15
+ pop r14
+ pop r13
+ pop r12
+ %endmacro
+%endif
+
+%ifidn __OUTPUT_FORMAT__, win64
+ %define arg0 rcx
+ %define arg1 rdx
+ %define arg2 r8
+ %define arg3 r9
+
+ %define arg4 r12 ; must be saved, loaded and restored
+ %define arg5 r15 ; must be saved and restored
+ %define tmp r11
+ %define tmp2 r10
+ %define tmp3 r13 ; must be saved and restored
+ %define tmp4 r14 ; must be saved and restored
+ %define tmp5 rdi ; must be saved and restored
+ %define tmp6 rsi ; must be saved and restored
+ %define tmp7 rbp ; must be saved and restored
+ %define stack_size 5*16 + 9*8 ; must be an odd multiple of 8
+ %define arg(x) [rsp + stack_size + 8 + 8*x]
+
+ %define func(x) proc_frame x
+ %macro FUNC_SAVE 0
+ alloc_stack stack_size
+ vmovdqa [rsp + 0*16], xmm6
+ vmovdqa [rsp + 1*16], xmm7
+ vmovdqa [rsp + 2*16], xmm8
+ vmovdqa [rsp + 3*16], xmm9
+ vmovdqa [rsp + 4*16], xmm10
+ mov [rsp + 5*16 + 0*8], r12
+ mov [rsp + 5*16 + 1*8], r13
+ mov [rsp + 5*16 + 2*8], r14
+ mov [rsp + 5*16 + 3*8], r15
+ mov [rsp + 5*16 + 4*8], rdi
+ mov [rsp + 5*16 + 5*8], rsi
+ mov [rsp + 5*16 + 6*8], rbp
+ end_prolog
+ mov arg4, arg(4)
+ %endmacro
+
+ %macro FUNC_RESTORE 0
+ vmovdqa xmm6, [rsp + 0*16]
+ vmovdqa xmm7, [rsp + 1*16]
+ vmovdqa xmm8, [rsp + 2*16]
+ vmovdqa xmm9, [rsp + 3*16]
+ vmovdqa xmm10, [rsp + 4*16]
+ mov r12, [rsp + 5*16 + 0*8]
+ mov r13, [rsp + 5*16 + 1*8]
+ mov r14, [rsp + 5*16 + 2*8]
+ mov r15, [rsp + 5*16 + 3*8]
+ mov rdi, [rsp + 5*16 + 4*8]
+ mov rsi, [rsp + 5*16 + 5*8]
+ mov rbp, [rsp + 5*16 + 6*8]
+ add rsp, stack_size
+ %endmacro
+%endif
+
+
+%define len arg0
+%define vec arg1
+%define mul_array arg2
+%define src arg3
+%define dest1 arg4
+%define ptr arg5
+%define vec_i tmp2
+%define dest2 tmp3
+%define dest3 tmp4
+%define dest4 tmp5
+%define vskip3 tmp6
+%define dest5 tmp7
+%define pos rax
+
+
+%ifndef EC_ALIGNED_ADDR
+;;; Use Un-aligned load/store
+ %define XLDR vmovdqu8
+ %define XSTR vmovdqu8
+%else
+;;; Use Non-temporal load/stor
+ %ifdef NO_NT_LDST
+ %define XLDR vmovdqa64
+ %define XSTR vmovdqa64
+ %else
+ %define XLDR vmovntdqa
+ %define XSTR vmovntdq
+ %endif
+%endif
+
+%define xgft1 zmm6
+%define xgft2 zmm7
+%define xgft3 zmm8
+%define xgft4 zmm9
+%define xgft5 zmm10
+
+%define x0 zmm0
+%define xp1 zmm1
+%define xp2 zmm2
+%define xp3 zmm3
+%define xp4 zmm4
+%define xp5 zmm5
+
+default rel
+[bits 64]
+
+section .text
+
+;;
+;; Encodes 64 bytes of all "k" sources into 5x 64 bytes (parity disks)
+;;
+%macro ENCODE_64B_5 0-1
+%define %%KMASK %1
+
+ vpxorq xp1, xp1, xp1
+ vpxorq xp2, xp2, xp2
+ vpxorq xp3, xp3, xp3
+ vpxorq xp4, xp4, xp4
+ vpxorq xp5, xp5, xp5
+ mov tmp, mul_array
+ xor vec_i, vec_i
+
+%%next_vect:
+ mov ptr, [src + vec_i]
+%if %0 == 1
+ vmovdqu8 x0{%%KMASK}, [ptr + pos] ;Get next source vector (less than 64 bytes)
+%else
+ XLDR x0, [ptr + pos] ;Get next source vector (64 bytes)
+%endif
+ add vec_i, 8
+
+ vbroadcastf32x2 xgft1, [tmp]
+ vbroadcastf32x2 xgft2, [tmp + vec]
+ vbroadcastf32x2 xgft3, [tmp + vec*2]
+ vbroadcastf32x2 xgft4, [tmp + vskip3]
+ vbroadcastf32x2 xgft5, [tmp + vec*4]
+ add tmp, 8
+
+ GF_MUL_XOR EVEX, x0, xgft1, xgft1, xp1, xgft2, xgft2, xp2, xgft3, xgft3, xp3, \
+ xgft4, xgft4, xp4, xgft5, xgft5, xp5
+
+ cmp vec_i, vec
+ jl %%next_vect
+
+ mov ptr, [dest1] ;reuse ptr
+ mov tmp, [dest1 + 5*8] ;reuse tmp
+
+%if %0 == 1
+ vmovdqu8 [dest1 + pos]{%%KMASK}, xp1
+ vmovdqu8 [dest2 + pos]{%%KMASK}, xp2
+ vmovdqu8 [dest3 + pos]{%%KMASK}, xp3
+ vmovdqu8 [dest4 + pos]{%%KMASK}, xp4
+ vmovdqu8 [dest5 + pos]{%%KMASK}, xp5
+%else
+ XSTR [dest1 + pos], xp1
+ XSTR [dest2 + pos], xp2
+ XSTR [dest3 + pos], xp3
+ XSTR [dest4 + pos], xp4
+ XSTR [dest5 + pos], xp5
+%endif
+%endmacro
+
+align 16
+global gf_5vect_dot_prod_avx512_gfni, function
+func(gf_5vect_dot_prod_avx512_gfni)
+ FUNC_SAVE
+
+ xor pos, pos
+ mov vskip3, vec
+ imul vskip3, 8*3
+ shl vec, 3 ;vec *= 8. Make vec_i count by 8
+ mov dest2, [dest1 + 8]
+ mov dest3, [dest1 + 2*8]
+ mov dest4, [dest1 + 3*8]
+ mov dest5, [dest1 + 4*8]
+ mov dest1, [dest1]
+
+ cmp len, 64
+ jl .len_lt_64
+
+.loop64:
+
+ ENCODE_64B_5
+
+ add pos, 64 ;Loop on 64 bytes at a time
+ sub len, 64
+ cmp len, 64
+ jge .loop64
+
+
+.len_lt_64:
+ cmp len, 0
+ jle .exit
+
+ xor tmp, tmp
+ bts tmp, len
+ dec tmp
+ kmovq k1, tmp
+
+ ENCODE_64B_5 k1
+
+.exit:
+ vzeroupper
+
+ FUNC_RESTORE
+ ret
+
+endproc_frame
+%endif ; if AS_FEATURE_LEVEL >= 10
diff --git a/contrib/libs/isa-l/erasure_code/gf_5vect_dot_prod_sse.asm b/contrib/libs/isa-l/erasure_code/gf_5vect_dot_prod_sse.asm
index 577875dbb4..b669ac6464 100644
--- a/contrib/libs/isa-l/erasure_code/gf_5vect_dot_prod_sse.asm
+++ b/contrib/libs/isa-l/erasure_code/gf_5vect_dot_prod_sse.asm
@@ -51,7 +51,7 @@
%define PS 8
%define LOG_PS 3
- %define func(x) x:
+ %define func(x) x: endbranch
%macro FUNC_SAVE 0
push r12
push r13
@@ -184,13 +184,8 @@ section .text
%define xp5 xmm14
align 16
-global gf_5vect_dot_prod_sse:ISAL_SYM_TYPE_FUNCTION
+global gf_5vect_dot_prod_sse, function
func(gf_5vect_dot_prod_sse)
-%ifidn __OUTPUT_FORMAT__, macho64
-global _gf_5vect_dot_prod_sse:ISAL_SYM_TYPE_FUNCTION
-func(_gf_5vect_dot_prod_sse)
-%endif
-
FUNC_SAVE
sub len, 16
jl .return_fail
@@ -304,6 +299,3 @@ section .data
align 16
mask0f: dq 0x0f0f0f0f0f0f0f0f, 0x0f0f0f0f0f0f0f0f
-
-;;; func core, ver, snum
-slversion gf_5vect_dot_prod_sse, 00, 05, 0065
diff --git a/contrib/libs/isa-l/erasure_code/gf_5vect_dot_prod_sse.patch b/contrib/libs/isa-l/erasure_code/gf_5vect_dot_prod_sse.patch
deleted file mode 100644
index eaa82dcc5d..0000000000
--- a/contrib/libs/isa-l/erasure_code/gf_5vect_dot_prod_sse.patch
+++ /dev/null
@@ -1,6 +0,0 @@
-189,193d188
-< %ifidn __OUTPUT_FORMAT__, macho64
-< global _gf_5vect_dot_prod_sse:ISAL_SYM_TYPE_FUNCTION
-< func(_gf_5vect_dot_prod_sse)
-< %endif
-<
diff --git a/contrib/libs/isa-l/erasure_code/gf_5vect_dot_prod_sse_test.c b/contrib/libs/isa-l/erasure_code/gf_5vect_dot_prod_sse_test.c
deleted file mode 100644
index b1eea664b1..0000000000
--- a/contrib/libs/isa-l/erasure_code/gf_5vect_dot_prod_sse_test.c
+++ /dev/null
@@ -1,805 +0,0 @@
-/**********************************************************************
- Copyright(c) 2011-2015 Intel Corporation All rights reserved.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions
- are met:
- * Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in
- the documentation and/or other materials provided with the
- distribution.
- * Neither the name of Intel Corporation nor the names of its
- contributors may be used to endorse or promote products derived
- from this software without specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-**********************************************************************/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h> // for memset, memcmp
-#include "erasure_code.h"
-// #include "types.h"
-
-#ifndef FUNCTION_UNDER_TEST
-# define FUNCTION_UNDER_TEST gf_5vect_dot_prod_sse
-#endif
-#ifndef TEST_MIN_SIZE
-# define TEST_MIN_SIZE 16
-#endif
-
-#define str(s) #s
-#define xstr(s) str(s)
-
-#define TEST_LEN 2048
-#define TEST_SIZE (TEST_LEN/2)
-#define TEST_MEM TEST_SIZE
-#define TEST_LOOPS 1000
-#define TEST_TYPE_STR ""
-
-#ifndef TEST_SOURCES
-# define TEST_SOURCES 16
-#endif
-#ifndef RANDOMS
-# define RANDOMS 20
-#endif
-
-#ifdef EC_ALIGNED_ADDR
-// Define power of 2 range to check ptr, len alignment
-# define PTR_ALIGN_CHK_B 0
-# define LEN_ALIGN_CHK_B 0 // 0 for aligned only
-#else
-// Define power of 2 range to check ptr, len alignment
-# define PTR_ALIGN_CHK_B 32
-# define LEN_ALIGN_CHK_B 32 // 0 for aligned only
-#endif
-
-typedef unsigned char u8;
-
-void dump(unsigned char *buf, int len)
-{
- int i;
- for (i = 0; i < len;) {
- printf(" %2x", 0xff & buf[i++]);
- if (i % 32 == 0)
- printf("\n");
- }
- printf("\n");
-}
-
-void dump_matrix(unsigned char **s, int k, int m)
-{
- int i, j;
- for (i = 0; i < k; i++) {
- for (j = 0; j < m; j++) {
- printf(" %2x", s[i][j]);
- }
- printf("\n");
- }
- printf("\n");
-}
-
-void dump_u8xu8(unsigned char *s, int k, int m)
-{
- int i, j;
- for (i = 0; i < k; i++) {
- for (j = 0; j < m; j++) {
- printf(" %2x", 0xff & s[j + (i * m)]);
- }
- printf("\n");
- }
- printf("\n");
-}
-
-int main(int argc, char *argv[])
-{
- int i, j, rtest, srcs;
- void *buf;
- u8 g1[TEST_SOURCES], g2[TEST_SOURCES], g3[TEST_SOURCES];
- u8 g4[TEST_SOURCES], g5[TEST_SOURCES], *g_tbls;
- u8 *dest1, *dest2, *dest3, *dest4, *dest5, *buffs[TEST_SOURCES];
- u8 *dest_ref1, *dest_ref2, *dest_ref3, *dest_ref4, *dest_ref5;
- u8 *dest_ptrs[5];
-
- int align, size;
- unsigned char *efence_buffs[TEST_SOURCES];
- unsigned int offset;
- u8 *ubuffs[TEST_SOURCES];
- u8 *udest_ptrs[5];
- printf(xstr(FUNCTION_UNDER_TEST) ": %dx%d ", TEST_SOURCES, TEST_LEN);
-
- // Allocate the arrays
- for (i = 0; i < TEST_SOURCES; i++) {
- if (posix_memalign(&buf, 64, TEST_LEN)) {
- printf("alloc error: Fail");
- return -1;
- }
- buffs[i] = buf;
- }
-
- if (posix_memalign(&buf, 16, 2 * (6 * TEST_SOURCES * 32))) {
- printf("alloc error: Fail");
- return -1;
- }
- g_tbls = buf;
-
- if (posix_memalign(&buf, 64, TEST_LEN)) {
- printf("alloc error: Fail");
- return -1;
- }
- dest1 = buf;
-
- if (posix_memalign(&buf, 64, TEST_LEN)) {
- printf("alloc error: Fail");
- return -1;
- }
- dest2 = buf;
-
- if (posix_memalign(&buf, 64, TEST_LEN)) {
- printf("alloc error: Fail");
- return -1;
- }
- dest3 = buf;
-
- if (posix_memalign(&buf, 64, TEST_LEN)) {
- printf("alloc error: Fail");
- return -1;
- }
- dest4 = buf;
-
- if (posix_memalign(&buf, 64, TEST_LEN)) {
- printf("alloc error: Fail");
- return -1;
- }
- dest5 = buf;
-
- if (posix_memalign(&buf, 64, TEST_LEN)) {
- printf("alloc error: Fail");
- return -1;
- }
- dest_ref1 = buf;
-
- if (posix_memalign(&buf, 64, TEST_LEN)) {
- printf("alloc error: Fail");
- return -1;
- }
- dest_ref2 = buf;
-
- if (posix_memalign(&buf, 64, TEST_LEN)) {
- printf("alloc error: Fail");
- return -1;
- }
- dest_ref3 = buf;
-
- if (posix_memalign(&buf, 64, TEST_LEN)) {
- printf("alloc error: Fail");
- return -1;
- }
- dest_ref4 = buf;
-
- if (posix_memalign(&buf, 64, TEST_LEN)) {
- printf("alloc error: Fail");
- return -1;
- }
- dest_ref5 = buf;
-
- dest_ptrs[0] = dest1;
- dest_ptrs[1] = dest2;
- dest_ptrs[2] = dest3;
- dest_ptrs[3] = dest4;
- dest_ptrs[4] = dest5;
-
- // Test of all zeros
- for (i = 0; i < TEST_SOURCES; i++)
- memset(buffs[i], 0, TEST_LEN);
-
- memset(dest1, 0, TEST_LEN);
- memset(dest2, 0, TEST_LEN);
- memset(dest3, 0, TEST_LEN);
- memset(dest4, 0, TEST_LEN);
- memset(dest5, 0, TEST_LEN);
- memset(dest_ref1, 0, TEST_LEN);
- memset(dest_ref2, 0, TEST_LEN);
- memset(dest_ref3, 0, TEST_LEN);
- memset(dest_ref4, 0, TEST_LEN);
- memset(dest_ref5, 0, TEST_LEN);
- memset(g1, 2, TEST_SOURCES);
- memset(g2, 1, TEST_SOURCES);
- memset(g3, 7, TEST_SOURCES);
- memset(g4, 9, TEST_SOURCES);
- memset(g5, 4, TEST_SOURCES);
-
- for (i = 0; i < TEST_SOURCES; i++) {
- gf_vect_mul_init(g1[i], &g_tbls[i * 32]);
- gf_vect_mul_init(g2[i], &g_tbls[32 * TEST_SOURCES + i * 32]);
- gf_vect_mul_init(g3[i], &g_tbls[64 * TEST_SOURCES + i * 32]);
- gf_vect_mul_init(g4[i], &g_tbls[96 * TEST_SOURCES + i * 32]);
- gf_vect_mul_init(g5[i], &g_tbls[128 * TEST_SOURCES + i * 32]);
- }
-
- gf_vect_dot_prod_base(TEST_LEN, TEST_SOURCES, &g_tbls[0], buffs, dest_ref1);
- gf_vect_dot_prod_base(TEST_LEN, TEST_SOURCES, &g_tbls[32 * TEST_SOURCES], buffs,
- dest_ref2);
- gf_vect_dot_prod_base(TEST_LEN, TEST_SOURCES, &g_tbls[64 * TEST_SOURCES], buffs,
- dest_ref3);
- gf_vect_dot_prod_base(TEST_LEN, TEST_SOURCES, &g_tbls[96 * TEST_SOURCES], buffs,
- dest_ref4);
- gf_vect_dot_prod_base(TEST_LEN, TEST_SOURCES, &g_tbls[128 * TEST_SOURCES], buffs,
- dest_ref5);
-
- FUNCTION_UNDER_TEST(TEST_LEN, TEST_SOURCES, g_tbls, buffs, dest_ptrs);
-
- if (0 != memcmp(dest_ref1, dest1, TEST_LEN)) {
- printf("Fail zero " xstr(FUNCTION_UNDER_TEST) " test1\n");
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref1, 25);
- printf("dprod_dut:");
- dump(dest1, 25);
- return -1;
- }
- if (0 != memcmp(dest_ref2, dest2, TEST_LEN)) {
- printf("Fail zero " xstr(FUNCTION_UNDER_TEST) " test2\n");
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref2, 25);
- printf("dprod_dut:");
- dump(dest2, 25);
- return -1;
- }
- if (0 != memcmp(dest_ref3, dest3, TEST_LEN)) {
- printf("Fail zero " xstr(FUNCTION_UNDER_TEST) " test3\n");
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref3, 25);
- printf("dprod_dut:");
- dump(dest3, 25);
- return -1;
- }
- if (0 != memcmp(dest_ref4, dest4, TEST_LEN)) {
- printf("Fail zero " xstr(FUNCTION_UNDER_TEST) " test4\n");
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref4, 25);
- printf("dprod_dut:");
- dump(dest4, 25);
- return -1;
- }
- if (0 != memcmp(dest_ref5, dest5, TEST_LEN)) {
- printf("Fail zero " xstr(FUNCTION_UNDER_TEST) " test5\n");
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref5, 25);
- printf("dprod_dut:");
- dump(dest5, 25);
- return -1;
- }
- putchar('.');
-
- // Rand data test
-
- for (rtest = 0; rtest < RANDOMS; rtest++) {
- for (i = 0; i < TEST_SOURCES; i++)
- for (j = 0; j < TEST_LEN; j++)
- buffs[i][j] = rand();
-
- for (i = 0; i < TEST_SOURCES; i++) {
- g1[i] = rand();
- g2[i] = rand();
- g3[i] = rand();
- g4[i] = rand();
- g5[i] = rand();
- }
-
- for (i = 0; i < TEST_SOURCES; i++) {
- gf_vect_mul_init(g1[i], &g_tbls[i * 32]);
- gf_vect_mul_init(g2[i], &g_tbls[(32 * TEST_SOURCES) + (i * 32)]);
- gf_vect_mul_init(g3[i], &g_tbls[(64 * TEST_SOURCES) + (i * 32)]);
- gf_vect_mul_init(g4[i], &g_tbls[(96 * TEST_SOURCES) + (i * 32)]);
- gf_vect_mul_init(g5[i], &g_tbls[(128 * TEST_SOURCES) + (i * 32)]);
- }
-
- gf_vect_dot_prod_base(TEST_LEN, TEST_SOURCES, &g_tbls[0], buffs, dest_ref1);
- gf_vect_dot_prod_base(TEST_LEN, TEST_SOURCES, &g_tbls[32 * TEST_SOURCES],
- buffs, dest_ref2);
- gf_vect_dot_prod_base(TEST_LEN, TEST_SOURCES, &g_tbls[64 * TEST_SOURCES],
- buffs, dest_ref3);
- gf_vect_dot_prod_base(TEST_LEN, TEST_SOURCES, &g_tbls[96 * TEST_SOURCES],
- buffs, dest_ref4);
- gf_vect_dot_prod_base(TEST_LEN, TEST_SOURCES, &g_tbls[128 * TEST_SOURCES],
- buffs, dest_ref5);
-
- FUNCTION_UNDER_TEST(TEST_LEN, TEST_SOURCES, g_tbls, buffs, dest_ptrs);
-
- if (0 != memcmp(dest_ref1, dest1, TEST_LEN)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test1 %d\n", rtest);
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref1, 25);
- printf("dprod_dut:");
- dump(dest1, 25);
- return -1;
- }
- if (0 != memcmp(dest_ref2, dest2, TEST_LEN)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test2 %d\n", rtest);
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref2, 25);
- printf("dprod_dut:");
- dump(dest2, 25);
- return -1;
- }
- if (0 != memcmp(dest_ref3, dest3, TEST_LEN)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test3 %d\n", rtest);
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref3, 25);
- printf("dprod_dut:");
- dump(dest3, 25);
- return -1;
- }
- if (0 != memcmp(dest_ref4, dest4, TEST_LEN)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test4 %d\n", rtest);
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref4, 25);
- printf("dprod_dut:");
- dump(dest4, 25);
- return -1;
- }
- if (0 != memcmp(dest_ref5, dest5, TEST_LEN)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test5 %d\n", rtest);
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref5, 25);
- printf("dprod_dut:");
- dump(dest5, 25);
- return -1;
- }
-
- putchar('.');
- }
-
- // Rand data test with varied parameters
- for (rtest = 0; rtest < RANDOMS; rtest++) {
- for (srcs = TEST_SOURCES; srcs > 0; srcs--) {
- for (i = 0; i < srcs; i++)
- for (j = 0; j < TEST_LEN; j++)
- buffs[i][j] = rand();
-
- for (i = 0; i < srcs; i++) {
- g1[i] = rand();
- g2[i] = rand();
- g3[i] = rand();
- g4[i] = rand();
- g5[i] = rand();
- }
-
- for (i = 0; i < srcs; i++) {
- gf_vect_mul_init(g1[i], &g_tbls[i * 32]);
- gf_vect_mul_init(g2[i], &g_tbls[(32 * srcs) + (i * 32)]);
- gf_vect_mul_init(g3[i], &g_tbls[(64 * srcs) + (i * 32)]);
- gf_vect_mul_init(g4[i], &g_tbls[(96 * srcs) + (i * 32)]);
- gf_vect_mul_init(g5[i], &g_tbls[(128 * srcs) + (i * 32)]);
- }
-
- gf_vect_dot_prod_base(TEST_LEN, srcs, &g_tbls[0], buffs, dest_ref1);
- gf_vect_dot_prod_base(TEST_LEN, srcs, &g_tbls[32 * srcs], buffs,
- dest_ref2);
- gf_vect_dot_prod_base(TEST_LEN, srcs, &g_tbls[64 * srcs], buffs,
- dest_ref3);
- gf_vect_dot_prod_base(TEST_LEN, srcs, &g_tbls[96 * srcs], buffs,
- dest_ref4);
- gf_vect_dot_prod_base(TEST_LEN, srcs, &g_tbls[128 * srcs], buffs,
- dest_ref5);
-
- FUNCTION_UNDER_TEST(TEST_LEN, srcs, g_tbls, buffs, dest_ptrs);
-
- if (0 != memcmp(dest_ref1, dest1, TEST_LEN)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST)
- " test1 srcs=%d\n", srcs);
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref1, 25);
- printf("dprod_dut:");
- dump(dest1, 25);
- return -1;
- }
- if (0 != memcmp(dest_ref2, dest2, TEST_LEN)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST)
- " test2 srcs=%d\n", srcs);
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref2, 25);
- printf("dprod_dut:");
- dump(dest2, 25);
- return -1;
- }
- if (0 != memcmp(dest_ref3, dest3, TEST_LEN)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST)
- " test3 srcs=%d\n", srcs);
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref3, 25);
- printf("dprod_dut:");
- dump(dest3, 25);
- return -1;
- }
- if (0 != memcmp(dest_ref4, dest4, TEST_LEN)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST)
- " test4 srcs=%d\n", srcs);
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref4, 25);
- printf("dprod_dut:");
- dump(dest4, 25);
- return -1;
- }
- if (0 != memcmp(dest_ref5, dest5, TEST_LEN)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST)
- " test5 srcs=%d\n", srcs);
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref5, 25);
- printf("dprod_dut:");
- dump(dest5, 25);
- return -1;
- }
-
- putchar('.');
- }
- }
-
- // Run tests at end of buffer for Electric Fence
- align = (LEN_ALIGN_CHK_B != 0) ? 1 : 16;
- for (size = TEST_MIN_SIZE; size <= TEST_SIZE; size += align) {
- for (i = 0; i < TEST_SOURCES; i++)
- for (j = 0; j < TEST_LEN; j++)
- buffs[i][j] = rand();
-
- for (i = 0; i < TEST_SOURCES; i++) // Line up TEST_SIZE from end
- efence_buffs[i] = buffs[i] + TEST_LEN - size;
-
- for (i = 0; i < TEST_SOURCES; i++) {
- g1[i] = rand();
- g2[i] = rand();
- g3[i] = rand();
- g4[i] = rand();
- g5[i] = rand();
- }
-
- for (i = 0; i < TEST_SOURCES; i++) {
- gf_vect_mul_init(g1[i], &g_tbls[i * 32]);
- gf_vect_mul_init(g2[i], &g_tbls[(32 * TEST_SOURCES) + (i * 32)]);
- gf_vect_mul_init(g3[i], &g_tbls[(64 * TEST_SOURCES) + (i * 32)]);
- gf_vect_mul_init(g4[i], &g_tbls[(96 * TEST_SOURCES) + (i * 32)]);
- gf_vect_mul_init(g5[i], &g_tbls[(128 * TEST_SOURCES) + (i * 32)]);
- }
-
- gf_vect_dot_prod_base(size, TEST_SOURCES, &g_tbls[0], efence_buffs, dest_ref1);
- gf_vect_dot_prod_base(size, TEST_SOURCES, &g_tbls[32 * TEST_SOURCES],
- efence_buffs, dest_ref2);
- gf_vect_dot_prod_base(size, TEST_SOURCES, &g_tbls[64 * TEST_SOURCES],
- efence_buffs, dest_ref3);
- gf_vect_dot_prod_base(size, TEST_SOURCES, &g_tbls[96 * TEST_SOURCES],
- efence_buffs, dest_ref4);
- gf_vect_dot_prod_base(size, TEST_SOURCES, &g_tbls[128 * TEST_SOURCES],
- efence_buffs, dest_ref5);
-
- FUNCTION_UNDER_TEST(size, TEST_SOURCES, g_tbls, efence_buffs, dest_ptrs);
-
- if (0 != memcmp(dest_ref1, dest1, size)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test1 %d\n", rtest);
- dump_matrix(efence_buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref1, align);
- printf("dprod_dut:");
- dump(dest1, align);
- return -1;
- }
-
- if (0 != memcmp(dest_ref2, dest2, size)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test2 %d\n", rtest);
- dump_matrix(efence_buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref2, align);
- printf("dprod_dut:");
- dump(dest2, align);
- return -1;
- }
-
- if (0 != memcmp(dest_ref3, dest3, size)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test3 %d\n", rtest);
- dump_matrix(efence_buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref3, align);
- printf("dprod_dut:");
- dump(dest3, align);
- return -1;
- }
-
- if (0 != memcmp(dest_ref4, dest4, size)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test4 %d\n", rtest);
- dump_matrix(efence_buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref4, align);
- printf("dprod_dut:");
- dump(dest4, align);
- return -1;
- }
-
- if (0 != memcmp(dest_ref5, dest5, size)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test5 %d\n", rtest);
- dump_matrix(efence_buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref5, align);
- printf("dprod_dut:");
- dump(dest5, align);
- return -1;
- }
-
- putchar('.');
- }
-
- // Test rand ptr alignment if available
-
- for (rtest = 0; rtest < RANDOMS; rtest++) {
- size = (TEST_LEN - PTR_ALIGN_CHK_B) & ~(TEST_MIN_SIZE - 1);
- srcs = rand() % TEST_SOURCES;
- if (srcs == 0)
- continue;
-
- offset = (PTR_ALIGN_CHK_B != 0) ? 1 : PTR_ALIGN_CHK_B;
- // Add random offsets
- for (i = 0; i < srcs; i++)
- ubuffs[i] = buffs[i] + (rand() & (PTR_ALIGN_CHK_B - offset));
-
- udest_ptrs[0] = dest1 + (rand() & (PTR_ALIGN_CHK_B - offset));
- udest_ptrs[1] = dest2 + (rand() & (PTR_ALIGN_CHK_B - offset));
- udest_ptrs[2] = dest3 + (rand() & (PTR_ALIGN_CHK_B - offset));
- udest_ptrs[3] = dest4 + (rand() & (PTR_ALIGN_CHK_B - offset));
- udest_ptrs[4] = dest5 + (rand() & (PTR_ALIGN_CHK_B - offset));
-
- memset(dest1, 0, TEST_LEN); // zero pad to check write-over
- memset(dest2, 0, TEST_LEN);
- memset(dest3, 0, TEST_LEN);
- memset(dest4, 0, TEST_LEN);
- memset(dest5, 0, TEST_LEN);
-
- for (i = 0; i < srcs; i++)
- for (j = 0; j < size; j++)
- ubuffs[i][j] = rand();
-
- for (i = 0; i < srcs; i++) {
- g1[i] = rand();
- g2[i] = rand();
- g3[i] = rand();
- g4[i] = rand();
- g5[i] = rand();
- }
-
- for (i = 0; i < srcs; i++) {
- gf_vect_mul_init(g1[i], &g_tbls[i * 32]);
- gf_vect_mul_init(g2[i], &g_tbls[(32 * srcs) + (i * 32)]);
- gf_vect_mul_init(g3[i], &g_tbls[(64 * srcs) + (i * 32)]);
- gf_vect_mul_init(g4[i], &g_tbls[(96 * srcs) + (i * 32)]);
- gf_vect_mul_init(g5[i], &g_tbls[(128 * srcs) + (i * 32)]);
- }
-
- gf_vect_dot_prod_base(size, srcs, &g_tbls[0], ubuffs, dest_ref1);
- gf_vect_dot_prod_base(size, srcs, &g_tbls[32 * srcs], ubuffs, dest_ref2);
- gf_vect_dot_prod_base(size, srcs, &g_tbls[64 * srcs], ubuffs, dest_ref3);
- gf_vect_dot_prod_base(size, srcs, &g_tbls[96 * srcs], ubuffs, dest_ref4);
- gf_vect_dot_prod_base(size, srcs, &g_tbls[128 * srcs], ubuffs, dest_ref5);
-
- FUNCTION_UNDER_TEST(size, srcs, g_tbls, ubuffs, udest_ptrs);
-
- if (memcmp(dest_ref1, udest_ptrs[0], size)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test ualign srcs=%d\n",
- srcs);
- dump_matrix(ubuffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref1, 25);
- printf("dprod_dut:");
- dump(udest_ptrs[0], 25);
- return -1;
- }
- if (memcmp(dest_ref2, udest_ptrs[1], size)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test ualign srcs=%d\n",
- srcs);
- dump_matrix(ubuffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref2, 25);
- printf("dprod_dut:");
- dump(udest_ptrs[1], 25);
- return -1;
- }
- if (memcmp(dest_ref3, udest_ptrs[2], size)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test ualign srcs=%d\n",
- srcs);
- dump_matrix(ubuffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref3, 25);
- printf("dprod_dut:");
- dump(udest_ptrs[2], 25);
- return -1;
- }
- if (memcmp(dest_ref4, udest_ptrs[3], size)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test ualign srcs=%d\n",
- srcs);
- dump_matrix(ubuffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref4, 25);
- printf("dprod_dut:");
- dump(udest_ptrs[3], 25);
- return -1;
- }
- if (memcmp(dest_ref5, udest_ptrs[4], size)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test ualign srcs=%d\n",
- srcs);
- dump_matrix(ubuffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref5, 25);
- printf("dprod_dut:");
- dump(udest_ptrs[4], 25);
- return -1;
- }
- // Confirm that padding around dests is unchanged
- memset(dest_ref1, 0, PTR_ALIGN_CHK_B); // Make reference zero buff
- offset = udest_ptrs[0] - dest1;
-
- if (memcmp(dest1, dest_ref1, offset)) {
- printf("Fail rand ualign pad1 start\n");
- return -1;
- }
- if (memcmp(dest1 + offset + size, dest_ref1, PTR_ALIGN_CHK_B - offset)) {
- printf("Fail rand ualign pad1 end\n");
- return -1;
- }
-
- offset = udest_ptrs[1] - dest2;
- if (memcmp(dest2, dest_ref1, offset)) {
- printf("Fail rand ualign pad2 start\n");
- return -1;
- }
- if (memcmp(dest2 + offset + size, dest_ref1, PTR_ALIGN_CHK_B - offset)) {
- printf("Fail rand ualign pad2 end\n");
- return -1;
- }
-
- offset = udest_ptrs[2] - dest3;
- if (memcmp(dest3, dest_ref1, offset)) {
- printf("Fail rand ualign pad3 start\n");
- return -1;
- }
- if (memcmp(dest3 + offset + size, dest_ref1, PTR_ALIGN_CHK_B - offset)) {
- printf("Fail rand ualign pad3 end\n");
- return -1;
- }
-
- offset = udest_ptrs[3] - dest4;
- if (memcmp(dest4, dest_ref1, offset)) {
- printf("Fail rand ualign pad4 start\n");
- return -1;
- }
- if (memcmp(dest4 + offset + size, dest_ref1, PTR_ALIGN_CHK_B - offset)) {
- printf("Fail rand ualign pad4 end\n");
- return -1;
- }
-
- offset = udest_ptrs[4] - dest5;
- if (memcmp(dest5, dest_ref1, offset)) {
- printf("Fail rand ualign pad5 start\n");
- return -1;
- }
- if (memcmp(dest5 + offset + size, dest_ref1, PTR_ALIGN_CHK_B - offset)) {
- printf("Fail rand ualign pad5 end\n");
- return -1;
- }
-
- putchar('.');
- }
-
- // Test all size alignment
- align = (LEN_ALIGN_CHK_B != 0) ? 1 : 16;
-
- for (size = TEST_LEN; size >= TEST_MIN_SIZE; size -= align) {
- srcs = TEST_SOURCES;
-
- for (i = 0; i < srcs; i++)
- for (j = 0; j < size; j++)
- buffs[i][j] = rand();
-
- for (i = 0; i < srcs; i++) {
- g1[i] = rand();
- g2[i] = rand();
- g3[i] = rand();
- g4[i] = rand();
- g5[i] = rand();
- }
-
- for (i = 0; i < srcs; i++) {
- gf_vect_mul_init(g1[i], &g_tbls[i * 32]);
- gf_vect_mul_init(g2[i], &g_tbls[(32 * srcs) + (i * 32)]);
- gf_vect_mul_init(g3[i], &g_tbls[(64 * srcs) + (i * 32)]);
- gf_vect_mul_init(g4[i], &g_tbls[(96 * srcs) + (i * 32)]);
- gf_vect_mul_init(g5[i], &g_tbls[(128 * srcs) + (i * 32)]);
- }
-
- gf_vect_dot_prod_base(size, srcs, &g_tbls[0], buffs, dest_ref1);
- gf_vect_dot_prod_base(size, srcs, &g_tbls[32 * srcs], buffs, dest_ref2);
- gf_vect_dot_prod_base(size, srcs, &g_tbls[64 * srcs], buffs, dest_ref3);
- gf_vect_dot_prod_base(size, srcs, &g_tbls[96 * srcs], buffs, dest_ref4);
- gf_vect_dot_prod_base(size, srcs, &g_tbls[128 * srcs], buffs, dest_ref5);
-
- FUNCTION_UNDER_TEST(size, srcs, g_tbls, buffs, dest_ptrs);
-
- if (memcmp(dest_ref1, dest_ptrs[0], size)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test ualign len=%d\n",
- size);
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref1, 25);
- printf("dprod_dut:");
- dump(dest_ptrs[0], 25);
-
- return -1;
- }
- if (memcmp(dest_ref2, dest_ptrs[1], size)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test ualign len=%d\n",
- size);
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref2, 25);
- printf("dprod_dut:");
- dump(dest_ptrs[1], 25);
- return -1;
- }
- if (memcmp(dest_ref3, dest_ptrs[2], size)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test ualign len=%d\n",
- size);
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref3, 25);
- printf("dprod_dut:");
- dump(dest_ptrs[2], 25);
- return -1;
- }
- if (memcmp(dest_ref4, dest_ptrs[3], size)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test ualign len=%d\n",
- size);
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref4, 25);
- printf("dprod_dut:");
- dump(dest_ptrs[3], 25);
- return -1;
- }
- if (memcmp(dest_ref5, dest_ptrs[4], size)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test ualign len=%d\n",
- size);
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref5, 25);
- printf("dprod_dut:");
- dump(dest_ptrs[4], 25);
- return -1;
- }
- }
-
- printf("Pass\n");
- return 0;
-
-}
diff --git a/contrib/libs/isa-l/erasure_code/gf_5vect_dot_prod_sse_test.patch b/contrib/libs/isa-l/erasure_code/gf_5vect_dot_prod_sse_test.patch
deleted file mode 100644
index 21bbfaa667..0000000000
--- a/contrib/libs/isa-l/erasure_code/gf_5vect_dot_prod_sse_test.patch
+++ /dev/null
@@ -1,4 +0,0 @@
-34c34
-< // #include "types.h"
----
-> #include "types.h"
diff --git a/contrib/libs/isa-l/erasure_code/gf_5vect_mad_avx.asm b/contrib/libs/isa-l/erasure_code/gf_5vect_mad_avx.asm
index 8f38a415a1..e72717328a 100644
--- a/contrib/libs/isa-l/erasure_code/gf_5vect_mad_avx.asm
+++ b/contrib/libs/isa-l/erasure_code/gf_5vect_mad_avx.asm
@@ -107,7 +107,7 @@
%define return rax
%define return.w eax
- %define func(x) x:
+ %define func(x) x: endbranch
%macro FUNC_SAVE 0
push r12
push r13
@@ -178,13 +178,8 @@ section .text
align 16
-global gf_5vect_mad_avx:ISAL_SYM_TYPE_FUNCTION
+global gf_5vect_mad_avx, function
func(gf_5vect_mad_avx)
-%ifidn __OUTPUT_FORMAT__, macho64
-global _gf_5vect_mad_avx:ISAL_SYM_TYPE_FUNCTION
-func(_gf_5vect_mad_avx)
-%endif
-
FUNC_SAVE
sub len, 16
jl .return_fail
@@ -365,6 +360,3 @@ align 16
mask0f: dq 0x0f0f0f0f0f0f0f0f, 0x0f0f0f0f0f0f0f0f
constip16:
dq 0xf8f9fafbfcfdfeff, 0xf0f1f2f3f4f5f6f7
-
-;;; func core, ver, snum
-slversion gf_5vect_mad_avx, 02, 01, 020d
diff --git a/contrib/libs/isa-l/erasure_code/gf_5vect_mad_avx.patch b/contrib/libs/isa-l/erasure_code/gf_5vect_mad_avx.patch
deleted file mode 100644
index d1a3e09445..0000000000
--- a/contrib/libs/isa-l/erasure_code/gf_5vect_mad_avx.patch
+++ /dev/null
@@ -1,6 +0,0 @@
-183,187d182
-< %ifidn __OUTPUT_FORMAT__, macho64
-< global _gf_5vect_mad_avx:ISAL_SYM_TYPE_FUNCTION
-< func(_gf_5vect_mad_avx)
-< %endif
-<
diff --git a/contrib/libs/isa-l/erasure_code/gf_5vect_mad_avx2.asm b/contrib/libs/isa-l/erasure_code/gf_5vect_mad_avx2.asm
index 9029f9287e..927cbcdd1a 100644
--- a/contrib/libs/isa-l/erasure_code/gf_5vect_mad_avx2.asm
+++ b/contrib/libs/isa-l/erasure_code/gf_5vect_mad_avx2.asm
@@ -103,7 +103,7 @@
%define return rax
%define return.w eax
- %define func(x) x:
+ %define func(x) x: endbranch
%define FUNC_SAVE
%define FUNC_RESTORE
%endif
@@ -166,13 +166,8 @@ section .text
%define xd5 ymm9
align 16
-global gf_5vect_mad_avx2:ISAL_SYM_TYPE_FUNCTION
+global gf_5vect_mad_avx2, function
func(gf_5vect_mad_avx2)
-%ifidn __OUTPUT_FORMAT__, macho64
-global _gf_5vect_mad_avx2:ISAL_SYM_TYPE_FUNCTION
-func(_gf_5vect_mad_avx2)
-%endif
-
FUNC_SAVE
sub len, 32
jl .return_fail
@@ -363,6 +358,3 @@ align 32
constip32:
dq 0xf8f9fafbfcfdfeff, 0xf0f1f2f3f4f5f6f7
dq 0xe8e9eaebecedeeef, 0xe0e1e2e3e4e5e6e7
-
-;;; func core, ver, snum
-slversion gf_5vect_mad_avx2, 04, 01, 020e
diff --git a/contrib/libs/isa-l/erasure_code/gf_5vect_mad_avx2.patch b/contrib/libs/isa-l/erasure_code/gf_5vect_mad_avx2.patch
deleted file mode 100644
index 1960386b1c..0000000000
--- a/contrib/libs/isa-l/erasure_code/gf_5vect_mad_avx2.patch
+++ /dev/null
@@ -1,6 +0,0 @@
-171,175d170
-< %ifidn __OUTPUT_FORMAT__, macho64
-< global _gf_5vect_mad_avx2:ISAL_SYM_TYPE_FUNCTION
-< func(_gf_5vect_mad_avx2)
-< %endif
-<
diff --git a/contrib/libs/isa-l/erasure_code/gf_5vect_mad_avx2_gfni.asm b/contrib/libs/isa-l/erasure_code/gf_5vect_mad_avx2_gfni.asm
new file mode 100644
index 0000000000..7ff768528e
--- /dev/null
+++ b/contrib/libs/isa-l/erasure_code/gf_5vect_mad_avx2_gfni.asm
@@ -0,0 +1,265 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; Copyright(c) 2023 Intel Corporation All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions
+; are met:
+; * Redistributions of source code must retain the above copyright
+; notice, this list of conditions and the following disclaimer.
+; * Redistributions in binary form must reproduce the above copyright
+; notice, this list of conditions and the following disclaimer in
+; the documentation and/or other materials provided with the
+; distribution.
+; * Neither the name of Intel Corporation nor the names of its
+; contributors may be used to endorse or promote products derived
+; from this software without specific prior written permission.
+;
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+; "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+; A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+; OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+; SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+; LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+; OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;;;
+;;; gf_5vect_mad_avx2_gfni(len, vec, vec_i, mul_array, src, dest);
+;;;
+
+%include "reg_sizes.asm"
+%include "gf_vect_gfni.inc"
+%include "memcpy.asm"
+
+%if AS_FEATURE_LEVEL >= 10
+
+%ifidn __OUTPUT_FORMAT__, elf64
+ %define arg0 rdi
+ %define arg1 rsi
+ %define arg2 rdx
+ %define arg3 rcx
+ %define arg4 r8
+ %define arg5 r9
+ %define tmp r11
+ %define tmp2 r10
+ %define tmp3 r12
+ %define tmp4 r13
+ %define func(x) x: endbranch
+ %define stack_size 2*8
+ %macro FUNC_SAVE 0
+ sub rsp, stack_size
+ mov [rsp + 0*8], r12
+ mov [rsp + 1*8], r13
+ %endmacro
+ %macro FUNC_RESTORE 0
+ mov r12, [rsp + 0*8]
+ mov r13, [rsp + 1*8]
+ add rsp, stack_size
+ %endmacro
+%endif
+
+%ifidn __OUTPUT_FORMAT__, win64
+ %define arg0 rcx
+ %define arg1 rdx
+ %define arg2 r8
+ %define arg3 r9
+ %define arg4 r12 ; must be saved, loaded and restored
+ %define arg5 r13 ; must be saved and restored
+ %define tmp r11
+ %define tmp2 r10
+ %define tmp3 r14
+ %define tmp4 r15
+ %define stack_size 16*10 + 5*8
+ %define arg(x) [rsp + stack_size + 8 + 8*x]
+ %define func(x) proc_frame x
+
+ %macro FUNC_SAVE 0
+ sub rsp, stack_size
+ vmovdqa [rsp + 0*16], xmm6
+ vmovdqa [rsp + 1*16], xmm7
+ vmovdqa [rsp + 2*16], xmm8
+ vmovdqa [rsp + 3*16], xmm9
+ vmovdqa [rsp + 4*16], xmm10
+ vmovdqa [rsp + 5*16], xmm11
+ vmovdqa [rsp + 6*16], xmm12
+ vmovdqa [rsp + 7*16], xmm13
+ vmovdqa [rsp + 8*16], xmm14
+ vmovdqa [rsp + 9*16], xmm15
+ mov [rsp + 10*16 + 0*8], r12
+ mov [rsp + 10*16 + 1*8], r13
+ mov [rsp + 10*16 + 2*8], r14
+ mov [rsp + 10*16 + 3*8], r15
+ end_prolog
+ mov arg4, arg(4)
+ mov arg5, arg(5)
+ %endmacro
+
+ %macro FUNC_RESTORE 0
+ vmovdqa xmm6, [rsp + 0*16]
+ vmovdqa xmm7, [rsp + 1*16]
+ vmovdqa xmm8, [rsp + 2*16]
+ vmovdqa xmm9, [rsp + 3*16]
+ vmovdqa xmm10, [rsp + 4*16]
+ vmovdqa xmm11, [rsp + 5*16]
+ vmovdqa xmm12, [rsp + 6*16]
+ vmovdqa xmm13, [rsp + 7*16]
+ vmovdqa xmm14, [rsp + 8*16]
+ vmovdqa xmm15, [rsp + 9*16]
+ mov r12, [rsp + 10*16 + 0*8]
+ mov r13, [rsp + 10*16 + 1*8]
+ mov r14, [rsp + 10*16 + 2*8]
+ mov r15, [rsp + 10*16 + 3*8]
+ add rsp, stack_size
+ %endmacro
+%endif
+
+%define len arg0
+%define vec arg1
+%define vec_i arg2
+%define mul_array arg3
+%define src arg4
+%define dest1 arg5
+%define pos rax
+%define dest2 mul_array
+%define dest3 vec_i
+%define dest4 tmp3
+%define dest5 tmp4
+
+%ifndef EC_ALIGNED_ADDR
+;;; Use Un-aligned load/store
+ %define XLDR vmovdqu
+ %define XSTR vmovdqu
+%else
+;;; Use Non-temporal load/stor
+ %ifdef NO_NT_LDST
+ %define XLDR vmovdqa
+ %define XSTR vmovdqa
+ %else
+ %define XLDR vmovntdqa
+ %define XSTR vmovntdq
+ %endif
+%endif
+
+default rel
+[bits 64]
+section .text
+
+%define x0 ymm0
+%define xd1 ymm1
+%define xd2 ymm2
+%define xd3 ymm3
+%define xd4 ymm4
+%define xd5 ymm5
+%define xgft1 ymm6
+%define xgft2 ymm7
+%define xgft3 ymm8
+%define xgft4 ymm9
+%define xgft5 ymm10
+%define xret1 ymm11
+%define xret2 ymm12
+%define xret3 ymm13
+%define xret4 ymm14
+%define xret5 ymm15
+
+;;
+;; Encodes 32 bytes of a single source into 5x 32 bytes (parity disks)
+;;
+%macro ENCODE_32B_5 0
+ ;; get next source vector
+ XLDR x0, [src + pos]
+ ;; get next dest vectors
+ XLDR xd1, [dest1 + pos]
+ XLDR xd2, [dest2 + pos]
+ XLDR xd3, [dest3 + pos]
+ XLDR xd4, [dest4 + pos]
+ XLDR xd5, [dest5 + pos]
+
+ GF_MUL_XOR VEX, x0, xgft1, xret1, xd1, xgft2, xret2, xd2, \
+ xgft3, xret3, xd3, xgft4, xret4, xd4, xgft5, xret5, xd5
+
+ XSTR [dest1 + pos], xd1
+ XSTR [dest2 + pos], xd2
+ XSTR [dest3 + pos], xd3
+ XSTR [dest4 + pos], xd4
+ XSTR [dest5 + pos], xd5
+%endmacro
+
+;;
+;; Encodes less than 32 bytes of a single source into 5x parity disks
+;;
+%macro ENCODE_LT_32B_5 1
+%define %%LEN %1
+ ;; get next source vector
+ simd_load_avx2 x0, src + pos, %%LEN, tmp, tmp2
+ ;; get next dest vectors
+ simd_load_avx2 xd1, dest1 + pos, %%LEN, tmp, tmp2
+ simd_load_avx2 xd2, dest2 + pos, %%LEN, tmp, tmp2
+ simd_load_avx2 xd3, dest3 + pos, %%LEN, tmp, tmp2
+ simd_load_avx2 xd4, dest4 + pos, %%LEN, tmp, tmp2
+ simd_load_avx2 xd5, dest5 + pos, %%LEN, tmp, tmp2
+
+ GF_MUL_XOR VEX, x0, xgft1, xret1, xd1, xgft2, xret2, xd2, \
+ xgft3, xret3, xd3, xgft4, xret4, xd4, xgft5, xret5, xd5
+
+ lea dest1, [dest1 + pos]
+ simd_store_avx2 dest1, xd1, %%LEN, tmp, tmp2
+ lea dest2, [dest2 + pos]
+ simd_store_avx2 dest2, xd2, %%LEN, tmp, tmp2
+ lea dest3, [dest3 + pos]
+ simd_store_avx2 dest3, xd3, %%LEN, tmp, tmp2
+ lea dest4, [dest4 + pos]
+ simd_store_avx2 dest4, xd4, %%LEN, tmp, tmp2
+ lea dest5, [dest5 + pos]
+ simd_store_avx2 dest5, xd5, %%LEN, tmp, tmp2
+%endmacro
+
+align 16
+global gf_5vect_mad_avx2_gfni, function
+func(gf_5vect_mad_avx2_gfni)
+ FUNC_SAVE
+
+ xor pos, pos
+ shl vec_i, 3 ;Multiply by 8
+ shl vec, 3 ;Multiply by 8
+ lea tmp, [mul_array + vec_i]
+ lea tmp2, [vec*3]
+ vbroadcastsd xgft1, [tmp]
+ vbroadcastsd xgft2, [tmp + vec]
+ vbroadcastsd xgft3, [tmp + vec*2]
+ vbroadcastsd xgft4, [tmp + tmp2]
+ vbroadcastsd xgft5, [tmp + vec*4]
+ mov dest2, [dest1 + 1*8] ; reuse mul_array
+ mov dest3, [dest1 + 2*8] ; reuse vec_i
+ mov dest4, [dest1 + 3*8]
+ mov dest5, [dest1 + 4*8]
+ mov dest1, [dest1]
+
+ cmp len, 32
+ jl .len_lt_32
+
+.loop32:
+ ENCODE_32B_5 ;; loop on 32 bytes at a time
+
+ add pos, 32
+ sub len, 32
+ cmp len, 32
+ jge .loop32
+
+.len_lt_32:
+ cmp len, 0
+ jle .exit
+
+ ENCODE_LT_32B_5 len ;; encode final bytes
+
+.exit:
+ vzeroupper
+
+ FUNC_RESTORE
+ ret
+
+endproc_frame
+%endif ; if AS_FEATURE_LEVEL >= 10
diff --git a/contrib/libs/isa-l/erasure_code/gf_5vect_mad_avx512.asm b/contrib/libs/isa-l/erasure_code/gf_5vect_mad_avx512.asm
new file mode 100644
index 0000000000..26f0964b94
--- /dev/null
+++ b/contrib/libs/isa-l/erasure_code/gf_5vect_mad_avx512.asm
@@ -0,0 +1,287 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; Copyright(c) 2011-2019 Intel Corporation All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions
+; are met:
+; * Redistributions of source code must retain the above copyright
+; notice, this list of conditions and the following disclaimer.
+; * Redistributions in binary form must reproduce the above copyright
+; notice, this list of conditions and the following disclaimer in
+; the documentation and/or other materials provided with the
+; distribution.
+; * Neither the name of Intel Corporation nor the names of its
+; contributors may be used to endorse or promote products derived
+; from this software without specific prior written permission.
+;
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+; "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+; A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+; OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+; SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+; LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+; OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;;;
+;;; gf_5vect_mad_avx512(len, vec, vec_i, mul_array, src, dest);
+;;;
+
+%include "reg_sizes.asm"
+
+%ifdef HAVE_AS_KNOWS_AVX512
+
+%ifidn __OUTPUT_FORMAT__, elf64
+ %define arg0 rdi
+ %define arg1 rsi
+ %define arg2 rdx
+ %define arg3 rcx
+ %define arg4 r8
+ %define arg5 r9
+ %define tmp r11
+ %define tmp2 r10
+ %define return rax
+ %define func(x) x: endbranch
+ %define FUNC_SAVE
+ %define FUNC_RESTORE
+%endif
+
+%ifidn __OUTPUT_FORMAT__, win64
+ %define arg0 rcx
+ %define arg1 rdx
+ %define arg2 r8
+ %define arg3 r9
+ %define arg4 r12
+ %define arg5 r15
+ %define tmp r11
+ %define tmp2 r10
+ %define return rax
+ %define stack_size 16*10 + 3*8
+ %define arg(x) [rsp + stack_size + PS + PS*x]
+ %define func(x) proc_frame x
+
+%macro FUNC_SAVE 0
+ sub rsp, stack_size
+ vmovdqa [rsp+16*0],xmm6
+ vmovdqa [rsp+16*1],xmm7
+ vmovdqa [rsp+16*2],xmm8
+ vmovdqa [rsp+16*3],xmm9
+ vmovdqa [rsp+16*4],xmm10
+ vmovdqa [rsp+16*5],xmm11
+ vmovdqa [rsp+16*6],xmm12
+ vmovdqa [rsp+16*7],xmm13
+ vmovdqa [rsp+16*8],xmm14
+ vmovdqa [rsp+16*9],xmm15
+ save_reg r12, 10*16 + 0*8
+ save_reg r15, 10*16 + 1*8
+ end_prolog
+ mov arg4, arg(4)
+ mov arg5, arg(5)
+%endmacro
+
+%macro FUNC_RESTORE 0
+ vmovdqa xmm6, [rsp+16*0]
+ vmovdqa xmm7, [rsp+16*1]
+ vmovdqa xmm8, [rsp+16*2]
+ vmovdqa xmm9, [rsp+16*3]
+ vmovdqa xmm10, [rsp+16*4]
+ vmovdqa xmm11, [rsp+16*5]
+ vmovdqa xmm12, [rsp+16*6]
+ vmovdqa xmm13, [rsp+16*7]
+ vmovdqa xmm14, [rsp+16*8]
+ vmovdqa xmm15, [rsp+16*9]
+ mov r12, [rsp + 10*16 + 0*8]
+ mov r15, [rsp + 10*16 + 1*8]
+ add rsp, stack_size
+%endmacro
+%endif
+
+%define PS 8
+%define len arg0
+%define vec arg1
+%define vec_i arg2
+%define mul_array arg3
+%define src arg4
+%define dest1 arg5
+%define pos return
+%define dest2 tmp2
+%define dest3 mul_array
+%define dest4 vec
+%define dest5 vec_i
+
+%ifndef EC_ALIGNED_ADDR
+;;; Use Un-aligned load/store
+ %define XLDR vmovdqu8
+ %define XSTR vmovdqu8
+%else
+;;; Use Non-temporal load/stor
+ %ifdef NO_NT_LDST
+ %define XLDR vmovdqa64
+ %define XSTR vmovdqa64
+ %else
+ %define XLDR vmovntdqa
+ %define XSTR vmovntdq
+ %endif
+%endif
+
+default rel
+[bits 64]
+section .text
+
+%define x0 zmm0
+%define xtmpa zmm1
+%define xtmpl1 zmm2
+%define xtmph1 zmm3
+%define xtmph2 zmm4
+%define xtmph3 zmm5
+%define xgft1_hi zmm6
+%define xgft1_lo zmm7
+%define xgft1_loy ymm7
+%define xgft2_hi zmm8
+%define xgft2_lo zmm9
+%define xgft2_loy ymm9
+%define xgft3_hi zmm10
+%define xgft3_lo zmm11
+%define xgft3_loy ymm11
+%define xgft4_hi zmm12
+%define xgft4_lo zmm13
+%define xgft4_loy ymm13
+%define xgft5_hi zmm14
+%define xgft5_lo zmm15
+%define xgft5_loy ymm15
+%define xd1 zmm16
+%define xd2 zmm17
+%define xd3 zmm18
+%define xd4 zmm19
+%define xd5 zmm20
+%define xmask0f zmm21
+%define xtmpl2 zmm22
+%define xtmpl3 zmm23
+%define xtmpl4 zmm24
+%define xtmpl5 zmm25
+%define xtmph4 zmm26
+%define xtmph5 zmm27
+
+align 16
+global gf_5vect_mad_avx512, function
+func(gf_5vect_mad_avx512)
+ FUNC_SAVE
+ sub len, 64
+ jl .return_fail
+ xor pos, pos
+ mov tmp, 0x0f
+ vpbroadcastb xmask0f, tmp ;Construct mask 0x0f0f0f...
+ sal vec_i, 5 ;Multiply by 32
+ sal vec, 5 ;Multiply by 32
+ lea tmp, [mul_array + vec_i]
+ vmovdqu xgft1_loy, [tmp] ;Load array Ax{00}..{0f}, Ax{00}..{f0}
+ vmovdqu xgft2_loy, [tmp+vec] ;Load array Bx{00}..{0f}, Bx{00}..{f0}
+ vmovdqu xgft3_loy, [tmp+2*vec] ;Load array Cx{00}..{0f}, Cx{00}..{f0}
+ vmovdqu xgft5_loy, [tmp+4*vec] ;Load array Ex{00}..{0f}, Ex{00}..{f0}
+ add tmp, vec
+ vmovdqu xgft4_loy, [tmp+2*vec] ;Load array Dx{00}..{0f}, Dx{00}..{f0}
+ vshufi64x2 xgft1_hi, xgft1_lo, xgft1_lo, 0x55
+ vshufi64x2 xgft1_lo, xgft1_lo, xgft1_lo, 0x00
+ vshufi64x2 xgft2_hi, xgft2_lo, xgft2_lo, 0x55
+ vshufi64x2 xgft2_lo, xgft2_lo, xgft2_lo, 0x00
+ vshufi64x2 xgft3_hi, xgft3_lo, xgft3_lo, 0x55
+ vshufi64x2 xgft3_lo, xgft3_lo, xgft3_lo, 0x00
+ vshufi64x2 xgft4_hi, xgft4_lo, xgft4_lo, 0x55
+ vshufi64x2 xgft4_lo, xgft4_lo, xgft4_lo, 0x00
+ vshufi64x2 xgft5_hi, xgft5_lo, xgft5_lo, 0x55
+ vshufi64x2 xgft5_lo, xgft5_lo, xgft5_lo, 0x00
+ mov dest2, [dest1+PS]
+ mov dest3, [dest1+2*PS] ; reuse mul_array
+ mov dest4, [dest1+3*PS] ; reuse vec
+ mov dest5, [dest1+4*PS] ; reuse vec_i
+ mov dest1, [dest1]
+ mov tmp, -1
+ kmovq k1, tmp
+
+.loop64:
+ XLDR x0, [src+pos] ;Get next source vector
+ XLDR xd1, [dest1+pos] ;Get next dest vector
+ XLDR xd2, [dest2+pos] ;Get next dest vector
+ XLDR xd3, [dest3+pos] ;Get next dest vector
+ XLDR xd4, [dest4+pos] ;reuse xtmpl1. Get next dest vector
+ XLDR xd5, [dest5+pos] ;Get next dest vector
+
+ vpandq xtmpa, x0, xmask0f ;Mask low src nibble in bits 4-0
+ vpsraw x0, x0, 4 ;Shift to put high nibble into bits 4-0
+ vpandq x0, x0, xmask0f ;Mask high src nibble in bits 4-0
+
+ ; dest1
+ vpshufb xtmph1 {k1}{z}, xgft1_hi, x0 ;Lookup mul table of high nibble
+ vpshufb xtmpl1 {k1}{z}, xgft1_lo, xtmpa ;Lookup mul table of low nibble
+ vpxorq xtmph1, xtmph1, xtmpl1 ;GF add high and low partials
+ vpxorq xd1, xd1, xtmph1 ;xd1 += partial
+
+ ; dest2
+ vpshufb xtmph2 {k1}{z}, xgft2_hi, x0 ;Lookup mul table of high nibble
+ vpshufb xtmpl2 {k1}{z}, xgft2_lo, xtmpa ;Lookup mul table of low nibble
+ vpxorq xtmph2, xtmph2, xtmpl2 ;GF add high and low partials
+ vpxorq xd2, xd2, xtmph2 ;xd2 += partial
+
+ ; dest3
+ vpshufb xtmph3 {k1}{z}, xgft3_hi, x0 ;Lookup mul table of high nibble
+ vpshufb xtmpl3 {k1}{z}, xgft3_lo, xtmpa ;Lookup mul table of low nibble
+ vpxorq xtmph3, xtmph3, xtmpl3 ;GF add high and low partials
+ vpxorq xd3, xd3, xtmph3 ;xd2 += partial
+
+ ; dest4
+ vpshufb xtmph4 {k1}{z}, xgft4_hi, x0 ;Lookup mul table of high nibble
+ vpshufb xtmpl4 {k1}{z}, xgft4_lo, xtmpa ;Lookup mul table of low nibble
+ vpxorq xtmph4, xtmph4, xtmpl4 ;GF add high and low partials
+ vpxorq xd4, xd4, xtmph4 ;xd2 += partial
+
+ ; dest5
+ vpshufb xtmph5 {k1}{z}, xgft5_hi, x0 ;Lookup mul table of high nibble
+ vpshufb xtmpl5 {k1}{z}, xgft5_lo, xtmpa ;Lookup mul table of low nibble
+ vpxorq xtmph5, xtmph5, xtmpl5 ;GF add high and low partials
+ vpxorq xd5, xd5, xtmph5 ;xd2 += partial
+
+ XSTR [dest1+pos], xd1
+ XSTR [dest2+pos], xd2
+ XSTR [dest3+pos], xd3
+ XSTR [dest4+pos], xd4
+ XSTR [dest5+pos], xd5
+
+ add pos, 64 ;Loop on 64 bytes at a time
+ cmp pos, len
+ jle .loop64
+
+ lea tmp, [len + 64]
+ cmp pos, tmp
+ je .return_pass
+
+ ;; Tail len
+ mov pos, (1 << 63)
+ lea tmp, [len + 64 - 1]
+ and tmp, 63
+ sarx pos, pos, tmp
+ kmovq k1, pos
+ mov pos, len ;Overlapped offset length-64
+ jmp .loop64 ;Do one more overlap pass
+
+.return_pass:
+ mov return, 0
+ FUNC_RESTORE
+ ret
+
+.return_fail:
+ mov return, 1
+ FUNC_RESTORE
+ ret
+
+endproc_frame
+
+%else
+%ifidn __OUTPUT_FORMAT__, win64
+global no_gf_5vect_mad_avx512
+no_gf_5vect_mad_avx512:
+%endif
+%endif ; ifdef HAVE_AS_KNOWS_AVX512
diff --git a/contrib/libs/isa-l/erasure_code/gf_5vect_mad_avx512_gfni.asm b/contrib/libs/isa-l/erasure_code/gf_5vect_mad_avx512_gfni.asm
new file mode 100644
index 0000000000..d89ecca970
--- /dev/null
+++ b/contrib/libs/isa-l/erasure_code/gf_5vect_mad_avx512_gfni.asm
@@ -0,0 +1,240 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; Copyright(c) 2023 Intel Corporation All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions
+; are met:
+; * Redistributions of source code must retain the above copyright
+; notice, this list of conditions and the following disclaimer.
+; * Redistributions in binary form must reproduce the above copyright
+; notice, this list of conditions and the following disclaimer in
+; the documentation and/or other materials provided with the
+; distribution.
+; * Neither the name of Intel Corporation nor the names of its
+; contributors may be used to endorse or promote products derived
+; from this software without specific prior written permission.
+;
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+; "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+; A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+; OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+; SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+; LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+; OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;;;
+;;; gf_5vect_mad_avx512_gfni(len, vec, vec_i, mul_array, src, dest);
+;;;
+
+%include "reg_sizes.asm"
+%include "gf_vect_gfni.inc"
+
+%if AS_FEATURE_LEVEL >= 10
+
+%ifidn __OUTPUT_FORMAT__, elf64
+ %define arg0 rdi
+ %define arg1 rsi
+ %define arg2 rdx
+ %define arg3 rcx
+ %define arg4 r8
+ %define arg5 r9
+ %define tmp r11
+ %define tmp2 r10
+ %define func(x) x: endbranch
+ %define FUNC_SAVE
+ %define FUNC_RESTORE
+%endif
+
+%ifidn __OUTPUT_FORMAT__, win64
+ %define arg0 rcx
+ %define arg1 rdx
+ %define arg2 r8
+ %define arg3 r9
+ %define arg4 r12
+ %define arg5 r13
+ %define tmp r11
+ %define tmp2 r10
+ %define stack_size 16*10 + 3*8
+ %define arg(x) [rsp + stack_size + 8 + 8*x]
+ %define func(x) proc_frame x
+
+%macro FUNC_SAVE 0
+ sub rsp, stack_size
+ vmovdqa [rsp + 16*0], xmm6
+ vmovdqa [rsp + 16*1], xmm7
+ vmovdqa [rsp + 16*2], xmm8
+ vmovdqa [rsp + 16*3], xmm9
+ vmovdqa [rsp + 16*4], xmm10
+ vmovdqa [rsp + 16*5], xmm11
+ vmovdqa [rsp + 16*6], xmm12
+ vmovdqa [rsp + 16*7], xmm13
+ vmovdqa [rsp + 16*8], xmm14
+ vmovdqa [rsp + 16*9], xmm15
+ mov [rsp + 10*16 + 0*8], r12
+ mov [rsp + 10*16 + 1*8], r13
+ end_prolog
+ mov arg4, arg(4)
+ mov arg5, arg(5)
+%endmacro
+
+%macro FUNC_RESTORE 0
+ vmovdqa xmm6, [rsp + 16*0]
+ vmovdqa xmm7, [rsp + 16*1]
+ vmovdqa xmm8, [rsp + 16*2]
+ vmovdqa xmm9, [rsp + 16*3]
+ vmovdqa xmm10, [rsp + 16*4]
+ vmovdqa xmm11, [rsp + 16*5]
+ vmovdqa xmm12, [rsp + 16*6]
+ vmovdqa xmm13, [rsp + 16*7]
+ vmovdqa xmm14, [rsp + 16*8]
+ vmovdqa xmm15, [rsp + 16*9]
+ mov r12, [rsp + 10*16 + 0*8]
+ mov r13, [rsp + 10*16 + 1*8]
+ add rsp, stack_size
+%endmacro
+%endif
+
+%define len arg0
+%define vec arg1
+%define vec_i arg2
+%define mul_array arg3
+%define src arg4
+%define dest1 arg5
+%define pos rax
+%define dest2 tmp2
+%define dest3 mul_array
+%define dest4 vec
+%define dest5 vec_i
+
+%ifndef EC_ALIGNED_ADDR
+;;; Use Un-aligned load/store
+ %define XLDR vmovdqu8
+ %define XSTR vmovdqu8
+%else
+;;; Use Non-temporal load/stor
+ %ifdef NO_NT_LDST
+ %define XLDR vmovdqa64
+ %define XSTR vmovdqa64
+ %else
+ %define XLDR vmovntdqa
+ %define XSTR vmovntdq
+ %endif
+%endif
+
+default rel
+[bits 64]
+section .text
+
+%define x0 zmm0
+%define xd1 zmm1
+%define xd2 zmm2
+%define xd3 zmm3
+%define xd4 zmm4
+%define xd5 zmm5
+
+%define xgft1 zmm6
+%define xgft2 zmm7
+%define xgft3 zmm8
+%define xgft4 zmm9
+%define xgft5 zmm10
+
+%define xret1 zmm11
+%define xret2 zmm12
+%define xret3 zmm13
+%define xret4 zmm14
+%define xret5 zmm15
+
+;;
+;; Encodes 64 bytes of a single source into 5x 64 bytes (parity disks)
+;;
+%macro ENCODE_64B_5 0-1
+%define %%KMASK %1
+
+%if %0 == 1
+ vmovdqu8 x0{%%KMASK}, [src + pos] ;Get next source vector
+ vmovdqu8 xd1{%%KMASK}, [dest1 + pos] ;Get next dest vector
+ vmovdqu8 xd2{%%KMASK}, [dest2 + pos] ;Get next dest vector
+ vmovdqu8 xd3{%%KMASK}, [dest3 + pos] ;Get next dest vector
+ vmovdqu8 xd4{%%KMASK}, [dest4 + pos] ;Get next dest vector
+ vmovdqu8 xd5{%%KMASK}, [dest5 + pos] ;Get next dest vector
+%else
+ XLDR x0, [src + pos] ;Get next source vector
+ XLDR xd1, [dest1 + pos] ;Get next dest vector
+ XLDR xd2, [dest2 + pos] ;Get next dest vector
+ XLDR xd3, [dest3 + pos] ;Get next dest vector
+ XLDR xd4, [dest4 + pos] ;Get next dest vector
+ XLDR xd5, [dest5 + pos] ;Get next dest vector
+%endif
+
+ GF_MUL_XOR EVEX, x0, xgft1, xret1, xd1, xgft2, xret2, xd2, xgft3, xret3, xd3, \
+ xgft4, xret4, xd4, xgft5, xret5, xd5
+
+%if %0 == 1
+ vmovdqu8 [dest1 + pos]{%%KMASK}, xd1
+ vmovdqu8 [dest2 + pos]{%%KMASK}, xd2
+ vmovdqu8 [dest3 + pos]{%%KMASK}, xd3
+ vmovdqu8 [dest4 + pos]{%%KMASK}, xd4
+ vmovdqu8 [dest5 + pos]{%%KMASK}, xd5
+%else
+ XSTR [dest1 + pos], xd1
+ XSTR [dest2 + pos], xd2
+ XSTR [dest3 + pos], xd3
+ XSTR [dest4 + pos], xd4
+ XSTR [dest5 + pos], xd5
+%endif
+%endmacro
+align 16
+global gf_5vect_mad_avx512_gfni, function
+func(gf_5vect_mad_avx512_gfni)
+ FUNC_SAVE
+
+ xor pos, pos
+ shl vec_i, 3 ;Multiply by 8
+ shl vec, 3 ;Multiply by 8
+ lea tmp, [mul_array + vec_i]
+ vbroadcastf32x2 xgft1, [tmp]
+ vbroadcastf32x2 xgft2, [tmp + vec]
+ vbroadcastf32x2 xgft3, [tmp + vec*2]
+ vbroadcastf32x2 xgft5, [tmp + vec*4]
+ add tmp, vec
+ vbroadcastf32x2 xgft4, [tmp + vec*2]
+ mov dest2, [dest1 + 8]
+ mov dest3, [dest1 + 2*8] ; reuse mul_array
+ mov dest4, [dest1 + 3*8] ; reuse vec
+ mov dest5, [dest1 + 4*8] ; reuse vec_i
+ mov dest1, [dest1]
+
+ cmp len, 64
+ jl .len_lt_64
+.loop64:
+ ENCODE_64B_5
+
+ add pos, 64 ;Loop on 64 bytes at a time
+ sub len, 64
+ cmp len, 64
+ jge .loop64
+
+.len_lt_64:
+ cmp len, 0
+ jle .exit
+
+ xor tmp, tmp
+ bts tmp, len
+ dec tmp
+ kmovq k1, tmp
+
+ ENCODE_64B_5 k1
+
+.exit:
+ vzeroupper
+
+ FUNC_RESTORE
+ ret
+
+endproc_frame
+%endif ; if AS_FEATURE_LEVEL >= 10
diff --git a/contrib/libs/isa-l/erasure_code/gf_5vect_mad_sse.asm b/contrib/libs/isa-l/erasure_code/gf_5vect_mad_sse.asm
index 15c96bf4dc..072c2b5632 100644
--- a/contrib/libs/isa-l/erasure_code/gf_5vect_mad_sse.asm
+++ b/contrib/libs/isa-l/erasure_code/gf_5vect_mad_sse.asm
@@ -107,7 +107,7 @@
%define return rax
%define return.w eax
- %define func(x) x:
+ %define func(x) x: endbranch
%macro FUNC_SAVE 0
push r12
push r13
@@ -177,13 +177,8 @@ section .text
align 16
-global gf_5vect_mad_sse:ISAL_SYM_TYPE_FUNCTION
+global gf_5vect_mad_sse, function
func(gf_5vect_mad_sse)
-%ifidn __OUTPUT_FORMAT__, macho64
-global _gf_5vect_mad_sse:ISAL_SYM_TYPE_FUNCTION
-func(_gf_5vect_mad_sse)
-%endif
-
FUNC_SAVE
sub len, 16
jl .return_fail
@@ -373,6 +368,3 @@ mask0f:
dq 0x0f0f0f0f0f0f0f0f, 0x0f0f0f0f0f0f0f0f
constip16:
dq 0xf8f9fafbfcfdfeff, 0xf0f1f2f3f4f5f6f7
-
-;;; func core, ver, snum
-slversion gf_5vect_mad_sse, 00, 01, 020c
diff --git a/contrib/libs/isa-l/erasure_code/gf_5vect_mad_sse.patch b/contrib/libs/isa-l/erasure_code/gf_5vect_mad_sse.patch
deleted file mode 100644
index 35d5094ffe..0000000000
--- a/contrib/libs/isa-l/erasure_code/gf_5vect_mad_sse.patch
+++ /dev/null
@@ -1,6 +0,0 @@
-182,186d181
-< %ifidn __OUTPUT_FORMAT__, macho64
-< global _gf_5vect_mad_sse:ISAL_SYM_TYPE_FUNCTION
-< func(_gf_5vect_mad_sse)
-< %endif
-<
diff --git a/contrib/libs/isa-l/erasure_code/gf_6vect_dot_prod_avx.asm b/contrib/libs/isa-l/erasure_code/gf_6vect_dot_prod_avx.asm
index f12798edec..86082e75af 100644
--- a/contrib/libs/isa-l/erasure_code/gf_6vect_dot_prod_avx.asm
+++ b/contrib/libs/isa-l/erasure_code/gf_6vect_dot_prod_avx.asm
@@ -51,7 +51,7 @@
%define PS 8
%define LOG_PS 3
- %define func(x) x:
+ %define func(x) x: endbranch
%macro FUNC_SAVE 0
push r12
push r13
@@ -89,16 +89,16 @@
%define func(x) proc_frame x
%macro FUNC_SAVE 0
alloc_stack stack_size
- save_xmm128 xmm6, 0*16
- save_xmm128 xmm7, 1*16
- save_xmm128 xmm8, 2*16
- save_xmm128 xmm9, 3*16
- save_xmm128 xmm10, 4*16
- save_xmm128 xmm11, 5*16
- save_xmm128 xmm12, 6*16
- save_xmm128 xmm13, 7*16
- save_xmm128 xmm14, 8*16
- save_xmm128 xmm15, 9*16
+ vmovdqa [rsp + 0*16], xmm6
+ vmovdqa [rsp + 1*16], xmm7
+ vmovdqa [rsp + 2*16], xmm8
+ vmovdqa [rsp + 3*16], xmm9
+ vmovdqa [rsp + 4*16], xmm10
+ vmovdqa [rsp + 5*16], xmm11
+ vmovdqa [rsp + 6*16], xmm12
+ vmovdqa [rsp + 7*16], xmm13
+ vmovdqa [rsp + 8*16], xmm14
+ vmovdqa [rsp + 9*16], xmm15
save_reg r12, 10*16 + 0*8
save_reg r13, 10*16 + 1*8
save_reg r14, 10*16 + 2*8
@@ -182,13 +182,8 @@ section .text
%define xp6 xmm7
align 16
-global gf_6vect_dot_prod_avx:ISAL_SYM_TYPE_FUNCTION
+global gf_6vect_dot_prod_avx, function
func(gf_6vect_dot_prod_avx)
-%ifidn __OUTPUT_FORMAT__, macho64
-global _gf_6vect_dot_prod_avx:ISAL_SYM_TYPE_FUNCTION
-func(_gf_6vect_dot_prod_avx)
-%endif
-
FUNC_SAVE
sub len, 16
jl .return_fail
@@ -315,6 +310,3 @@ section .data
align 16
mask0f: dq 0x0f0f0f0f0f0f0f0f, 0x0f0f0f0f0f0f0f0f
-
-;;; func core, ver, snum
-slversion gf_6vect_dot_prod_avx, 02, 04, 0195
diff --git a/contrib/libs/isa-l/erasure_code/gf_6vect_dot_prod_avx.patch b/contrib/libs/isa-l/erasure_code/gf_6vect_dot_prod_avx.patch
deleted file mode 100644
index 42b790fcab..0000000000
--- a/contrib/libs/isa-l/erasure_code/gf_6vect_dot_prod_avx.patch
+++ /dev/null
@@ -1,6 +0,0 @@
-187,191d186
-< %ifidn __OUTPUT_FORMAT__, macho64
-< global _gf_6vect_dot_prod_avx:ISAL_SYM_TYPE_FUNCTION
-< func(_gf_6vect_dot_prod_avx)
-< %endif
-<
diff --git a/contrib/libs/isa-l/erasure_code/gf_6vect_dot_prod_avx2.asm b/contrib/libs/isa-l/erasure_code/gf_6vect_dot_prod_avx2.asm
index d5b2543225..ee2d92665e 100644
--- a/contrib/libs/isa-l/erasure_code/gf_6vect_dot_prod_avx2.asm
+++ b/contrib/libs/isa-l/erasure_code/gf_6vect_dot_prod_avx2.asm
@@ -53,7 +53,7 @@
%define PS 8
%define LOG_PS 3
- %define func(x) x:
+ %define func(x) x: endbranch
%macro FUNC_SAVE 0
push r12
push r13
@@ -187,13 +187,8 @@ section .text
%define xp6 ymm7
align 16
-global gf_6vect_dot_prod_avx2:ISAL_SYM_TYPE_FUNCTION
+global gf_6vect_dot_prod_avx2, function
func(gf_6vect_dot_prod_avx2)
-%ifidn __OUTPUT_FORMAT__, macho64
-global _gf_6vect_dot_prod_avx2:ISAL_SYM_TYPE_FUNCTION
-func(_gf_6vect_dot_prod_avx2)
-%endif
-
FUNC_SAVE
sub len, 32
jl .return_fail
@@ -324,8 +319,3 @@ func(_gf_6vect_dot_prod_avx2)
ret
endproc_frame
-
-section .data
-
-;;; func core, ver, snum
-slversion gf_6vect_dot_prod_avx2, 04, 04, 019a
diff --git a/contrib/libs/isa-l/erasure_code/gf_6vect_dot_prod_avx2.patch b/contrib/libs/isa-l/erasure_code/gf_6vect_dot_prod_avx2.patch
deleted file mode 100644
index 531cd8cdda..0000000000
--- a/contrib/libs/isa-l/erasure_code/gf_6vect_dot_prod_avx2.patch
+++ /dev/null
@@ -1,6 +0,0 @@
-192,196d191
-< %ifidn __OUTPUT_FORMAT__, macho64
-< global _gf_6vect_dot_prod_avx2:ISAL_SYM_TYPE_FUNCTION
-< func(_gf_6vect_dot_prod_avx2)
-< %endif
-<
diff --git a/contrib/libs/isa-l/erasure_code/gf_6vect_dot_prod_avx512.asm b/contrib/libs/isa-l/erasure_code/gf_6vect_dot_prod_avx512.asm
new file mode 100644
index 0000000000..531dce90d1
--- /dev/null
+++ b/contrib/libs/isa-l/erasure_code/gf_6vect_dot_prod_avx512.asm
@@ -0,0 +1,353 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; Copyright(c) 2011-2019 Intel Corporation All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions
+; are met:
+; * Redistributions of source code must retain the above copyright
+; notice, this list of conditions and the following disclaimer.
+; * Redistributions in binary form must reproduce the above copyright
+; notice, this list of conditions and the following disclaimer in
+; the documentation and/or other materials provided with the
+; distribution.
+; * Neither the name of Intel Corporation nor the names of its
+; contributors may be used to endorse or promote products derived
+; from this software without specific prior written permission.
+;
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+; "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+; A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+; OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+; SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+; LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+; OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;;;
+;;; gf_6vect_dot_prod_avx512(len, vec, *g_tbls, **buffs, **dests);
+;;;
+
+%include "reg_sizes.asm"
+
+%ifdef HAVE_AS_KNOWS_AVX512
+
+%ifidn __OUTPUT_FORMAT__, elf64
+ %define arg0 rdi
+ %define arg1 rsi
+ %define arg2 rdx
+ %define arg3 rcx
+ %define arg4 r8
+ %define arg5 r9
+
+ %define tmp r11
+ %define tmp2 r10
+ %define tmp3 r13 ; must be saved and restored
+ %define tmp4 r12 ; must be saved and restored
+ %define tmp5 r14 ; must be saved and restored
+ %define tmp6 r15 ; must be saved and restored
+ %define tmp7 rbp ; must be saved and restored
+ %define tmp8 rbx ; must be saved and restored
+ %define return rax
+ %define PS 8
+ %define LOG_PS 3
+ %define stack_size 6*8
+
+ %define func(x) x: endbranch
+ %macro FUNC_SAVE 0
+ sub rsp, stack_size
+ mov [rsp + 0*8], r12
+ mov [rsp + 1*8], r13
+ mov [rsp + 2*8], r14
+ mov [rsp + 3*8], r15
+ mov [rsp + 4*8], rbp
+ mov [rsp + 5*8], rbx
+ %endmacro
+ %macro FUNC_RESTORE 0
+ mov r12, [rsp + 0*8]
+ mov r13, [rsp + 1*8]
+ mov r14, [rsp + 2*8]
+ mov r15, [rsp + 3*8]
+ mov rbp, [rsp + 4*8]
+ mov rbx, [rsp + 5*8]
+ add rsp, stack_size
+ %endmacro
+%endif
+
+%ifidn __OUTPUT_FORMAT__, win64
+ %define arg0 rcx
+ %define arg1 rdx
+ %define arg2 r8
+ %define arg3 r9
+
+ %define arg4 r12 ; must be saved, loaded and restored
+ %define arg5 r15 ; must be saved and restored
+ %define tmp r11
+ %define tmp2 r10
+ %define tmp3 r13 ; must be saved and restored
+ %define tmp4 r14 ; must be saved and restored
+ %define tmp5 rdi ; must be saved and restored
+ %define tmp6 rsi ; must be saved and restored
+ %define tmp7 rbp ; must be saved and restored
+ %define tmp8 rbx ; must be saved and restored
+ %define return rax
+ %define PS 8
+ %define LOG_PS 3
+ %define stack_size 10*16 + 9*8 ; must be an odd multiple of 8
+ %define arg(x) [rsp + stack_size + PS + PS*x]
+
+ %define func(x) proc_frame x
+ %macro FUNC_SAVE 0
+ alloc_stack stack_size
+ vmovdqa [rsp + 0*16], xmm6
+ vmovdqa [rsp + 1*16], xmm7
+ vmovdqa [rsp + 2*16], xmm8
+ vmovdqa [rsp + 3*16], xmm9
+ vmovdqa [rsp + 4*16], xmm10
+ vmovdqa [rsp + 5*16], xmm11
+ vmovdqa [rsp + 6*16], xmm12
+ vmovdqa [rsp + 7*16], xmm13
+ vmovdqa [rsp + 8*16], xmm14
+ vmovdqa [rsp + 9*16], xmm15
+ save_reg r12, 10*16 + 0*8
+ save_reg r13, 10*16 + 1*8
+ save_reg r14, 10*16 + 2*8
+ save_reg r15, 10*16 + 3*8
+ save_reg rdi, 10*16 + 4*8
+ save_reg rsi, 10*16 + 5*8
+ save_reg rbp, 10*16 + 6*8
+ save_reg rbx, 10*16 + 7*8
+ end_prolog
+ mov arg4, arg(4)
+ %endmacro
+
+ %macro FUNC_RESTORE 0
+ vmovdqa xmm6, [rsp + 0*16]
+ vmovdqa xmm7, [rsp + 1*16]
+ vmovdqa xmm8, [rsp + 2*16]
+ vmovdqa xmm9, [rsp + 3*16]
+ vmovdqa xmm10, [rsp + 4*16]
+ vmovdqa xmm11, [rsp + 5*16]
+ vmovdqa xmm12, [rsp + 6*16]
+ vmovdqa xmm13, [rsp + 7*16]
+ vmovdqa xmm14, [rsp + 8*16]
+ vmovdqa xmm15, [rsp + 9*16]
+ mov r12, [rsp + 10*16 + 0*8]
+ mov r13, [rsp + 10*16 + 1*8]
+ mov r14, [rsp + 10*16 + 2*8]
+ mov r15, [rsp + 10*16 + 3*8]
+ mov rdi, [rsp + 10*16 + 4*8]
+ mov rsi, [rsp + 10*16 + 5*8]
+ mov rbp, [rsp + 10*16 + 6*8]
+ mov rbx, [rsp + 10*16 + 7*8]
+ add rsp, stack_size
+ %endmacro
+%endif
+
+
+%define len arg0
+%define vec arg1
+%define mul_array arg2
+%define src arg3
+%define dest1 arg4
+%define ptr arg5
+%define vec_i tmp2
+%define dest2 tmp3
+%define dest3 tmp4
+%define dest4 tmp5
+%define vskip3 tmp6
+%define dest5 tmp7
+%define vskip1 tmp8
+%define pos return
+
+
+%ifndef EC_ALIGNED_ADDR
+;;; Use Un-aligned load/store
+ %define XLDR vmovdqu8
+ %define XSTR vmovdqu8
+%else
+;;; Use Non-temporal load/stor
+ %ifdef NO_NT_LDST
+ %define XLDR vmovdqa64
+ %define XSTR vmovdqa64
+ %else
+ %define XLDR vmovntdqa
+ %define XSTR vmovntdq
+ %endif
+%endif
+
+%define xmask0f zmm20
+%define xgft1_lo zmm19
+%define xgft1_loy ymm19
+%define xgft1_hi zmm18
+%define xgft2_lo zmm17
+%define xgft2_loy ymm17
+%define xgft2_hi zmm16
+%define xgft3_lo zmm15
+%define xgft3_loy ymm15
+%define xgft3_hi zmm14
+%define xgft4_lo zmm13
+%define xgft4_loy ymm13
+%define xgft4_hi zmm12
+%define xgft5_lo zmm11
+%define xgft5_loy ymm11
+%define xgft5_hi zmm10
+%define xgft6_lo zmm9
+%define xgft6_loy ymm9
+%define xgft6_hi zmm8
+
+%define x0 zmm0
+%define xtmpa zmm1
+%define xp1 zmm2
+%define xp2 zmm3
+%define xp3 zmm4
+%define xp4 zmm5
+%define xp5 zmm6
+%define xp6 zmm7
+
+default rel
+[bits 64]
+
+section .text
+
+align 16
+global gf_6vect_dot_prod_avx512, function
+func(gf_6vect_dot_prod_avx512)
+ FUNC_SAVE
+ sub len, 64
+ jl .return_fail
+
+ xor pos, pos
+ mov tmp, 0x0f
+ vpbroadcastb xmask0f, tmp ;Construct mask 0x0f0f0f...
+ mov vskip1, vec
+ imul vskip1, 32
+ mov vskip3, vec
+ imul vskip3, 96
+ sal vec, LOG_PS ;vec *= PS. Make vec_i count by PS
+ mov dest2, [dest1+PS]
+ mov dest3, [dest1+2*PS]
+ mov dest4, [dest1+3*PS]
+ mov dest5, [dest1+4*PS]
+
+.loop64:
+ vpxorq xp1, xp1, xp1
+ vpxorq xp2, xp2, xp2
+ vpxorq xp3, xp3, xp3
+ vpxorq xp4, xp4, xp4
+ vpxorq xp5, xp5, xp5
+ vpxorq xp6, xp6, xp6
+ mov tmp, mul_array
+ xor vec_i, vec_i
+
+.next_vect:
+ mov ptr, [src+vec_i]
+ XLDR x0, [ptr+pos] ;Get next source vector
+ add vec_i, PS
+
+ vpandq xtmpa, x0, xmask0f ;Mask low src nibble in bits 4-0
+ vpsraw x0, x0, 4 ;Shift to put high nibble into bits 4-0
+ vpandq x0, x0, xmask0f ;Mask high src nibble in bits 4-0
+
+ vmovdqu8 xgft1_loy, [tmp] ;Load array Ax{00}..{0f}, Ax{00}..{f0}
+ vmovdqu8 xgft2_loy, [tmp+vec*(32/PS)] ;Load array Bx{00}..{0f}, Bx{00}..{f0}
+ vmovdqu8 xgft3_loy, [tmp+vec*(64/PS)] ;Load array Cx{00}..{0f}, Cx{00}..{f0}
+ vmovdqu8 xgft4_loy, [tmp+vskip3] ;Load array Dx{00}..{0f}, Dx{00}..{f0}
+ vmovdqu8 xgft5_loy, [tmp+vskip1*4] ;Load array Ex{00}..{0f}, Ex{00}..{f0}
+ lea ptr, [vskip1 + vskip1*4] ;ptr = vskip5
+ vmovdqu8 xgft6_loy, [tmp+ptr] ;Load array Fx{00}..{0f}, Fx{00}..{f0}
+ add tmp, 32
+
+ vshufi64x2 xgft1_hi, xgft1_lo, xgft1_lo, 0x55
+ vshufi64x2 xgft1_lo, xgft1_lo, xgft1_lo, 0x00
+ vshufi64x2 xgft2_hi, xgft2_lo, xgft2_lo, 0x55
+ vshufi64x2 xgft2_lo, xgft2_lo, xgft2_lo, 0x00
+
+ vpshufb xgft1_hi, xgft1_hi, x0 ;Lookup mul table of high nibble
+ vpshufb xgft1_lo, xgft1_lo, xtmpa ;Lookup mul table of low nibble
+ vpxorq xgft1_hi, xgft1_hi, xgft1_lo ;GF add high and low partials
+ vpxorq xp1, xp1, xgft1_hi ;xp1 += partial
+
+ vpshufb xgft2_hi, xgft2_hi, x0 ;Lookup mul table of high nibble
+ vpshufb xgft2_lo, xgft2_lo, xtmpa ;Lookup mul table of low nibble
+ vpxorq xgft2_hi, xgft2_hi, xgft2_lo ;GF add high and low partials
+ vpxorq xp2, xp2, xgft2_hi ;xp2 += partial
+
+ vshufi64x2 xgft3_hi, xgft3_lo, xgft3_lo, 0x55
+ vshufi64x2 xgft3_lo, xgft3_lo, xgft3_lo, 0x00
+ vshufi64x2 xgft4_hi, xgft4_lo, xgft4_lo, 0x55
+ vshufi64x2 xgft4_lo, xgft4_lo, xgft4_lo, 0x00
+
+ vpshufb xgft3_hi, xgft3_hi, x0 ;Lookup mul table of high nibble
+ vpshufb xgft3_lo, xgft3_lo, xtmpa ;Lookup mul table of low nibble
+ vpxorq xgft3_hi, xgft3_hi, xgft3_lo ;GF add high and low partials
+ vpxorq xp3, xp3, xgft3_hi ;xp3 += partial
+
+ vpshufb xgft4_hi, xgft4_hi, x0 ;Lookup mul table of high nibble
+ vpshufb xgft4_lo, xgft4_lo, xtmpa ;Lookup mul table of low nibble
+ vpxorq xgft4_hi, xgft4_hi, xgft4_lo ;GF add high and low partials
+ vpxorq xp4, xp4, xgft4_hi ;xp4 += partial
+
+ vshufi64x2 xgft5_hi, xgft5_lo, xgft5_lo, 0x55
+ vshufi64x2 xgft5_lo, xgft5_lo, xgft5_lo, 0x00
+
+ vpshufb xgft5_hi, xgft5_hi, x0 ;Lookup mul table of high nibble
+ vpshufb xgft5_lo, xgft5_lo, xtmpa ;Lookup mul table of low nibble
+ vpxorq xgft5_hi, xgft5_hi, xgft5_lo ;GF add high and low partials
+ vpxorq xp5, xp5, xgft5_hi ;xp5 += partial
+
+ vshufi64x2 xgft6_hi, xgft6_lo, xgft6_lo, 0x55
+ vshufi64x2 xgft6_lo, xgft6_lo, xgft6_lo, 0x00
+
+ vpshufb xgft6_hi, xgft6_hi, x0 ;Lookup mul table of high nibble
+ vpshufb xgft6_lo, xgft6_lo, xtmpa ;Lookup mul table of low nibble
+ vpxorq xgft6_hi, xgft6_hi, xgft6_lo ;GF add high and low partials
+ vpxorq xp6, xp6, xgft6_hi ;x6 += partial
+
+ cmp vec_i, vec
+ jl .next_vect
+
+ mov ptr, [dest1] ;reuse ptr
+ mov tmp, [dest1+5*PS] ;reuse tmp
+
+ XSTR [dest2+pos], xp2
+ XSTR [dest3+pos], xp3
+ XSTR [dest4+pos], xp4
+ XSTR [dest5+pos], xp5
+
+ XSTR [ptr+pos], xp1
+ XSTR [tmp+pos], xp6
+
+ add pos, 64 ;Loop on 64 bytes at a time
+ cmp pos, len
+ jle .loop64
+
+ lea tmp, [len + 64]
+ cmp pos, tmp
+ je .return_pass
+
+ ;; Tail len
+ mov pos, len ;Overlapped offset length-64
+ jmp .loop64 ;Do one more overlap pass
+
+.return_pass:
+ mov return, 0
+ FUNC_RESTORE
+ ret
+
+.return_fail:
+ mov return, 1
+ FUNC_RESTORE
+ ret
+
+endproc_frame
+
+%else
+%ifidn __OUTPUT_FORMAT__, win64
+global no_gf_6vect_dot_prod_avx512
+no_gf_6vect_dot_prod_avx512:
+%endif
+%endif ; ifdef HAVE_AS_KNOWS_AVX512
diff --git a/contrib/libs/isa-l/erasure_code/gf_6vect_dot_prod_avx512_gfni.asm b/contrib/libs/isa-l/erasure_code/gf_6vect_dot_prod_avx512_gfni.asm
new file mode 100644
index 0000000000..b4b8c654bb
--- /dev/null
+++ b/contrib/libs/isa-l/erasure_code/gf_6vect_dot_prod_avx512_gfni.asm
@@ -0,0 +1,292 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; Copyright(c) 2023 Intel Corporation All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions
+; are met:
+; * Redistributions of source code must retain the above copyright
+; notice, this list of conditions and the following disclaimer.
+; * Redistributions in binary form must reproduce the above copyright
+; notice, this list of conditions and the following disclaimer in
+; the documentation and/or other materials provided with the
+; distribution.
+; * Neither the name of Intel Corporation nor the names of its
+; contributors may be used to endorse or promote products derived
+; from this software without specific prior written permission.
+;
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+; "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+; A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+; OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+; SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+; LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+; OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;;;
+;;; gf_6vect_dot_prod_avx512_gfni(len, vec, *g_tbls, **buffs, **dests);
+;;;
+
+%include "reg_sizes.asm"
+%include "gf_vect_gfni.inc"
+
+%if AS_FEATURE_LEVEL >= 10
+
+%ifidn __OUTPUT_FORMAT__, elf64
+ %define arg0 rdi
+ %define arg1 rsi
+ %define arg2 rdx
+ %define arg3 rcx
+ %define arg4 r8
+ %define arg5 r9
+
+ %define tmp r11
+ %define tmp2 r10
+ %define tmp3 r13 ; must be saved and restored
+ %define tmp4 r12 ; must be saved and restored
+ %define tmp5 r14 ; must be saved and restored
+ %define tmp6 r15 ; must be saved and restored
+ %define tmp7 rbp ; must be saved and restored
+ %define tmp8 rbx ; must be saved and restored
+
+ %define func(x) x: endbranch
+ %macro FUNC_SAVE 0
+ push r12
+ push r13
+ push r14
+ push r15
+ push rbp
+ push rbx
+ %endmacro
+ %macro FUNC_RESTORE 0
+ pop rbx
+ pop rbp
+ pop r15
+ pop r14
+ pop r13
+ pop r12
+ %endmacro
+%endif
+
+%ifidn __OUTPUT_FORMAT__, win64
+ %define arg0 rcx
+ %define arg1 rdx
+ %define arg2 r8
+ %define arg3 r9
+
+ %define arg4 r12 ; must be saved, loaded and restored
+ %define arg5 r15 ; must be saved and restored
+ %define tmp r11
+ %define tmp2 r10
+ %define tmp3 r13 ; must be saved and restored
+ %define tmp4 r14 ; must be saved and restored
+ %define tmp5 rdi ; must be saved and restored
+ %define tmp6 rsi ; must be saved and restored
+ %define tmp7 rbp ; must be saved and restored
+ %define tmp8 rbx ; must be saved and restored
+ %define stack_size 7*16 + 9*8 ; must be an odd multiple of 8
+ %define arg(x) [rsp + stack_size + 8 + 8*x]
+
+ %define func(x) proc_frame x
+ %macro FUNC_SAVE 0
+ alloc_stack stack_size
+ vmovdqa [rsp + 0*16], xmm6
+ vmovdqa [rsp + 1*16], xmm7
+ vmovdqa [rsp + 2*16], xmm8
+ vmovdqa [rsp + 3*16], xmm9
+ vmovdqa [rsp + 4*16], xmm10
+ vmovdqa [rsp + 5*16], xmm11
+ vmovdqa [rsp + 6*16], xmm12
+ mov [rsp + 7*16 + 0*8], r12
+ mov [rsp + 7*16 + 1*8], r13
+ mov [rsp + 7*16 + 2*8], r14
+ mov [rsp + 7*16 + 3*8], r15
+ mov [rsp + 7*16 + 4*8], rdi
+ mov [rsp + 7*16 + 5*8], rsi
+ mov [rsp + 7*16 + 6*8], rbp
+ mov [rsp + 7*16 + 7*8], rbx
+ end_prolog
+ mov arg4, arg(4)
+ %endmacro
+
+ %macro FUNC_RESTORE 0
+ vmovdqa xmm6, [rsp + 0*16]
+ vmovdqa xmm7, [rsp + 1*16]
+ vmovdqa xmm8, [rsp + 2*16]
+ vmovdqa xmm9, [rsp + 3*16]
+ vmovdqa xmm10, [rsp + 4*16]
+ vmovdqa xmm11, [rsp + 5*16]
+ vmovdqa xmm12, [rsp + 6*16]
+ mov r12, [rsp + 7*16 + 0*8]
+ mov r13, [rsp + 7*16 + 1*8]
+ mov r14, [rsp + 7*16 + 2*8]
+ mov r15, [rsp + 7*16 + 3*8]
+ mov rdi, [rsp + 7*16 + 4*8]
+ mov rsi, [rsp + 7*16 + 5*8]
+ mov rbp, [rsp + 7*16 + 6*8]
+ mov rbx, [rsp + 7*16 + 7*8]
+ add rsp, stack_size
+ %endmacro
+%endif
+
+
+%define len arg0
+%define vec arg1
+%define mul_array arg2
+%define src arg3
+%define dest1 arg4
+%define ptr arg5
+%define vec_i tmp2
+%define dest2 tmp3
+%define dest3 tmp4
+%define dest4 tmp5
+%define vskip3 tmp6
+%define dest5 tmp7
+%define vskip5 tmp8
+%define pos rax
+
+
+%ifndef EC_ALIGNED_ADDR
+;;; Use Un-aligned load/store
+ %define XLDR vmovdqu8
+ %define XSTR vmovdqu8
+%else
+;;; Use Non-temporal load/stor
+ %ifdef NO_NT_LDST
+ %define XLDR vmovdqa64
+ %define XSTR vmovdqa64
+ %else
+ %define XLDR vmovntdqa
+ %define XSTR vmovntdq
+ %endif
+%endif
+
+%define xgft1 zmm7
+%define xgft2 zmm8
+%define xgft3 zmm9
+%define xgft4 zmm10
+%define xgft5 zmm11
+%define xgft6 zmm12
+
+%define x0 zmm0
+%define xp1 zmm1
+%define xp2 zmm2
+%define xp3 zmm3
+%define xp4 zmm4
+%define xp5 zmm5
+%define xp6 zmm6
+
+default rel
+[bits 64]
+
+section .text
+
+;;
+;; Encodes 64 bytes of all "k" sources into 6x 64 bytes (parity disks)
+;;
+%macro ENCODE_64B_6 0-1
+%define %%KMASK %1
+
+ vpxorq xp1, xp1, xp1
+ vpxorq xp2, xp2, xp2
+ vpxorq xp3, xp3, xp3
+ vpxorq xp4, xp4, xp4
+ vpxorq xp5, xp5, xp5
+ vpxorq xp6, xp6, xp6
+ mov tmp, mul_array
+ xor vec_i, vec_i
+
+%%next_vect:
+ mov ptr, [src + vec_i]
+%if %0 == 1
+ vmovdqu8 x0{%%KMASK}, [ptr + pos] ;Get next source vector (less than 64 bytes)
+%else
+ XLDR x0, [ptr + pos] ;Get next source vector (64 bytes)
+%endif
+ add vec_i, 8
+
+ vbroadcastf32x2 xgft1, [tmp]
+ vbroadcastf32x2 xgft2, [tmp + vec]
+ vbroadcastf32x2 xgft3, [tmp + vec*2]
+ vbroadcastf32x2 xgft4, [tmp + vskip3]
+ vbroadcastf32x2 xgft5, [tmp + vec*4]
+ vbroadcastf32x2 xgft6, [tmp + vskip5]
+ add tmp, 8
+
+ GF_MUL_XOR EVEX, x0, xgft1, xgft1, xp1, xgft2, xgft2, xp2, xgft3, xgft3, xp3, \
+ xgft4, xgft4, xp4, xgft5, xgft5, xp5, xgft6, xgft6, xp6
+
+ cmp vec_i, vec
+ jl %%next_vect
+
+ mov ptr, [dest1] ;reuse ptr
+ mov tmp, [dest1 + 5*8] ;reuse tmp
+
+%if %0 == 1
+ vmovdqu8 [dest2 + pos]{%%KMASK}, xp2
+ vmovdqu8 [dest3 + pos]{%%KMASK}, xp3
+ vmovdqu8 [dest4 + pos]{%%KMASK}, xp4
+ vmovdqu8 [dest5 + pos]{%%KMASK}, xp5
+ vmovdqu8 [ptr + pos]{%%KMASK}, xp1 ; dest 1
+ vmovdqu8 [tmp + pos]{%%KMASK}, xp6 ; dest 6
+%else
+ XSTR [dest2 + pos], xp2
+ XSTR [dest3 + pos], xp3
+ XSTR [dest4 + pos], xp4
+ XSTR [dest5 + pos], xp5
+ XSTR [ptr + pos], xp1 ; dest 1
+ XSTR [tmp + pos], xp6 ; dest 6
+%endif
+%endmacro
+
+align 16
+global gf_6vect_dot_prod_avx512_gfni, function
+func(gf_6vect_dot_prod_avx512_gfni)
+ FUNC_SAVE
+
+ xor pos, pos
+ mov vskip3, vec
+ imul vskip3, 3*8
+ mov vskip5, vec
+ imul vskip5, 5*8
+ shl vec, 3 ;vec *= 8. Make vec_i count by 8
+ mov dest2, [dest1 + 8]
+ mov dest3, [dest1 + 2*8]
+ mov dest4, [dest1 + 3*8]
+ mov dest5, [dest1 + 4*8] ;dest1 and dest6 are calculated later
+
+ cmp len, 64
+ jl .len_lt_64
+
+.loop64:
+
+ ENCODE_64B_6
+
+ add pos, 64 ;Loop on 64 bytes at a time
+ sub len, 64
+ cmp len, 64
+ jge .loop64
+
+.len_lt_64:
+ cmp len, 0
+ jle .exit
+
+ xor tmp, tmp
+ bts tmp, len
+ dec tmp
+ kmovq k1, tmp
+
+ ENCODE_64B_6 k1
+
+.exit:
+ vzeroupper
+
+ FUNC_RESTORE
+ ret
+
+endproc_frame
+%endif ; if AS_FEATURE_LEVEL >= 10
diff --git a/contrib/libs/isa-l/erasure_code/gf_6vect_dot_prod_sse.asm b/contrib/libs/isa-l/erasure_code/gf_6vect_dot_prod_sse.asm
index 5dea0be18e..b877411da8 100644
--- a/contrib/libs/isa-l/erasure_code/gf_6vect_dot_prod_sse.asm
+++ b/contrib/libs/isa-l/erasure_code/gf_6vect_dot_prod_sse.asm
@@ -51,7 +51,7 @@
%define PS 8
%define LOG_PS 3
- %define func(x) x:
+ %define func(x) x: endbranch
%macro FUNC_SAVE 0
push r12
push r13
@@ -182,13 +182,8 @@ section .text
%define xp6 xmm13
align 16
-global gf_6vect_dot_prod_sse:ISAL_SYM_TYPE_FUNCTION
+global gf_6vect_dot_prod_sse, function
func(gf_6vect_dot_prod_sse)
-%ifidn __OUTPUT_FORMAT__, macho64
-global _gf_6vect_dot_prod_sse:ISAL_SYM_TYPE_FUNCTION
-func(_gf_6vect_dot_prod_sse)
-%endif
-
FUNC_SAVE
sub len, 16
jl .return_fail
@@ -315,6 +310,3 @@ section .data
align 16
mask0f: dq 0x0f0f0f0f0f0f0f0f, 0x0f0f0f0f0f0f0f0f
-
-;;; func core, ver, snum
-slversion gf_6vect_dot_prod_sse, 00, 05, 0066
diff --git a/contrib/libs/isa-l/erasure_code/gf_6vect_dot_prod_sse.patch b/contrib/libs/isa-l/erasure_code/gf_6vect_dot_prod_sse.patch
deleted file mode 100644
index 1255245edf..0000000000
--- a/contrib/libs/isa-l/erasure_code/gf_6vect_dot_prod_sse.patch
+++ /dev/null
@@ -1,6 +0,0 @@
-187,191d186
-< %ifidn __OUTPUT_FORMAT__, macho64
-< global _gf_6vect_dot_prod_sse:ISAL_SYM_TYPE_FUNCTION
-< func(_gf_6vect_dot_prod_sse)
-< %endif
-<
diff --git a/contrib/libs/isa-l/erasure_code/gf_6vect_dot_prod_sse_test.c b/contrib/libs/isa-l/erasure_code/gf_6vect_dot_prod_sse_test.c
deleted file mode 100644
index f0075a00e8..0000000000
--- a/contrib/libs/isa-l/erasure_code/gf_6vect_dot_prod_sse_test.c
+++ /dev/null
@@ -1,911 +0,0 @@
-/**********************************************************************
- Copyright(c) 2011-2015 Intel Corporation All rights reserved.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions
- are met:
- * Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in
- the documentation and/or other materials provided with the
- distribution.
- * Neither the name of Intel Corporation nor the names of its
- contributors may be used to endorse or promote products derived
- from this software without specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-**********************************************************************/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h> // for memset, memcmp
-#include "erasure_code.h"
-// #include "types.h"
-
-#ifndef FUNCTION_UNDER_TEST
-# define FUNCTION_UNDER_TEST gf_6vect_dot_prod_sse
-#endif
-#ifndef TEST_MIN_SIZE
-# define TEST_MIN_SIZE 16
-#endif
-
-#define str(s) #s
-#define xstr(s) str(s)
-
-#define TEST_LEN 2048
-#define TEST_SIZE (TEST_LEN/2)
-#define TEST_MEM TEST_SIZE
-#define TEST_LOOPS 1000
-#define TEST_TYPE_STR ""
-
-#ifndef TEST_SOURCES
-# define TEST_SOURCES 16
-#endif
-#ifndef RANDOMS
-# define RANDOMS 20
-#endif
-
-#ifdef EC_ALIGNED_ADDR
-// Define power of 2 range to check ptr, len alignment
-# define PTR_ALIGN_CHK_B 0
-# define LEN_ALIGN_CHK_B 0 // 0 for aligned only
-#else
-// Define power of 2 range to check ptr, len alignment
-# define PTR_ALIGN_CHK_B 32
-# define LEN_ALIGN_CHK_B 32 // 0 for aligned only
-#endif
-
-typedef unsigned char u8;
-
-void dump(unsigned char *buf, int len)
-{
- int i;
- for (i = 0; i < len;) {
- printf(" %2x", 0xff & buf[i++]);
- if (i % 32 == 0)
- printf("\n");
- }
- printf("\n");
-}
-
-void dump_matrix(unsigned char **s, int k, int m)
-{
- int i, j;
- for (i = 0; i < k; i++) {
- for (j = 0; j < m; j++) {
- printf(" %2x", s[i][j]);
- }
- printf("\n");
- }
- printf("\n");
-}
-
-void dump_u8xu8(unsigned char *s, int k, int m)
-{
- int i, j;
- for (i = 0; i < k; i++) {
- for (j = 0; j < m; j++) {
- printf(" %2x", 0xff & s[j + (i * m)]);
- }
- printf("\n");
- }
- printf("\n");
-}
-
-int main(int argc, char *argv[])
-{
- int i, j, rtest, srcs;
- void *buf;
- u8 g1[TEST_SOURCES], g2[TEST_SOURCES], g3[TEST_SOURCES];
- u8 g4[TEST_SOURCES], g5[TEST_SOURCES], g6[TEST_SOURCES], *g_tbls;
- u8 *dest1, *dest2, *dest3, *dest4, *dest5, *dest6, *dest_ref1;
- u8 *dest_ref2, *dest_ref3, *dest_ref4, *dest_ref5, *dest_ref6;
- u8 *dest_ptrs[6], *buffs[TEST_SOURCES];
-
- int align, size;
- unsigned char *efence_buffs[TEST_SOURCES];
- unsigned int offset;
- u8 *ubuffs[TEST_SOURCES];
- u8 *udest_ptrs[6];
- printf(xstr(FUNCTION_UNDER_TEST) ": %dx%d ", TEST_SOURCES, TEST_LEN);
-
- // Allocate the arrays
- for (i = 0; i < TEST_SOURCES; i++) {
- if (posix_memalign(&buf, 64, TEST_LEN)) {
- printf("alloc error: Fail");
- return -1;
- }
- buffs[i] = buf;
- }
-
- if (posix_memalign(&buf, 16, 2 * (6 * TEST_SOURCES * 32))) {
- printf("alloc error: Fail");
- return -1;
- }
- g_tbls = buf;
-
- if (posix_memalign(&buf, 64, TEST_LEN)) {
- printf("alloc error: Fail");
- return -1;
- }
- dest1 = buf;
-
- if (posix_memalign(&buf, 64, TEST_LEN)) {
- printf("alloc error: Fail");
- return -1;
- }
- dest2 = buf;
-
- if (posix_memalign(&buf, 64, TEST_LEN)) {
- printf("alloc error: Fail");
- return -1;
- }
- dest3 = buf;
-
- if (posix_memalign(&buf, 64, TEST_LEN)) {
- printf("alloc error: Fail");
- return -1;
- }
- dest4 = buf;
-
- if (posix_memalign(&buf, 64, TEST_LEN)) {
- printf("alloc error: Fail");
- return -1;
- }
- dest5 = buf;
-
- if (posix_memalign(&buf, 64, TEST_LEN)) {
- printf("alloc error: Fail");
- return -1;
- }
- dest6 = buf;
-
- if (posix_memalign(&buf, 64, TEST_LEN)) {
- printf("alloc error: Fail");
- return -1;
- }
- dest_ref1 = buf;
-
- if (posix_memalign(&buf, 64, TEST_LEN)) {
- printf("alloc error: Fail");
- return -1;
- }
- dest_ref2 = buf;
-
- if (posix_memalign(&buf, 64, TEST_LEN)) {
- printf("alloc error: Fail");
- return -1;
- }
- dest_ref3 = buf;
-
- if (posix_memalign(&buf, 64, TEST_LEN)) {
- printf("alloc error: Fail");
- return -1;
- }
- dest_ref4 = buf;
-
- if (posix_memalign(&buf, 64, TEST_LEN)) {
- printf("alloc error: Fail");
- return -1;
- }
- dest_ref5 = buf;
-
- if (posix_memalign(&buf, 64, TEST_LEN)) {
- printf("alloc error: Fail");
- return -1;
- }
- dest_ref6 = buf;
-
- dest_ptrs[0] = dest1;
- dest_ptrs[1] = dest2;
- dest_ptrs[2] = dest3;
- dest_ptrs[3] = dest4;
- dest_ptrs[4] = dest5;
- dest_ptrs[5] = dest6;
-
- // Test of all zeros
- for (i = 0; i < TEST_SOURCES; i++)
- memset(buffs[i], 0, TEST_LEN);
-
- memset(dest1, 0, TEST_LEN);
- memset(dest2, 0, TEST_LEN);
- memset(dest3, 0, TEST_LEN);
- memset(dest4, 0, TEST_LEN);
- memset(dest5, 0, TEST_LEN);
- memset(dest6, 0, TEST_LEN);
- memset(dest_ref1, 0, TEST_LEN);
- memset(dest_ref2, 0, TEST_LEN);
- memset(dest_ref3, 0, TEST_LEN);
- memset(dest_ref4, 0, TEST_LEN);
- memset(dest_ref5, 0, TEST_LEN);
- memset(dest_ref6, 0, TEST_LEN);
- memset(g1, 2, TEST_SOURCES);
- memset(g2, 1, TEST_SOURCES);
- memset(g3, 7, TEST_SOURCES);
- memset(g4, 9, TEST_SOURCES);
- memset(g5, 4, TEST_SOURCES);
- memset(g6, 0xe6, TEST_SOURCES);
-
- for (i = 0; i < TEST_SOURCES; i++) {
- gf_vect_mul_init(g1[i], &g_tbls[i * 32]);
- gf_vect_mul_init(g2[i], &g_tbls[32 * TEST_SOURCES + i * 32]);
- gf_vect_mul_init(g3[i], &g_tbls[64 * TEST_SOURCES + i * 32]);
- gf_vect_mul_init(g4[i], &g_tbls[96 * TEST_SOURCES + i * 32]);
- gf_vect_mul_init(g5[i], &g_tbls[128 * TEST_SOURCES + i * 32]);
- gf_vect_mul_init(g6[i], &g_tbls[160 * TEST_SOURCES + i * 32]);
- }
-
- gf_vect_dot_prod_base(TEST_LEN, TEST_SOURCES, &g_tbls[0], buffs, dest_ref1);
- gf_vect_dot_prod_base(TEST_LEN, TEST_SOURCES, &g_tbls[32 * TEST_SOURCES], buffs,
- dest_ref2);
- gf_vect_dot_prod_base(TEST_LEN, TEST_SOURCES, &g_tbls[64 * TEST_SOURCES], buffs,
- dest_ref3);
- gf_vect_dot_prod_base(TEST_LEN, TEST_SOURCES, &g_tbls[96 * TEST_SOURCES], buffs,
- dest_ref4);
- gf_vect_dot_prod_base(TEST_LEN, TEST_SOURCES, &g_tbls[128 * TEST_SOURCES], buffs,
- dest_ref5);
- gf_vect_dot_prod_base(TEST_LEN, TEST_SOURCES, &g_tbls[160 * TEST_SOURCES], buffs,
- dest_ref6);
-
- FUNCTION_UNDER_TEST(TEST_LEN, TEST_SOURCES, g_tbls, buffs, dest_ptrs);
-
- if (0 != memcmp(dest_ref1, dest1, TEST_LEN)) {
- printf("Fail zero " xstr(FUNCTION_UNDER_TEST) " test1\n");
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref1, 25);
- printf("dprod_dut:");
- dump(dest1, 25);
- return -1;
- }
- if (0 != memcmp(dest_ref2, dest2, TEST_LEN)) {
- printf("Fail zero " xstr(FUNCTION_UNDER_TEST) " test2\n");
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref2, 25);
- printf("dprod_dut:");
- dump(dest2, 25);
- return -1;
- }
- if (0 != memcmp(dest_ref3, dest3, TEST_LEN)) {
- printf("Fail zero " xstr(FUNCTION_UNDER_TEST) " test3\n");
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref3, 25);
- printf("dprod_dut:");
- dump(dest3, 25);
- return -1;
- }
- if (0 != memcmp(dest_ref4, dest4, TEST_LEN)) {
- printf("Fail zero " xstr(FUNCTION_UNDER_TEST) " test4\n");
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref4, 25);
- printf("dprod_dut:");
- dump(dest4, 25);
- return -1;
- }
- if (0 != memcmp(dest_ref5, dest5, TEST_LEN)) {
- printf("Fail zero " xstr(FUNCTION_UNDER_TEST) " test5\n");
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref5, 25);
- printf("dprod_dut:");
- dump(dest5, 25);
- return -1;
- }
- if (0 != memcmp(dest_ref6, dest6, TEST_LEN)) {
- printf("Fail zero " xstr(FUNCTION_UNDER_TEST) " test6\n");
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref6, 25);
- printf("dprod_dut:");
- dump(dest6, 25);
- return -1;
- }
- putchar('.');
-
- // Rand data test
-
- for (rtest = 0; rtest < RANDOMS; rtest++) {
- for (i = 0; i < TEST_SOURCES; i++)
- for (j = 0; j < TEST_LEN; j++)
- buffs[i][j] = rand();
-
- for (i = 0; i < TEST_SOURCES; i++) {
- g1[i] = rand();
- g2[i] = rand();
- g3[i] = rand();
- g4[i] = rand();
- g5[i] = rand();
- g6[i] = rand();
- }
-
- for (i = 0; i < TEST_SOURCES; i++) {
- gf_vect_mul_init(g1[i], &g_tbls[i * 32]);
- gf_vect_mul_init(g2[i], &g_tbls[(32 * TEST_SOURCES) + (i * 32)]);
- gf_vect_mul_init(g3[i], &g_tbls[(64 * TEST_SOURCES) + (i * 32)]);
- gf_vect_mul_init(g4[i], &g_tbls[(96 * TEST_SOURCES) + (i * 32)]);
- gf_vect_mul_init(g5[i], &g_tbls[(128 * TEST_SOURCES) + (i * 32)]);
- gf_vect_mul_init(g6[i], &g_tbls[(160 * TEST_SOURCES) + (i * 32)]);
- }
-
- gf_vect_dot_prod_base(TEST_LEN, TEST_SOURCES, &g_tbls[0], buffs, dest_ref1);
- gf_vect_dot_prod_base(TEST_LEN, TEST_SOURCES, &g_tbls[32 * TEST_SOURCES],
- buffs, dest_ref2);
- gf_vect_dot_prod_base(TEST_LEN, TEST_SOURCES, &g_tbls[64 * TEST_SOURCES],
- buffs, dest_ref3);
- gf_vect_dot_prod_base(TEST_LEN, TEST_SOURCES, &g_tbls[96 * TEST_SOURCES],
- buffs, dest_ref4);
- gf_vect_dot_prod_base(TEST_LEN, TEST_SOURCES, &g_tbls[128 * TEST_SOURCES],
- buffs, dest_ref5);
- gf_vect_dot_prod_base(TEST_LEN, TEST_SOURCES, &g_tbls[160 * TEST_SOURCES],
- buffs, dest_ref6);
-
- FUNCTION_UNDER_TEST(TEST_LEN, TEST_SOURCES, g_tbls, buffs, dest_ptrs);
-
- if (0 != memcmp(dest_ref1, dest1, TEST_LEN)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test1 %d\n", rtest);
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref1, 25);
- printf("dprod_dut:");
- dump(dest1, 25);
- return -1;
- }
- if (0 != memcmp(dest_ref2, dest2, TEST_LEN)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test2 %d\n", rtest);
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref2, 25);
- printf("dprod_dut:");
- dump(dest2, 25);
- return -1;
- }
- if (0 != memcmp(dest_ref3, dest3, TEST_LEN)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test3 %d\n", rtest);
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref3, 25);
- printf("dprod_dut:");
- dump(dest3, 25);
- return -1;
- }
- if (0 != memcmp(dest_ref4, dest4, TEST_LEN)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test4 %d\n", rtest);
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref4, 25);
- printf("dprod_dut:");
- dump(dest4, 25);
- return -1;
- }
- if (0 != memcmp(dest_ref5, dest5, TEST_LEN)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test5 %d\n", rtest);
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref5, 25);
- printf("dprod_dut:");
- dump(dest5, 25);
- return -1;
- }
- if (0 != memcmp(dest_ref6, dest6, TEST_LEN)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test6 %d\n", rtest);
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref6, 25);
- printf("dprod_dut:");
- dump(dest6, 25);
- return -1;
- }
-
- putchar('.');
- }
-
- // Rand data test with varied parameters
- for (rtest = 0; rtest < RANDOMS; rtest++) {
- for (srcs = TEST_SOURCES; srcs > 0; srcs--) {
- for (i = 0; i < srcs; i++)
- for (j = 0; j < TEST_LEN; j++)
- buffs[i][j] = rand();
-
- for (i = 0; i < srcs; i++) {
- g1[i] = rand();
- g2[i] = rand();
- g3[i] = rand();
- g4[i] = rand();
- g5[i] = rand();
- g6[i] = rand();
- }
-
- for (i = 0; i < srcs; i++) {
- gf_vect_mul_init(g1[i], &g_tbls[i * 32]);
- gf_vect_mul_init(g2[i], &g_tbls[(32 * srcs) + (i * 32)]);
- gf_vect_mul_init(g3[i], &g_tbls[(64 * srcs) + (i * 32)]);
- gf_vect_mul_init(g4[i], &g_tbls[(96 * srcs) + (i * 32)]);
- gf_vect_mul_init(g5[i], &g_tbls[(128 * srcs) + (i * 32)]);
- gf_vect_mul_init(g6[i], &g_tbls[(160 * srcs) + (i * 32)]);
- }
-
- gf_vect_dot_prod_base(TEST_LEN, srcs, &g_tbls[0], buffs, dest_ref1);
- gf_vect_dot_prod_base(TEST_LEN, srcs, &g_tbls[32 * srcs], buffs,
- dest_ref2);
- gf_vect_dot_prod_base(TEST_LEN, srcs, &g_tbls[64 * srcs], buffs,
- dest_ref3);
- gf_vect_dot_prod_base(TEST_LEN, srcs, &g_tbls[96 * srcs], buffs,
- dest_ref4);
- gf_vect_dot_prod_base(TEST_LEN, srcs, &g_tbls[128 * srcs], buffs,
- dest_ref5);
- gf_vect_dot_prod_base(TEST_LEN, srcs, &g_tbls[160 * srcs], buffs,
- dest_ref6);
-
- FUNCTION_UNDER_TEST(TEST_LEN, srcs, g_tbls, buffs, dest_ptrs);
-
- if (0 != memcmp(dest_ref1, dest1, TEST_LEN)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST)
- " test1 srcs=%d\n", srcs);
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref1, 25);
- printf("dprod_dut:");
- dump(dest1, 25);
- return -1;
- }
- if (0 != memcmp(dest_ref2, dest2, TEST_LEN)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST)
- " test2 srcs=%d\n", srcs);
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref2, 25);
- printf("dprod_dut:");
- dump(dest2, 25);
- return -1;
- }
- if (0 != memcmp(dest_ref3, dest3, TEST_LEN)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST)
- " test3 srcs=%d\n", srcs);
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref3, 25);
- printf("dprod_dut:");
- dump(dest3, 25);
- return -1;
- }
- if (0 != memcmp(dest_ref4, dest4, TEST_LEN)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST)
- " test4 srcs=%d\n", srcs);
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref4, 25);
- printf("dprod_dut:");
- dump(dest4, 25);
- return -1;
- }
- if (0 != memcmp(dest_ref5, dest5, TEST_LEN)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST)
- " test5 srcs=%d\n", srcs);
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref5, 25);
- printf("dprod_dut:");
- dump(dest5, 25);
- return -1;
- }
- if (0 != memcmp(dest_ref6, dest6, TEST_LEN)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST)
- " test6 srcs=%d\n", srcs);
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref6, 25);
- printf("dprod_dut:");
- dump(dest6, 25);
- return -1;
- }
-
- putchar('.');
- }
- }
-
- // Run tests at end of buffer for Electric Fence
- align = (LEN_ALIGN_CHK_B != 0) ? 1 : 16;
- for (size = TEST_MIN_SIZE; size <= TEST_SIZE; size += align) {
- for (i = 0; i < TEST_SOURCES; i++)
- for (j = 0; j < TEST_LEN; j++)
- buffs[i][j] = rand();
-
- for (i = 0; i < TEST_SOURCES; i++) // Line up TEST_SIZE from end
- efence_buffs[i] = buffs[i] + TEST_LEN - size;
-
- for (i = 0; i < TEST_SOURCES; i++) {
- g1[i] = rand();
- g2[i] = rand();
- g3[i] = rand();
- g4[i] = rand();
- g5[i] = rand();
- g6[i] = rand();
- }
-
- for (i = 0; i < TEST_SOURCES; i++) {
- gf_vect_mul_init(g1[i], &g_tbls[i * 32]);
- gf_vect_mul_init(g2[i], &g_tbls[(32 * TEST_SOURCES) + (i * 32)]);
- gf_vect_mul_init(g3[i], &g_tbls[(64 * TEST_SOURCES) + (i * 32)]);
- gf_vect_mul_init(g4[i], &g_tbls[(96 * TEST_SOURCES) + (i * 32)]);
- gf_vect_mul_init(g5[i], &g_tbls[(128 * TEST_SOURCES) + (i * 32)]);
- gf_vect_mul_init(g6[i], &g_tbls[(160 * TEST_SOURCES) + (i * 32)]);
- }
-
- gf_vect_dot_prod_base(size, TEST_SOURCES, &g_tbls[0], efence_buffs, dest_ref1);
- gf_vect_dot_prod_base(size, TEST_SOURCES, &g_tbls[32 * TEST_SOURCES],
- efence_buffs, dest_ref2);
- gf_vect_dot_prod_base(size, TEST_SOURCES, &g_tbls[64 * TEST_SOURCES],
- efence_buffs, dest_ref3);
- gf_vect_dot_prod_base(size, TEST_SOURCES, &g_tbls[96 * TEST_SOURCES],
- efence_buffs, dest_ref4);
- gf_vect_dot_prod_base(size, TEST_SOURCES, &g_tbls[128 * TEST_SOURCES],
- efence_buffs, dest_ref5);
- gf_vect_dot_prod_base(size, TEST_SOURCES, &g_tbls[160 * TEST_SOURCES],
- efence_buffs, dest_ref6);
-
- FUNCTION_UNDER_TEST(size, TEST_SOURCES, g_tbls, efence_buffs, dest_ptrs);
-
- if (0 != memcmp(dest_ref1, dest1, size)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test1 %d\n", rtest);
- dump_matrix(efence_buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref1, align);
- printf("dprod_dut:");
- dump(dest1, align);
- return -1;
- }
-
- if (0 != memcmp(dest_ref2, dest2, size)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test2 %d\n", rtest);
- dump_matrix(efence_buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref2, align);
- printf("dprod_dut:");
- dump(dest2, align);
- return -1;
- }
-
- if (0 != memcmp(dest_ref3, dest3, size)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test3 %d\n", rtest);
- dump_matrix(efence_buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref3, align);
- printf("dprod_dut:");
- dump(dest3, align);
- return -1;
- }
-
- if (0 != memcmp(dest_ref4, dest4, size)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test4 %d\n", rtest);
- dump_matrix(efence_buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref4, align);
- printf("dprod_dut:");
- dump(dest4, align);
- return -1;
- }
-
- if (0 != memcmp(dest_ref5, dest5, size)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test5 %d\n", rtest);
- dump_matrix(efence_buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref5, align);
- printf("dprod_dut:");
- dump(dest5, align);
- return -1;
- }
-
- if (0 != memcmp(dest_ref6, dest6, size)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test6 %d\n", rtest);
- dump_matrix(efence_buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref6, align);
- printf("dprod_dut:");
- dump(dest6, align);
- return -1;
- }
-
- putchar('.');
- }
-
- // Test rand ptr alignment if available
-
- for (rtest = 0; rtest < RANDOMS; rtest++) {
- size = (TEST_LEN - PTR_ALIGN_CHK_B) & ~(TEST_MIN_SIZE - 1);
- srcs = rand() % TEST_SOURCES;
- if (srcs == 0)
- continue;
-
- offset = (PTR_ALIGN_CHK_B != 0) ? 1 : PTR_ALIGN_CHK_B;
- // Add random offsets
- for (i = 0; i < srcs; i++)
- ubuffs[i] = buffs[i] + (rand() & (PTR_ALIGN_CHK_B - offset));
-
- udest_ptrs[0] = dest1 + (rand() & (PTR_ALIGN_CHK_B - offset));
- udest_ptrs[1] = dest2 + (rand() & (PTR_ALIGN_CHK_B - offset));
- udest_ptrs[2] = dest3 + (rand() & (PTR_ALIGN_CHK_B - offset));
- udest_ptrs[3] = dest4 + (rand() & (PTR_ALIGN_CHK_B - offset));
- udest_ptrs[4] = dest5 + (rand() & (PTR_ALIGN_CHK_B - offset));
- udest_ptrs[5] = dest6 + (rand() & (PTR_ALIGN_CHK_B - offset));
-
- memset(dest1, 0, TEST_LEN); // zero pad to check write-over
- memset(dest2, 0, TEST_LEN);
- memset(dest3, 0, TEST_LEN);
- memset(dest4, 0, TEST_LEN);
- memset(dest5, 0, TEST_LEN);
- memset(dest6, 0, TEST_LEN);
-
- for (i = 0; i < srcs; i++)
- for (j = 0; j < size; j++)
- ubuffs[i][j] = rand();
-
- for (i = 0; i < srcs; i++) {
- g1[i] = rand();
- g2[i] = rand();
- g3[i] = rand();
- g4[i] = rand();
- g5[i] = rand();
- g6[i] = rand();
- }
-
- for (i = 0; i < srcs; i++) {
- gf_vect_mul_init(g1[i], &g_tbls[i * 32]);
- gf_vect_mul_init(g2[i], &g_tbls[(32 * srcs) + (i * 32)]);
- gf_vect_mul_init(g3[i], &g_tbls[(64 * srcs) + (i * 32)]);
- gf_vect_mul_init(g4[i], &g_tbls[(96 * srcs) + (i * 32)]);
- gf_vect_mul_init(g5[i], &g_tbls[(128 * srcs) + (i * 32)]);
- gf_vect_mul_init(g6[i], &g_tbls[(160 * srcs) + (i * 32)]);
- }
-
- gf_vect_dot_prod_base(size, srcs, &g_tbls[0], ubuffs, dest_ref1);
- gf_vect_dot_prod_base(size, srcs, &g_tbls[32 * srcs], ubuffs, dest_ref2);
- gf_vect_dot_prod_base(size, srcs, &g_tbls[64 * srcs], ubuffs, dest_ref3);
- gf_vect_dot_prod_base(size, srcs, &g_tbls[96 * srcs], ubuffs, dest_ref4);
- gf_vect_dot_prod_base(size, srcs, &g_tbls[128 * srcs], ubuffs, dest_ref5);
- gf_vect_dot_prod_base(size, srcs, &g_tbls[160 * srcs], ubuffs, dest_ref6);
-
- FUNCTION_UNDER_TEST(size, srcs, g_tbls, ubuffs, udest_ptrs);
-
- if (memcmp(dest_ref1, udest_ptrs[0], size)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test ualign srcs=%d\n",
- srcs);
- dump_matrix(ubuffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref1, 25);
- printf("dprod_dut:");
- dump(udest_ptrs[0], 25);
- return -1;
- }
- if (memcmp(dest_ref2, udest_ptrs[1], size)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test ualign srcs=%d\n",
- srcs);
- dump_matrix(ubuffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref2, 25);
- printf("dprod_dut:");
- dump(udest_ptrs[1], 25);
- return -1;
- }
- if (memcmp(dest_ref3, udest_ptrs[2], size)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test ualign srcs=%d\n",
- srcs);
- dump_matrix(ubuffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref3, 25);
- printf("dprod_dut:");
- dump(udest_ptrs[2], 25);
- return -1;
- }
- if (memcmp(dest_ref4, udest_ptrs[3], size)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test ualign srcs=%d\n",
- srcs);
- dump_matrix(ubuffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref4, 25);
- printf("dprod_dut:");
- dump(udest_ptrs[3], 25);
- return -1;
- }
- if (memcmp(dest_ref5, udest_ptrs[4], size)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test ualign srcs=%d\n",
- srcs);
- dump_matrix(ubuffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref5, 25);
- printf("dprod_dut:");
- dump(udest_ptrs[4], 25);
- return -1;
- }
- if (memcmp(dest_ref6, udest_ptrs[5], size)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test ualign srcs=%d\n",
- srcs);
- dump_matrix(ubuffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref6, 25);
- printf("dprod_dut:");
- dump(udest_ptrs[5], 25);
- return -1;
- }
- // Confirm that padding around dests is unchanged
- memset(dest_ref1, 0, PTR_ALIGN_CHK_B); // Make reference zero buff
- offset = udest_ptrs[0] - dest1;
-
- if (memcmp(dest1, dest_ref1, offset)) {
- printf("Fail rand ualign pad1 start\n");
- return -1;
- }
- if (memcmp(dest1 + offset + size, dest_ref1, PTR_ALIGN_CHK_B - offset)) {
- printf("Fail rand ualign pad1 end\n");
- return -1;
- }
-
- offset = udest_ptrs[1] - dest2;
- if (memcmp(dest2, dest_ref1, offset)) {
- printf("Fail rand ualign pad2 start\n");
- return -1;
- }
- if (memcmp(dest2 + offset + size, dest_ref1, PTR_ALIGN_CHK_B - offset)) {
- printf("Fail rand ualign pad2 end\n");
- return -1;
- }
-
- offset = udest_ptrs[2] - dest3;
- if (memcmp(dest3, dest_ref1, offset)) {
- printf("Fail rand ualign pad3 start\n");
- return -1;
- }
- if (memcmp(dest3 + offset + size, dest_ref1, PTR_ALIGN_CHK_B - offset)) {
- printf("Fail rand ualign pad3 end\n");
- return -1;
- }
-
- offset = udest_ptrs[3] - dest4;
- if (memcmp(dest4, dest_ref1, offset)) {
- printf("Fail rand ualign pad4 start\n");
- return -1;
- }
- if (memcmp(dest4 + offset + size, dest_ref1, PTR_ALIGN_CHK_B - offset)) {
- printf("Fail rand ualign pad4 end\n");
- return -1;
- }
-
- offset = udest_ptrs[4] - dest5;
- if (memcmp(dest5, dest_ref1, offset)) {
- printf("Fail rand ualign pad5 start\n");
- return -1;
- }
- if (memcmp(dest5 + offset + size, dest_ref1, PTR_ALIGN_CHK_B - offset)) {
- printf("Fail rand ualign pad5 end\n");
- return -1;
- }
-
- offset = udest_ptrs[5] - dest6;
- if (memcmp(dest6, dest_ref1, offset)) {
- printf("Fail rand ualign pad6 start\n");
- return -1;
- }
- if (memcmp(dest6 + offset + size, dest_ref1, PTR_ALIGN_CHK_B - offset)) {
- printf("Fail rand ualign pad6 end\n");
- return -1;
- }
-
- putchar('.');
- }
-
- // Test all size alignment
- align = (LEN_ALIGN_CHK_B != 0) ? 1 : 16;
-
- for (size = TEST_LEN; size >= TEST_MIN_SIZE; size -= align) {
- srcs = TEST_SOURCES;
-
- for (i = 0; i < srcs; i++)
- for (j = 0; j < size; j++)
- buffs[i][j] = rand();
-
- for (i = 0; i < srcs; i++) {
- g1[i] = rand();
- g2[i] = rand();
- g3[i] = rand();
- g4[i] = rand();
- g5[i] = rand();
- g6[i] = rand();
- }
-
- for (i = 0; i < srcs; i++) {
- gf_vect_mul_init(g1[i], &g_tbls[i * 32]);
- gf_vect_mul_init(g2[i], &g_tbls[(32 * srcs) + (i * 32)]);
- gf_vect_mul_init(g3[i], &g_tbls[(64 * srcs) + (i * 32)]);
- gf_vect_mul_init(g4[i], &g_tbls[(96 * srcs) + (i * 32)]);
- gf_vect_mul_init(g5[i], &g_tbls[(128 * srcs) + (i * 32)]);
- gf_vect_mul_init(g6[i], &g_tbls[(160 * srcs) + (i * 32)]);
- }
-
- gf_vect_dot_prod_base(size, srcs, &g_tbls[0], buffs, dest_ref1);
- gf_vect_dot_prod_base(size, srcs, &g_tbls[32 * srcs], buffs, dest_ref2);
- gf_vect_dot_prod_base(size, srcs, &g_tbls[64 * srcs], buffs, dest_ref3);
- gf_vect_dot_prod_base(size, srcs, &g_tbls[96 * srcs], buffs, dest_ref4);
- gf_vect_dot_prod_base(size, srcs, &g_tbls[128 * srcs], buffs, dest_ref5);
- gf_vect_dot_prod_base(size, srcs, &g_tbls[160 * srcs], buffs, dest_ref6);
-
- FUNCTION_UNDER_TEST(size, srcs, g_tbls, buffs, dest_ptrs);
-
- if (memcmp(dest_ref1, dest_ptrs[0], size)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test ualign len=%d\n",
- size);
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref1, 25);
- printf("dprod_dut:");
- dump(dest_ptrs[0], 25);
- return -1;
- }
- if (memcmp(dest_ref2, dest_ptrs[1], size)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test ualign len=%d\n",
- size);
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref2, 25);
- printf("dprod_dut:");
- dump(dest_ptrs[1], 25);
- return -1;
- }
- if (memcmp(dest_ref3, dest_ptrs[2], size)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test ualign len=%d\n",
- size);
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref3, 25);
- printf("dprod_dut:");
- dump(dest_ptrs[2], 25);
- return -1;
- }
- if (memcmp(dest_ref4, dest_ptrs[3], size)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test ualign len=%d\n",
- size);
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref4, 25);
- printf("dprod_dut:");
- dump(dest_ptrs[3], 25);
- return -1;
- }
- if (memcmp(dest_ref5, dest_ptrs[4], size)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test ualign len=%d\n",
- size);
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref5, 25);
- printf("dprod_dut:");
- dump(dest_ptrs[4], 25);
- return -1;
- }
- if (memcmp(dest_ref6, dest_ptrs[5], size)) {
- printf("Fail rand " xstr(FUNCTION_UNDER_TEST) " test ualign len=%d\n",
- size);
- dump_matrix(buffs, 5, TEST_SOURCES);
- printf("dprod_base:");
- dump(dest_ref6, 25);
- printf("dprod_dut:");
- dump(dest_ptrs[5], 25);
- return -1;
- }
- }
-
- printf("Pass\n");
- return 0;
-
-}
diff --git a/contrib/libs/isa-l/erasure_code/gf_6vect_dot_prod_sse_test.patch b/contrib/libs/isa-l/erasure_code/gf_6vect_dot_prod_sse_test.patch
deleted file mode 100644
index 21bbfaa667..0000000000
--- a/contrib/libs/isa-l/erasure_code/gf_6vect_dot_prod_sse_test.patch
+++ /dev/null
@@ -1,4 +0,0 @@
-34c34
-< // #include "types.h"
----
-> #include "types.h"
diff --git a/contrib/libs/isa-l/erasure_code/gf_6vect_mad_avx.asm b/contrib/libs/isa-l/erasure_code/gf_6vect_mad_avx.asm
index c9d7e57472..13a9af79c2 100644
--- a/contrib/libs/isa-l/erasure_code/gf_6vect_mad_avx.asm
+++ b/contrib/libs/isa-l/erasure_code/gf_6vect_mad_avx.asm
@@ -111,7 +111,7 @@
%define return rax
%define return.w eax
- %define func(x) x:
+ %define func(x) x: endbranch
%macro FUNC_SAVE 0
push r12
push r13
@@ -184,13 +184,8 @@ section .text
align 16
-global gf_6vect_mad_avx:ISAL_SYM_TYPE_FUNCTION
+global gf_6vect_mad_avx, function
func(gf_6vect_mad_avx)
-%ifidn __OUTPUT_FORMAT__, macho64
-global _gf_6vect_mad_avx:ISAL_SYM_TYPE_FUNCTION
-func(_gf_6vect_mad_avx)
-%endif
-
FUNC_SAVE
sub len, 16
jl .return_fail
@@ -394,6 +389,3 @@ align 16
mask0f: dq 0x0f0f0f0f0f0f0f0f, 0x0f0f0f0f0f0f0f0f
constip16:
dq 0xf8f9fafbfcfdfeff, 0xf0f1f2f3f4f5f6f7
-
-;;; func core, ver, snum
-slversion gf_6vect_mad_avx, 02, 01, 0210
diff --git a/contrib/libs/isa-l/erasure_code/gf_6vect_mad_avx.patch b/contrib/libs/isa-l/erasure_code/gf_6vect_mad_avx.patch
deleted file mode 100644
index d5afa0f167..0000000000
--- a/contrib/libs/isa-l/erasure_code/gf_6vect_mad_avx.patch
+++ /dev/null
@@ -1,6 +0,0 @@
-189,193d188
-< %ifidn __OUTPUT_FORMAT__, macho64
-< global _gf_6vect_mad_avx:ISAL_SYM_TYPE_FUNCTION
-< func(_gf_6vect_mad_avx)
-< %endif
-<
diff --git a/contrib/libs/isa-l/erasure_code/gf_6vect_mad_avx2.asm b/contrib/libs/isa-l/erasure_code/gf_6vect_mad_avx2.asm
index 2b6babcba5..5f0b3477bb 100644
--- a/contrib/libs/isa-l/erasure_code/gf_6vect_mad_avx2.asm
+++ b/contrib/libs/isa-l/erasure_code/gf_6vect_mad_avx2.asm
@@ -107,7 +107,7 @@
%define return rax
%define return.w eax
- %define func(x) x:
+ %define func(x) x: endbranch
%macro FUNC_SAVE 0
push r12
%endmacro
@@ -177,13 +177,8 @@ section .text
%define xd6 xd1
align 16
-global gf_6vect_mad_avx2:ISAL_SYM_TYPE_FUNCTION
+global gf_6vect_mad_avx2, function
func(gf_6vect_mad_avx2)
-%ifidn __OUTPUT_FORMAT__, macho64
-global _gf_6vect_mad_avx2:ISAL_SYM_TYPE_FUNCTION
-func(_gf_6vect_mad_avx2)
-%endif
-
FUNC_SAVE
sub len, 32
jl .return_fail
@@ -400,6 +395,3 @@ align 32
constip32:
dq 0xf8f9fafbfcfdfeff, 0xf0f1f2f3f4f5f6f7
dq 0xe8e9eaebecedeeef, 0xe0e1e2e3e4e5e6e7
-
-;;; func core, ver, snum
-slversion gf_6vect_mad_avx2, 04, 01, 0211
diff --git a/contrib/libs/isa-l/erasure_code/gf_6vect_mad_avx2.patch b/contrib/libs/isa-l/erasure_code/gf_6vect_mad_avx2.patch
deleted file mode 100644
index add3a8e3a2..0000000000
--- a/contrib/libs/isa-l/erasure_code/gf_6vect_mad_avx2.patch
+++ /dev/null
@@ -1,6 +0,0 @@
-182,186d181
-< %ifidn __OUTPUT_FORMAT__, macho64
-< global _gf_6vect_mad_avx2:ISAL_SYM_TYPE_FUNCTION
-< func(_gf_6vect_mad_avx2)
-< %endif
-<
diff --git a/contrib/libs/isa-l/erasure_code/gf_6vect_mad_avx512.asm b/contrib/libs/isa-l/erasure_code/gf_6vect_mad_avx512.asm
new file mode 100644
index 0000000000..2d18c529be
--- /dev/null
+++ b/contrib/libs/isa-l/erasure_code/gf_6vect_mad_avx512.asm
@@ -0,0 +1,321 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; Copyright(c) 2011-2019 Intel Corporation All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions
+; are met:
+; * Redistributions of source code must retain the above copyright
+; notice, this list of conditions and the following disclaimer.
+; * Redistributions in binary form must reproduce the above copyright
+; notice, this list of conditions and the following disclaimer in
+; the documentation and/or other materials provided with the
+; distribution.
+; * Neither the name of Intel Corporation nor the names of its
+; contributors may be used to endorse or promote products derived
+; from this software without specific prior written permission.
+;
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+; "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+; A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+; OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+; SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+; LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+; OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;;;
+;;; gf_6vect_mad_avx512(len, vec, vec_i, mul_array, src, dest);
+;;;
+
+%include "reg_sizes.asm"
+
+%ifdef HAVE_AS_KNOWS_AVX512
+
+%ifidn __OUTPUT_FORMAT__, elf64
+ %define arg0 rdi
+ %define arg1 rsi
+ %define arg2 rdx
+ %define arg3 rcx
+ %define arg4 r8
+ %define arg5 r9
+ %define tmp r11
+ %define tmp2 r10
+ %define tmp3 r12 ;must be saved and restored
+ %define return rax
+ %define func(x) x: endbranch
+ %macro FUNC_SAVE 0
+ push r12
+ %endmacro
+ %macro FUNC_RESTORE 0
+ pop r12
+ %endmacro
+%endif
+
+%ifidn __OUTPUT_FORMAT__, win64
+ %define arg0 rcx
+ %define arg1 rdx
+ %define arg2 r8
+ %define arg3 r9
+ %define arg4 r12
+ %define arg5 r15
+ %define tmp r11
+ %define tmp2 r10
+ %define tmp3 r13
+ %define return rax
+ %define stack_size 16*10 + 3*8
+ %define arg(x) [rsp + stack_size + PS + PS*x]
+ %define func(x) proc_frame x
+
+%macro FUNC_SAVE 0
+ sub rsp, stack_size
+ vmovdqa [rsp+16*0],xmm6
+ vmovdqa [rsp+16*1],xmm7
+ vmovdqa [rsp+16*2],xmm8
+ vmovdqa [rsp+16*3],xmm9
+ vmovdqa [rsp+16*4],xmm10
+ vmovdqa [rsp+16*5],xmm11
+ vmovdqa [rsp+16*6],xmm12
+ vmovdqa [rsp+16*7],xmm13
+ vmovdqa [rsp+16*8],xmm14
+ vmovdqa [rsp+16*9],xmm15
+ save_reg r12, 10*16 + 0*8
+ save_reg r15, 10*16 + 1*8
+ save_reg r13, 10*16 + 2*8
+ end_prolog
+ mov arg4, arg(4)
+ mov arg5, arg(5)
+%endmacro
+
+%macro FUNC_RESTORE 0
+ vmovdqa xmm6, [rsp+16*0]
+ vmovdqa xmm7, [rsp+16*1]
+ vmovdqa xmm8, [rsp+16*2]
+ vmovdqa xmm9, [rsp+16*3]
+ vmovdqa xmm10, [rsp+16*4]
+ vmovdqa xmm11, [rsp+16*5]
+ vmovdqa xmm12, [rsp+16*6]
+ vmovdqa xmm13, [rsp+16*7]
+ vmovdqa xmm14, [rsp+16*8]
+ vmovdqa xmm15, [rsp+16*9]
+ mov r12, [rsp + 10*16 + 0*8]
+ mov r15, [rsp + 10*16 + 1*8]
+ mov r13, [rsp + 10*16 + 2*8]
+ add rsp, stack_size
+%endmacro
+%endif
+
+%define PS 8
+%define len arg0
+%define vec arg1
+%define vec_i arg2
+%define mul_array arg3
+%define src arg4
+%define dest1 arg5
+%define pos return
+%define dest2 tmp3
+%define dest3 tmp2
+%define dest4 mul_array
+%define dest5 vec
+%define dest6 vec_i
+
+%ifndef EC_ALIGNED_ADDR
+;;; Use Un-aligned load/store
+ %define XLDR vmovdqu8
+ %define XSTR vmovdqu8
+%else
+;;; Use Non-temporal load/stor
+ %ifdef NO_NT_LDST
+ %define XLDR vmovdqa64
+ %define XSTR vmovdqa64
+ %else
+ %define XLDR vmovntdqa
+ %define XSTR vmovntdq
+ %endif
+%endif
+
+default rel
+[bits 64]
+section .text
+
+%define x0 zmm0
+%define xtmpa zmm1
+%define xtmpl1 zmm2
+%define xtmph1 zmm3
+%define xgft1_hi zmm4
+%define xgft1_lo zmm5
+%define xgft1_loy ymm5
+%define xgft2_hi zmm6
+%define xgft2_lo zmm7
+%define xgft2_loy ymm7
+%define xgft3_hi zmm8
+%define xgft3_lo zmm9
+%define xgft3_loy ymm9
+%define xgft4_hi zmm10
+%define xgft4_lo zmm11
+%define xgft4_loy ymm11
+%define xgft5_hi zmm12
+%define xgft5_lo zmm13
+%define xgft5_loy ymm13
+%define xgft6_hi zmm14
+%define xgft6_lo zmm15
+%define xgft6_loy ymm15
+%define xd1 zmm16
+%define xd2 zmm17
+%define xd3 zmm18
+%define xd4 zmm19
+%define xd5 zmm20
+%define xd6 zmm21
+%define xmask0f zmm22
+%define xtmpl2 zmm23
+%define xtmpl3 zmm24
+%define xtmpl4 zmm25
+%define xtmpl5 zmm26
+%define xtmph2 zmm27
+%define xtmph3 zmm28
+%define xtmph4 zmm29
+%define xtmph5 zmm30
+%define xtmph6 zmm31
+
+align 16
+global gf_6vect_mad_avx512, function
+func(gf_6vect_mad_avx512)
+ FUNC_SAVE
+ sub len, 64
+ jl .return_fail
+ xor pos, pos
+ mov tmp, 0x0f
+ vpbroadcastb xmask0f, tmp ;Construct mask 0x0f0f0f...
+ sal vec_i, 5 ;Multiply by 32
+ sal vec, 5 ;Multiply by 32
+ lea tmp, [mul_array + vec_i]
+ mov vec_i, vec
+ mov mul_array, vec
+ sal vec_i, 1 ;vec_i=vec*64
+ sal mul_array, 1 ;mul_array=vec*64
+ add vec_i, vec ;vec_i=vec*96
+ add mul_array, vec_i ;vec_i=vec*160
+
+ vmovdqu xgft1_loy, [tmp] ;Load array Ax{00}..{0f}, Ax{00}..{f0}
+ vmovdqu xgft2_loy, [tmp+vec] ;Load array Bx{00}..{0f}, Bx{00}..{f0}
+ vmovdqu xgft3_loy, [tmp+2*vec] ;Load array Cx{00}..{0f}, Cx{00}..{f0}
+ vmovdqu xgft4_loy, [tmp+vec_i] ;Load array Dx{00}..{0f}, Dx{00}..{f0}
+ vmovdqu xgft5_loy, [tmp+4*vec] ;Load array Ex{00}..{0f}, Ex{00}..{f0}
+ vmovdqu xgft6_loy, [tmp+mul_array] ;Load array Fx{00}..{0f}, Fx{00}..{f0}
+
+ vshufi64x2 xgft1_hi, xgft1_lo, xgft1_lo, 0x55
+ vshufi64x2 xgft1_lo, xgft1_lo, xgft1_lo, 0x00
+ vshufi64x2 xgft2_hi, xgft2_lo, xgft2_lo, 0x55
+ vshufi64x2 xgft2_lo, xgft2_lo, xgft2_lo, 0x00
+ vshufi64x2 xgft3_hi, xgft3_lo, xgft3_lo, 0x55
+ vshufi64x2 xgft3_lo, xgft3_lo, xgft3_lo, 0x00
+ vshufi64x2 xgft4_hi, xgft4_lo, xgft4_lo, 0x55
+ vshufi64x2 xgft4_lo, xgft4_lo, xgft4_lo, 0x00
+ vshufi64x2 xgft5_hi, xgft5_lo, xgft5_lo, 0x55
+ vshufi64x2 xgft5_lo, xgft5_lo, xgft5_lo, 0x00
+ vshufi64x2 xgft6_hi, xgft6_lo, xgft6_lo, 0x55
+ vshufi64x2 xgft6_lo, xgft6_lo, xgft6_lo, 0x00
+
+ mov dest2, [dest1+PS]
+ mov dest3, [dest1+2*PS]
+ mov dest4, [dest1+3*PS] ; reuse mul_array
+ mov dest5, [dest1+4*PS] ; reuse vec
+ mov dest6, [dest1+5*PS] ; reuse vec_i
+ mov dest1, [dest1]
+ mov tmp, -1
+ kmovq k1, tmp
+
+.loop64:
+ XLDR x0, [src+pos] ;Get next source vector
+ XLDR xd1, [dest1+pos] ;Get next dest vector
+ XLDR xd2, [dest2+pos] ;Get next dest vector
+ XLDR xd3, [dest3+pos] ;Get next dest vector
+ XLDR xd4, [dest4+pos] ;Get next dest vector
+ XLDR xd5, [dest5+pos] ;Get next dest vector
+ XLDR xd6, [dest6+pos] ;Get next dest vector
+
+ vpandq xtmpa, x0, xmask0f ;Mask low src nibble in bits 4-0
+ vpsraw x0, x0, 4 ;Shift to put high nibble into bits 4-0
+ vpandq x0, x0, xmask0f ;Mask high src nibble in bits 4-0
+
+ ; dest1
+ vpshufb xtmph1 {k1}{z}, xgft1_hi, x0 ;Lookup mul table of high nibble
+ vpshufb xtmpl1 {k1}{z}, xgft1_lo, xtmpa ;Lookup mul table of low nibble
+ vpxorq xtmph1, xtmph1, xtmpl1 ;GF add high and low partials
+ vpxorq xd1, xd1, xtmph1 ;xd1 += partial
+
+ ; dest2
+ vpshufb xtmph2 {k1}{z}, xgft2_hi, x0 ;Lookup mul table of high nibble
+ vpshufb xtmpl2 {k1}{z}, xgft2_lo, xtmpa ;Lookup mul table of low nibble
+ vpxorq xtmph2, xtmph2, xtmpl2 ;GF add high and low partials
+ vpxorq xd2, xd2, xtmph2 ;xd2 += partial
+
+ ; dest3
+ vpshufb xtmph3 {k1}{z}, xgft3_hi, x0 ;Lookup mul table of high nibble
+ vpshufb xtmpl3 {k1}{z}, xgft3_lo, xtmpa ;Lookup mul table of low nibble
+ vpxorq xtmph3, xtmph3, xtmpl3 ;GF add high and low partials
+ vpxorq xd3, xd3, xtmph3 ;xd3 += partial
+
+ ; dest4
+ vpshufb xtmph4 {k1}{z}, xgft4_hi, x0 ;Lookup mul table of high nibble
+ vpshufb xtmpl4 {k1}{z}, xgft4_lo, xtmpa ;Lookup mul table of low nibble
+ vpxorq xtmph4, xtmph4, xtmpl4 ;GF add high and low partials
+ vpxorq xd4, xd4, xtmph4 ;xd4 += partial
+
+ ; dest5
+ vpshufb xtmph5 {k1}{z}, xgft5_hi, x0 ;Lookup mul table of high nibble
+ vpshufb xtmpl5 {k1}{z}, xgft5_lo, xtmpa ;Lookup mul table of low nibble
+ vpxorq xtmph5, xtmph5, xtmpl5 ;GF add high and low partials
+ vpxorq xd5, xd5, xtmph5 ;xd5 += partial
+
+ ; dest6
+ vpshufb xtmph6 {k1}{z}, xgft6_hi, x0 ;Lookup mul table of high nibble
+ vpshufb xtmpl5 {k1}{z}, xgft6_lo, xtmpa ;Lookup mul table of low nibble. Reuse xtmpl5
+ vpxorq xtmph6, xtmph6, xtmpl5 ;GF add high and low partials.
+ vpxorq xd6, xd6, xtmph6 ;xd6 += partial
+
+ XSTR [dest1+pos], xd1
+ XSTR [dest2+pos], xd2
+ XSTR [dest3+pos], xd3
+ XSTR [dest4+pos], xd4
+ XSTR [dest5+pos], xd5
+ XSTR [dest6+pos], xd6
+
+ add pos, 64 ;Loop on 64 bytes at a time
+ cmp pos, len
+ jle .loop64
+
+ lea tmp, [len + 64]
+ cmp pos, tmp
+ je .return_pass
+
+ ;; Tail len
+ mov pos, (1 << 63)
+ lea tmp, [len + 64 - 1]
+ and tmp, 63
+ sarx pos, pos, tmp
+ kmovq k1, pos
+ mov pos, len ;Overlapped offset length-64
+ jmp .loop64 ;Do one more overlap pass
+
+.return_pass:
+ mov return, 0
+ FUNC_RESTORE
+ ret
+
+.return_fail:
+ mov return, 1
+ FUNC_RESTORE
+ ret
+
+endproc_frame
+
+%else
+%ifidn __OUTPUT_FORMAT__, win64
+global no_gf_6vect_mad_avx512
+no_gf_6vect_mad_avx512:
+%endif
+%endif ; ifdef HAVE_AS_KNOWS_AVX512
diff --git a/contrib/libs/isa-l/erasure_code/gf_6vect_mad_avx512_gfni.asm b/contrib/libs/isa-l/erasure_code/gf_6vect_mad_avx512_gfni.asm
new file mode 100644
index 0000000000..b1853b65fd
--- /dev/null
+++ b/contrib/libs/isa-l/erasure_code/gf_6vect_mad_avx512_gfni.asm
@@ -0,0 +1,259 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; Copyright(c) 2023 Intel Corporation All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions
+; are met:
+; * Redistributions of source code must retain the above copyright
+; notice, this list of conditions and the following disclaimer.
+; * Redistributions in binary form must reproduce the above copyright
+; notice, this list of conditions and the following disclaimer in
+; the documentation and/or other materials provided with the
+; distribution.
+; * Neither the name of Intel Corporation nor the names of its
+; contributors may be used to endorse or promote products derived
+; from this software without specific prior written permission.
+;
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+; "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+; A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+; OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+; SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+; LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+; OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;;;
+;;; gf_6vect_mad_avx512_gfni(len, vec, vec_i, mul_array, src, dest);
+;;;
+
+%include "reg_sizes.asm"
+%include "gf_vect_gfni.inc"
+
+%if AS_FEATURE_LEVEL >= 10
+
+%ifidn __OUTPUT_FORMAT__, elf64
+ %define arg0 rdi
+ %define arg1 rsi
+ %define arg2 rdx
+ %define arg3 rcx
+ %define arg4 r8
+ %define arg5 r9
+ %define tmp r11
+ %define tmp2 r10
+ %define tmp3 r12 ;must be saved and restored
+ %define func(x) x: endbranch
+ %macro FUNC_SAVE 0
+ push r12
+ %endmacro
+ %macro FUNC_RESTORE 0
+ pop r12
+ %endmacro
+%endif
+
+%ifidn __OUTPUT_FORMAT__, win64
+ %define arg0 rcx
+ %define arg1 rdx
+ %define arg2 r8
+ %define arg3 r9
+ %define arg4 r12
+ %define arg5 r14
+ %define tmp r11
+ %define tmp2 r10
+ %define tmp3 r13
+ %define stack_size 16*10 + 3*8
+ %define arg(x) [rsp + stack_size + 8 + 8*x]
+ %define func(x) proc_frame x
+
+%macro FUNC_SAVE 0
+ sub rsp, stack_size
+ vmovdqa [rsp + 16*0], xmm6
+ vmovdqa [rsp + 16*1], xmm7
+ vmovdqa [rsp + 16*2], xmm8
+ vmovdqa [rsp + 16*3], xmm9
+ vmovdqa [rsp + 16*4], xmm10
+ vmovdqa [rsp + 16*5], xmm11
+ vmovdqa [rsp + 16*6], xmm12
+ vmovdqa [rsp + 16*7], xmm13
+ vmovdqa [rsp + 16*8], xmm14
+ vmovdqa [rsp + 16*9], xmm15
+ mov [rsp + 10*16 + 0*8], r12
+ mov [rsp + 10*16 + 1*8], r13
+ mov [rsp + 10*16 + 2*8], r14
+ end_prolog
+ mov arg4, arg(4)
+ mov arg5, arg(5)
+%endmacro
+
+%macro FUNC_RESTORE 0
+ vmovdqa xmm6, [rsp + 16*0]
+ vmovdqa xmm7, [rsp + 16*1]
+ vmovdqa xmm8, [rsp + 16*2]
+ vmovdqa xmm9, [rsp + 16*3]
+ vmovdqa xmm10, [rsp + 16*4]
+ vmovdqa xmm11, [rsp + 16*5]
+ vmovdqa xmm12, [rsp + 16*6]
+ vmovdqa xmm13, [rsp + 16*7]
+ vmovdqa xmm14, [rsp + 16*8]
+ vmovdqa xmm15, [rsp + 16*9]
+ mov r12, [rsp + 10*16 + 0*8]
+ mov r13, [rsp + 10*16 + 1*8]
+ mov r14, [rsp + 10*16 + 2*8]
+ add rsp, stack_size
+%endmacro
+%endif
+
+%define len arg0
+%define vec arg1
+%define vec_i arg2
+%define mul_array arg3
+%define src arg4
+%define dest1 arg5
+%define pos rax
+%define dest2 tmp3
+%define dest3 tmp2
+%define dest4 mul_array
+%define dest5 vec
+%define dest6 vec_i
+
+%ifndef EC_ALIGNED_ADDR
+;;; Use Un-aligned load/store
+ %define XLDR vmovdqu8
+ %define XSTR vmovdqu8
+%else
+;;; Use Non-temporal load/stor
+ %ifdef NO_NT_LDST
+ %define XLDR vmovdqa64
+ %define XSTR vmovdqa64
+ %else
+ %define XLDR vmovntdqa
+ %define XSTR vmovntdq
+ %endif
+%endif
+
+default rel
+[bits 64]
+section .text
+
+%define x0 zmm0
+%define xd1 zmm1
+%define xd2 zmm2
+%define xd3 zmm3
+%define xd4 zmm4
+%define xd5 zmm5
+%define xd6 zmm6
+
+%define xgft1 zmm7
+%define xgft2 zmm8
+%define xgft3 zmm9
+%define xgft4 zmm10
+%define xgft5 zmm11
+%define xgft6 zmm12
+
+%define xret1 zmm13
+%define xret2 zmm14
+%define xret3 zmm15
+%define xret4 zmm16
+%define xret5 zmm17
+%define xret6 zmm18
+
+;;
+;; Encodes 64 bytes of a single source into 6x 64 bytes (parity disks)
+;;
+%macro ENCODE_64B_6 0-1
+%define %%KMASK %1
+
+%if %0 == 1
+ vmovdqu8 x0{%%KMASK}, [src + pos] ;Get next source vector
+ vmovdqu8 xd1{%%KMASK}, [dest1 + pos] ;Get next dest vector
+ vmovdqu8 xd2{%%KMASK}, [dest2 + pos] ;Get next dest vector
+ vmovdqu8 xd3{%%KMASK}, [dest3 + pos] ;Get next dest vector
+ vmovdqu8 xd4{%%KMASK}, [dest4 + pos] ;Get next dest vector
+ vmovdqu8 xd5{%%KMASK}, [dest5 + pos] ;Get next dest vector
+ vmovdqu8 xd6{%%KMASK}, [dest6 + pos] ;Get next dest vector
+%else
+ XLDR x0, [src + pos] ;Get next source vector
+ XLDR xd1, [dest1 + pos] ;Get next dest vector
+ XLDR xd2, [dest2 + pos] ;Get next dest vector
+ XLDR xd3, [dest3 + pos] ;Get next dest vector
+ XLDR xd4, [dest4 + pos] ;Get next dest vector
+ XLDR xd5, [dest5 + pos] ;Get next dest vector
+ XLDR xd6, [dest6 + pos] ;Get next dest vector
+%endif
+
+ GF_MUL_XOR EVEX, x0, xgft1, xret1, xd1, xgft2, xret2, xd2, xgft3, xret3, xd3, \
+ xgft4, xret4, xd4, xgft5, xret5, xd5, xgft6, xret6, xd6
+
+%if %0 == 1
+ vmovdqu8 [dest1 + pos]{%%KMASK}, xd1
+ vmovdqu8 [dest2 + pos]{%%KMASK}, xd2
+ vmovdqu8 [dest3 + pos]{%%KMASK}, xd3
+ vmovdqu8 [dest4 + pos]{%%KMASK}, xd4
+ vmovdqu8 [dest5 + pos]{%%KMASK}, xd5
+ vmovdqu8 [dest6 + pos]{%%KMASK}, xd6
+%else
+ XSTR [dest1 + pos], xd1
+ XSTR [dest2 + pos], xd2
+ XSTR [dest3 + pos], xd3
+ XSTR [dest4 + pos], xd4
+ XSTR [dest5 + pos], xd5
+ XSTR [dest6 + pos], xd6
+%endif
+%endmacro
+
+align 16
+global gf_6vect_mad_avx512_gfni, function
+func(gf_6vect_mad_avx512_gfni)
+ FUNC_SAVE
+
+ xor pos, pos
+ shl vec_i, 3 ;Multiply by 8
+ shl vec, 3 ;Multiply by 8
+ lea tmp, [mul_array + vec_i]
+ vbroadcastf32x2 xgft1, [tmp]
+ vbroadcastf32x2 xgft2, [tmp + vec]
+ vbroadcastf32x2 xgft3, [tmp + vec*2]
+ vbroadcastf32x2 xgft5, [tmp + vec*4]
+ add tmp, vec
+ vbroadcastf32x2 xgft4, [tmp + vec*2]
+ vbroadcastf32x2 xgft6, [tmp + vec*4]
+ mov dest2, [dest1 + 8]
+ mov dest3, [dest1 + 2*8]
+ mov dest4, [dest1 + 3*8] ; reuse mul_array
+ mov dest5, [dest1 + 4*8] ; reuse vec
+ mov dest6, [dest1 + 5*8] ; reuse vec_i
+ mov dest1, [dest1]
+
+ cmp len, 64
+ jl .len_lt_64
+.loop64:
+ ENCODE_64B_6
+
+ add pos, 64 ;Loop on 64 bytes at a time
+ sub len, 64
+ cmp len, 64
+ jge .loop64
+
+.len_lt_64:
+ cmp len, 0
+ jle .exit
+
+ xor tmp, tmp
+ bts tmp, len
+ dec tmp
+ kmovq k1, tmp
+
+ ENCODE_64B_6 k1
+
+.exit:
+ vzeroupper
+
+ FUNC_RESTORE
+ ret
+
+endproc_frame
+%endif ; if AS_FEATURE_LEVEL >= 10
diff --git a/contrib/libs/isa-l/erasure_code/gf_6vect_mad_sse.asm b/contrib/libs/isa-l/erasure_code/gf_6vect_mad_sse.asm
index 8e0fc0e0a4..a816f8bbf4 100644
--- a/contrib/libs/isa-l/erasure_code/gf_6vect_mad_sse.asm
+++ b/contrib/libs/isa-l/erasure_code/gf_6vect_mad_sse.asm
@@ -113,7 +113,7 @@
%define return rax
%define return.w eax
- %define func(x) x:
+ %define func(x) x: endbranch
%macro FUNC_SAVE 0
push r12
push r13
@@ -185,13 +185,8 @@ section .text
align 16
-global gf_6vect_mad_sse:ISAL_SYM_TYPE_FUNCTION
+global gf_6vect_mad_sse, function
func(gf_6vect_mad_sse)
-%ifidn __OUTPUT_FORMAT__, macho64
-global _gf_6vect_mad_sse:ISAL_SYM_TYPE_FUNCTION
-func(_gf_6vect_mad_sse)
-%endif
-
FUNC_SAVE
sub len, 16
jl .return_fail
@@ -406,6 +401,3 @@ align 16
mask0f: dq 0x0f0f0f0f0f0f0f0f, 0x0f0f0f0f0f0f0f0f
constip16:
dq 0xf8f9fafbfcfdfeff, 0xf0f1f2f3f4f5f6f7
-
-;;; func core, ver, snum
-slversion gf_6vect_mad_sse, 00, 01, 020f
diff --git a/contrib/libs/isa-l/erasure_code/gf_6vect_mad_sse.patch b/contrib/libs/isa-l/erasure_code/gf_6vect_mad_sse.patch
deleted file mode 100644
index 619072af53..0000000000
--- a/contrib/libs/isa-l/erasure_code/gf_6vect_mad_sse.patch
+++ /dev/null
@@ -1,6 +0,0 @@
-190,194d189
-< %ifidn __OUTPUT_FORMAT__, macho64
-< global _gf_6vect_mad_sse:ISAL_SYM_TYPE_FUNCTION
-< func(_gf_6vect_mad_sse)
-< %endif
-<
diff --git a/contrib/libs/isa-l/erasure_code/gf_inverse_test.c b/contrib/libs/isa-l/erasure_code/gf_inverse_test.c
index fe2006eeb7..54e70bb46e 100644
--- a/contrib/libs/isa-l/erasure_code/gf_inverse_test.c
+++ b/contrib/libs/isa-l/erasure_code/gf_inverse_test.c
@@ -111,7 +111,9 @@ int inv_test(u8 * in, u8 * inv, u8 * sav, int n)
print_matrix(in, n);
return -1;
}
+#ifdef TEST_VERBOSE
putchar('.');
+#endif
return 0;
}
@@ -119,7 +121,8 @@ int inv_test(u8 * in, u8 * inv, u8 * sav, int n)
int main(int argc, char *argv[])
{
int i, k, t;
- u8 *test_mat, *save_mat, *invr_mat;
+ u8 *test_mat = NULL, *save_mat = NULL, *invr_mat = NULL;
+ int ret = -1;
u8 test1[] = { 1, 1, 6,
1, 1, 1,
@@ -149,25 +152,25 @@ int main(int argc, char *argv[])
invr_mat = malloc(KMAX * KMAX);
if (NULL == test_mat || NULL == save_mat || NULL == invr_mat)
- return -1;
+ goto exit;
// Test with lots of leading 1's
k = 3;
memcpy(test_mat, test1, k * k);
if (inv_test(test_mat, invr_mat, save_mat, k))
- return -1;
+ goto exit;
// Test with leading zeros
k = 3;
memcpy(test_mat, test2, k * k);
if (inv_test(test_mat, invr_mat, save_mat, k))
- return -1;
+ goto exit;
// Test 3
k = 3;
memcpy(test_mat, test3, k * k);
if (inv_test(test_mat, invr_mat, save_mat, k))
- return -1;
+ goto exit;
// Test 4 - try a singular matrix
k = 4;
@@ -175,7 +178,7 @@ int main(int argc, char *argv[])
if (!gf_invert_matrix(test_mat, invr_mat, k)) {
printf("Fail: didn't catch singular matrix\n");
print_matrix(test4, 4);
- return -1;
+ goto exit;
}
// Do random test of size KMAX
k = KMAX;
@@ -185,7 +188,7 @@ int main(int argc, char *argv[])
if (gf_invert_matrix(test_mat, invr_mat, k)) {
printf("rand picked a singular matrix, try again\n");
- return -1;
+ goto exit;
}
matrix_mult(invr_mat, save_mat, test_mat, k);
@@ -195,7 +198,7 @@ int main(int argc, char *argv[])
print_matrix(save_mat, k);
print_matrix(invr_mat, k);
print_matrix(test_mat, k);
- return -1;
+ goto exit;
}
// Do Randoms. Random size and coefficients
for (t = 0; t < RANDOMS; t++) {
@@ -214,12 +217,22 @@ int main(int argc, char *argv[])
print_matrix(save_mat, k);
print_matrix(invr_mat, k);
print_matrix(test_mat, k);
- return -1;
+ goto exit;
}
+#ifdef TEST_VERBOSE
if (0 == (t % 8))
putchar('.');
+#endif
}
printf(" Pass\n");
- return 0;
+
+ ret = 0;
+
+ exit:
+ free(test_mat);
+ free(save_mat);
+ free(invr_mat);
+
+ return ret;
}
diff --git a/contrib/libs/isa-l/erasure_code/gf_inverse_test.patch b/contrib/libs/isa-l/erasure_code/gf_inverse_test.patch
deleted file mode 100644
index b91cf7f348..0000000000
--- a/contrib/libs/isa-l/erasure_code/gf_inverse_test.patch
+++ /dev/null
@@ -1,4 +0,0 @@
-59c59
-< d ^= gf_mul_erasure(a[n * i + k], b[n * k + j]);
----
-> d ^= gf_mul(a[n * i + k], b[n * k + j]);
diff --git a/contrib/libs/isa-l/erasure_code/gf_vect_dot_prod_1tbl.c b/contrib/libs/isa-l/erasure_code/gf_vect_dot_prod_1tbl.c
index d2959c3c51..bd202fdcf1 100644
--- a/contrib/libs/isa-l/erasure_code/gf_vect_dot_prod_1tbl.c
+++ b/contrib/libs/isa-l/erasure_code/gf_vect_dot_prod_1tbl.c
@@ -33,22 +33,22 @@
#include "test.h"
#include "erasure_code.h"
-//#define CACHED_TEST
-#ifdef CACHED_TEST
+#ifndef GT_L3_CACHE
+# define GT_L3_CACHE 32*1024*1024 /* some number > last level cache */
+#endif
+
+#if !defined(COLD_TEST) && !defined(TEST_CUSTOM)
// Cached test, loop many times over small dataset
# define TEST_SOURCES 10
# define TEST_LEN 8*1024
# define TEST_TYPE_STR "_warm"
-#else
-# ifndef TEST_CUSTOM
+#elif defined (COLD_TEST)
// Uncached test. Pull from large mem base.
-# define TEST_SOURCES 10
-# define GT_L3_CACHE 32*1024*1024 /* some number > last level cache */
-# define TEST_LEN GT_L3_CACHE / TEST_SOURCES
-# define TEST_TYPE_STR "_cold"
-# else
-# define TEST_TYPE_STR "_cus"
-# endif
+# define TEST_SOURCES 10
+# define TEST_LEN (GT_L3_CACHE / TEST_SOURCES)
+# define TEST_TYPE_STR "_cold"
+#elif defined (TEST_CUSTOM)
+# define TEST_TYPE_STR "_cus"
#endif
typedef unsigned char u8;
@@ -111,10 +111,20 @@ void gf_vect_dot_prod_mult(int len, int vlen, u8 * v, u8 ** src, u8 * dest)
int main(void)
{
int i, j;
- u8 vec[TEST_SOURCES], dest1[TEST_LEN], dest2[TEST_LEN];
+ u8 vec[TEST_SOURCES], *dest1, *dest2;
u8 *matrix[TEST_SOURCES];
struct perf start;
+ dest1 = (u8 *) malloc(TEST_LEN);
+ dest2 = (u8 *) malloc(TEST_LEN);
+
+ if (NULL == dest1 || NULL == dest2) {
+ printf("buffer alloc error\n");
+ return -1;
+ }
+ memset(dest1, 0xfe, TEST_LEN);
+ memset(dest2, 0xfe, TEST_LEN);
+
mk_gf_field();
mk_gf_mul_table(gf_mul_table);
diff --git a/contrib/libs/isa-l/erasure_code/gf_vect_dot_prod_1tbl.patch b/contrib/libs/isa-l/erasure_code/gf_vect_dot_prod_1tbl.patch
deleted file mode 100644
index 5ea8eab7d0..0000000000
--- a/contrib/libs/isa-l/erasure_code/gf_vect_dot_prod_1tbl.patch
+++ /dev/null
@@ -1,8 +0,0 @@
-81c81
-< table[i * 256 + j] = gf_mul_erasure(i, j);
----
-> table[i * 256 + j] = gf_mul(i, j);
-91c91
-< s ^= gf_mul_erasure(src[j][i], v[j]);
----
-> s ^= gf_mul(src[j][i], v[j]);
diff --git a/contrib/libs/isa-l/erasure_code/gf_vect_dot_prod_avx.asm b/contrib/libs/isa-l/erasure_code/gf_vect_dot_prod_avx.asm
index dc1eebb972..37915c873b 100644
--- a/contrib/libs/isa-l/erasure_code/gf_vect_dot_prod_avx.asm
+++ b/contrib/libs/isa-l/erasure_code/gf_vect_dot_prod_avx.asm
@@ -48,7 +48,7 @@
%endmacro
%define SSTR SLDR
%define PS 8
- %define func(x) x:
+ %define func(x) x: endbranch
%define FUNC_SAVE
%define FUNC_RESTORE
%endif
@@ -106,7 +106,7 @@
%define PS 4
%define LOG_PS 2
- %define func(x) x:
+ %define func(x) x: endbranch
%define arg(x) [ebp + PS*2 + PS*x]
%define trans ecx ;trans is for the variables in stack
@@ -194,13 +194,8 @@ section .text
%define xp xmm2
align 16
-global gf_vect_dot_prod_avx:ISAL_SYM_TYPE_FUNCTION
+global gf_vect_dot_prod_avx, function
func(gf_vect_dot_prod_avx)
-%ifidn __OUTPUT_FORMAT__, macho64
-global _gf_vect_dot_prod_avx:ISAL_SYM_TYPE_FUNCTION
-func(_gf_vect_dot_prod_avx)
-%endif
-
FUNC_SAVE
SLDR len, len_m
sub len, 16
@@ -271,6 +266,3 @@ align 16
mask0f:
dq 0x0f0f0f0f0f0f0f0f, 0x0f0f0f0f0f0f0f0f
-
-;;; func core, ver, snum
-slversion gf_vect_dot_prod_avx, 02, 05, 0061
diff --git a/contrib/libs/isa-l/erasure_code/gf_vect_dot_prod_avx.patch b/contrib/libs/isa-l/erasure_code/gf_vect_dot_prod_avx.patch
deleted file mode 100644
index 30bdc75785..0000000000
--- a/contrib/libs/isa-l/erasure_code/gf_vect_dot_prod_avx.patch
+++ /dev/null
@@ -1,6 +0,0 @@
-199,203d198
-< %ifidn __OUTPUT_FORMAT__, macho64
-< global _gf_vect_dot_prod_avx:ISAL_SYM_TYPE_FUNCTION
-< func(_gf_vect_dot_prod_avx)
-< %endif
-<
diff --git a/contrib/libs/isa-l/erasure_code/gf_vect_dot_prod_avx2.asm b/contrib/libs/isa-l/erasure_code/gf_vect_dot_prod_avx2.asm
index 986fd28a4e..fb9b022975 100644
--- a/contrib/libs/isa-l/erasure_code/gf_vect_dot_prod_avx2.asm
+++ b/contrib/libs/isa-l/erasure_code/gf_vect_dot_prod_avx2.asm
@@ -51,7 +51,7 @@
%endmacro
%define SSTR SLDR
%define PS 8
- %define func(x) x:
+ %define func(x) x: endbranch
%define FUNC_SAVE
%define FUNC_RESTORE
%endif
@@ -111,7 +111,7 @@
%define PS 4
%define LOG_PS 2
- %define func(x) x:
+ %define func(x) x: endbranch
%define arg(x) [ebp + PS*2 + PS*x]
%define trans ecx ;trans is for the variables in stack
@@ -202,13 +202,8 @@ section .text
%define xp ymm2
align 16
-global gf_vect_dot_prod_avx2:ISAL_SYM_TYPE_FUNCTION
+global gf_vect_dot_prod_avx2, function
func(gf_vect_dot_prod_avx2)
-%ifidn __OUTPUT_FORMAT__, macho64
-global _gf_vect_dot_prod_avx2:ISAL_SYM_TYPE_FUNCTION
-func(_gf_vect_dot_prod_avx2)
-%endif
-
FUNC_SAVE
SLDR len, len_m
sub len, 32
@@ -278,8 +273,3 @@ func(_gf_vect_dot_prod_avx2)
ret
endproc_frame
-
-section .data
-
-;;; func core, ver, snum
-slversion gf_vect_dot_prod_avx2, 04, 05, 0190
diff --git a/contrib/libs/isa-l/erasure_code/gf_vect_dot_prod_avx2.patch b/contrib/libs/isa-l/erasure_code/gf_vect_dot_prod_avx2.patch
deleted file mode 100644
index c2890dbc39..0000000000
--- a/contrib/libs/isa-l/erasure_code/gf_vect_dot_prod_avx2.patch
+++ /dev/null
@@ -1,6 +0,0 @@
-207,211d206
-< %ifidn __OUTPUT_FORMAT__, macho64
-< global _gf_vect_dot_prod_avx2:ISAL_SYM_TYPE_FUNCTION
-< func(_gf_vect_dot_prod_avx2)
-< %endif
-<
diff --git a/contrib/libs/isa-l/erasure_code/gf_vect_dot_prod_avx2_gfni.asm b/contrib/libs/isa-l/erasure_code/gf_vect_dot_prod_avx2_gfni.asm
new file mode 100644
index 0000000000..c084894c7b
--- /dev/null
+++ b/contrib/libs/isa-l/erasure_code/gf_vect_dot_prod_avx2_gfni.asm
@@ -0,0 +1,318 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; Copyright(c) 2023 Intel Corporation All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions
+; are met:
+; * Redistributions of source code must retain the above copyright
+; notice, this list of conditions and the following disclaimer.
+; * Redistributions in binary form must reproduce the above copyright
+; notice, this list of conditions and the following disclaimer in
+; the documentation and/or other materials provided with the
+; distribution.
+; * Neither the name of Intel Corporation nor the names of its
+; contributors may be used to endorse or promote products derived
+; from this software without specific prior written permission.
+;
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+; "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+; A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+; OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+; SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+; LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+; OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;;;
+;;; gf_vect_dot_prod_avx2_gfni(len, vec, *g_tbls, **buffs, *dest);
+;;;
+
+%include "reg_sizes.asm"
+%include "gf_vect_gfni.inc"
+%include "memcpy.asm"
+
+%if AS_FEATURE_LEVEL >= 10
+
+%ifidn __OUTPUT_FORMAT__, elf64
+ %define arg0 rdi
+ %define arg1 rsi
+ %define arg2 rdx
+ %define arg3 rcx
+ %define arg4 r8
+ %define arg5 r9
+
+ %define tmp r11
+ %define tmp2 r10
+ %define tmp3 r12 ; must be saved and restored
+
+ %define stack_size 1*8
+ %define func(x) x: endbranch
+ %macro FUNC_SAVE 0
+ sub rsp, stack_size
+ mov [rsp + 0*8], r12
+ %endmacro
+ %macro FUNC_RESTORE 0
+ mov r12, [rsp + 0*8]
+ add rsp, stack_size
+ %endmacro
+%endif
+
+%ifidn __OUTPUT_FORMAT__, win64
+ %define arg0 rcx
+ %define arg1 rdx
+ %define arg2 r8
+ %define arg3 r9
+
+ %define arg4 r12 ; must be saved, loaded and restored
+ %define arg5 r15 ; must be saved and restored
+ %define tmp r11
+ %define tmp2 r10
+ %define tmp3 r13 ; must be saved and restored
+ %define stack_size 4*16 + 3*8 ; must be an odd multiple of 8
+ %define arg(x) [rsp + stack_size + 8 + 8*x]
+
+ %define func(x) proc_frame x
+ %macro FUNC_SAVE 0
+ alloc_stack stack_size
+ vmovdqa [rsp + 0*16], xmm6
+ vmovdqa [rsp + 1*16], xmm7
+ vmovdqa [rsp + 2*16], xmm8
+ vmovdqa [rsp + 3*16], xmm9
+ mov [rsp + 4*16 + 0*8], r12
+ mov [rsp + 4*16 + 1*8], r13
+ mov [rsp + 4*16 + 2*8], r15
+ end_prolog
+ mov arg4, arg(4)
+ %endmacro
+
+ %macro FUNC_RESTORE 0
+ vmovdqa xmm6, [rsp + 0*16]
+ vmovdqa xmm7, [rsp + 1*16]
+ vmovdqa xmm8, [rsp + 2*16]
+ vmovdqa xmm9, [rsp + 3*16]
+ mov r12, [rsp + 4*16 + 0*8]
+ mov r13, [rsp + 4*16 + 1*8]
+ mov r15, [rsp + 4*16 + 2*8]
+ add rsp, stack_size
+ %endmacro
+%endif
+
+
+%define len arg0
+%define vec arg1
+%define mul_array arg2
+%define src arg3
+%define dest1 arg4
+%define ptr arg5
+%define vec_i tmp2
+%define pos rax
+
+%ifndef EC_ALIGNED_ADDR
+;;; Use Un-aligned load/store
+ %define XLDR vmovdqu
+ %define XSTR vmovdqu
+%else
+;;; Use Non-temporal load/stor
+ %ifdef NO_NT_LDST
+ %define XLDR vmovdqa
+ %define XSTR vmovdqa
+ %else
+ %define XLDR vmovntdqa
+ %define XSTR vmovntdq
+ %endif
+%endif
+
+%define x0l ymm0
+%define x0h ymm1
+%define x0x ymm2
+
+%define xp1l ymm3
+%define xp1h ymm4
+%define xp1x ymm5
+
+%define xgft1 ymm6
+%define xgft2 ymm7
+%define xgft3 ymm8
+
+%define xtmp1 ymm9
+
+%define x0 x0l
+%define xp1 xp1l
+%define xp2 xp2l
+%define xp3 xp3l
+
+default rel
+[bits 64]
+
+section .text
+
+;;
+;; Encodes 96 bytes of all "k" sources into 96 bytes (single parity disk)
+;;
+%macro ENCODE_96B 0
+ vpxor xp1l, xp1l, xp1l
+ vpxor xp1h, xp1h, xp1h
+ vpxor xp1x, xp1x, xp1x
+ mov tmp, mul_array
+ xor vec_i, vec_i
+
+%%next_vect:
+ ;; load next source vector
+ mov ptr, [src + vec_i]
+ XLDR x0l, [ptr + pos]
+ XLDR x0h, [ptr + pos + 32]
+ XLDR x0x, [ptr + pos + 64]
+ add vec_i, 8
+
+ vbroadcastsd xgft1, [tmp]
+ add tmp, 8
+
+ GF_MUL_XOR VEX, x0l, xgft1, xtmp1, xp1l
+ GF_MUL_XOR VEX, x0h, xgft1, xtmp1, xp1h
+ GF_MUL_XOR VEX, x0x, xgft1, xtmp1, xp1x
+
+ cmp vec_i, vec
+ jl %%next_vect
+
+ XSTR [dest1 + pos], xp1l
+ XSTR [dest1 + pos + 32], xp1h
+ XSTR [dest1 + pos + 64], xp1x
+%endmacro
+
+;;
+;; Encodes 64 bytes of all "k" sources into 64 bytes (single parity disk)
+;;
+%macro ENCODE_64B 0
+ vpxor xp1l, xp1l, xp1l
+ vpxor xp1h, xp1h, xp1h
+ mov tmp, mul_array
+ xor vec_i, vec_i
+
+%%next_vect:
+ ;; load next source vector
+ mov ptr, [src + vec_i]
+ XLDR x0l, [ptr + pos]
+ XLDR x0h, [ptr + pos + 32]
+ add vec_i, 8
+
+ vbroadcastsd xgft1, [tmp]
+ add tmp, 8
+
+ GF_MUL_XOR VEX, x0l, xgft1, xtmp1, xp1l
+ GF_MUL_XOR VEX, x0h, xgft1, xgft1, xp1h
+
+ cmp vec_i, vec
+ jl %%next_vect
+
+ XSTR [dest1 + pos], xp1l
+ XSTR [dest1 + pos + 32], xp1h
+%endmacro
+
+;;
+;; Encodes 32 bytes of all "k" sources into 32 bytes (single parity disks)
+;;
+%macro ENCODE_32B 0
+ vpxor xp1, xp1, xp1
+ mov tmp, mul_array
+ xor vec_i, vec_i
+
+%%next_vect:
+ ;; load next source vector
+ mov ptr, [src + vec_i]
+ XLDR x0, [ptr + pos]
+ add vec_i, 8
+
+ vbroadcastsd xgft1, [tmp]
+ add tmp, 8
+
+ GF_MUL_XOR VEX, x0, xgft1, xgft1, xp1
+
+ cmp vec_i, vec
+ jl %%next_vect
+
+ XSTR [dest1 + pos], xp1
+%endmacro
+
+;;
+;; Encodes less than 32 bytes of all "k" sources into single parity disks
+;;
+%macro ENCODE_LT_32B 1
+%define %%LEN %1
+
+ vpxor xp1, xp1, xp1
+ xor vec_i, vec_i
+
+%%next_vect:
+ ; get next source vector
+ mov ptr, [src + vec_i]
+ simd_load_avx2 x0, ptr + pos, %%LEN, tmp, tmp3
+ add vec_i, 8
+
+ vbroadcastsd xgft1, [mul_array]
+ add mul_array, 8
+
+ GF_MUL_XOR VEX, x0, xgft1, xgft1, xp1
+
+ cmp vec_i, vec
+ jl %%next_vect
+
+ ;; Store updated encoded data
+ lea ptr, [dest1 + pos]
+ simd_store_avx2 ptr, xp1, %%LEN, tmp, vec_i
+%endmacro
+
+align 16
+global gf_vect_dot_prod_avx2_gfni, function
+func(gf_vect_dot_prod_avx2_gfni)
+ FUNC_SAVE
+
+ xor pos, pos
+ shl vec, 3 ;; vec *= 8. Make vec_i count by 8
+
+ cmp len, 96
+ jl .len_lt_96
+
+.loop96:
+ ENCODE_96B
+
+ add pos, 96 ;; Loop on 96 bytes at a time first
+ sub len, 96
+ cmp len, 96
+ jge .loop96
+
+.len_lt_96:
+ cmp len, 64
+ jl .len_lt_64
+
+ ENCODE_64B
+
+ add pos, 64 ;; encode next 64 bytes
+ sub len, 64
+
+.len_lt_64:
+ cmp len, 32
+ jl .len_lt_32
+
+ ENCODE_32B
+
+ add pos, 32 ;; encode next 32 bytes
+ sub len, 32
+
+.len_lt_32:
+ cmp len, 0
+ jle .exit
+
+ ENCODE_LT_32B len ;; encode final bytes
+
+.exit:
+ vzeroupper
+
+ FUNC_RESTORE
+ ret
+
+endproc_frame
+%endif ; if AS_FEATURE_LEVEL >= 10
diff --git a/contrib/libs/isa-l/erasure_code/gf_vect_dot_prod_avx512.asm b/contrib/libs/isa-l/erasure_code/gf_vect_dot_prod_avx512.asm
index 405c1e48e2..b5fbf42498 100644
--- a/contrib/libs/isa-l/erasure_code/gf_vect_dot_prod_avx512.asm
+++ b/contrib/libs/isa-l/erasure_code/gf_vect_dot_prod_avx512.asm
@@ -49,7 +49,7 @@
%define PS 8
%define LOG_PS 3
- %define func(x) x:
+ %define func(x) x: endbranch
%define FUNC_SAVE
%define FUNC_RESTORE
%endif
@@ -73,15 +73,15 @@
%define func(x) proc_frame x
%macro FUNC_SAVE 0
alloc_stack stack_size
- save_reg r12, 9*16 + 0*8
- save_reg r15, 9*16 + 3*8
+ save_reg r12, 0*8
+ save_reg r15, 1*8
end_prolog
mov arg4, arg(4)
%endmacro
%macro FUNC_RESTORE 0
- mov r12, [rsp + 9*16 + 0*8]
- mov r15, [rsp + 9*16 + 3*8]
+ mov r12, [rsp + 0*8]
+ mov r15, [rsp + 1*8]
add rsp, stack_size
%endmacro
%endif
@@ -104,8 +104,8 @@
%else
;;; Use Non-temporal load/stor
%ifdef NO_NT_LDST
- %define XLDR vmovdqa
- %define XSTR vmovdqa
+ %define XLDR vmovdqa64
+ %define XSTR vmovdqa64
%else
%define XLDR vmovntdqa
%define XSTR vmovntdq
@@ -128,13 +128,8 @@ default rel
section .text
align 16
-global gf_vect_dot_prod_avx512:ISAL_SYM_TYPE_FUNCTION
+global gf_vect_dot_prod_avx512, function
func(gf_vect_dot_prod_avx512)
-%ifidn __OUTPUT_FORMAT__, macho64
-global _gf_vect_dot_prod_avx512:ISAL_SYM_TYPE_FUNCTION
-func(_gf_vect_dot_prod_avx512)
-%endif
-
FUNC_SAVE
xor pos, pos
mov tmp, 0x0f
diff --git a/contrib/libs/isa-l/erasure_code/gf_vect_dot_prod_avx512.patch b/contrib/libs/isa-l/erasure_code/gf_vect_dot_prod_avx512.patch
deleted file mode 100644
index 61be77efd3..0000000000
--- a/contrib/libs/isa-l/erasure_code/gf_vect_dot_prod_avx512.patch
+++ /dev/null
@@ -1,6 +0,0 @@
-133,137d132
-< %ifidn __OUTPUT_FORMAT__, macho64
-< global _gf_vect_dot_prod_avx512:ISAL_SYM_TYPE_FUNCTION
-< func(_gf_vect_dot_prod_avx512)
-< %endif
-<
diff --git a/contrib/libs/isa-l/erasure_code/gf_vect_dot_prod_avx512_gfni.asm b/contrib/libs/isa-l/erasure_code/gf_vect_dot_prod_avx512_gfni.asm
new file mode 100644
index 0000000000..b8fc778a88
--- /dev/null
+++ b/contrib/libs/isa-l/erasure_code/gf_vect_dot_prod_avx512_gfni.asm
@@ -0,0 +1,190 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; Copyright(c) 2023 Intel Corporation All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions
+; are met:
+; * Redistributions of source code must retain the above copyright
+; notice, this list of conditions and the following disclaimer.
+; * Redistributions in binary form must reproduce the above copyright
+; notice, this list of conditions and the following disclaimer in
+; the documentation and/or other materials provided with the
+; distribution.
+; * Neither the name of Intel Corporation nor the names of its
+; contributors may be used to endorse or promote products derived
+; from this software without specific prior written permission.
+;
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+; "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+; A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+; OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+; SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+; LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+; OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;;;
+;;; gf_vect_dot_prod_avx512_gfni(len, vec, *g_tbls, **buffs, *dest);
+;;;
+
+%include "reg_sizes.asm"
+%include "gf_vect_gfni.inc"
+
+%if AS_FEATURE_LEVEL >= 10
+
+%ifidn __OUTPUT_FORMAT__, elf64
+ %define arg0 rdi
+ %define arg1 rsi
+ %define arg2 rdx
+ %define arg3 rcx
+ %define arg4 r8
+ %define arg5 r9
+
+ %define tmp r11
+ %define tmp2 r10
+
+ %define func(x) x: endbranch
+ %define FUNC_SAVE
+ %define FUNC_RESTORE
+%endif
+
+%ifidn __OUTPUT_FORMAT__, win64
+ %define arg0 rcx
+ %define arg1 rdx
+ %define arg2 r8
+ %define arg3 r9
+
+ %define arg4 r12 ; must be saved, loaded and restored
+ %define arg5 r13 ; must be saved and restored
+ %define tmp r11
+ %define tmp2 r10
+ %define stack_size 0*16 + 3*8 ; must be an odd multiple of 8
+ %define arg(x) [rsp + stack_size + 8 + 8*x]
+
+ %define func(x) proc_frame x
+ %macro FUNC_SAVE 0
+ alloc_stack stack_size
+ mov [rsp + 0*8], r12
+ mov [rsp + 1*8], r13
+ end_prolog
+ mov arg4, arg(4)
+ %endmacro
+
+ %macro FUNC_RESTORE 0
+ mov r12, [rsp + 0*8]
+ mov r13, [rsp + 1*8]
+ add rsp, stack_size
+ %endmacro
+%endif
+
+
+%define len arg0
+%define vec arg1
+%define mul_array arg2
+%define src arg3
+%define dest1 arg4
+%define ptr arg5
+%define vec_i tmp2
+%define pos rax
+
+
+%ifndef EC_ALIGNED_ADDR
+;;; Use Un-aligned load/store
+ %define XLDR vmovdqu8
+ %define XSTR vmovdqu8
+%else
+;;; Use Non-temporal load/stor
+ %ifdef NO_NT_LDST
+ %define XLDR vmovdqa64
+ %define XSTR vmovdqa64
+ %else
+ %define XLDR vmovntdqa
+ %define XSTR vmovntdq
+ %endif
+%endif
+
+%define xgft1 zmm2
+
+%define x0 zmm0
+%define xp1 zmm1
+
+default rel
+[bits 64]
+section .text
+
+;;
+;; Encodes 64 bytes of all "k" sources into 64 bytes (single parity disk)
+;;
+%macro ENCODE_64B 0-1
+%define %%KMASK %1
+
+ vpxorq xp1, xp1, xp1
+ mov tmp, mul_array
+ xor vec_i, vec_i
+
+%%next_vect:
+ mov ptr, [src + vec_i]
+%if %0 == 1
+ vmovdqu8 x0{%%KMASK}, [ptr + pos] ;Get next source vector (less than 64 bytes)
+%else
+ XLDR x0, [ptr + pos] ;Get next source vector (64 bytes)
+%endif
+ add vec_i, 8
+
+ vbroadcastf32x2 xgft1, [tmp]
+ add tmp, 8
+
+ GF_MUL_XOR EVEX, x0, xgft1, xgft1, xp1
+
+ cmp vec_i, vec
+ jl %%next_vect
+
+%if %0 == 1
+ vmovdqu8 [dest1 + pos]{%%KMASK}, xp1
+%else
+ XSTR [dest1 + pos], xp1
+%endif
+%endmacro
+
+align 16
+global gf_vect_dot_prod_avx512_gfni, function
+func(gf_vect_dot_prod_avx512_gfni)
+ FUNC_SAVE
+ xor pos, pos
+ shl vec, 3 ;vec *= 8. Make vec_i count by 8
+
+ cmp len, 64
+ jl .len_lt_64
+
+.loop64:
+
+ ENCODE_64B
+
+ add pos, 64 ;Loop on 64 bytes at a time
+ sub len, 64
+ cmp len, 64
+ jge .loop64
+
+.len_lt_64:
+ cmp len, 0
+ jle .exit
+
+ xor tmp, tmp
+ bts tmp, len
+ dec tmp
+ kmovq k1, tmp
+
+ ENCODE_64B k1
+
+.exit:
+ vzeroupper
+
+ FUNC_RESTORE
+ ret
+
+endproc_frame
+%endif ; if AS_FEATURE_LEVEL >= 10
diff --git a/contrib/libs/isa-l/erasure_code/gf_vect_dot_prod_base_test.c b/contrib/libs/isa-l/erasure_code/gf_vect_dot_prod_base_test.c
index b2601226e9..0cfd444413 100644
--- a/contrib/libs/isa-l/erasure_code/gf_vect_dot_prod_base_test.c
+++ b/contrib/libs/isa-l/erasure_code/gf_vect_dot_prod_base_test.c
@@ -30,10 +30,11 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h> // for memset, memcmp
+#include <assert.h>
#include "erasure_code.h"
-// #include "types.h"
+#include "test.h"
-#define TEST_LEN 2048
+#define TEST_LEN 8192
#define TEST_SIZE (TEST_LEN/2)
#ifndef TEST_SOURCES
@@ -134,8 +135,7 @@ int main(int argc, char *argv[])
// Pick a first test
m = 9;
k = 5;
- if (m > MMAX || k > KMAX)
- return -1;
+ assert(!(m > MMAX || k > KMAX));
gf_gen_cauchy1_matrix(a, m, k);
@@ -282,7 +282,9 @@ int main(int argc, char *argv[])
return -1;
}
}
+#ifdef TEST_VERBOSE
putchar('.');
+#endif
}
printf("done all: Pass\n");
diff --git a/contrib/libs/isa-l/erasure_code/gf_vect_dot_prod_base_test.patch b/contrib/libs/isa-l/erasure_code/gf_vect_dot_prod_base_test.patch
deleted file mode 100644
index 21bbfaa667..0000000000
--- a/contrib/libs/isa-l/erasure_code/gf_vect_dot_prod_base_test.patch
+++ /dev/null
@@ -1,4 +0,0 @@
-34c34
-< // #include "types.h"
----
-> #include "types.h"
diff --git a/contrib/libs/isa-l/erasure_code/gf_vect_dot_prod_perf.c b/contrib/libs/isa-l/erasure_code/gf_vect_dot_prod_perf.c
index bd2b555b0a..3b051c67a4 100644
--- a/contrib/libs/isa-l/erasure_code/gf_vect_dot_prod_perf.c
+++ b/contrib/libs/isa-l/erasure_code/gf_vect_dot_prod_perf.c
@@ -40,22 +40,22 @@
#define str(s) #s
#define xstr(s) str(s)
-//#define CACHED_TEST
-#ifdef CACHED_TEST
+#ifndef GT_L3_CACHE
+# define GT_L3_CACHE 32*1024*1024 /* some number > last level cache */
+#endif
+
+#if !defined(COLD_TEST) && !defined(TEST_CUSTOM)
// Cached test, loop many times over small dataset
# define TEST_SOURCES 10
# define TEST_LEN 8*1024
# define TEST_TYPE_STR "_warm"
-#else
-# ifndef TEST_CUSTOM
+#elif defined (COLD_TEST)
// Uncached test. Pull from large mem base.
-# define TEST_SOURCES 10
-# define GT_L3_CACHE 32*1024*1024 /* some number > last level cache */
-# define TEST_LEN ((GT_L3_CACHE / TEST_SOURCES) & ~(64-1))
-# define TEST_TYPE_STR "_cold"
-# else
-# define TEST_TYPE_STR "_cus"
-# endif
+# define TEST_SOURCES 10
+# define TEST_LEN ((GT_L3_CACHE / TEST_SOURCES) & ~(64-1))
+# define TEST_TYPE_STR "_cold"
+#elif defined (TEST_CUSTOM)
+# define TEST_TYPE_STR "_cus"
#endif
typedef unsigned char u8;
diff --git a/contrib/libs/isa-l/erasure_code/gf_vect_dot_prod_sse.asm b/contrib/libs/isa-l/erasure_code/gf_vect_dot_prod_sse.asm
index 67f4a1a329..ef245b4961 100644
--- a/contrib/libs/isa-l/erasure_code/gf_vect_dot_prod_sse.asm
+++ b/contrib/libs/isa-l/erasure_code/gf_vect_dot_prod_sse.asm
@@ -48,7 +48,7 @@
%endmacro
%define SSTR SLDR
%define PS 8
- %define func(x) x:
+ %define func(x) x: endbranch
%define FUNC_SAVE
%define FUNC_RESTORE
%endif
@@ -106,7 +106,7 @@
%define PS 4
%define LOG_PS 2
- %define func(x) x:
+ %define func(x) x: endbranch
%define arg(x) [ebp + PS*2 + PS*x]
%define trans ecx ;trans is for the variables in stack
@@ -194,13 +194,8 @@ section .text
%define xp xmm2
align 16
-global gf_vect_dot_prod_sse:ISAL_SYM_TYPE_FUNCTION
+global gf_vect_dot_prod_sse, function
func(gf_vect_dot_prod_sse)
-%ifidn __OUTPUT_FORMAT__, macho64
-global _gf_vect_dot_prod_sse:ISAL_SYM_TYPE_FUNCTION
-func(_gf_vect_dot_prod_sse)
-%endif
-
FUNC_SAVE
SLDR len, len_m
sub len, 16
@@ -271,6 +266,3 @@ section .data
align 16
mask0f: dq 0x0f0f0f0f0f0f0f0f, 0x0f0f0f0f0f0f0f0f
-
-;;; func core, ver, snum
-slversion gf_vect_dot_prod_sse, 00, 05, 0060
diff --git a/contrib/libs/isa-l/erasure_code/gf_vect_dot_prod_sse.patch b/contrib/libs/isa-l/erasure_code/gf_vect_dot_prod_sse.patch
deleted file mode 100644
index ab47fc7a53..0000000000
--- a/contrib/libs/isa-l/erasure_code/gf_vect_dot_prod_sse.patch
+++ /dev/null
@@ -1,6 +0,0 @@
-199,203d198
-< %ifidn __OUTPUT_FORMAT__, macho64
-< global _gf_vect_dot_prod_sse:ISAL_SYM_TYPE_FUNCTION
-< func(_gf_vect_dot_prod_sse)
-< %endif
-<
diff --git a/contrib/libs/isa-l/erasure_code/gf_vect_dot_prod_test.c b/contrib/libs/isa-l/erasure_code/gf_vect_dot_prod_test.c
index dbfc2da045..8300fbd70d 100644
--- a/contrib/libs/isa-l/erasure_code/gf_vect_dot_prod_test.c
+++ b/contrib/libs/isa-l/erasure_code/gf_vect_dot_prod_test.c
@@ -31,7 +31,7 @@
#include <stdlib.h>
#include <string.h> // for memset, memcmp
#include "erasure_code.h"
-// #include "types.h"
+#include "test.h"
#ifndef FUNCTION_UNDER_TEST
# define FUNCTION_UNDER_TEST gf_vect_dot_prod
@@ -43,7 +43,7 @@
#define str(s) #s
#define xstr(s) str(s)
-#define TEST_LEN 2048
+#define TEST_LEN 8192
#define TEST_SIZE (TEST_LEN/2)
#ifndef TEST_SOURCES
@@ -171,8 +171,11 @@ int main(int argc, char *argv[])
printf("dprod:");
dump(dest, 25);
return -1;
- } else
+ }
+#ifdef TEST_VERBOSE
+ else
putchar('.');
+#endif
// Rand data test
for (rtest = 0; rtest < RANDOMS; rtest++) {
@@ -199,7 +202,9 @@ int main(int argc, char *argv[])
return -1;
}
+#ifdef TEST_VERBOSE
putchar('.');
+#endif
}
// Rand data test with varied parameters
@@ -228,7 +233,9 @@ int main(int argc, char *argv[])
return -1;
}
+#ifdef TEST_VERBOSE
putchar('.');
+#endif
}
}
@@ -396,7 +403,9 @@ int main(int argc, char *argv[])
return -1;
}
}
+#ifdef TEST_VERBOSE
putchar('.');
+#endif
}
// Run tests at end of buffer for Electric Fence
@@ -428,7 +437,9 @@ int main(int argc, char *argv[])
return -1;
}
+#ifdef TEST_VERBOSE
putchar('.');
+#endif
}
// Test rand ptr alignment if available
@@ -485,7 +496,9 @@ int main(int argc, char *argv[])
return -1;
}
+#ifdef TEST_VERBOSE
putchar('.');
+#endif
}
// Test all size alignment
diff --git a/contrib/libs/isa-l/erasure_code/gf_vect_dot_prod_test.patch b/contrib/libs/isa-l/erasure_code/gf_vect_dot_prod_test.patch
deleted file mode 100644
index 21bbfaa667..0000000000
--- a/contrib/libs/isa-l/erasure_code/gf_vect_dot_prod_test.patch
+++ /dev/null
@@ -1,4 +0,0 @@
-34c34
-< // #include "types.h"
----
-> #include "types.h"
diff --git a/contrib/libs/isa-l/erasure_code/gf_vect_gfni.inc b/contrib/libs/isa-l/erasure_code/gf_vect_gfni.inc
new file mode 100644
index 0000000000..83d362bdae
--- /dev/null
+++ b/contrib/libs/isa-l/erasure_code/gf_vect_gfni.inc
@@ -0,0 +1,72 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; Copyright(c) 2023 Intel Corporation All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions
+; are met:
+; * Redistributions of source code must retain the above copyright
+; notice, this list of conditions and the following disclaimer.
+; * Redistributions in binary form must reproduce the above copyright
+; notice, this list of conditions and the following disclaimer in
+; the documentation and/or other materials provided with the
+; distribution.
+; * Neither the name of Intel Corporation nor the names of its
+; contributors may be used to endorse or promote products derived
+; from this software without specific prior written permission.
+;
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+; "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+; A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+; OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+; SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+; LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+; OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;
+; Multiply 1 source register to up to 6 different GF table registers
+; and XOR the results to partial registers
+;
+%macro GF_MUL_XOR 5-20
+%define %%ENCODING %1
+%define %%SRC %2
+%define %%GFTABLE1 %3
+%define %%TMP1 %4
+%define %%PARTIAL1 %5
+%define %%GFTABLE2 %6
+%define %%TMP2 %7
+%define %%PARTIAL2 %8
+%define %%GFTABLE3 %9
+%define %%TMP3 %10
+%define %%PARTIAL3 %11
+%define %%GFTABLE4 %12
+%define %%TMP4 %13
+%define %%PARTIAL4 %14
+%define %%GFTABLE5 %15
+%define %%TMP5 %16
+%define %%PARTIAL5 %17
+%define %%GFTABLE6 %18
+%define %%TMP6 %19
+%define %%PARTIAL6 %20
+
+%define %%N_BLOCKS ((%0 - 2) / 3)
+
+%assign %%I 1
+%rep %%N_BLOCKS
+ vgf2p8affineqb %%TMP %+ %%I, %%SRC, %%GFTABLE %+ %%I, 0x00
+%assign %%I (%%I + 1)
+%endrep
+%assign %%I 1
+%rep %%N_BLOCKS
+%ifidn %%ENCODING, VEX
+ vpxor %%PARTIAL %+ %%I, %%TMP %+ %%I
+%else
+ vpxorq %%PARTIAL %+ %%I, %%TMP %+ %%I
+%endif
+%assign %%I (%%I + 1)
+%endrep
+%endmacro
diff --git a/contrib/libs/isa-l/erasure_code/gf_vect_mad_avx.asm b/contrib/libs/isa-l/erasure_code/gf_vect_mad_avx.asm
index 1a252c474f..20a44d7aa3 100644
--- a/contrib/libs/isa-l/erasure_code/gf_vect_mad_avx.asm
+++ b/contrib/libs/isa-l/erasure_code/gf_vect_mad_avx.asm
@@ -82,7 +82,7 @@
%define return rax
%define return.w eax
- %define func(x) x:
+ %define func(x) x: endbranch
%define FUNC_SAVE
%define FUNC_RESTORE
%endif
@@ -131,13 +131,8 @@ section .text
%define xtmpd xmm5
align 16
-global gf_vect_mad_avx:ISAL_SYM_TYPE_FUNCTION
+global gf_vect_mad_avx, function
func(gf_vect_mad_avx)
-%ifidn __OUTPUT_FORMAT__, macho64
-global _gf_vect_mad_avx:ISAL_SYM_TYPE_FUNCTION
-func(_gf_vect_mad_avx)
-%endif
-
FUNC_SAVE
sub len, 16
jl .return_fail
@@ -196,6 +191,3 @@ section .data
align 16
mask0f: dq 0x0f0f0f0f0f0f0f0f, 0x0f0f0f0f0f0f0f0f
-
-;;; func core, ver, snum
-slversion gf_vect_mad_avx, 02, 01, 0201
diff --git a/contrib/libs/isa-l/erasure_code/gf_vect_mad_avx.patch b/contrib/libs/isa-l/erasure_code/gf_vect_mad_avx.patch
deleted file mode 100644
index e3932a80b5..0000000000
--- a/contrib/libs/isa-l/erasure_code/gf_vect_mad_avx.patch
+++ /dev/null
@@ -1,6 +0,0 @@
-136,140d135
-< %ifidn __OUTPUT_FORMAT__, macho64
-< global _gf_vect_mad_avx:ISAL_SYM_TYPE_FUNCTION
-< func(_gf_vect_mad_avx)
-< %endif
-<
diff --git a/contrib/libs/isa-l/erasure_code/gf_vect_mad_avx2.asm b/contrib/libs/isa-l/erasure_code/gf_vect_mad_avx2.asm
index 9b24c6e62a..c833f5e98c 100644
--- a/contrib/libs/isa-l/erasure_code/gf_vect_mad_avx2.asm
+++ b/contrib/libs/isa-l/erasure_code/gf_vect_mad_avx2.asm
@@ -88,7 +88,7 @@
%define return rax
%define return.w eax
- %define func(x) x:
+ %define func(x) x: endbranch
%define FUNC_SAVE
%define FUNC_RESTORE
%endif
@@ -139,13 +139,8 @@ section .text
%define xtmpd ymm5
align 16
-global gf_vect_mad_avx2:ISAL_SYM_TYPE_FUNCTION
+global gf_vect_mad_avx2, function
func(gf_vect_mad_avx2)
-%ifidn __OUTPUT_FORMAT__, macho64
-global _gf_vect_mad_avx2:ISAL_SYM_TYPE_FUNCTION
-func(_gf_vect_mad_avx2)
-%endif
-
FUNC_SAVE
sub len, 32
jl .return_fail
@@ -201,8 +196,3 @@ func(_gf_vect_mad_avx2)
ret
endproc_frame
-
-section .data
-
-;;; func core, ver, snum
-slversion gf_vect_mad_avx2, 04, 01, 0202
diff --git a/contrib/libs/isa-l/erasure_code/gf_vect_mad_avx2.patch b/contrib/libs/isa-l/erasure_code/gf_vect_mad_avx2.patch
deleted file mode 100644
index 9d37d75b8d..0000000000
--- a/contrib/libs/isa-l/erasure_code/gf_vect_mad_avx2.patch
+++ /dev/null
@@ -1,6 +0,0 @@
-144,148d143
-< %ifidn __OUTPUT_FORMAT__, macho64
-< global _gf_vect_mad_avx2:ISAL_SYM_TYPE_FUNCTION
-< func(_gf_vect_mad_avx2)
-< %endif
-<
diff --git a/contrib/libs/isa-l/erasure_code/gf_vect_mad_avx2_gfni.asm b/contrib/libs/isa-l/erasure_code/gf_vect_mad_avx2_gfni.asm
new file mode 100644
index 0000000000..29af12a0fc
--- /dev/null
+++ b/contrib/libs/isa-l/erasure_code/gf_vect_mad_avx2_gfni.asm
@@ -0,0 +1,255 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; Copyright(c) 2023 Intel Corporation All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions
+; are met:
+; * Redistributions of source code must retain the above copyright
+; notice, this list of conditions and the following disclaimer.
+; * Redistributions in binary form must reproduce the above copyright
+; notice, this list of conditions and the following disclaimer in
+; the documentation and/or other materials provided with the
+; distribution.
+; * Neither the name of Intel Corporation nor the names of its
+; contributors may be used to endorse or promote products derived
+; from this software without specific prior written permission.
+;
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+; "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+; A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+; OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+; SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+; LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+; OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;;;
+;;; gf_vect_mad_avx2_gfni(len, vec, vec_i, mul_array, src, dest);
+;;;
+
+%include "reg_sizes.asm"
+%include "gf_vect_gfni.inc"
+%include "memcpy.asm"
+
+%if AS_FEATURE_LEVEL >= 10
+
+%ifidn __OUTPUT_FORMAT__, elf64
+ %define arg0 rdi
+ %define arg1 rsi
+ %define arg2 rdx
+ %define arg3 rcx
+ %define arg4 r8
+ %define arg5 r9
+ %define tmp r11
+ %define tmp2 r10
+ %define func(x) x: endbranch
+ %define FUNC_SAVE
+ %define FUNC_RESTORE
+%endif
+
+%ifidn __OUTPUT_FORMAT__, win64
+ %define arg0 rcx
+ %define arg1 rdx
+ %define arg2 r8
+ %define arg3 r9
+ %define arg4 r12 ; must be saved, loaded and restored
+ %define arg5 r13 ; must be saved and restored
+ %define tmp r11
+ %define tmp2 r10
+ %define stack_size 16*3 + 3*8
+ %define arg(x) [rsp + stack_size + 8 + 8*x]
+ %define func(x) proc_frame x
+
+ %macro FUNC_SAVE 0
+ sub rsp, stack_size
+ vmovdqa [rsp + 0*16], xmm6
+ vmovdqa [rsp + 1*16], xmm7
+ vmovdqa [rsp + 2*16], xmm8
+ mov [rsp + 3*16 + 0*8], r12
+ mov [rsp + 3*16 + 1*8], r13
+ end_prolog
+ mov arg4, arg(4)
+ mov arg5, arg(5)
+ %endmacro
+
+ %macro FUNC_RESTORE 0
+ vmovdqa xmm6, [rsp + 0*16]
+ vmovdqa xmm7, [rsp + 1*16]
+ vmovdqa xmm8, [rsp + 2*16]
+ mov r12, [rsp + 3*16 + 0*8]
+ mov r13, [rsp + 3*16 + 1*8]
+ add rsp, stack_size
+ %endmacro
+%endif
+
+%define len arg0
+%define vec arg1
+%define vec_i arg2
+%define mul_array arg3
+%define src arg4
+%define dest1 arg5
+%define pos rax
+
+%ifndef EC_ALIGNED_ADDR
+;;; Use Un-aligned load/store
+ %define XLDR vmovdqu
+ %define XSTR vmovdqu
+%else
+;;; Use Non-temporal load/stor
+ %ifdef NO_NT_LDST
+ %define XLDR vmovdqa
+ %define XSTR vmovdqa
+ %else
+ %define XLDR vmovntdqa
+ %define XSTR vmovntdq
+ %endif
+%endif
+
+default rel
+[bits 64]
+section .text
+
+%define x0l ymm0
+%define x0h ymm1
+%define x0x ymm2
+
+%define xgft1 ymm3
+
+%define xd1l ymm4
+%define xd1h ymm5
+%define xd1x ymm6
+
+%define xret1l ymm7
+%define xret1h ymm8
+
+%define x0 x0l
+%define xd1 xd1l
+%define xret1 xret1l
+
+;;
+;; Encodes 96 bytes of a single source and updates a single parity disk
+;;
+%macro ENCODE_96B 0
+ ;; get next source vector
+ XLDR x0l, [src + pos]
+ XLDR x0h, [src + pos + 32]
+ XLDR x0x, [src + pos + 64]
+ ;; get next dest vector
+ XLDR xd1l, [dest1 + pos]
+ XLDR xd1h, [dest1 + pos + 32]
+ XLDR xd1x, [dest1 + pos + 64]
+
+ GF_MUL_XOR VEX, x0l, xgft1, xret1l, xd1l
+ GF_MUL_XOR VEX, x0h, xgft1, xret1h, xd1h
+ GF_MUL_XOR VEX, x0x, xgft1, xret1l, xd1x
+
+ XSTR [dest1 + pos], xd1l
+ XSTR [dest1 + pos + 32], xd1h
+ XSTR [dest1 + pos + 64], xd1x
+%endmacro
+
+;;
+;; Encodes 64 bytes of a single source and updates a single parity disk
+;;
+%macro ENCODE_64B 0
+ ;; get next source vector
+ XLDR x0l, [src + pos]
+ XLDR x0h, [src + pos + 32]
+ ;; get next dest vector
+ XLDR xd1l, [dest1 + pos]
+ XLDR xd1h, [dest1 + pos + 32]
+
+ GF_MUL_XOR VEX, x0l, xgft1, xret1l, xd1l
+ GF_MUL_XOR VEX, x0h, xgft1, xret1h, xd1h
+
+ XSTR [dest1 + pos], xd1l
+ XSTR [dest1 + pos + 32], xd1h
+%endmacro
+
+;;
+;; Encodes 32 bytes of a single source and updates single parity disk
+;;
+%macro ENCODE_32B 0
+ ;; get next source vector
+ XLDR x0, [src + pos]
+ ;; get next dest vector
+ XLDR xd1, [dest1 + pos]
+
+ GF_MUL_XOR VEX, x0, xgft1, xret1, xd1
+
+ XSTR [dest1 + pos], xd1
+%endmacro
+
+;;
+;; Encodes less than 32 bytes of a single source and updates parity disk
+;;
+%macro ENCODE_LT_32B 1
+%define %%LEN %1
+ ;; get next source vector
+ simd_load_avx2 x0, src + pos, %%LEN, tmp, tmp2
+ ;; get next dest vector
+ simd_load_avx2 xd1, dest1 + pos, %%LEN, tmp, tmp2
+
+ GF_MUL_XOR VEX, x0, xgft1, xret1, xd1
+
+ lea dest1, [dest1 + pos]
+ simd_store_avx2 dest1, xd1, %%LEN, tmp, tmp2
+%endmacro
+
+align 16
+global gf_vect_mad_avx2_gfni, function
+func(gf_vect_mad_avx2_gfni)
+ FUNC_SAVE
+
+ xor pos, pos
+ shl vec_i, 3 ;Multiply by 8
+ shl vec, 3 ;Multiply by 8
+ lea tmp, [mul_array + vec_i]
+ vbroadcastsd xgft1, [tmp]
+
+ cmp len, 96
+ jl .len_lt_96
+
+.loop96:
+ ENCODE_96B ;; loop on 96 bytes at a time
+ add pos, 96
+ sub len, 96
+ cmp len, 96
+ jge .loop96
+
+.len_lt_96:
+ cmp len, 64
+ jl .len_lt_64
+
+ ENCODE_64B ;; encode next 64 bytes
+
+ add pos, 64
+ sub len, 64
+
+.len_lt_64:
+ cmp len, 32
+ jl .len_lt_32
+
+ ENCODE_32B ;; encode next 32 bytes
+
+ add pos, 32
+ sub len, 32
+
+.len_lt_32:
+ cmp len, 0
+ jle .exit
+
+ ENCODE_LT_32B len ;; encode final bytes
+
+.exit:
+ vzeroupper
+
+ FUNC_RESTORE
+ ret
+
+endproc_frame
+%endif ; if AS_FEATURE_LEVEL >= 10
diff --git a/contrib/libs/isa-l/erasure_code/gf_vect_mad_avx512.asm b/contrib/libs/isa-l/erasure_code/gf_vect_mad_avx512.asm
index adc2acf3e8..6f1bf35197 100644
--- a/contrib/libs/isa-l/erasure_code/gf_vect_mad_avx512.asm
+++ b/contrib/libs/isa-l/erasure_code/gf_vect_mad_avx512.asm
@@ -44,7 +44,7 @@
%define arg5 r9
%define tmp r11
%define return rax
- %define func(x) x:
+ %define func(x) x: endbranch
%define FUNC_SAVE
%define FUNC_RESTORE
%endif
@@ -101,8 +101,8 @@
%else
;;; Use Non-temporal load/stor
%ifdef NO_NT_LDST
- %define XLDR vmovdqa
- %define XSTR vmovdqa
+ %define XLDR vmovdqa64
+ %define XSTR vmovdqa64
%else
%define XLDR vmovntdqa
%define XSTR vmovntdq
@@ -127,13 +127,8 @@ section .text
%define xmask0f zmm8
align 16
-global gf_vect_mad_avx512:ISAL_SYM_TYPE_FUNCTION
+global gf_vect_mad_avx512, function
func(gf_vect_mad_avx512)
-%ifidn __OUTPUT_FORMAT__, macho64
-global _gf_vect_mad_avx512:ISAL_SYM_TYPE_FUNCTION
-func(_gf_vect_mad_avx512)
-%endif
-
FUNC_SAVE
sub len, 64
jl .return_fail
diff --git a/contrib/libs/isa-l/erasure_code/gf_vect_mad_avx512.patch b/contrib/libs/isa-l/erasure_code/gf_vect_mad_avx512.patch
deleted file mode 100644
index 9a20fa281a..0000000000
--- a/contrib/libs/isa-l/erasure_code/gf_vect_mad_avx512.patch
+++ /dev/null
@@ -1,6 +0,0 @@
-132,136d131
-< %ifidn __OUTPUT_FORMAT__, macho64
-< global _gf_vect_mad_avx512:ISAL_SYM_TYPE_FUNCTION
-< func(_gf_vect_mad_avx512)
-< %endif
-<
diff --git a/contrib/libs/isa-l/erasure_code/gf_vect_mad_avx512_gfni.asm b/contrib/libs/isa-l/erasure_code/gf_vect_mad_avx512_gfni.asm
new file mode 100644
index 0000000000..09073ce157
--- /dev/null
+++ b/contrib/libs/isa-l/erasure_code/gf_vect_mad_avx512_gfni.asm
@@ -0,0 +1,175 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; Copyright(c) 2023 Intel Corporation All rights reserved.
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions
+; are met:
+; * Redistributions of source code must retain the above copyright
+; notice, this list of conditions and the following disclaimer.
+; * Redistributions in binary form must reproduce the above copyright
+; notice, this list of conditions and the following disclaimer in
+; the documentation and/or other materials provided with the
+; distribution.
+; * Neither the name of Intel Corporation nor the names of its
+; contributors may be used to endorse or promote products derived
+; from this software without specific prior written permission.
+;
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+; "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+; A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+; OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+; SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+; LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+; OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;;;
+;;; gf_vect_mad_avx512_gfni(len, vec, vec_i, mul_array, src, dest);
+;;;
+
+%include "reg_sizes.asm"
+%include "gf_vect_gfni.inc"
+
+%if AS_FEATURE_LEVEL >= 10
+
+%ifidn __OUTPUT_FORMAT__, elf64
+ %define arg0 rdi
+ %define arg1 rsi
+ %define arg2 rdx
+ %define arg3 rcx
+ %define arg4 r8
+ %define arg5 r9
+ %define tmp r11
+ %define func(x) x: endbranch
+ %define FUNC_SAVE
+ %define FUNC_RESTORE
+%endif
+
+%ifidn __OUTPUT_FORMAT__, win64
+ %define arg0 rcx
+ %define arg1 rdx
+ %define arg2 r8
+ %define arg3 r9
+ %define arg4 r12 ; must be saved and loaded
+ %define arg5 r13
+ %define tmp r11
+ %define stack_size 3*8
+ %define arg(x) [rsp + stack_size + 8 + 8*x]
+ %define func(x) proc_frame x
+
+ %macro FUNC_SAVE 0
+ sub rsp, stack_size
+ mov [rsp + 0*8], r12
+ mov [rsp + 1*8], r13
+ end_prolog
+ mov arg4, arg(4)
+ mov arg5, arg(5)
+ %endmacro
+
+ %macro FUNC_RESTORE 0
+ mov r12, [rsp + 0*8]
+ mov r13, [rsp + 1*8]
+ add rsp, stack_size
+ %endmacro
+%endif
+
+;;; gf_vect_mad_avx512_gfni(len, vec, vec_i, mul_array, src, dest)
+%define len arg0
+%define vec arg1
+%define vec_i arg2
+%define mul_array arg3
+%define src arg4
+%define dest arg5
+%define pos rax
+
+%ifndef EC_ALIGNED_ADDR
+;;; Use Un-aligned load/store
+ %define XLDR vmovdqu8
+ %define XSTR vmovdqu8
+%else
+;;; Use Non-temporal load/stor
+ %ifdef NO_NT_LDST
+ %define XLDR vmovdqa64
+ %define XSTR vmovdqa64
+ %else
+ %define XLDR vmovntdqa
+ %define XSTR vmovntdq
+ %endif
+%endif
+
+
+default rel
+
+[bits 64]
+section .text
+
+%define x0 zmm0
+%define xd zmm1
+%define xgft1 zmm2
+%define xret1 zmm3
+
+;;
+;; Encodes 64 bytes of a single source into 64 bytes (single parity disk)
+;;
+%macro ENCODE_64B 0-1
+%define %%KMASK %1
+
+%if %0 == 1
+ vmovdqu8 x0{%%KMASK}, [src + pos] ;Get next source vector
+ vmovdqu8 xd{%%KMASK}, [dest + pos] ;Get next dest vector
+%else
+ XLDR x0, [src + pos] ;Get next source vector
+ XLDR xd, [dest + pos] ;Get next dest vector
+%endif
+
+ GF_MUL_XOR EVEX, x0, xgft1, xret1, xd
+
+%if %0 == 1
+ vmovdqu8 [dest + pos]{%%KMASK}, xd
+%else
+ XSTR [dest + pos], xd
+%endif
+%endmacro
+
+align 16
+global gf_vect_mad_avx512_gfni, function
+func(gf_vect_mad_avx512_gfni)
+ FUNC_SAVE
+ xor pos, pos
+ shl vec_i, 3 ;Multiply by 8
+
+ vbroadcastf32x2 xgft1, [vec_i + mul_array]
+
+ cmp len, 64
+ jl .len_lt_64
+.loop64:
+ ENCODE_64B
+
+ add pos, 64 ;Loop on 64 bytes at a time
+ sub len, 64
+ cmp len, 64
+ jge .loop64
+
+.len_lt_64:
+ cmp len, 0
+ jle .exit
+
+ xor tmp, tmp
+ bts tmp, len
+ dec tmp
+ kmovq k1, tmp
+
+ ENCODE_64B k1
+
+.exit:
+ vzeroupper
+
+ FUNC_RESTORE
+ ret
+
+endproc_frame
+%endif ; if AS_FEATURE_LEVEL >= 10
diff --git a/contrib/libs/isa-l/erasure_code/gf_vect_mad_sse.asm b/contrib/libs/isa-l/erasure_code/gf_vect_mad_sse.asm
index ea48612324..c3afe72041 100644
--- a/contrib/libs/isa-l/erasure_code/gf_vect_mad_sse.asm
+++ b/contrib/libs/isa-l/erasure_code/gf_vect_mad_sse.asm
@@ -82,7 +82,7 @@
%define return rax
%define return.w eax
- %define func(x) x:
+ %define func(x) x: endbranch
%define FUNC_SAVE
%define FUNC_RESTORE
%endif
@@ -131,13 +131,8 @@ section .text
align 16
-global gf_vect_mad_sse:ISAL_SYM_TYPE_FUNCTION
+global gf_vect_mad_sse, function
func(gf_vect_mad_sse)
-%ifidn __OUTPUT_FORMAT__, macho64
-global _gf_vect_mad_sse:ISAL_SYM_TYPE_FUNCTION
-func(_gf_vect_mad_sse)
-%endif
-
FUNC_SAVE
sub len, 16
jl .return_fail
@@ -197,6 +192,3 @@ section .data
align 16
mask0f: dq 0x0f0f0f0f0f0f0f0f, 0x0f0f0f0f0f0f0f0f
-
-;;; func core, ver, snum
-slversion gf_vect_mad_sse, 00, 01, 0200
diff --git a/contrib/libs/isa-l/erasure_code/gf_vect_mad_sse.patch b/contrib/libs/isa-l/erasure_code/gf_vect_mad_sse.patch
deleted file mode 100644
index 9af95a1e02..0000000000
--- a/contrib/libs/isa-l/erasure_code/gf_vect_mad_sse.patch
+++ /dev/null
@@ -1,6 +0,0 @@
-136,140d135
-< %ifidn __OUTPUT_FORMAT__, macho64
-< global _gf_vect_mad_sse:ISAL_SYM_TYPE_FUNCTION
-< func(_gf_vect_mad_sse)
-< %endif
-<
diff --git a/contrib/libs/isa-l/erasure_code/gf_vect_mad_test.c b/contrib/libs/isa-l/erasure_code/gf_vect_mad_test.c
index e2cbc1063d..3a552b2c08 100644
--- a/contrib/libs/isa-l/erasure_code/gf_vect_mad_test.c
+++ b/contrib/libs/isa-l/erasure_code/gf_vect_mad_test.c
@@ -31,7 +31,7 @@
#include <stdlib.h>
#include <string.h> // for memset, memcmp
#include "erasure_code.h"
-// #include "types.h"
+#include "test.h"
#ifndef ALIGN_SIZE
# define ALIGN_SIZE 32
@@ -51,7 +51,7 @@
#define str(s) #s
#define xstr(s) str(s)
-#define TEST_LEN 2048
+#define TEST_LEN 8192
#define TEST_SIZE (TEST_LEN/2)
#define TEST_MEM TEST_SIZE
#define TEST_LOOPS 20000
@@ -249,7 +249,9 @@ int main(int argc, char *argv[])
}
}
+#ifdef TEST_VERBOSE
putchar('.');
+#endif
// Rand data test
@@ -294,7 +296,9 @@ int main(int argc, char *argv[])
}
}
+#ifdef TEST_VERBOSE
putchar('.');
+#endif
}
// Rand data test with varied parameters
@@ -340,7 +344,9 @@ int main(int argc, char *argv[])
}
}
+#ifdef TEST_VERBOSE
putchar('.');
+#endif
}
}
@@ -390,7 +396,9 @@ int main(int argc, char *argv[])
}
}
+#ifdef TEST_VERBOSE
putchar('.');
+#endif
}
// Test rand ptr alignment if available
@@ -462,7 +470,9 @@ int main(int argc, char *argv[])
}
}
+#ifdef TEST_VERBOSE
putchar('.');
+#endif
}
// Test all size alignment
@@ -509,7 +519,9 @@ int main(int argc, char *argv[])
}
}
+#ifdef TEST_VERBOSE
putchar('.');
+#endif
}
diff --git a/contrib/libs/isa-l/erasure_code/gf_vect_mad_test.patch b/contrib/libs/isa-l/erasure_code/gf_vect_mad_test.patch
deleted file mode 100644
index 21bbfaa667..0000000000
--- a/contrib/libs/isa-l/erasure_code/gf_vect_mad_test.patch
+++ /dev/null
@@ -1,4 +0,0 @@
-34c34
-< // #include "types.h"
----
-> #include "types.h"
diff --git a/contrib/libs/isa-l/erasure_code/gf_vect_mul_avx.asm b/contrib/libs/isa-l/erasure_code/gf_vect_mul_avx.asm
index 86121b298a..d8d8c4c050 100644
--- a/contrib/libs/isa-l/erasure_code/gf_vect_mul_avx.asm
+++ b/contrib/libs/isa-l/erasure_code/gf_vect_mul_avx.asm
@@ -38,11 +38,8 @@
%define arg1 rsi
%define arg2 rdx
%define arg3 rcx
- %define arg4 r8
- %define arg5 r9
- %define tmp r11
%define return rax
- %define func(x) x:
+ %define func(x) x: endbranch
%define FUNC_SAVE
%define FUNC_RESTORE
@@ -56,11 +53,11 @@
%define func(x) proc_frame x
%macro FUNC_SAVE 0
alloc_stack stack_size
- save_xmm128 xmm6, 0*16
- save_xmm128 xmm7, 1*16
- save_xmm128 xmm13, 2*16
- save_xmm128 xmm14, 3*16
- save_xmm128 xmm15, 4*16
+ vmovdqa [rsp + 0*16], xmm6
+ vmovdqa [rsp + 1*16], xmm7
+ vmovdqa [rsp + 2*16], xmm13
+ vmovdqa [rsp + 3*16], xmm14
+ vmovdqa [rsp + 4*16], xmm15
end_prolog
%endmacro
@@ -81,6 +78,7 @@
%define src arg2
%define dest arg3
%define pos return
+%define tmp r11
;;; Use Non-temporal load/stor
@@ -111,13 +109,16 @@ section .text
%define xtmp2c xmm7
align 16
-global gf_vect_mul_avx:ISAL_SYM_TYPE_FUNCTION
+global gf_vect_mul_avx, function
func(gf_vect_mul_avx)
-%ifidn __OUTPUT_FORMAT__, macho64
-global _gf_vect_mul_avx:ISAL_SYM_TYPE_FUNCTION
-func(_gf_vect_mul_avx)
-%endif
+
+ ; Check if length is multiple of 32 bytes
+ mov tmp, len
+ and tmp, 0x1f
+ jnz return_fail
+
FUNC_SAVE
+
mov pos, 0
vmovdqa xmask0f, [mask0f] ;Load mask of lower nibble in each byte
vmovdqu xgft_lo, [mul_array] ;Load array Cx{00}, Cx{01}, Cx{02}, ...
@@ -144,14 +145,13 @@ loop32:
XSTR [dest+pos-16], xtmp2b ;Store +16B result
jl loop32
+ FUNC_RESTORE
return_pass:
- FUNC_RESTORE
- sub pos, len
+ xor return, return
ret
return_fail:
- FUNC_RESTORE
mov return, 1
ret
@@ -163,6 +163,3 @@ align 16
mask0f:
dq 0x0f0f0f0f0f0f0f0f, 0x0f0f0f0f0f0f0f0f
-
-;;; func core, ver, snum
-slversion gf_vect_mul_avx, 01, 03, 0036
diff --git a/contrib/libs/isa-l/erasure_code/gf_vect_mul_avx.patch b/contrib/libs/isa-l/erasure_code/gf_vect_mul_avx.patch
deleted file mode 100644
index 99d4bd2d35..0000000000
--- a/contrib/libs/isa-l/erasure_code/gf_vect_mul_avx.patch
+++ /dev/null
@@ -1,5 +0,0 @@
-116,119d115
-< %ifidn __OUTPUT_FORMAT__, macho64
-< global _gf_vect_mul_avx:ISAL_SYM_TYPE_FUNCTION
-< func(_gf_vect_mul_avx)
-< %endif
diff --git a/contrib/libs/isa-l/erasure_code/gf_vect_mul_base_test.c b/contrib/libs/isa-l/erasure_code/gf_vect_mul_base_test.c
index 81f04c4443..5ac40cd079 100644
--- a/contrib/libs/isa-l/erasure_code/gf_vect_mul_base_test.c
+++ b/contrib/libs/isa-l/erasure_code/gf_vect_mul_base_test.c
@@ -63,7 +63,10 @@ int main(int argc, char *argv[])
for (i = 0; i < TEST_SIZE; i++)
buff1[i] = rand();
- gf_vect_mul_base(TEST_SIZE, gf_const_tbl, buff1, buff2);
+ if (gf_vect_mul_base(TEST_SIZE, gf_const_tbl, buff1, buff2) != 0) {
+ printf("fail fill with rand data\n");
+ return 1;
+ }
for (i = 0; i < TEST_SIZE; i++)
if (gf_mul_erasure(a, buff1[i]) != buff2[i]) {
@@ -72,8 +75,10 @@ int main(int argc, char *argv[])
return 1;
}
- gf_vect_mul_base(TEST_SIZE, gf_const_tbl, buff1, buff3);
-
+ if (gf_vect_mul_base(TEST_SIZE, gf_const_tbl, buff1, buff3) != 0) {
+ printf("fail fill with rand data for buff1\n");
+ return -1;
+ }
// Check reference function
for (i = 0; i < TEST_SIZE; i++)
if (buff2[i] != buff3[i]) {
@@ -89,7 +94,10 @@ int main(int argc, char *argv[])
printf("Random tests ");
for (a = 0; a != 255; a++) {
gf_vect_mul_init(a, gf_const_tbl);
- gf_vect_mul_base(TEST_SIZE, gf_const_tbl, buff1, buff2);
+ if (gf_vect_mul_base(TEST_SIZE, gf_const_tbl, buff1, buff2) != 0) {
+ printf("fail random tests\n");
+ return 1;
+ }
for (i = 0; i < TEST_SIZE; i++)
if (gf_mul_erasure(a, buff1[i]) != buff2[i]) {
@@ -97,7 +105,9 @@ int main(int argc, char *argv[])
i, a, buff1[i], buff2[i], gf_mul_erasure(2, buff1[i]));
return 1;
}
+#ifdef TEST_VERBOSE
putchar('.');
+#endif
}
// Run tests at end of buffer for Electric Fence
@@ -110,7 +120,11 @@ int main(int argc, char *argv[])
efence_buff1 = buff1 + size;
efence_buff2 = buff2 + size;
- gf_vect_mul_base(TEST_SIZE - size, gf_const_tbl, efence_buff1, efence_buff2);
+ if (gf_vect_mul_base
+ (TEST_SIZE - size, gf_const_tbl, efence_buff1, efence_buff2) != 0) {
+ printf("fail tests at end of buffer\n");
+ return -1;
+ }
for (i = 0; i < TEST_SIZE - size; i++)
if (gf_mul_erasure(a, efence_buff1[i]) != efence_buff2[i]) {
@@ -121,7 +135,9 @@ int main(int argc, char *argv[])
return 1;
}
+#ifdef TEST_VERBOSE
putchar('.');
+#endif
}
printf(" done: Pass\n");
diff --git a/contrib/libs/isa-l/erasure_code/gf_vect_mul_base_test.patch b/contrib/libs/isa-l/erasure_code/gf_vect_mul_base_test.patch
deleted file mode 100644
index 84c965985f..0000000000
--- a/contrib/libs/isa-l/erasure_code/gf_vect_mul_base_test.patch
+++ /dev/null
@@ -1,28 +0,0 @@
-69c69
-< if (gf_mul_erasure(a, buff1[i]) != buff2[i]) {
----
-> if (gf_mul(a, buff1[i]) != buff2[i]) {
-71c71
-< gf_mul_erasure(2, buff1[i]));
----
-> gf_mul(2, buff1[i]));
-81c81
-< i, a, buff1[i], buff2[i], gf_mul_erasure(a, buff1[i]));
----
-> i, a, buff1[i], buff2[i], gf_mul(a, buff1[i]));
-95c95
-< if (gf_mul_erasure(a, buff1[i]) != buff2[i]) {
----
-> if (gf_mul(a, buff1[i]) != buff2[i]) {
-97c97
-< i, a, buff1[i], buff2[i], gf_mul_erasure(2, buff1[i]));
----
-> i, a, buff1[i], buff2[i], gf_mul(2, buff1[i]));
-116c116
-< if (gf_mul_erasure(a, efence_buff1[i]) != efence_buff2[i]) {
----
-> if (gf_mul(a, efence_buff1[i]) != efence_buff2[i]) {
-118c118
-< i, efence_buff1[i], efence_buff2[i], gf_mul_erasure(2,
----
-> i, efence_buff1[i], efence_buff2[i], gf_mul(2,
diff --git a/contrib/libs/isa-l/erasure_code/gf_vect_mul_perf.c b/contrib/libs/isa-l/erasure_code/gf_vect_mul_perf.c
index 58194ccebc..ae41cee43e 100644
--- a/contrib/libs/isa-l/erasure_code/gf_vect_mul_perf.c
+++ b/contrib/libs/isa-l/erasure_code/gf_vect_mul_perf.c
@@ -33,21 +33,22 @@
#include "erasure_code.h"
#include "test.h"
-//#define CACHED_TEST
-#ifdef CACHED_TEST
+#ifndef GT_L3_CACHE
+# define GT_L3_CACHE 32*1024*1024 /* some number > last level cache */
+#endif
+
+#if !defined(COLD_TEST) && !defined(TEST_CUSTOM)
// Cached test, loop many times over small dataset
+# define TEST_SOURCES 10
# define TEST_LEN 8*1024
# define TEST_TYPE_STR "_warm"
-#else
-# ifndef TEST_CUSTOM
+#elif defined (COLD_TEST)
// Uncached test. Pull from large mem base.
-# define TEST_SOURCES 10
-# define GT_L3_CACHE 32*1024*1024 /* some number > last level cache */
-# define TEST_LEN GT_L3_CACHE / 2
-# define TEST_TYPE_STR "_cold"
-# else
-# define TEST_TYPE_STR "_cus"
-# endif
+# define TEST_SOURCES 10
+# define TEST_LEN (GT_L3_CACHE / 2)
+# define TEST_TYPE_STR "_cold"
+#elif defined (TEST_CUSTOM)
+# define TEST_TYPE_STR "_cus"
#endif
#define TEST_MEM (2 * TEST_LEN)
diff --git a/contrib/libs/isa-l/erasure_code/gf_vect_mul_sse.asm b/contrib/libs/isa-l/erasure_code/gf_vect_mul_sse.asm
index 01a3269d65..ddccb129e1 100644
--- a/contrib/libs/isa-l/erasure_code/gf_vect_mul_sse.asm
+++ b/contrib/libs/isa-l/erasure_code/gf_vect_mul_sse.asm
@@ -38,11 +38,8 @@
%define arg1 rsi
%define arg2 rdx
%define arg3 rcx
- %define arg4 r8
- %define arg5 r9
- %define tmp r11
%define return rax
- %define func(x) x:
+ %define func(x) x: endbranch
%define FUNC_SAVE
%define FUNC_RESTORE
@@ -81,6 +78,7 @@
%define src arg2
%define dest arg3
%define pos return
+%define tmp r11
;;; Use Non-temporal load/stor
@@ -112,14 +110,15 @@ section .text
align 16
-global gf_vect_mul_sse:ISAL_SYM_TYPE_FUNCTION
+global gf_vect_mul_sse, function
func(gf_vect_mul_sse)
-%ifidn __OUTPUT_FORMAT__, macho64
-global _gf_vect_mul_sse:ISAL_SYM_TYPE_FUNCTION
-func(_gf_vect_mul_sse)
-%endif
+ ; Check if length is multiple of 32 bytes
+ mov tmp, len
+ and tmp, 0x1f
+ jnz return_fail
FUNC_SAVE
+
mov pos, 0
movdqa xmask0f, [mask0f] ;Load mask of lower nibble in each byte
movdqu xgft_lo, [mul_array] ;Load array Cx{00}, Cx{01}, Cx{02}, ...
@@ -152,15 +151,14 @@ loop32:
cmp pos, len
jl loop32
+ FUNC_RESTORE
return_pass:
- sub pos, len
- FUNC_RESTORE
+ xor return, return
ret
return_fail:
mov return, 1
- FUNC_RESTORE
ret
endproc_frame
@@ -170,6 +168,3 @@ section .data
align 16
mask0f:
dq 0x0f0f0f0f0f0f0f0f, 0x0f0f0f0f0f0f0f0f
-
-;;; func core, ver, snum
-slversion gf_vect_mul_sse, 00, 03, 0034
diff --git a/contrib/libs/isa-l/erasure_code/gf_vect_mul_sse.patch b/contrib/libs/isa-l/erasure_code/gf_vect_mul_sse.patch
deleted file mode 100644
index 93027e3cf7..0000000000
--- a/contrib/libs/isa-l/erasure_code/gf_vect_mul_sse.patch
+++ /dev/null
@@ -1,6 +0,0 @@
-117,121d116
-< %ifidn __OUTPUT_FORMAT__, macho64
-< global _gf_vect_mul_sse:ISAL_SYM_TYPE_FUNCTION
-< func(_gf_vect_mul_sse)
-< %endif
-<
diff --git a/contrib/libs/isa-l/erasure_code/gf_vect_mul_test.c b/contrib/libs/isa-l/erasure_code/gf_vect_mul_test.c
index c34e88b889..7e6457879c 100644
--- a/contrib/libs/isa-l/erasure_code/gf_vect_mul_test.c
+++ b/contrib/libs/isa-l/erasure_code/gf_vect_mul_test.c
@@ -31,14 +31,14 @@
#include <stdlib.h>
#include "erasure_code.h"
-#define TEST_SIZE (64*1024)
+#define TEST_SIZE (128*1024)
typedef unsigned char u8;
int main(int argc, char *argv[])
{
- int i;
- u8 *buff1, *buff2, *buff3, gf_const_tbl[64], a = 2;
+ int i, ret = -1;
+ u8 *buff1 = NULL, *buff2 = NULL, *buff3 = NULL, gf_const_tbl[64], a = 2;
int tsize;
int align, size;
unsigned char *efence_buff1;
@@ -55,30 +55,35 @@ int main(int argc, char *argv[])
if (NULL == buff1 || NULL == buff2 || NULL == buff3) {
printf("buffer alloc error\n");
- return -1;
+ goto exit;
}
// Fill with rand data
for (i = 0; i < TEST_SIZE; i++)
buff1[i] = rand();
- gf_vect_mul(TEST_SIZE, gf_const_tbl, buff1, buff2);
+ if (gf_vect_mul(TEST_SIZE, gf_const_tbl, buff1, buff2) != 0) {
+ printf("fail creating buff2\n");
+ goto exit;
+ }
for (i = 0; i < TEST_SIZE; i++) {
if (gf_mul_erasure(a, buff1[i]) != buff2[i]) {
printf("fail at %d, 0x%x x 2 = 0x%x (0x%x)\n", i,
buff1[i], buff2[i], gf_mul_erasure(2, buff1[i]));
- return -1;
+ goto exit;
}
}
- gf_vect_mul_base(TEST_SIZE, gf_const_tbl, buff1, buff3);
-
+ if (gf_vect_mul_base(TEST_SIZE, gf_const_tbl, buff1, buff3) != 0) {
+ printf("fail fill with rand data\n");
+ goto exit;
+ }
// Check reference function
for (i = 0; i < TEST_SIZE; i++) {
if (buff2[i] != buff3[i]) {
printf("fail at %d, 0x%x x 0x%d = 0x%x (0x%x)\n",
i, a, buff1[i], buff2[i], gf_mul_erasure(a, buff1[i]));
- return -1;
+ goto exit;
}
}
@@ -88,33 +93,43 @@ int main(int argc, char *argv[])
// Check each possible constant
for (a = 0; a != 255; a++) {
gf_vect_mul_init(a, gf_const_tbl);
- gf_vect_mul(TEST_SIZE, gf_const_tbl, buff1, buff2);
+ if (gf_vect_mul(TEST_SIZE, gf_const_tbl, buff1, buff2) != 0) {
+ printf("fail creating buff2\n");
+ goto exit;
+ }
for (i = 0; i < TEST_SIZE; i++)
if (gf_mul_erasure(a, buff1[i]) != buff2[i]) {
printf("fail at %d, 0x%x x %d = 0x%x (0x%x)\n",
i, a, buff1[i], buff2[i], gf_mul_erasure(2, buff1[i]));
- return -1;
+ goto exit;
}
+#ifdef TEST_VERBOSE
putchar('.');
+#endif
}
// Check buffer len
for (tsize = TEST_SIZE; tsize > 0; tsize -= 32) {
a = rand();
gf_vect_mul_init(a, gf_const_tbl);
- gf_vect_mul(tsize, gf_const_tbl, buff1, buff2);
+ if (gf_vect_mul(tsize, gf_const_tbl, buff1, buff2) != 0) {
+ printf("fail creating buff2 (len %d)\n", tsize);
+ goto exit;
+ }
for (i = 0; i < tsize; i++)
if (gf_mul_erasure(a, buff1[i]) != buff2[i]) {
printf("fail at %d, 0x%x x %d = 0x%x (0x%x)\n",
i, a, buff1[i], buff2[i], gf_mul_erasure(2, buff1[i]));
- return -1;
+ goto exit;
}
+#ifdef TEST_VERBOSE
if (0 == tsize % (32 * 8)) {
putchar('.');
fflush(0);
}
+#endif
}
// Run tests at end of buffer for Electric Fence
@@ -135,24 +150,46 @@ int main(int argc, char *argv[])
printf("fail at %d, 0x%x x 2 = 0x%x (0x%x)\n",
i, efence_buff1[i], efence_buff2[i],
gf_mul_erasure(2, efence_buff1[i]));
- return 1;
+ goto exit;
}
- gf_vect_mul_base(TEST_SIZE - size, gf_const_tbl, efence_buff1, efence_buff3);
-
+ if (gf_vect_mul_base
+ (TEST_SIZE - size, gf_const_tbl, efence_buff1, efence_buff3) != 0) {
+ printf("fail line up TEST_SIZE from end\n");
+ goto exit;
+ }
// Check reference function
for (i = 0; i < TEST_SIZE - size; i++)
if (efence_buff2[i] != efence_buff3[i]) {
printf("fail at %d, 0x%x x 0x%d = 0x%x (0x%x)\n",
i, a, efence_buff2[i], efence_buff3[i],
gf_mul_erasure(2, efence_buff1[i]));
- return 1;
+ goto exit;
}
-
+#ifdef TEST_VERBOSE
putchar('.');
+#endif
+ }
+
+ // Test all unsupported sizes up to TEST_SIZE
+ for (size = 0; size < TEST_SIZE; size++) {
+ if (size % align != 0 && gf_vect_mul(size, gf_const_tbl, buff1, buff2) == 0) {
+ printf
+ ("fail expecting nonzero return code for unaligned size param (%d)\n",
+ size);
+ goto exit;
+ }
}
printf(" done: Pass\n");
fflush(0);
- return 0;
+
+ ret = 0;
+ exit:
+
+ free(buff1);
+ free(buff2);
+ free(buff3);
+
+ return ret;
}
diff --git a/contrib/libs/isa-l/erasure_code/gf_vect_mul_test.patch b/contrib/libs/isa-l/erasure_code/gf_vect_mul_test.patch
deleted file mode 100644
index 4f5b5b575d..0000000000
--- a/contrib/libs/isa-l/erasure_code/gf_vect_mul_test.patch
+++ /dev/null
@@ -1,40 +0,0 @@
-67c67
-< if (gf_mul_erasure(a, buff1[i]) != buff2[i]) {
----
-> if (gf_mul(a, buff1[i]) != buff2[i]) {
-69c69
-< buff1[i], buff2[i], gf_mul_erasure(2, buff1[i]));
----
-> buff1[i], buff2[i], gf_mul(2, buff1[i]));
-80c80
-< i, a, buff1[i], buff2[i], gf_mul_erasure(a, buff1[i]));
----
-> i, a, buff1[i], buff2[i], gf_mul(a, buff1[i]));
-94c94
-< if (gf_mul_erasure(a, buff1[i]) != buff2[i]) {
----
-> if (gf_mul(a, buff1[i]) != buff2[i]) {
-96c96
-< i, a, buff1[i], buff2[i], gf_mul_erasure(2, buff1[i]));
----
-> i, a, buff1[i], buff2[i], gf_mul(2, buff1[i]));
-109c109
-< if (gf_mul_erasure(a, buff1[i]) != buff2[i]) {
----
-> if (gf_mul(a, buff1[i]) != buff2[i]) {
-111c111
-< i, a, buff1[i], buff2[i], gf_mul_erasure(2, buff1[i]));
----
-> i, a, buff1[i], buff2[i], gf_mul(2, buff1[i]));
-134c134
-< if (gf_mul_erasure(a, efence_buff1[i]) != efence_buff2[i]) {
----
-> if (gf_mul(a, efence_buff1[i]) != efence_buff2[i]) {
-137c137
-< gf_mul_erasure(2, efence_buff1[i]));
----
-> gf_mul(2, efence_buff1[i]));
-148c148
-< gf_mul_erasure(2, efence_buff1[i]));
----
-> gf_mul(2, efence_buff1[i]));
diff --git a/contrib/libs/isa-l/erasure_code/ppc64le/Makefile.am b/contrib/libs/isa-l/erasure_code/ppc64le/Makefile.am
new file mode 100644
index 0000000000..9d263ac22f
--- /dev/null
+++ b/contrib/libs/isa-l/erasure_code/ppc64le/Makefile.am
@@ -0,0 +1,15 @@
+lsrc_ppc64le += erasure_code/ppc64le/ec_base_vsx.c \
+ erasure_code/ppc64le/gf_vect_mul_vsx.c \
+ erasure_code/ppc64le/gf_vect_dot_prod_vsx.c \
+ erasure_code/ppc64le/gf_vect_mad_vsx.c \
+ erasure_code/ppc64le/gf_2vect_dot_prod_vsx.c \
+ erasure_code/ppc64le/gf_2vect_mad_vsx.c \
+ erasure_code/ppc64le/gf_3vect_dot_prod_vsx.c \
+ erasure_code/ppc64le/gf_3vect_mad_vsx.c \
+ erasure_code/ppc64le/gf_4vect_dot_prod_vsx.c \
+ erasure_code/ppc64le/gf_4vect_mad_vsx.c \
+ erasure_code/ppc64le/gf_5vect_dot_prod_vsx.c \
+ erasure_code/ppc64le/gf_5vect_mad_vsx.c \
+ erasure_code/ppc64le/gf_6vect_dot_prod_vsx.c \
+ erasure_code/ppc64le/gf_6vect_mad_vsx.c
+
diff --git a/contrib/libs/isa-l/erasure_code/ppc64le/ec_base_vsx.c b/contrib/libs/isa-l/erasure_code/ppc64le/ec_base_vsx.c
new file mode 100644
index 0000000000..c3163a58ff
--- /dev/null
+++ b/contrib/libs/isa-l/erasure_code/ppc64le/ec_base_vsx.c
@@ -0,0 +1,106 @@
+#include "erasure_code.h"
+#include "ec_base_vsx.h"
+
+void gf_vect_dot_prod(int len, int vlen, unsigned char *v,
+ unsigned char **src, unsigned char *dest)
+{
+ gf_vect_dot_prod_vsx(len, vlen, v, src, dest);
+}
+
+void gf_vect_mad(int len, int vec, int vec_i, unsigned char *v,
+ unsigned char *src, unsigned char *dest)
+{
+ gf_vect_mad_vsx(len, vec, vec_i, v, src, dest);
+
+}
+
+void ec_encode_data(int len, int srcs, int dests, unsigned char *v,
+ unsigned char **src, unsigned char **dest)
+{
+ if (len < 64) {
+ ec_encode_data_base(len, srcs, dests, v, src, dest);
+ return;
+ }
+
+ while (dests >= 6) {
+ gf_6vect_dot_prod_vsx(len, srcs, v, src, dest);
+ v += 6 * srcs * 32;
+ dest += 6;
+ dests -= 6;
+ }
+ switch (dests) {
+ case 6:
+ gf_6vect_dot_prod_vsx(len, srcs, v, src, dest);
+ break;
+ case 5:
+ gf_5vect_dot_prod_vsx(len, srcs, v, src, dest);
+ break;
+ case 4:
+ gf_4vect_dot_prod_vsx(len, srcs, v, src, dest);
+ break;
+ case 3:
+ gf_3vect_dot_prod_vsx(len, srcs, v, src, dest);
+ break;
+ case 2:
+ gf_2vect_dot_prod_vsx(len, srcs, v, src, dest);
+ break;
+ case 1:
+ gf_vect_dot_prod_vsx(len, srcs, v, src, *dest);
+ break;
+ case 0:
+ break;
+ }
+}
+
+void ec_encode_data_update(int len, int k, int rows, int vec_i, unsigned char *v,
+ unsigned char *data, unsigned char **dest)
+{
+ if (len < 64) {
+ ec_encode_data_update_base(len, k, rows, vec_i, v, data, dest);
+ return;
+ }
+
+ while (rows >= 6) {
+ gf_6vect_mad_vsx(len, k, vec_i, v, data, dest);
+ v += 6 * k * 32;
+ dest += 6;
+ rows -= 6;
+ }
+ switch (rows) {
+ case 6:
+ gf_6vect_mad_vsx(len, k, vec_i, v, data, dest);
+ break;
+ case 5:
+ gf_5vect_mad_vsx(len, k, vec_i, v, data, dest);
+ break;
+ case 4:
+ gf_4vect_mad_vsx(len, k, vec_i, v, data, dest);
+ break;
+ case 3:
+ gf_3vect_mad_vsx(len, k, vec_i, v, data, dest);
+ break;
+ case 2:
+ gf_2vect_mad_vsx(len, k, vec_i, v, data, dest);
+ break;
+ case 1:
+ gf_vect_mad_vsx(len, k, vec_i, v, data, *dest);
+ break;
+ case 0:
+ break;
+ }
+}
+
+int gf_vect_mul(int len, unsigned char *a, void *src, void *dest)
+{
+ /* Size must be aligned to 32 bytes */
+ if ((len % 32) != 0)
+ return -1;
+
+ gf_vect_mul_vsx(len, a, (unsigned char *)src, (unsigned char *)dest);
+ return 0;
+}
+
+void ec_init_tables(int k, int rows, unsigned char *a, unsigned char *g_tbls)
+{
+ return ec_init_tables_base(k, rows, a, g_tbls);
+}
diff --git a/contrib/libs/isa-l/erasure_code/ppc64le/ec_base_vsx.h b/contrib/libs/isa-l/erasure_code/ppc64le/ec_base_vsx.h
new file mode 100644
index 0000000000..c808629a95
--- /dev/null
+++ b/contrib/libs/isa-l/erasure_code/ppc64le/ec_base_vsx.h
@@ -0,0 +1,338 @@
+#ifndef _ERASURE_CODE_PPC64LE_H_
+#define _ERASURE_CODE_PPC64LE_H_
+
+#include "erasure_code.h"
+#include <altivec.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(__ibmxl__)
+#define EC_vec_xl(a, b) vec_xl_be(a, b)
+#define EC_vec_permxor(va, vb, vc) __vpermxor(va, vb, vc)
+#elif defined __GNUC__ && __GNUC__ >= 8
+#define EC_vec_xl(a, b) vec_xl_be(a, b)
+#define EC_vec_permxor(va, vb, vc) __builtin_crypto_vpermxor(va, vb, vc)
+#elif defined __GNUC__ && __GNUC__ >= 7
+#if defined _ARCH_PWR9
+#define EC_vec_xl(a, b) vec_vsx_ld(a, b)
+#define EC_vec_permxor(va, vb, vc) __builtin_crypto_vpermxor(va, vb, vec_nor(vc, vc))
+#else
+inline vector unsigned char EC_vec_xl(int off, unsigned char *ptr) {
+ vector unsigned char vc;
+ __asm__ __volatile__("lxvd2x %x0, %1, %2; xxswapd %x0, %x0" : "=wa" (vc) : "r" (off), "r" (ptr));
+ return vc;
+}
+#define EC_vec_permxor(va, vb, vc) __builtin_crypto_vpermxor(va, vb, vec_nor(vc, vc))
+#endif
+#else
+#if defined _ARCH_PWR8
+inline vector unsigned char EC_vec_xl(int off, unsigned char *ptr) {
+ vector unsigned char vc;
+ __asm__ __volatile__("lxvd2x %x0, %1, %2; xxswapd %x0, %x0" : "=wa" (vc) : "r" (off), "r" (ptr));
+ return vc;
+}
+#define EC_vec_permxor(va, vb, vc) __builtin_crypto_vpermxor(va, vb, vec_nor(vc, vc))
+#else
+#error "This code is only supported on ppc64le."
+#endif
+#endif
+
+/**
+ * @brief GF(2^8) vector multiply. VSX version.
+ *
+ * Does a GF(2^8) multiply across each byte of input source with expanded
+ * constant and save to destination array. Can be used for erasure coding encode
+ * and decode update when only one source is available at a time. Function
+ * requires pre-calculation of a 32 byte constant array based on the input
+ * coefficients.
+ * @requires VSX
+ *
+ * @param len Length of each vector in bytes.
+ * @param gftbls Pointer to array of input tables generated from coding
+ * coefficients in ec_init_tables(). Must be of size 32.
+ * @param src Array of pointers to source inputs.
+ * @param dest Pointer to destination data array.
+ * @returns none
+ */
+
+void gf_vect_mul_vsx(int len, unsigned char *gftbls, unsigned char *src, unsigned char *dest);
+
+/**
+ * @brief GF(2^8) vector dot product. VSX version.
+ *
+ * Does a GF(2^8) dot product across each byte of the input array and a constant
+ * set of coefficients to produce each byte of the output. Can be used for
+ * erasure coding encode and decode. Function requires pre-calculation of a
+ * 32*vlen byte constant array based on the input coefficients.
+ * @requires VSX
+ *
+ * @param len Length of each vector in bytes.
+ * @param vlen Number of vector sources.
+ * @param gftbls Pointer to 32*vlen byte array of pre-calculated constants based
+ * on the array of input coefficients.
+ * @param src Array of pointers to source inputs.
+ * @param dest Pointer to destination data array.
+ * @returns none
+ */
+
+void gf_vect_dot_prod_vsx(int len, int vlen, unsigned char *gftbls,
+ unsigned char **src, unsigned char *dest);
+
+/**
+ * @brief GF(2^8) vector dot product with two outputs. VSX version.
+ *
+ * Vector dot product optimized to calculate two outputs at a time. Does two
+ * GF(2^8) dot products across each byte of the input array and two constant
+ * sets of coefficients to produce each byte of the outputs. Can be used for
+ * erasure coding encode and decode. Function requires pre-calculation of a
+ * 2*32*vlen byte constant array based on the two sets of input coefficients.
+ * @requires VSX
+ *
+ * @param len Length of each vector in bytes.
+ * @param vlen Number of vector sources.
+ * @param gftbls Pointer to 2*32*vlen byte array of pre-calculated constants
+ * based on the array of input coefficients.
+ * @param src Array of pointers to source inputs.
+ * @param dest Array of pointers to destination data buffers.
+ * @returns none
+ */
+
+void gf_2vect_dot_prod_vsx(int len, int vlen, unsigned char *gftbls,
+ unsigned char **src, unsigned char **dest);
+
+/**
+ * @brief GF(2^8) vector dot product with three outputs. VSX version.
+ *
+ * Vector dot product optimized to calculate three outputs at a time. Does three
+ * GF(2^8) dot products across each byte of the input array and three constant
+ * sets of coefficients to produce each byte of the outputs. Can be used for
+ * erasure coding encode and decode. Function requires pre-calculation of a
+ * 3*32*vlen byte constant array based on the three sets of input coefficients.
+ * @requires VSX
+ *
+ * @param len Length of each vector in bytes.
+ * @param vlen Number of vector sources.
+ * @param gftbls Pointer to 3*32*vlen byte array of pre-calculated constants
+ * based on the array of input coefficients.
+ * @param src Array of pointers to source inputs.
+ * @param dest Array of pointers to destination data buffers.
+ * @returns none
+ */
+
+void gf_3vect_dot_prod_vsx(int len, int vlen, unsigned char *gftbls,
+ unsigned char **src, unsigned char **dest);
+
+/**
+ * @brief GF(2^8) vector dot product with four outputs. VSX version.
+ *
+ * Vector dot product optimized to calculate four outputs at a time. Does four
+ * GF(2^8) dot products across each byte of the input array and four constant
+ * sets of coefficients to produce each byte of the outputs. Can be used for
+ * erasure coding encode and decode. Function requires pre-calculation of a
+ * 4*32*vlen byte constant array based on the four sets of input coefficients.
+ * @requires VSX
+ *
+ * @param len Length of each vector in bytes.
+ * @param vlen Number of vector sources.
+ * @param gftbls Pointer to 4*32*vlen byte array of pre-calculated constants
+ * based on the array of input coefficients.
+ * @param src Array of pointers to source inputs.
+ * @param dest Array of pointers to destination data buffers.
+ * @returns none
+ */
+
+void gf_4vect_dot_prod_vsx(int len, int vlen, unsigned char *gftbls,
+ unsigned char **src, unsigned char **dest);
+
+/**
+ * @brief GF(2^8) vector dot product with five outputs. VSX version.
+ *
+ * Vector dot product optimized to calculate five outputs at a time. Does five
+ * GF(2^8) dot products across each byte of the input array and five constant
+ * sets of coefficients to produce each byte of the outputs. Can be used for
+ * erasure coding encode and decode. Function requires pre-calculation of a
+ * 5*32*vlen byte constant array based on the five sets of input coefficients.
+ * @requires VSX
+ *
+ * @param len Length of each vector in bytes. Must >= 16.
+ * @param vlen Number of vector sources.
+ * @param gftbls Pointer to 5*32*vlen byte array of pre-calculated constants
+ * based on the array of input coefficients.
+ * @param src Array of pointers to source inputs.
+ * @param dest Array of pointers to destination data buffers.
+ * @returns none
+ */
+
+void gf_5vect_dot_prod_vsx(int len, int vlen, unsigned char *gftbls,
+ unsigned char **src, unsigned char **dest);
+
+/**
+ * @brief GF(2^8) vector dot product with six outputs. VSX version.
+ *
+ * Vector dot product optimized to calculate six outputs at a time. Does six
+ * GF(2^8) dot products across each byte of the input array and six constant
+ * sets of coefficients to produce each byte of the outputs. Can be used for
+ * erasure coding encode and decode. Function requires pre-calculation of a
+ * 6*32*vlen byte constant array based on the six sets of input coefficients.
+ * @requires VSX
+ *
+ * @param len Length of each vector in bytes.
+ * @param vlen Number of vector sources.
+ * @param gftbls Pointer to 6*32*vlen byte array of pre-calculated constants
+ * based on the array of input coefficients.
+ * @param src Array of pointers to source inputs.
+ * @param dest Array of pointers to destination data buffers.
+ * @returns none
+ */
+
+void gf_6vect_dot_prod_vsx(int len, int vlen, unsigned char *gftbls,
+ unsigned char **src, unsigned char **dest);
+
+/**
+ * @brief GF(2^8) vector multiply accumulate. VSX version.
+ *
+ * Does a GF(2^8) multiply across each byte of input source with expanded
+ * constant and add to destination array. Can be used for erasure coding encode
+ * and decode update when only one source is available at a time. Function
+ * requires pre-calculation of a 32*vec byte constant array based on the input
+ * coefficients.
+ * @requires VSX
+ *
+ * @param len Length of each vector in bytes.
+ * @param vec The number of vector sources or rows in the generator matrix
+ * for coding.
+ * @param vec_i The vector index corresponding to the single input source.
+ * @param gftbls Pointer to array of input tables generated from coding
+ * coefficients in ec_init_tables(). Must be of size 32*vec.
+ * @param src Array of pointers to source inputs.
+ * @param dest Pointer to destination data array.
+ * @returns none
+ */
+
+void gf_vect_mad_vsx(int len, int vec, int vec_i, unsigned char *gftbls, unsigned char *src,
+ unsigned char *dest);
+/**
+ * @brief GF(2^8) vector multiply with 2 accumulate. VSX version.
+ *
+ * Does a GF(2^8) multiply across each byte of input source with expanded
+ * constants and add to destination arrays. Can be used for erasure coding
+ * encode and decode update when only one source is available at a
+ * time. Function requires pre-calculation of a 32*vec byte constant array based
+ * on the input coefficients.
+ * @requires VSX
+ *
+ * @param len Length of each vector in bytes.
+ * @param vec The number of vector sources or rows in the generator matrix
+ * for coding.
+ * @param vec_i The vector index corresponding to the single input source.
+ * @param gftbls Pointer to array of input tables generated from coding
+ * coefficients in ec_init_tables(). Must be of size 32*vec.
+ * @param src Pointer to source input array.
+ * @param dest Array of pointers to destination input/outputs.
+ * @returns none
+ */
+
+void gf_2vect_mad_vsx(int len, int vec, int vec_i, unsigned char *gftbls, unsigned char *src,
+ unsigned char **dest);
+
+/**
+ * @brief GF(2^8) vector multiply with 3 accumulate. VSX version.
+ *
+ * Does a GF(2^8) multiply across each byte of input source with expanded
+ * constants and add to destination arrays. Can be used for erasure coding
+ * encode and decode update when only one source is available at a
+ * time. Function requires pre-calculation of a 32*vec byte constant array based
+ * on the input coefficients.
+ * @requires VSX
+ *
+ * @param len Length of each vector in bytes.
+ * @param vec The number of vector sources or rows in the generator matrix
+ * for coding.
+ * @param vec_i The vector index corresponding to the single input source.
+ * @param gftbls Pointer to array of input tables generated from coding
+ * coefficients in ec_init_tables(). Must be of size 32*vec.
+ * @param src Pointer to source input array.
+ * @param dest Array of pointers to destination input/outputs.
+ * @returns none
+ */
+
+void gf_3vect_mad_vsx(int len, int vec, int vec_i, unsigned char *gftbls, unsigned char *src,
+ unsigned char **dest);
+
+/**
+ * @brief GF(2^8) vector multiply with 4 accumulate. VSX version.
+ *
+ * Does a GF(2^8) multiply across each byte of input source with expanded
+ * constants and add to destination arrays. Can be used for erasure coding
+ * encode and decode update when only one source is available at a
+ * time. Function requires pre-calculation of a 32*vec byte constant array based
+ * on the input coefficients.
+ * @requires VSX
+ *
+ * @param len Length of each vector in bytes.
+ * @param vec The number of vector sources or rows in the generator matrix
+ * for coding.
+ * @param vec_i The vector index corresponding to the single input source.
+ * @param gftbls Pointer to array of input tables generated from coding
+ * coefficients in ec_init_tables(). Must be of size 32*vec.
+ * @param src Pointer to source input array.
+ * @param dest Array of pointers to destination input/outputs.
+ * @returns none
+ */
+
+void gf_4vect_mad_vsx(int len, int vec, int vec_i, unsigned char *gftbls, unsigned char *src,
+ unsigned char **dest);
+
+/**
+ * @brief GF(2^8) vector multiply with 5 accumulate. VSX version.
+ *
+ * Does a GF(2^8) multiply across each byte of input source with expanded
+ * constants and add to destination arrays. Can be used for erasure coding
+ * encode and decode update when only one source is available at a
+ * time. Function requires pre-calculation of a 32*vec byte constant array based
+ * on the input coefficients.
+ * @requires VSX
+ *
+ * @param len Length of each vector in bytes.
+ * @param vec The number of vector sources or rows in the generator matrix
+ * for coding.
+ * @param vec_i The vector index corresponding to the single input source.
+ * @param gftbls Pointer to array of input tables generated from coding
+ * coefficients in ec_init_tables(). Must be of size 32*vec.
+ * @param src Pointer to source input array.
+ * @param dest Array of pointers to destination input/outputs.
+ * @returns none
+ */
+void gf_5vect_mad_vsx(int len, int vec, int vec_i, unsigned char *gftbls, unsigned char *src,
+ unsigned char **dest);
+
+/**
+ * @brief GF(2^8) vector multiply with 6 accumulate. VSX version.
+ *
+ * Does a GF(2^8) multiply across each byte of input source with expanded
+ * constants and add to destination arrays. Can be used for erasure coding
+ * encode and decode update when only one source is available at a
+ * time. Function requires pre-calculation of a 32*vec byte constant array based
+ * on the input coefficients.
+ * @requires VSX
+ *
+ * @param len Length of each vector in bytes.
+ * @param vec The number of vector sources or rows in the generator matrix
+ * for coding.
+ * @param vec_i The vector index corresponding to the single input source.
+ * @param gftbls Pointer to array of input tables generated from coding
+ * coefficients in ec_init_tables(). Must be of size 32*vec.
+ * @param src Pointer to source input array.
+ * @param dest Array of pointers to destination input/outputs.
+ * @returns none
+ */
+void gf_6vect_mad_vsx(int len, int vec, int vec_i, unsigned char *gftbls, unsigned char *src,
+ unsigned char **dest);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //_ERASURE_CODE_PPC64LE_H_
diff --git a/contrib/libs/isa-l/erasure_code/ppc64le/gf_2vect_dot_prod_vsx.c b/contrib/libs/isa-l/erasure_code/ppc64le/gf_2vect_dot_prod_vsx.c
new file mode 100644
index 0000000000..3cb269ccef
--- /dev/null
+++ b/contrib/libs/isa-l/erasure_code/ppc64le/gf_2vect_dot_prod_vsx.c
@@ -0,0 +1,83 @@
+#include "ec_base_vsx.h"
+
+void gf_2vect_dot_prod_vsx(int len, int vlen, unsigned char *gftbls,
+ unsigned char **src, unsigned char **dest)
+{
+ unsigned char *s, *t0, *t1;
+ vector unsigned char vX1, vX2, vX3, vX4;
+ vector unsigned char vY1, vY2, vY3, vY4;
+ vector unsigned char vYD, vYE, vYF, vYG;
+ vector unsigned char vhi0, vlo0, vhi1, vlo1;
+ int i, j, head;
+
+ if (vlen < 128) {
+ gf_vect_mul_vsx(len, &gftbls[0 * 32 * vlen], src[0], (unsigned char *)dest[0]);
+ gf_vect_mul_vsx(len, &gftbls[1 * 32 * vlen], src[0], (unsigned char *)dest[1]);
+
+ for (j = 1; j < vlen; j++) {
+ gf_2vect_mad_vsx(len, vlen, j, gftbls, src[j], dest);
+ }
+ return;
+ }
+
+ t0 = (unsigned char *)dest[0];
+ t1 = (unsigned char *)dest[1];
+
+ head = len % 64;
+ if (head != 0) {
+ gf_vect_dot_prod_base(head, vlen, &gftbls[0 * 32 * vlen], src, t0);
+ gf_vect_dot_prod_base(head, vlen, &gftbls[1 * 32 * vlen], src, t1);
+ }
+
+ for (i = head; i < len - 63; i += 64) {
+ vY1 = vY1 ^ vY1;
+ vY2 = vY2 ^ vY2;
+ vY3 = vY3 ^ vY3;
+ vY4 = vY4 ^ vY4;
+
+ vYD = vYD ^ vYD;
+ vYE = vYE ^ vYE;
+ vYF = vYF ^ vYF;
+ vYG = vYG ^ vYG;
+
+ unsigned char *g0 = &gftbls[0 * 32 * vlen];
+ unsigned char *g1 = &gftbls[1 * 32 * vlen];
+
+ for (j = 0; j < vlen; j++) {
+ s = (unsigned char *)src[j];
+ vX1 = vec_xl(0, s + i);
+ vX2 = vec_xl(16, s + i);
+ vX3 = vec_xl(32, s + i);
+ vX4 = vec_xl(48, s + i);
+
+ vlo0 = EC_vec_xl(0, g0);
+ vhi0 = EC_vec_xl(16, g0);
+ vlo1 = EC_vec_xl(0, g1);
+ vhi1 = EC_vec_xl(16, g1);
+
+ vY1 = vY1 ^ EC_vec_permxor(vhi0, vlo0, vX1);
+ vY2 = vY2 ^ EC_vec_permxor(vhi0, vlo0, vX2);
+ vYD = vYD ^ EC_vec_permxor(vhi0, vlo0, vX3);
+ vYE = vYE ^ EC_vec_permxor(vhi0, vlo0, vX4);
+
+ vY3 = vY3 ^ EC_vec_permxor(vhi1, vlo1, vX1);
+ vY4 = vY4 ^ EC_vec_permxor(vhi1, vlo1, vX2);
+ vYF = vYF ^ EC_vec_permxor(vhi1, vlo1, vX3);
+ vYG = vYG ^ EC_vec_permxor(vhi1, vlo1, vX4);
+
+ g0 += 32;
+ g1 += 32;
+ }
+
+ vec_xst(vY1, 0, t0 + i);
+ vec_xst(vY2, 16, t0 + i);
+ vec_xst(vY3, 0, t1 + i);
+ vec_xst(vY4, 16, t1 + i);
+
+ vec_xst(vYD, 32, t0 + i);
+ vec_xst(vYE, 48, t0 + i);
+ vec_xst(vYF, 32, t1 + i);
+ vec_xst(vYG, 48, t1 + i);
+ }
+ return;
+}
diff --git a/contrib/libs/isa-l/erasure_code/ppc64le/gf_2vect_mad_vsx.c b/contrib/libs/isa-l/erasure_code/ppc64le/gf_2vect_mad_vsx.c
new file mode 100644
index 0000000000..621684a5fb
--- /dev/null
+++ b/contrib/libs/isa-l/erasure_code/ppc64le/gf_2vect_mad_vsx.c
@@ -0,0 +1,65 @@
+#include "ec_base_vsx.h"
+
+void gf_2vect_mad_vsx(int len, int vec, int vec_i, unsigned char *gftbls,
+ unsigned char *src, unsigned char **dest)
+{
+ unsigned char *s, *t0, *t1;
+ vector unsigned char vX1, vX2, vX3, vX4;
+ vector unsigned char vY1, vY2, vY3, vY4;
+ vector unsigned char vYD, vYE, vYF, vYG;
+ vector unsigned char vhi0, vlo0, vhi1, vlo1;
+ int i, head;
+
+ s = (unsigned char *)src;
+ t0 = (unsigned char *)dest[0];
+ t1 = (unsigned char *)dest[1];
+
+ head = len % 64;
+ if (head != 0) {
+ gf_vect_mad_base(head, vec, vec_i, &gftbls[0 * 32 * vec], src, t0);
+ gf_vect_mad_base(head, vec, vec_i, &gftbls[1 * 32 * vec], src, t1);
+ }
+
+ vlo0 = EC_vec_xl(0, gftbls + (((0 * vec) << 5) + (vec_i << 5)));
+ vhi0 = EC_vec_xl(16, gftbls + (((0 * vec) << 5) + (vec_i << 5)));
+ vlo1 = EC_vec_xl(0, gftbls + (((1 * vec) << 5) + (vec_i << 5)));
+ vhi1 = EC_vec_xl(16, gftbls + (((1 * vec) << 5) + (vec_i << 5)));
+
+ for (i = head; i < len - 63; i += 64) {
+ vX1 = vec_xl(0, s + i);
+ vX2 = vec_xl(16, s + i);
+ vX3 = vec_xl(32, s + i);
+ vX4 = vec_xl(48, s + i);
+
+ vY1 = vec_xl(0, t0 + i);
+ vY2 = vec_xl(16, t0 + i);
+ vYD = vec_xl(32, t0 + i);
+ vYE = vec_xl(48, t0 + i);
+
+ vY1 = vY1 ^ EC_vec_permxor(vhi0, vlo0, vX1);
+ vY2 = vY2 ^ EC_vec_permxor(vhi0, vlo0, vX2);
+ vYD = vYD ^ EC_vec_permxor(vhi0, vlo0, vX3);
+ vYE = vYE ^ EC_vec_permxor(vhi0, vlo0, vX4);
+
+ vY3 = vec_xl(0, t1 + i);
+ vY4 = vec_xl(16, t1 + i);
+ vYF = vec_xl(32, t1 + i);
+ vYG = vec_xl(48, t1 + i);
+
+ vec_xst(vY1, 0, t0 + i);
+ vec_xst(vY2, 16, t0 + i);
+ vec_xst(vYD, 32, t0 + i);
+ vec_xst(vYE, 48, t0 + i);
+
+ vY3 = vY3 ^ EC_vec_permxor(vhi1, vlo1, vX1);
+ vY4 = vY4 ^ EC_vec_permxor(vhi1, vlo1, vX2);
+ vYF = vYF ^ EC_vec_permxor(vhi1, vlo1, vX3);
+ vYG = vYG ^ EC_vec_permxor(vhi1, vlo1, vX4);
+
+ vec_xst(vY3, 0, t1 + i);
+ vec_xst(vY4, 16, t1 + i);
+ vec_xst(vYF, 32, t1 + i);
+ vec_xst(vYG, 48, t1 + i);
+ }
+ return;
+}
diff --git a/contrib/libs/isa-l/erasure_code/ppc64le/gf_3vect_dot_prod_vsx.c b/contrib/libs/isa-l/erasure_code/ppc64le/gf_3vect_dot_prod_vsx.c
new file mode 100644
index 0000000000..23b72dc4ba
--- /dev/null
+++ b/contrib/libs/isa-l/erasure_code/ppc64le/gf_3vect_dot_prod_vsx.c
@@ -0,0 +1,104 @@
+#include "ec_base_vsx.h"
+
+void gf_3vect_dot_prod_vsx(int len, int vlen, unsigned char *gftbls,
+ unsigned char **src, unsigned char **dest)
+{
+ unsigned char *s, *t0, *t1, *t2;
+ vector unsigned char vX1, vX2, vX3, vX4;
+ vector unsigned char vY1, vY2, vY3, vY4, vY5, vY6;
+ vector unsigned char vYD, vYE, vYF, vYG, vYH, vYI;
+ vector unsigned char vhi0, vlo0, vhi1, vlo1, vhi2, vlo2;
+ int i, j, head;
+
+ if (vlen < 128) {
+ gf_vect_mul_vsx(len, &gftbls[0 * 32 * vlen], src[0], (unsigned char *)dest[0]);
+ gf_vect_mul_vsx(len, &gftbls[1 * 32 * vlen], src[0], (unsigned char *)dest[1]);
+ gf_vect_mul_vsx(len, &gftbls[2 * 32 * vlen], src[0], (unsigned char *)dest[2]);
+
+ for (j = 1; j < vlen; j++) {
+ gf_3vect_mad_vsx(len, vlen, j, gftbls, src[j], dest);
+ }
+ return;
+ }
+
+ t0 = (unsigned char *)dest[0];
+ t1 = (unsigned char *)dest[1];
+ t2 = (unsigned char *)dest[2];
+
+ head = len % 64;
+ if (head != 0) {
+ gf_vect_dot_prod_base(head, vlen, &gftbls[0 * 32 * vlen], src, t0);
+ gf_vect_dot_prod_base(head, vlen, &gftbls[1 * 32 * vlen], src, t1);
+ gf_vect_dot_prod_base(head, vlen, &gftbls[2 * 32 * vlen], src, t2);
+ }
+
+ for (i = head; i < len - 63; i += 64) {
+ vY1 = vY1 ^ vY1;
+ vY2 = vY2 ^ vY2;
+ vY3 = vY3 ^ vY3;
+ vY4 = vY4 ^ vY4;
+ vY5 = vY5 ^ vY5;
+ vY6 = vY6 ^ vY6;
+
+ vYD = vYD ^ vYD;
+ vYE = vYE ^ vYE;
+ vYF = vYF ^ vYF;
+ vYG = vYG ^ vYG;
+ vYH = vYH ^ vYH;
+ vYI = vYI ^ vYI;
+
+ unsigned char *g0 = &gftbls[0 * 32 * vlen];
+ unsigned char *g1 = &gftbls[1 * 32 * vlen];
+ unsigned char *g2 = &gftbls[2 * 32 * vlen];
+
+ for (j = 0; j < vlen; j++) {
+ s = (unsigned char *)src[j];
+ vX1 = vec_xl(0, s + i);
+ vX2 = vec_xl(16, s + i);
+ vX3 = vec_xl(32, s + i);
+ vX4 = vec_xl(48, s + i);
+
+ vlo0 = EC_vec_xl(0, g0);
+ vhi0 = EC_vec_xl(16, g0);
+ vlo1 = EC_vec_xl(0, g1);
+ vhi1 = EC_vec_xl(16, g1);
+
+ vY1 = vY1 ^ EC_vec_permxor(vhi0, vlo0, vX1);
+ vY2 = vY2 ^ EC_vec_permxor(vhi0, vlo0, vX2);
+ vYD = vYD ^ EC_vec_permxor(vhi0, vlo0, vX3);
+ vYE = vYE ^ EC_vec_permxor(vhi0, vlo0, vX4);
+
+ vlo2 = vec_xl(0, g2);
+ vhi2 = vec_xl(16, g2);
+
+ vY3 = vY3 ^ EC_vec_permxor(vhi1, vlo1, vX1);
+ vY4 = vY4 ^ EC_vec_permxor(vhi1, vlo1, vX2);
+ vYF = vYF ^ EC_vec_permxor(vhi1, vlo1, vX3);
+ vYG = vYG ^ EC_vec_permxor(vhi1, vlo1, vX4);
+
+ vY5 = vY5 ^ EC_vec_permxor(vhi2, vlo2, vX1);
+ vY6 = vY6 ^ EC_vec_permxor(vhi2, vlo2, vX2);
+ vYH = vYH ^ EC_vec_permxor(vhi2, vlo2, vX3);
+ vYI = vYI ^ EC_vec_permxor(vhi2, vlo2, vX4);
+
+ g0 += 32;
+ g1 += 32;
+ g2 += 32;
+ }
+
+ vec_xst(vY1, 0, t0 + i);
+ vec_xst(vY2, 16, t0 + i);
+ vec_xst(vY3, 0, t1 + i);
+ vec_xst(vY4, 16, t1 + i);
+ vec_xst(vY5, 0, t2 + i);
+ vec_xst(vY6, 16, t2 + i);
+
+ vec_xst(vYD, 32, t0 + i);
+ vec_xst(vYE, 48, t0 + i);
+ vec_xst(vYF, 32, t1 + i);
+ vec_xst(vYG, 48, t1 + i);
+ vec_xst(vYH, 32, t2 + i);
+ vec_xst(vYI, 48, t2 + i);
+ }
+ return;
+}
diff --git a/contrib/libs/isa-l/erasure_code/ppc64le/gf_3vect_mad_vsx.c b/contrib/libs/isa-l/erasure_code/ppc64le/gf_3vect_mad_vsx.c
new file mode 100644
index 0000000000..ba90c1fdbf
--- /dev/null
+++ b/contrib/libs/isa-l/erasure_code/ppc64le/gf_3vect_mad_vsx.c
@@ -0,0 +1,84 @@
+#include "ec_base_vsx.h"
+
+void gf_3vect_mad_vsx(int len, int vec, int vec_i, unsigned char *gftbls,
+ unsigned char *src, unsigned char **dest)
+{
+ unsigned char *s, *t0, *t1, *t2;
+ vector unsigned char vX1, vX2, vX3, vX4;
+ vector unsigned char vY1, vY2, vY3, vY4, vY5, vY6;
+ vector unsigned char vYD, vYE, vYF, vYG, vYH, vYI;
+ vector unsigned char vhi0, vlo0, vhi1, vlo1, vhi2, vlo2;
+ int i, head;
+
+ s = (unsigned char *)src;
+ t0 = (unsigned char *)dest[0];
+ t1 = (unsigned char *)dest[1];
+ t2 = (unsigned char *)dest[2];
+
+ head = len % 64;
+ if (head != 0) {
+ gf_vect_mad_base(head, vec, vec_i, &gftbls[0 * 32 * vec], src, t0);
+ gf_vect_mad_base(head, vec, vec_i, &gftbls[1 * 32 * vec], src, t1);
+ gf_vect_mad_base(head, vec, vec_i, &gftbls[2 * 32 * vec], src, t2);
+ }
+
+ vlo0 = EC_vec_xl(0, gftbls + (((0 * vec) << 5) + (vec_i << 5)));
+ vhi0 = EC_vec_xl(16, gftbls + (((0 * vec) << 5) + (vec_i << 5)));
+ vlo1 = EC_vec_xl(0, gftbls + (((1 * vec) << 5) + (vec_i << 5)));
+ vhi1 = EC_vec_xl(16, gftbls + (((1 * vec) << 5) + (vec_i << 5)));
+ vlo2 = EC_vec_xl(0, gftbls + (((2 * vec) << 5) + (vec_i << 5)));
+ vhi2 = EC_vec_xl(16, gftbls + (((2 * vec) << 5) + (vec_i << 5)));
+
+ for (i = head; i < len - 63; i += 64) {
+ vX1 = vec_xl(0, s + i);
+ vX2 = vec_xl(16, s + i);
+ vX3 = vec_xl(32, s + i);
+ vX4 = vec_xl(48, s + i);
+
+ vY1 = vec_xl(0, t0 + i);
+ vY2 = vec_xl(16, t0 + i);
+ vYD = vec_xl(32, t0 + i);
+ vYE = vec_xl(48, t0 + i);
+
+ vY1 = vY1 ^ EC_vec_permxor(vhi0, vlo0, vX1);
+ vY2 = vY2 ^ EC_vec_permxor(vhi0, vlo0, vX2);
+ vYD = vYD ^ EC_vec_permxor(vhi0, vlo0, vX3);
+ vYE = vYE ^ EC_vec_permxor(vhi0, vlo0, vX4);
+
+ vY3 = vec_xl(0, t1 + i);
+ vY4 = vec_xl(16, t1 + i);
+ vYF = vec_xl(32, t1 + i);
+ vYG = vec_xl(48, t1 + i);
+
+ vec_xst(vY1, 0, t0 + i);
+ vec_xst(vY2, 16, t0 + i);
+ vec_xst(vYD, 32, t0 + i);
+ vec_xst(vYE, 48, t0 + i);
+
+ vY3 = vY3 ^ EC_vec_permxor(vhi1, vlo1, vX1);
+ vY4 = vY4 ^ EC_vec_permxor(vhi1, vlo1, vX2);
+ vYF = vYF ^ EC_vec_permxor(vhi1, vlo1, vX3);
+ vYG = vYG ^ EC_vec_permxor(vhi1, vlo1, vX4);
+
+ vY5 = vec_xl(0, t2 + i);
+ vY6 = vec_xl(16, t2 + i);
+ vYH = vec_xl(32, t2 + i);
+ vYI = vec_xl(48, t2 + i);
+
+ vec_xst(vY3, 0, t1 + i);
+ vec_xst(vY4, 16, t1 + i);
+ vec_xst(vYF, 32, t1 + i);
+ vec_xst(vYG, 48, t1 + i);
+
+ vY5 = vY5 ^ EC_vec_permxor(vhi2, vlo2, vX1);
+ vY6 = vY6 ^ EC_vec_permxor(vhi2, vlo2, vX2);
+ vYH = vYH ^ EC_vec_permxor(vhi2, vlo2, vX3);
+ vYI = vYI ^ EC_vec_permxor(vhi2, vlo2, vX4);
+
+ vec_xst(vY5, 0, t2 + i);
+ vec_xst(vY6, 16, t2 + i);
+ vec_xst(vYH, 32, t2 + i);
+ vec_xst(vYI, 48, t2 + i);
+ }
+ return;
+}
diff --git a/contrib/libs/isa-l/erasure_code/ppc64le/gf_4vect_dot_prod_vsx.c b/contrib/libs/isa-l/erasure_code/ppc64le/gf_4vect_dot_prod_vsx.c
new file mode 100644
index 0000000000..e656544530
--- /dev/null
+++ b/contrib/libs/isa-l/erasure_code/ppc64le/gf_4vect_dot_prod_vsx.c
@@ -0,0 +1,124 @@
+#include "ec_base_vsx.h"
+
+void gf_4vect_dot_prod_vsx(int len, int vlen, unsigned char *gftbls,
+ unsigned char **src, unsigned char **dest)
+{
+ unsigned char *s, *t0, *t1, *t2, *t3;
+ vector unsigned char vX1, vX2, vX3, vX4;
+ vector unsigned char vY1, vY2, vY3, vY4, vY5, vY6, vY7, vY8;
+ vector unsigned char vYD, vYE, vYF, vYG, vYH, vYI, vYJ, vYK;
+ vector unsigned char vhi0, vlo0, vhi1, vlo1, vhi2, vlo2, vhi3, vlo3;
+ int i, j, head;
+
+ if (vlen < 128) {
+ gf_vect_mul_vsx(len, &gftbls[0 * 32 * vlen], src[0], (unsigned char *)dest[0]);
+ gf_vect_mul_vsx(len, &gftbls[1 * 32 * vlen], src[0], (unsigned char *)dest[1]);
+ gf_vect_mul_vsx(len, &gftbls[2 * 32 * vlen], src[0], (unsigned char *)dest[2]);
+ gf_vect_mul_vsx(len, &gftbls[3 * 32 * vlen], src[0], (unsigned char *)dest[3]);
+
+ for (j = 1; j < vlen; j++) {
+ gf_4vect_mad_vsx(len, vlen, j, gftbls, src[j], dest);
+ }
+ return;
+ }
+
+ t0 = (unsigned char *)dest[0];
+ t1 = (unsigned char *)dest[1];
+ t2 = (unsigned char *)dest[2];
+ t3 = (unsigned char *)dest[3];
+
+ head = len % 64;
+ if (head != 0) {
+ gf_vect_dot_prod_base(head, vlen, &gftbls[0 * 32 * vlen], src, t0);
+ gf_vect_dot_prod_base(head, vlen, &gftbls[1 * 32 * vlen], src, t1);
+ gf_vect_dot_prod_base(head, vlen, &gftbls[2 * 32 * vlen], src, t2);
+ gf_vect_dot_prod_base(head, vlen, &gftbls[3 * 32 * vlen], src, t3);
+ }
+
+ for (i = head; i < len - 63; i += 64) {
+ vY1 = vY1 ^ vY1;
+ vY2 = vY2 ^ vY2;
+ vY3 = vY3 ^ vY3;
+ vY4 = vY4 ^ vY4;
+ vY5 = vY5 ^ vY5;
+ vY6 = vY6 ^ vY6;
+ vY7 = vY7 ^ vY7;
+ vY8 = vY8 ^ vY8;
+
+ vYD = vYD ^ vYD;
+ vYE = vYE ^ vYE;
+ vYF = vYF ^ vYF;
+ vYG = vYG ^ vYG;
+ vYH = vYH ^ vYH;
+ vYI = vYI ^ vYI;
+ vYJ = vYJ ^ vYJ;
+ vYK = vYK ^ vYK;
+
+ unsigned char *g0 = &gftbls[0 * 32 * vlen];
+ unsigned char *g1 = &gftbls[1 * 32 * vlen];
+ unsigned char *g2 = &gftbls[2 * 32 * vlen];
+ unsigned char *g3 = &gftbls[3 * 32 * vlen];
+
+ for (j = 0; j < vlen; j++) {
+ s = (unsigned char *)src[j];
+ vX1 = vec_xl(0, s + i);
+ vX2 = vec_xl(16, s + i);
+ vX3 = vec_xl(32, s + i);
+ vX4 = vec_xl(48, s + i);
+
+ vlo0 = EC_vec_xl(0, g0);
+ vhi0 = EC_vec_xl(16, g0);
+ vlo1 = EC_vec_xl(0, g1);
+ vhi1 = EC_vec_xl(16, g1);
+
+ vY1 = vY1 ^ EC_vec_permxor(vhi0, vlo0, vX1);
+ vY2 = vY2 ^ EC_vec_permxor(vhi0, vlo0, vX2);
+ vYD = vYD ^ EC_vec_permxor(vhi0, vlo0, vX3);
+ vYE = vYE ^ EC_vec_permxor(vhi0, vlo0, vX4);
+
+ vlo2 = vec_xl(0, g2);
+ vhi2 = vec_xl(16, g2);
+ vlo3 = vec_xl(0, g3);
+ vhi3 = vec_xl(16, g3);
+
+ vY3 = vY3 ^ EC_vec_permxor(vhi1, vlo1, vX1);
+ vY4 = vY4 ^ EC_vec_permxor(vhi1, vlo1, vX2);
+ vYF = vYF ^ EC_vec_permxor(vhi1, vlo1, vX3);
+ vYG = vYG ^ EC_vec_permxor(vhi1, vlo1, vX4);
+
+ vY5 = vY5 ^ EC_vec_permxor(vhi2, vlo2, vX1);
+ vY6 = vY6 ^ EC_vec_permxor(vhi2, vlo2, vX2);
+ vYH = vYH ^ EC_vec_permxor(vhi2, vlo2, vX3);
+ vYI = vYI ^ EC_vec_permxor(vhi2, vlo2, vX4);
+
+ vY7 = vY7 ^ EC_vec_permxor(vhi3, vlo3, vX1);
+ vY8 = vY8 ^ EC_vec_permxor(vhi3, vlo3, vX2);
+ vYJ = vYJ ^ EC_vec_permxor(vhi3, vlo3, vX3);
+ vYK = vYK ^ EC_vec_permxor(vhi3, vlo3, vX4);
+
+ g0 += 32;
+ g1 += 32;
+ g2 += 32;
+ g3 += 32;
+ }
+
+ vec_xst(vY1, 0, t0 + i);
+ vec_xst(vY2, 16, t0 + i);
+ vec_xst(vY3, 0, t1 + i);
+ vec_xst(vY4, 16, t1 + i);
+ vec_xst(vY5, 0, t2 + i);
+ vec_xst(vY6, 16, t2 + i);
+ vec_xst(vY7, 0, t3 + i);
+ vec_xst(vY8, 16, t3 + i);
+
+ vec_xst(vYD, 32, t0 + i);
+ vec_xst(vYE, 48, t0 + i);
+ vec_xst(vYF, 32, t1 + i);
+ vec_xst(vYG, 48, t1 + i);
+ vec_xst(vYH, 32, t2 + i);
+ vec_xst(vYI, 48, t2 + i);
+ vec_xst(vYJ, 32, t3 + i);
+ vec_xst(vYK, 48, t3 + i);
+ }
+ return;
+}
diff --git a/contrib/libs/isa-l/erasure_code/ppc64le/gf_4vect_mad_vsx.c b/contrib/libs/isa-l/erasure_code/ppc64le/gf_4vect_mad_vsx.c
new file mode 100644
index 0000000000..7b236b6f81
--- /dev/null
+++ b/contrib/libs/isa-l/erasure_code/ppc64le/gf_4vect_mad_vsx.c
@@ -0,0 +1,103 @@
+#include "ec_base_vsx.h"
+
+void gf_4vect_mad_vsx(int len, int vec, int vec_i, unsigned char *gftbls,
+ unsigned char *src, unsigned char **dest)
+{
+ unsigned char *s, *t0, *t1, *t2, *t3;
+ vector unsigned char vX1, vX2, vX3, vX4;
+ vector unsigned char vY1, vY2, vY3, vY4, vY5, vY6, vY7, vY8;
+ vector unsigned char vYD, vYE, vYF, vYG, vYH, vYI, vYJ, vYK;
+ vector unsigned char vhi0, vlo0, vhi1, vlo1, vhi2, vlo2, vhi3, vlo3;
+ int i, head;
+
+ s = (unsigned char *)src;
+ t0 = (unsigned char *)dest[0];
+ t1 = (unsigned char *)dest[1];
+ t2 = (unsigned char *)dest[2];
+ t3 = (unsigned char *)dest[3];
+
+ head = len % 64;
+ if (head != 0) {
+ gf_vect_mad_base(head, vec, vec_i, &gftbls[0 * 32 * vec], src, t0);
+ gf_vect_mad_base(head, vec, vec_i, &gftbls[1 * 32 * vec], src, t1);
+ gf_vect_mad_base(head, vec, vec_i, &gftbls[2 * 32 * vec], src, t2);
+ gf_vect_mad_base(head, vec, vec_i, &gftbls[3 * 32 * vec], src, t3);
+ }
+
+ vlo0 = EC_vec_xl(0, gftbls + (((0 * vec) << 5) + (vec_i << 5)));
+ vhi0 = EC_vec_xl(16, gftbls + (((0 * vec) << 5) + (vec_i << 5)));
+ vlo1 = EC_vec_xl(0, gftbls + (((1 * vec) << 5) + (vec_i << 5)));
+ vhi1 = EC_vec_xl(16, gftbls + (((1 * vec) << 5) + (vec_i << 5)));
+ vlo2 = EC_vec_xl(0, gftbls + (((2 * vec) << 5) + (vec_i << 5)));
+ vhi2 = EC_vec_xl(16, gftbls + (((2 * vec) << 5) + (vec_i << 5)));
+ vlo3 = EC_vec_xl(0, gftbls + (((3 * vec) << 5) + (vec_i << 5)));
+ vhi3 = EC_vec_xl(16, gftbls + (((3 * vec) << 5) + (vec_i << 5)));
+
+ for (i = head; i < len - 63; i += 64) {
+ vX1 = vec_xl(0, s + i);
+ vX2 = vec_xl(16, s + i);
+ vX3 = vec_xl(32, s + i);
+ vX4 = vec_xl(48, s + i);
+
+ vY1 = vec_xl(0, t0 + i);
+ vY2 = vec_xl(16, t0 + i);
+ vYD = vec_xl(32, t0 + i);
+ vYE = vec_xl(48, t0 + i);
+
+ vY1 = vY1 ^ EC_vec_permxor(vhi0, vlo0, vX1);
+ vY2 = vY2 ^ EC_vec_permxor(vhi0, vlo0, vX2);
+ vYD = vYD ^ EC_vec_permxor(vhi0, vlo0, vX3);
+ vYE = vYE ^ EC_vec_permxor(vhi0, vlo0, vX4);
+
+ vY3 = vec_xl(0, t1 + i);
+ vY4 = vec_xl(16, t1 + i);
+ vYF = vec_xl(32, t1 + i);
+ vYG = vec_xl(48, t1 + i);
+
+ vec_xst(vY1, 0, t0 + i);
+ vec_xst(vY2, 16, t0 + i);
+ vec_xst(vYD, 32, t0 + i);
+ vec_xst(vYE, 48, t0 + i);
+
+ vY3 = vY3 ^ EC_vec_permxor(vhi1, vlo1, vX1);
+ vY4 = vY4 ^ EC_vec_permxor(vhi1, vlo1, vX2);
+ vYF = vYF ^ EC_vec_permxor(vhi1, vlo1, vX3);
+ vYG = vYG ^ EC_vec_permxor(vhi1, vlo1, vX4);
+
+ vY5 = vec_xl(0, t2 + i);
+ vY6 = vec_xl(16, t2 + i);
+ vYH = vec_xl(32, t2 + i);
+ vYI = vec_xl(48, t2 + i);
+
+ vec_xst(vY3, 0, t1 + i);
+ vec_xst(vY4, 16, t1 + i);
+ vec_xst(vYF, 32, t1 + i);
+ vec_xst(vYG, 48, t1 + i);
+
+ vY5 = vY5 ^ EC_vec_permxor(vhi2, vlo2, vX1);
+ vY6 = vY6 ^ EC_vec_permxor(vhi2, vlo2, vX2);
+ vYH = vYH ^ EC_vec_permxor(vhi2, vlo2, vX3);
+ vYI = vYI ^ EC_vec_permxor(vhi2, vlo2, vX4);
+
+ vY7 = vec_xl(0, t3 + i);
+ vY8 = vec_xl(16, t3 + i);
+ vYJ = vec_xl(32, t3 + i);
+ vYK = vec_xl(48, t3 + i);
+
+ vec_xst(vY5, 0, t2 + i);
+ vec_xst(vY6, 16, t2 + i);
+ vec_xst(vYH, 32, t2 + i);
+ vec_xst(vYI, 48, t2 + i);
+
+ vY7 = vY7 ^ EC_vec_permxor(vhi3, vlo3, vX1);
+ vY8 = vY8 ^ EC_vec_permxor(vhi3, vlo3, vX2);
+ vYJ = vYJ ^ EC_vec_permxor(vhi3, vlo3, vX3);
+ vYK = vYK ^ EC_vec_permxor(vhi3, vlo3, vX4);
+
+ vec_xst(vY7, 0, t3 + i);
+ vec_xst(vY8, 16, t3 + i);
+ vec_xst(vYJ, 32, t3 + i);
+ vec_xst(vYK, 48, t3 + i);
+ }
+ return;
+}
diff --git a/contrib/libs/isa-l/erasure_code/ppc64le/gf_5vect_dot_prod_vsx.c b/contrib/libs/isa-l/erasure_code/ppc64le/gf_5vect_dot_prod_vsx.c
new file mode 100644
index 0000000000..e9eef0e638
--- /dev/null
+++ b/contrib/libs/isa-l/erasure_code/ppc64le/gf_5vect_dot_prod_vsx.c
@@ -0,0 +1,145 @@
+#include "ec_base_vsx.h"
+
+void gf_5vect_dot_prod_vsx(int len, int vlen, unsigned char *gftbls,
+ unsigned char **src, unsigned char **dest)
+{
+ unsigned char *s, *t0, *t1, *t2, *t3, *t4;
+ vector unsigned char vX1, vX2, vX3, vX4;
+ vector unsigned char vY1, vY2, vY3, vY4, vY5, vY6, vY7, vY8, vY9, vYA;
+ vector unsigned char vYD, vYE, vYF, vYG, vYH, vYI, vYJ, vYK, vYL, vYM;
+ vector unsigned char vhi0, vlo0, vhi1, vlo1, vhi2, vlo2, vhi3, vlo3, vhi4, vlo4;
+ int i, j, head;
+
+ if (vlen < 128) {
+ gf_vect_mul_vsx(len, &gftbls[0 * 32 * vlen], src[0], (unsigned char *)dest[0]);
+ gf_vect_mul_vsx(len, &gftbls[1 * 32 * vlen], src[0], (unsigned char *)dest[1]);
+ gf_vect_mul_vsx(len, &gftbls[2 * 32 * vlen], src[0], (unsigned char *)dest[2]);
+ gf_vect_mul_vsx(len, &gftbls[3 * 32 * vlen], src[0], (unsigned char *)dest[3]);
+ gf_vect_mul_vsx(len, &gftbls[4 * 32 * vlen], src[0], (unsigned char *)dest[4]);
+
+ for (j = 1; j < vlen; j++) {
+ gf_5vect_mad_vsx(len, vlen, j, gftbls, src[j], dest);
+ }
+ return;
+ }
+
+ t0 = (unsigned char *)dest[0];
+ t1 = (unsigned char *)dest[1];
+ t2 = (unsigned char *)dest[2];
+ t3 = (unsigned char *)dest[3];
+ t4 = (unsigned char *)dest[4];
+
+ head = len % 64;
+ if (head != 0) {
+ gf_vect_dot_prod_base(head, vlen, &gftbls[0 * 32 * vlen], src, t0);
+ gf_vect_dot_prod_base(head, vlen, &gftbls[1 * 32 * vlen], src, t1);
+ gf_vect_dot_prod_base(head, vlen, &gftbls[2 * 32 * vlen], src, t2);
+ gf_vect_dot_prod_base(head, vlen, &gftbls[3 * 32 * vlen], src, t3);
+ gf_vect_dot_prod_base(head, vlen, &gftbls[4 * 32 * vlen], src, t4);
+ }
+
+ for (i = head; i < len - 63; i += 64) {
+ vY1 = vY1 ^ vY1;
+ vY2 = vY2 ^ vY2;
+ vY3 = vY3 ^ vY3;
+ vY4 = vY4 ^ vY4;
+ vY5 = vY5 ^ vY5;
+ vY6 = vY6 ^ vY6;
+ vY7 = vY7 ^ vY7;
+ vY8 = vY8 ^ vY8;
+ vY9 = vY9 ^ vY9;
+ vYA = vYA ^ vYA;
+
+ vYD = vYD ^ vYD;
+ vYE = vYE ^ vYE;
+ vYF = vYF ^ vYF;
+ vYG = vYG ^ vYG;
+ vYH = vYH ^ vYH;
+ vYI = vYI ^ vYI;
+ vYJ = vYJ ^ vYJ;
+ vYK = vYK ^ vYK;
+ vYL = vYL ^ vYL;
+ vYM = vYM ^ vYM;
+
+ unsigned char *g0 = &gftbls[0 * 32 * vlen];
+ unsigned char *g1 = &gftbls[1 * 32 * vlen];
+ unsigned char *g2 = &gftbls[2 * 32 * vlen];
+ unsigned char *g3 = &gftbls[3 * 32 * vlen];
+ unsigned char *g4 = &gftbls[4 * 32 * vlen];
+
+ for (j = 0; j < vlen; j++) {
+ s = (unsigned char *)src[j];
+ vX1 = vec_xl(0, s + i);
+ vX2 = vec_xl(16, s + i);
+ vX3 = vec_xl(32, s + i);
+ vX4 = vec_xl(48, s + i);
+
+ vlo0 = EC_vec_xl(0, g0);
+ vhi0 = EC_vec_xl(16, g0);
+ vlo1 = EC_vec_xl(0, g1);
+ vhi1 = EC_vec_xl(16, g1);
+
+ vY1 = vY1 ^ EC_vec_permxor(vhi0, vlo0, vX1);
+ vY2 = vY2 ^ EC_vec_permxor(vhi0, vlo0, vX2);
+ vYD = vYD ^ EC_vec_permxor(vhi0, vlo0, vX3);
+ vYE = vYE ^ EC_vec_permxor(vhi0, vlo0, vX4);
+
+ vlo2 = vec_xl(0, g2);
+ vhi2 = vec_xl(16, g2);
+ vlo3 = vec_xl(0, g3);
+ vhi3 = vec_xl(16, g3);
+
+ vY3 = vY3 ^ EC_vec_permxor(vhi1, vlo1, vX1);
+ vY4 = vY4 ^ EC_vec_permxor(vhi1, vlo1, vX2);
+ vYF = vYF ^ EC_vec_permxor(vhi1, vlo1, vX3);
+ vYG = vYG ^ EC_vec_permxor(vhi1, vlo1, vX4);
+
+ vlo4 = vec_xl(0, g4);
+ vhi4 = vec_xl(16, g4);
+
+ vY5 = vY5 ^ EC_vec_permxor(vhi2, vlo2, vX1);
+ vY6 = vY6 ^ EC_vec_permxor(vhi2, vlo2, vX2);
+ vYH = vYH ^ EC_vec_permxor(vhi2, vlo2, vX3);
+ vYI = vYI ^ EC_vec_permxor(vhi2, vlo2, vX4);
+
+ vY7 = vY7 ^ EC_vec_permxor(vhi3, vlo3, vX1);
+ vY8 = vY8 ^ EC_vec_permxor(vhi3, vlo3, vX2);
+ vYJ = vYJ ^ EC_vec_permxor(vhi3, vlo3, vX3);
+ vYK = vYK ^ EC_vec_permxor(vhi3, vlo3, vX4);
+
+ vY9 = vY9 ^ EC_vec_permxor(vhi4, vlo4, vX1);
+ vYA = vYA ^ EC_vec_permxor(vhi4, vlo4, vX2);
+ vYL = vYL ^ EC_vec_permxor(vhi4, vlo4, vX3);
+ vYM = vYM ^ EC_vec_permxor(vhi4, vlo4, vX4);
+
+ g0 += 32;
+ g1 += 32;
+ g2 += 32;
+ g3 += 32;
+ g4 += 32;
+ }
+
+ vec_xst(vY1, 0, t0 + i);
+ vec_xst(vY2, 16, t0 + i);
+ vec_xst(vY3, 0, t1 + i);
+ vec_xst(vY4, 16, t1 + i);
+ vec_xst(vY5, 0, t2 + i);
+ vec_xst(vY6, 16, t2 + i);
+ vec_xst(vY7, 0, t3 + i);
+ vec_xst(vY8, 16, t3 + i);
+ vec_xst(vY9, 0, t4 + i);
+ vec_xst(vYA, 16, t4 + i);
+
+ vec_xst(vYD, 32, t0 + i);
+ vec_xst(vYE, 48, t0 + i);
+ vec_xst(vYF, 32, t1 + i);
+ vec_xst(vYG, 48, t1 + i);
+ vec_xst(vYH, 32, t2 + i);
+ vec_xst(vYI, 48, t2 + i);
+ vec_xst(vYJ, 32, t3 + i);
+ vec_xst(vYK, 48, t3 + i);
+ vec_xst(vYL, 32, t4 + i);
+ vec_xst(vYM, 48, t4 + i);
+ }
+ return;
+}
diff --git a/contrib/libs/isa-l/erasure_code/ppc64le/gf_5vect_mad_vsx.c b/contrib/libs/isa-l/erasure_code/ppc64le/gf_5vect_mad_vsx.c
new file mode 100644
index 0000000000..7bb7bb2115
--- /dev/null
+++ b/contrib/libs/isa-l/erasure_code/ppc64le/gf_5vect_mad_vsx.c
@@ -0,0 +1,122 @@
+#include "ec_base_vsx.h"
+
+void gf_5vect_mad_vsx(int len, int vec, int vec_i, unsigned char *gftbls,
+ unsigned char *src, unsigned char **dest)
+{
+ unsigned char *s, *t0, *t1, *t2, *t3, *t4;
+ vector unsigned char vX1, vX2, vX3, vX4;
+ vector unsigned char vY1, vY2, vY3, vY4, vY5, vY6, vY7, vY8, vY9, vYA;
+ vector unsigned char vYD, vYE, vYF, vYG, vYH, vYI, vYJ, vYK, vYL, vYM;
+ vector unsigned char vhi0, vlo0, vhi1, vlo1, vhi2, vlo2, vhi3, vlo3, vhi4, vlo4;
+ int i, head;
+
+ s = (unsigned char *)src;
+ t0 = (unsigned char *)dest[0];
+ t1 = (unsigned char *)dest[1];
+ t2 = (unsigned char *)dest[2];
+ t3 = (unsigned char *)dest[3];
+ t4 = (unsigned char *)dest[4];
+
+ head = len % 64;
+ if (head != 0) {
+ gf_vect_mad_base(head, vec, vec_i, &gftbls[0 * 32 * vec], src, t0);
+ gf_vect_mad_base(head, vec, vec_i, &gftbls[1 * 32 * vec], src, t1);
+ gf_vect_mad_base(head, vec, vec_i, &gftbls[2 * 32 * vec], src, t2);
+ gf_vect_mad_base(head, vec, vec_i, &gftbls[3 * 32 * vec], src, t3);
+ gf_vect_mad_base(head, vec, vec_i, &gftbls[4 * 32 * vec], src, t4);
+ }
+
+ vlo0 = EC_vec_xl(0, gftbls + (((0 * vec) << 5) + (vec_i << 5)));
+ vhi0 = EC_vec_xl(16, gftbls + (((0 * vec) << 5) + (vec_i << 5)));
+ vlo1 = EC_vec_xl(0, gftbls + (((1 * vec) << 5) + (vec_i << 5)));
+ vhi1 = EC_vec_xl(16, gftbls + (((1 * vec) << 5) + (vec_i << 5)));
+ vlo2 = EC_vec_xl(0, gftbls + (((2 * vec) << 5) + (vec_i << 5)));
+ vhi2 = EC_vec_xl(16, gftbls + (((2 * vec) << 5) + (vec_i << 5)));
+ vlo3 = EC_vec_xl(0, gftbls + (((3 * vec) << 5) + (vec_i << 5)));
+ vhi3 = EC_vec_xl(16, gftbls + (((3 * vec) << 5) + (vec_i << 5)));
+ vlo4 = EC_vec_xl(0, gftbls + (((4 * vec) << 5) + (vec_i << 5)));
+ vhi4 = EC_vec_xl(16, gftbls + (((4 * vec) << 5) + (vec_i << 5)));
+
+ for (i = head; i < len - 63; i += 64) {
+ vX1 = vec_xl(0, s + i);
+ vX2 = vec_xl(16, s + i);
+ vX3 = vec_xl(32, s + i);
+ vX4 = vec_xl(48, s + i);
+
+ vY1 = vec_xl(0, t0 + i);
+ vY2 = vec_xl(16, t0 + i);
+ vYD = vec_xl(32, t0 + i);
+ vYE = vec_xl(48, t0 + i);
+
+ vY1 = vY1 ^ EC_vec_permxor(vhi0, vlo0, vX1);
+ vY2 = vY2 ^ EC_vec_permxor(vhi0, vlo0, vX2);
+ vYD = vYD ^ EC_vec_permxor(vhi0, vlo0, vX3);
+ vYE = vYE ^ EC_vec_permxor(vhi0, vlo0, vX4);
+
+ vY3 = vec_xl(0, t1 + i);
+ vY4 = vec_xl(16, t1 + i);
+ vYF = vec_xl(32, t1 + i);
+ vYG = vec_xl(48, t1 + i);
+
+ vec_xst(vY1, 0, t0 + i);
+ vec_xst(vY2, 16, t0 + i);
+ vec_xst(vYD, 32, t0 + i);
+ vec_xst(vYE, 48, t0 + i);
+
+ vY3 = vY3 ^ EC_vec_permxor(vhi1, vlo1, vX1);
+ vY4 = vY4 ^ EC_vec_permxor(vhi1, vlo1, vX2);
+ vYF = vYF ^ EC_vec_permxor(vhi1, vlo1, vX3);
+ vYG = vYG ^ EC_vec_permxor(vhi1, vlo1, vX4);
+
+ vY5 = vec_xl(0, t2 + i);
+ vY6 = vec_xl(16, t2 + i);
+ vYH = vec_xl(32, t2 + i);
+ vYI = vec_xl(48, t2 + i);
+
+ vec_xst(vY3, 0, t1 + i);
+ vec_xst(vY4, 16, t1 + i);
+ vec_xst(vYF, 32, t1 + i);
+ vec_xst(vYG, 48, t1 + i);
+
+ vY5 = vY5 ^ EC_vec_permxor(vhi2, vlo2, vX1);
+ vY6 = vY6 ^ EC_vec_permxor(vhi2, vlo2, vX2);
+ vYH = vYH ^ EC_vec_permxor(vhi2, vlo2, vX3);
+ vYI = vYI ^ EC_vec_permxor(vhi2, vlo2, vX4);
+
+ vY7 = vec_xl(0, t3 + i);
+ vY8 = vec_xl(16, t3 + i);
+ vYJ = vec_xl(32, t3 + i);
+ vYK = vec_xl(48, t3 + i);
+
+ vec_xst(vY5, 0, t2 + i);
+ vec_xst(vY6, 16, t2 + i);
+ vec_xst(vYH, 32, t2 + i);
+ vec_xst(vYI, 48, t2 + i);
+
+ vY7 = vY7 ^ EC_vec_permxor(vhi3, vlo3, vX1);
+ vY8 = vY8 ^ EC_vec_permxor(vhi3, vlo3, vX2);
+ vYJ = vYJ ^ EC_vec_permxor(vhi3, vlo3, vX3);
+ vYK = vYK ^ EC_vec_permxor(vhi3, vlo3, vX4);
+
+ vY9 = vec_xl(0, t4 + i);
+ vYA = vec_xl(16, t4 + i);
+ vYL = vec_xl(32, t4 + i);
+ vYM = vec_xl(48, t4 + i);
+
+ vec_xst(vY7, 0, t3 + i);
+ vec_xst(vY8, 16, t3 + i);
+ vec_xst(vYJ, 32, t3 + i);
+ vec_xst(vYK, 48, t3 + i);
+
+ vY9 = vY9 ^ EC_vec_permxor(vhi4, vlo4, vX1);
+ vYA = vYA ^ EC_vec_permxor(vhi4, vlo4, vX2);
+ vYL = vYL ^ EC_vec_permxor(vhi4, vlo4, vX3);
+ vYM = vYM ^ EC_vec_permxor(vhi4, vlo4, vX4);
+
+ vec_xst(vY9, 0, t4 + i);
+ vec_xst(vYA, 16, t4 + i);
+ vec_xst(vYL, 32, t4 + i);
+ vec_xst(vYM, 48, t4 + i);
+ }
+ return;
+}
diff --git a/contrib/libs/isa-l/erasure_code/ppc64le/gf_6vect_dot_prod_vsx.c b/contrib/libs/isa-l/erasure_code/ppc64le/gf_6vect_dot_prod_vsx.c
new file mode 100644
index 0000000000..ac918bd493
--- /dev/null
+++ b/contrib/libs/isa-l/erasure_code/ppc64le/gf_6vect_dot_prod_vsx.c
@@ -0,0 +1,166 @@
+#include "ec_base_vsx.h"
+
+void gf_6vect_dot_prod_vsx(int len, int vlen, unsigned char *gftbls,
+ unsigned char **src, unsigned char **dest)
+{
+ unsigned char *s, *t0, *t1, *t2, *t3, *t4, *t5;
+ vector unsigned char vX1, vX2, vX3, vX4;
+ vector unsigned char vY1, vY2, vY3, vY4, vY5, vY6, vY7, vY8, vY9, vYA, vYB, vYC;
+ vector unsigned char vYD, vYE, vYF, vYG, vYH, vYI, vYJ, vYK, vYL, vYM, vYN, vYO;
+ vector unsigned char vhi0, vlo0, vhi1, vlo1, vhi2, vlo2;
+ vector unsigned char vhi3, vlo3, vhi4, vlo4, vhi5, vlo5;
+ int i, j, head;
+
+ if (vlen < 128) {
+ gf_vect_mul_vsx(len, &gftbls[0 * 32 * vlen], src[0], (unsigned char *)dest[0]);
+ gf_vect_mul_vsx(len, &gftbls[1 * 32 * vlen], src[0], (unsigned char *)dest[1]);
+ gf_vect_mul_vsx(len, &gftbls[2 * 32 * vlen], src[0], (unsigned char *)dest[2]);
+ gf_vect_mul_vsx(len, &gftbls[3 * 32 * vlen], src[0], (unsigned char *)dest[3]);
+ gf_vect_mul_vsx(len, &gftbls[4 * 32 * vlen], src[0], (unsigned char *)dest[4]);
+ gf_vect_mul_vsx(len, &gftbls[5 * 32 * vlen], src[0], (unsigned char *)dest[5]);
+
+ for (j = 1; j < vlen; j++) {
+ gf_6vect_mad_vsx(len, vlen, j, gftbls, src[j], dest);
+ }
+ return;
+ }
+
+ t0 = (unsigned char *)dest[0];
+ t1 = (unsigned char *)dest[1];
+ t2 = (unsigned char *)dest[2];
+ t3 = (unsigned char *)dest[3];
+ t4 = (unsigned char *)dest[4];
+ t5 = (unsigned char *)dest[5];
+
+ head = len % 64;
+ if (head != 0) {
+ gf_vect_dot_prod_base(head, vlen, &gftbls[0 * 32 * vlen], src, t0);
+ gf_vect_dot_prod_base(head, vlen, &gftbls[1 * 32 * vlen], src, t1);
+ gf_vect_dot_prod_base(head, vlen, &gftbls[2 * 32 * vlen], src, t2);
+ gf_vect_dot_prod_base(head, vlen, &gftbls[3 * 32 * vlen], src, t3);
+ gf_vect_dot_prod_base(head, vlen, &gftbls[4 * 32 * vlen], src, t4);
+ gf_vect_dot_prod_base(head, vlen, &gftbls[5 * 32 * vlen], src, t5);
+ }
+
+ for (i = head; i < len - 63; i += 64) {
+ vY1 = vY1 ^ vY1;
+ vY2 = vY2 ^ vY2;
+ vY3 = vY3 ^ vY3;
+ vY4 = vY4 ^ vY4;
+ vY5 = vY5 ^ vY5;
+ vY6 = vY6 ^ vY6;
+ vY7 = vY7 ^ vY7;
+ vY8 = vY8 ^ vY8;
+ vY9 = vY9 ^ vY9;
+ vYA = vYA ^ vYA;
+ vYB = vYB ^ vYB;
+ vYC = vYC ^ vYC;
+
+ vYD = vYD ^ vYD;
+ vYE = vYE ^ vYE;
+ vYF = vYF ^ vYF;
+ vYG = vYG ^ vYG;
+ vYH = vYH ^ vYH;
+ vYI = vYI ^ vYI;
+ vYJ = vYJ ^ vYJ;
+ vYK = vYK ^ vYK;
+ vYL = vYL ^ vYL;
+ vYM = vYM ^ vYM;
+ vYN = vYN ^ vYN;
+ vYO = vYO ^ vYO;
+
+ unsigned char *g0 = &gftbls[0 * 32 * vlen];
+ unsigned char *g1 = &gftbls[1 * 32 * vlen];
+ unsigned char *g2 = &gftbls[2 * 32 * vlen];
+ unsigned char *g3 = &gftbls[3 * 32 * vlen];
+ unsigned char *g4 = &gftbls[4 * 32 * vlen];
+ unsigned char *g5 = &gftbls[5 * 32 * vlen];
+
+ for (j = 0; j < vlen; j++) {
+ s = (unsigned char *)src[j];
+ vX1 = vec_xl(0, s + i);
+ vX2 = vec_xl(16, s + i);
+ vX3 = vec_xl(32, s + i);
+ vX4 = vec_xl(48, s + i);
+
+ vlo0 = EC_vec_xl(0, g0);
+ vhi0 = EC_vec_xl(16, g0);
+ vlo1 = EC_vec_xl(0, g1);
+ vhi1 = EC_vec_xl(16, g1);
+
+ vY1 = vY1 ^ EC_vec_permxor(vhi0, vlo0, vX1);
+ vY2 = vY2 ^ EC_vec_permxor(vhi0, vlo0, vX2);
+ vYD = vYD ^ EC_vec_permxor(vhi0, vlo0, vX3);
+ vYE = vYE ^ EC_vec_permxor(vhi0, vlo0, vX4);
+
+ vlo2 = EC_vec_xl(0, g2);
+ vhi2 = EC_vec_xl(16, g2);
+ vlo3 = EC_vec_xl(0, g3);
+ vhi3 = EC_vec_xl(16, g3);
+
+ vY3 = vY3 ^ EC_vec_permxor(vhi1, vlo1, vX1);
+ vY4 = vY4 ^ EC_vec_permxor(vhi1, vlo1, vX2);
+ vYF = vYF ^ EC_vec_permxor(vhi1, vlo1, vX3);
+ vYG = vYG ^ EC_vec_permxor(vhi1, vlo1, vX4);
+
+ vlo4 = EC_vec_xl(0, g4);
+ vhi4 = EC_vec_xl(16, g4);
+ vlo5 = EC_vec_xl(0, g5);
+ vhi5 = EC_vec_xl(16, g5);
+
+ vY5 = vY5 ^ EC_vec_permxor(vhi2, vlo2, vX1);
+ vY6 = vY6 ^ EC_vec_permxor(vhi2, vlo2, vX2);
+ vYH = vYH ^ EC_vec_permxor(vhi2, vlo2, vX3);
+ vYI = vYI ^ EC_vec_permxor(vhi2, vlo2, vX4);
+
+ vY7 = vY7 ^ EC_vec_permxor(vhi3, vlo3, vX1);
+ vY8 = vY8 ^ EC_vec_permxor(vhi3, vlo3, vX2);
+ vYJ = vYJ ^ EC_vec_permxor(vhi3, vlo3, vX3);
+ vYK = vYK ^ EC_vec_permxor(vhi3, vlo3, vX4);
+
+ vY9 = vY9 ^ EC_vec_permxor(vhi4, vlo4, vX1);
+ vYA = vYA ^ EC_vec_permxor(vhi4, vlo4, vX2);
+ vYL = vYL ^ EC_vec_permxor(vhi4, vlo4, vX3);
+ vYM = vYM ^ EC_vec_permxor(vhi4, vlo4, vX4);
+
+ vYB = vYB ^ EC_vec_permxor(vhi5, vlo5, vX1);
+ vYC = vYC ^ EC_vec_permxor(vhi5, vlo5, vX2);
+ vYN = vYN ^ EC_vec_permxor(vhi5, vlo5, vX3);
+ vYO = vYO ^ EC_vec_permxor(vhi5, vlo5, vX4);
+
+ g0 += 32;
+ g1 += 32;
+ g2 += 32;
+ g3 += 32;
+ g4 += 32;
+ g5 += 32;
+ }
+
+ vec_xst(vY1, 0, t0 + i);
+ vec_xst(vY2, 16, t0 + i);
+ vec_xst(vY3, 0, t1 + i);
+ vec_xst(vY4, 16, t1 + i);
+ vec_xst(vY5, 0, t2 + i);
+ vec_xst(vY6, 16, t2 + i);
+ vec_xst(vY7, 0, t3 + i);
+ vec_xst(vY8, 16, t3 + i);
+ vec_xst(vY9, 0, t4 + i);
+ vec_xst(vYA, 16, t4 + i);
+ vec_xst(vYB, 0, t5 + i);
+ vec_xst(vYC, 16, t5 + i);
+
+ vec_xst(vYD, 32, t0 + i);
+ vec_xst(vYE, 48, t0 + i);
+ vec_xst(vYF, 32, t1 + i);
+ vec_xst(vYG, 48, t1 + i);
+ vec_xst(vYH, 32, t2 + i);
+ vec_xst(vYI, 48, t2 + i);
+ vec_xst(vYJ, 32, t3 + i);
+ vec_xst(vYK, 48, t3 + i);
+ vec_xst(vYL, 32, t4 + i);
+ vec_xst(vYM, 48, t4 + i);
+ vec_xst(vYN, 32, t5 + i);
+ vec_xst(vYO, 48, t5 + i);
+ }
+ return;
+}
diff --git a/contrib/libs/isa-l/erasure_code/ppc64le/gf_6vect_mad_vsx.c b/contrib/libs/isa-l/erasure_code/ppc64le/gf_6vect_mad_vsx.c
new file mode 100644
index 0000000000..43ea6c6966
--- /dev/null
+++ b/contrib/libs/isa-l/erasure_code/ppc64le/gf_6vect_mad_vsx.c
@@ -0,0 +1,142 @@
+#include "ec_base_vsx.h"
+
+void gf_6vect_mad_vsx(int len, int vec, int vec_i, unsigned char *gftbls,
+ unsigned char *src, unsigned char **dest)
+{
+ unsigned char *s, *t0, *t1, *t2, *t3, *t4, *t5;
+ vector unsigned char vX1, vX2, vX3, vX4;
+ vector unsigned char vY1, vY2, vY3, vY4, vY5, vY6, vY7, vY8, vY9, vYA, vYB, vYC;
+ vector unsigned char vYD, vYE, vYF, vYG, vYH, vYI, vYJ, vYK, vYL, vYM, vYN, vYO;
+ vector unsigned char vhi0, vlo0, vhi1, vlo1, vhi2, vlo2;
+ vector unsigned char vhi3, vlo3, vhi4, vlo4, vhi5, vlo5;
+ int i, head;
+
+ s = (unsigned char *)src;
+ t0 = (unsigned char *)dest[0];
+ t1 = (unsigned char *)dest[1];
+ t2 = (unsigned char *)dest[2];
+ t3 = (unsigned char *)dest[3];
+ t4 = (unsigned char *)dest[4];
+ t5 = (unsigned char *)dest[5];
+
+ head = len % 64;
+ if (head != 0) {
+ gf_vect_mad_base(head, vec, vec_i, &gftbls[0 * 32 * vec], src, t0);
+ gf_vect_mad_base(head, vec, vec_i, &gftbls[1 * 32 * vec], src, t1);
+ gf_vect_mad_base(head, vec, vec_i, &gftbls[2 * 32 * vec], src, t2);
+ gf_vect_mad_base(head, vec, vec_i, &gftbls[3 * 32 * vec], src, t3);
+ gf_vect_mad_base(head, vec, vec_i, &gftbls[4 * 32 * vec], src, t4);
+ gf_vect_mad_base(head, vec, vec_i, &gftbls[5 * 32 * vec], src, t5);
+ }
+
+ vlo0 = EC_vec_xl(0, gftbls + (((0 * vec) << 5) + (vec_i << 5)));
+ vhi0 = EC_vec_xl(16, gftbls + (((0 * vec) << 5) + (vec_i << 5)));
+ vlo1 = EC_vec_xl(0, gftbls + (((1 * vec) << 5) + (vec_i << 5)));
+ vhi1 = EC_vec_xl(16, gftbls + (((1 * vec) << 5) + (vec_i << 5)));
+ vlo2 = EC_vec_xl(0, gftbls + (((2 * vec) << 5) + (vec_i << 5)));
+ vhi2 = EC_vec_xl(16, gftbls + (((2 * vec) << 5) + (vec_i << 5)));
+ vlo3 = EC_vec_xl(0, gftbls + (((3 * vec) << 5) + (vec_i << 5)));
+ vhi3 = EC_vec_xl(16, gftbls + (((3 * vec) << 5) + (vec_i << 5)));
+ vlo4 = EC_vec_xl(0, gftbls + (((4 * vec) << 5) + (vec_i << 5)));
+ vhi4 = EC_vec_xl(16, gftbls + (((4 * vec) << 5) + (vec_i << 5)));
+ vlo5 = EC_vec_xl(0, gftbls + (((5 * vec) << 5) + (vec_i << 5)));
+ vhi5 = EC_vec_xl(16, gftbls + (((5 * vec) << 5) + (vec_i << 5)));
+
+ for (i = head; i < len - 63; i += 64) {
+ vX1 = vec_xl(0, s + i);
+ vX2 = vec_xl(16, s + i);
+ vX3 = vec_xl(32, s + i);
+ vX4 = vec_xl(48, s + i);
+
+ vY1 = vec_xl(0, t0 + i);
+ vY2 = vec_xl(16, t0 + i);
+ vYD = vec_xl(32, t0 + i);
+ vYE = vec_xl(48, t0 + i);
+
+ vY1 = vY1 ^ EC_vec_permxor(vhi0, vlo0, vX1);
+ vY2 = vY2 ^ EC_vec_permxor(vhi0, vlo0, vX2);
+ vYD = vYD ^ EC_vec_permxor(vhi0, vlo0, vX3);
+ vYE = vYE ^ EC_vec_permxor(vhi0, vlo0, vX4);
+
+ vec_xst(vY1, 0, t0 + i);
+ vec_xst(vY2, 16, t0 + i);
+ vec_xst(vYD, 32, t0 + i);
+ vec_xst(vYE, 48, t0 + i);
+
+ vY3 = vec_xl(0, t1 + i);
+ vY4 = vec_xl(16, t1 + i);
+ vYF = vec_xl(32, t1 + i);
+ vYG = vec_xl(48, t1 + i);
+
+ vY3 = vY3 ^ EC_vec_permxor(vhi1, vlo1, vX1);
+ vY4 = vY4 ^ EC_vec_permxor(vhi1, vlo1, vX2);
+ vYF = vYF ^ EC_vec_permxor(vhi1, vlo1, vX3);
+ vYG = vYG ^ EC_vec_permxor(vhi1, vlo1, vX4);
+
+ vec_xst(vY3, 0, t1 + i);
+ vec_xst(vY4, 16, t1 + i);
+ vec_xst(vYF, 32, t1 + i);
+ vec_xst(vYG, 48, t1 + i);
+
+ vY5 = vec_xl(0, t2 + i);
+ vY6 = vec_xl(16, t2 + i);
+ vYH = vec_xl(32, t2 + i);
+ vYI = vec_xl(48, t2 + i);
+
+ vY5 = vY5 ^ EC_vec_permxor(vhi2, vlo2, vX1);
+ vY6 = vY6 ^ EC_vec_permxor(vhi2, vlo2, vX2);
+ vYH = vYH ^ EC_vec_permxor(vhi2, vlo2, vX3);
+ vYI = vYI ^ EC_vec_permxor(vhi2, vlo2, vX4);
+
+ vY7 = vec_xl(0, t3 + i);
+ vY8 = vec_xl(16, t3 + i);
+ vYJ = vec_xl(32, t3 + i);
+ vYK = vec_xl(48, t3 + i);
+
+ vec_xst(vY5, 0, t2 + i);
+ vec_xst(vY6, 16, t2 + i);
+ vec_xst(vYH, 32, t2 + i);
+ vec_xst(vYI, 48, t2 + i);
+
+ vY7 = vY7 ^ EC_vec_permxor(vhi3, vlo3, vX1);
+ vY8 = vY8 ^ EC_vec_permxor(vhi3, vlo3, vX2);
+ vYJ = vYJ ^ EC_vec_permxor(vhi3, vlo3, vX3);
+ vYK = vYK ^ EC_vec_permxor(vhi3, vlo3, vX4);
+
+ vY9 = vec_xl(0, t4 + i);
+ vYA = vec_xl(16, t4 + i);
+ vYL = vec_xl(32, t4 + i);
+ vYM = vec_xl(48, t4 + i);
+
+ vec_xst(vY7, 0, t3 + i);
+ vec_xst(vY8, 16, t3 + i);
+ vec_xst(vYJ, 32, t3 + i);
+ vec_xst(vYK, 48, t3 + i);
+
+ vY9 = vY9 ^ EC_vec_permxor(vhi4, vlo4, vX1);
+ vYA = vYA ^ EC_vec_permxor(vhi4, vlo4, vX2);
+ vYL = vYL ^ EC_vec_permxor(vhi4, vlo4, vX3);
+ vYM = vYM ^ EC_vec_permxor(vhi4, vlo4, vX4);
+
+ vYB = vec_xl(0, t5 + i);
+ vYC = vec_xl(16, t5 + i);
+ vYN = vec_xl(32, t5 + i);
+ vYO = vec_xl(48, t5 + i);
+
+ vec_xst(vY9, 0, t4 + i);
+ vec_xst(vYA, 16, t4 + i);
+ vec_xst(vYL, 32, t4 + i);
+ vec_xst(vYM, 48, t4 + i);
+
+ vYB = vYB ^ EC_vec_permxor(vhi5, vlo5, vX1);
+ vYC = vYC ^ EC_vec_permxor(vhi5, vlo5, vX2);
+ vYN = vYN ^ EC_vec_permxor(vhi5, vlo5, vX3);
+ vYO = vYO ^ EC_vec_permxor(vhi5, vlo5, vX4);
+
+ vec_xst(vYB, 0, t5 + i);
+ vec_xst(vYC, 16, t5 + i);
+ vec_xst(vYN, 32, t5 + i);
+ vec_xst(vYO, 48, t5 + i);
+ }
+ return;
+}
diff --git a/contrib/libs/isa-l/erasure_code/ppc64le/gf_vect_dot_prod_vsx.c b/contrib/libs/isa-l/erasure_code/ppc64le/gf_vect_dot_prod_vsx.c
new file mode 100644
index 0000000000..2f97e3421f
--- /dev/null
+++ b/contrib/libs/isa-l/erasure_code/ppc64le/gf_vect_dot_prod_vsx.c
@@ -0,0 +1,85 @@
+#include "ec_base_vsx.h"
+
+void gf_vect_dot_prod_vsx(int len, int vlen, unsigned char *gftbls,
+ unsigned char **src, unsigned char *dest)
+{
+ unsigned char *s, *t0;
+ vector unsigned char vX1, vY1;
+ vector unsigned char vX2, vY2;
+ vector unsigned char vX3, vY3;
+ vector unsigned char vX4, vY4;
+ vector unsigned char vX5, vY5;
+ vector unsigned char vX6, vY6;
+ vector unsigned char vX7, vY7;
+ vector unsigned char vX8, vY8;
+ vector unsigned char vhi0, vlo0;
+ int i, j, head;
+
+ if (vlen < 128) {
+ gf_vect_mul_vsx(len, &gftbls[0 * 32 * vlen], src[0], (unsigned char *)dest);
+
+ for (j = 1; j < vlen; j++) {
+ gf_vect_mad_vsx(len, vlen, j, gftbls, src[j], dest);
+ }
+ return;
+ }
+
+ t0 = (unsigned char *)dest;
+
+ head = len % 128;
+ if (head != 0) {
+ gf_vect_dot_prod_base(head, vlen, &gftbls[0 * 32 * vlen], src, t0);
+ }
+
+ for (i = head; i < len - 127; i += 128) {
+ vY1 = vY1 ^ vY1;
+ vY2 = vY2 ^ vY2;
+ vY3 = vY3 ^ vY3;
+ vY4 = vY4 ^ vY4;
+
+ vY5 = vY5 ^ vY5;
+ vY6 = vY6 ^ vY6;
+ vY7 = vY7 ^ vY7;
+ vY8 = vY8 ^ vY8;
+
+ unsigned char *g0 = &gftbls[0 * 32 * vlen];
+
+ for (j = 0; j < vlen; j++) {
+ s = (unsigned char *)src[j];
+ vX1 = vec_xl(0, s + i);
+ vX2 = vec_xl(16, s + i);
+ vX3 = vec_xl(32, s + i);
+ vX4 = vec_xl(48, s + i);
+
+ vlo0 = EC_vec_xl(0, g0);
+ vhi0 = EC_vec_xl(16, g0);
+
+ vX5 = vec_xl(64, s + i);
+ vX6 = vec_xl(80, s + i);
+ vX7 = vec_xl(96, s + i);
+ vX8 = vec_xl(112, s + i);
+
+ vY1 = vY1 ^ EC_vec_permxor(vhi0, vlo0, vX1);
+ vY2 = vY2 ^ EC_vec_permxor(vhi0, vlo0, vX2);
+ vY3 = vY3 ^ EC_vec_permxor(vhi0, vlo0, vX3);
+ vY4 = vY4 ^ EC_vec_permxor(vhi0, vlo0, vX4);
+
+ vY5 = vY5 ^ EC_vec_permxor(vhi0, vlo0, vX5);
+ vY6 = vY6 ^ EC_vec_permxor(vhi0, vlo0, vX6);
+ vY7 = vY7 ^ EC_vec_permxor(vhi0, vlo0, vX7);
+ vY8 = vY8 ^ EC_vec_permxor(vhi0, vlo0, vX8);
+
+ g0 += 32;
+ }
+ vec_xst(vY1, 0, t0 + i);
+ vec_xst(vY2, 16, t0 + i);
+ vec_xst(vY3, 32, t0 + i);
+ vec_xst(vY4, 48, t0 + i);
+
+ vec_xst(vY5, 64, t0 + i);
+ vec_xst(vY6, 80, t0 + i);
+ vec_xst(vY7, 96, t0 + i);
+ vec_xst(vY8, 112, t0 + i);
+ }
+ return;
+}
diff --git a/contrib/libs/isa-l/erasure_code/ppc64le/gf_vect_mad_vsx.c b/contrib/libs/isa-l/erasure_code/ppc64le/gf_vect_mad_vsx.c
new file mode 100644
index 0000000000..a4810b96db
--- /dev/null
+++ b/contrib/libs/isa-l/erasure_code/ppc64le/gf_vect_mad_vsx.c
@@ -0,0 +1,48 @@
+#include "ec_base_vsx.h"
+
+void gf_vect_mad_vsx(int len, int vec, int vec_i, unsigned char *gftbls,
+ unsigned char *src, unsigned char *dest)
+{
+ unsigned char *s, *t0;
+ vector unsigned char vX1, vY1;
+ vector unsigned char vX2, vY2;
+ vector unsigned char vX3, vY3;
+ vector unsigned char vX4, vY4;
+ vector unsigned char vhi0, vlo0;
+ int i, head;
+
+ s = (unsigned char *)src;
+ t0 = (unsigned char *)dest;
+
+ head = len % 64;
+ if (head != 0) {
+ gf_vect_mad_base(head, vec, vec_i, &gftbls[0 * 32 * vec], src, dest);
+ }
+
+ vlo0 = EC_vec_xl(0, gftbls + (((0 * vec) << 5) + (vec_i << 5)));
+ vhi0 = EC_vec_xl(16, gftbls + (((0 * vec) << 5) + (vec_i << 5)));
+
+ for (i = head; i < len - 63; i += 64) {
+ vX1 = vec_xl(0, s + i);
+ vX2 = vec_xl(16, s + i);
+ vX3 = vec_xl(32, s + i);
+ vX4 = vec_xl(48, s + i);
+
+ vY1 = vec_xl(0, t0 + i);
+ vY2 = vec_xl(16, t0 + i);
+ vY3 = vec_xl(32, t0 + i);
+ vY4 = vec_xl(48, t0 + i);
+
+ vY1 = vY1 ^ EC_vec_permxor(vhi0, vlo0, vX1);
+ vY2 = vY2 ^ EC_vec_permxor(vhi0, vlo0, vX2);
+ vY3 = vY3 ^ EC_vec_permxor(vhi0, vlo0, vX3);
+ vY4 = vY4 ^ EC_vec_permxor(vhi0, vlo0, vX4);
+
+ vec_xst(vY1, 0, t0 + i);
+ vec_xst(vY2, 16, t0 + i);
+ vec_xst(vY3, 32, t0 + i);
+ vec_xst(vY4, 48, t0 + i);
+ }
+
+ return;
+}
diff --git a/contrib/libs/isa-l/erasure_code/ppc64le/gf_vect_mul_vsx.c b/contrib/libs/isa-l/erasure_code/ppc64le/gf_vect_mul_vsx.c
new file mode 100644
index 0000000000..812eb83d82
--- /dev/null
+++ b/contrib/libs/isa-l/erasure_code/ppc64le/gf_vect_mul_vsx.c
@@ -0,0 +1,75 @@
+#include "ec_base_vsx.h"
+
+/*
+ * Same as gf_vect_mul_base in "ec_base.h" but without the size restriction.
+ */
+static void _gf_vect_mul_base(int len, unsigned char *a, unsigned char *src,
+ unsigned char *dest)
+{
+ //2nd element of table array is ref value used to fill it in
+ unsigned char c = a[1];
+
+ while (len-- > 0)
+ *dest++ = gf_mul_erasure(c, *src++);
+ return 0;
+}
+
+void gf_vect_mul_vsx(int len, unsigned char *gftbl, unsigned char *src, unsigned char *dest)
+{
+ unsigned char *s, *t0;
+ vector unsigned char vX1, vY1;
+ vector unsigned char vX2, vY2;
+ vector unsigned char vX3, vY3;
+ vector unsigned char vX4, vY4;
+ vector unsigned char vX5, vY5;
+ vector unsigned char vX6, vY6;
+ vector unsigned char vX7, vY7;
+ vector unsigned char vX8, vY8;
+ vector unsigned char vhi0, vlo0;
+ int i, head;
+
+ s = (unsigned char *)src;
+ t0 = (unsigned char *)dest;
+
+ head = len % 128;
+ if (head != 0) {
+ _gf_vect_mul_base(head, gftbl, src, dest);
+ }
+
+ vlo0 = EC_vec_xl(0, gftbl);
+ vhi0 = EC_vec_xl(16, gftbl);
+
+ for (i = head; i < len - 127; i += 128) {
+ vX1 = vec_xl(0, s + i);
+ vX2 = vec_xl(16, s + i);
+ vX3 = vec_xl(32, s + i);
+ vX4 = vec_xl(48, s + i);
+
+ vX5 = vec_xl(64, s + i);
+ vX6 = vec_xl(80, s + i);
+ vX7 = vec_xl(96, s + i);
+ vX8 = vec_xl(112, s + i);
+
+ vY1 = EC_vec_permxor(vhi0, vlo0, vX1);
+ vY2 = EC_vec_permxor(vhi0, vlo0, vX2);
+ vY3 = EC_vec_permxor(vhi0, vlo0, vX3);
+ vY4 = EC_vec_permxor(vhi0, vlo0, vX4);
+
+ vY5 = EC_vec_permxor(vhi0, vlo0, vX5);
+ vY6 = EC_vec_permxor(vhi0, vlo0, vX6);
+ vY7 = EC_vec_permxor(vhi0, vlo0, vX7);
+ vY8 = EC_vec_permxor(vhi0, vlo0, vX8);
+
+ vec_xst(vY1, 0, t0 + i);
+ vec_xst(vY2, 16, t0 + i);
+ vec_xst(vY3, 32, t0 + i);
+ vec_xst(vY4, 48, t0 + i);
+
+ vec_xst(vY5, 64, t0 + i);
+ vec_xst(vY6, 80, t0 + i);
+ vec_xst(vY7, 96, t0 + i);
+ vec_xst(vY8, 112, t0 + i);
+ }
+
+ return;
+}
diff --git a/contrib/libs/isa-l/erasure_code/ut/erasure_code_base_test/ya.make b/contrib/libs/isa-l/erasure_code/ut/erasure_code_base_test/ya.make
index 28acf0f7da..ad59a89cd1 100644
--- a/contrib/libs/isa-l/erasure_code/ut/erasure_code_base_test/ya.make
+++ b/contrib/libs/isa-l/erasure_code/ut/erasure_code_base_test/ya.make
@@ -1,6 +1,6 @@
PROGRAM()
-VERSION(2.28)
+VERSION(2.31)
LICENSE(BSD-3-Clause)
diff --git a/contrib/libs/isa-l/erasure_code/ut/erasure_code_test/ya.make b/contrib/libs/isa-l/erasure_code/ut/erasure_code_test/ya.make
index 1efbc5231f..4daab8f3ef 100644
--- a/contrib/libs/isa-l/erasure_code/ut/erasure_code_test/ya.make
+++ b/contrib/libs/isa-l/erasure_code/ut/erasure_code_test/ya.make
@@ -1,6 +1,6 @@
PROGRAM()
-VERSION(2.28)
+VERSION(2.31)
LICENSE(BSD-3-Clause)
diff --git a/contrib/libs/isa-l/erasure_code/ut/erasure_code_update_test/ya.make b/contrib/libs/isa-l/erasure_code/ut/erasure_code_update_test/ya.make
index 2b9e11fcaa..1fa89c9034 100644
--- a/contrib/libs/isa-l/erasure_code/ut/erasure_code_update_test/ya.make
+++ b/contrib/libs/isa-l/erasure_code/ut/erasure_code_update_test/ya.make
@@ -1,6 +1,6 @@
PROGRAM()
-VERSION(2.28)
+VERSION(2.31)
LICENSE(BSD-3-Clause)
diff --git a/contrib/libs/isa-l/erasure_code/ut/gf_2vect_dot_prod_sse_test/ya.make b/contrib/libs/isa-l/erasure_code/ut/gf_2vect_dot_prod_sse_test/ya.make
deleted file mode 100644
index 2a0c6baf2c..0000000000
--- a/contrib/libs/isa-l/erasure_code/ut/gf_2vect_dot_prod_sse_test/ya.make
+++ /dev/null
@@ -1,29 +0,0 @@
-PROGRAM()
-
-VERSION(2.28)
-
-LICENSE(BSD-3-Clause)
-
-LICENSE_TEXTS(.yandex_meta/licenses.list.txt)
-
-NO_UTIL()
-
-SUBSCRIBER(
- akozhikhov
- g:base
- g:yt
-)
-
-ADDINCL(contrib/libs/isa-l/include)
-
-NO_COMPILER_WARNINGS()
-
-SRCS(
- ../../gf_2vect_dot_prod_sse_test.c
-)
-
-PEERDIR(
- contrib/libs/isa-l/erasure_code
-)
-
-END()
diff --git a/contrib/libs/isa-l/erasure_code/ut/gf_3vect_dot_prod_sse_test/.yandex_meta/licenses.list.txt b/contrib/libs/isa-l/erasure_code/ut/gf_3vect_dot_prod_sse_test/.yandex_meta/licenses.list.txt
deleted file mode 100644
index 8f218b47cb..0000000000
--- a/contrib/libs/isa-l/erasure_code/ut/gf_3vect_dot_prod_sse_test/.yandex_meta/licenses.list.txt
+++ /dev/null
@@ -1,164 +0,0 @@
-====================BSD-3-Clause====================
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions
- are met:
- * Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in
- the documentation and/or other materials provided with the
- distribution.
- * Neither the name of Intel Corporation nor the names of its
- contributors may be used to endorse or promote products derived
- from this software without specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-====================BSD-3-Clause====================
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above copyright
-# notice, this list of conditions and the following disclaimer in
-# the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Arm Corporation nor the names of its
-# contributors may be used to endorse or promote products derived
-# from this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-
-====================BSD-3-Clause====================
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above copyright
-# notice, this list of conditions and the following disclaimer in
-# the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Intel Corporation nor the names of its
-# contributors may be used to endorse or promote products derived
-# from this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-
-====================BSD-3-Clause====================
-; Redistribution and use in source and binary forms, with or without
-; modification, are permitted provided that the following conditions
-; are met:
-; * Redistributions of source code must retain the above copyright
-; notice, this list of conditions and the following disclaimer.
-; * Redistributions in binary form must reproduce the above copyright
-; notice, this list of conditions and the following disclaimer in
-; the documentation and/or other materials provided with the
-; distribution.
-; * Neither the name of Intel Corporation nor the names of its
-; contributors may be used to endorse or promote products derived
-; from this software without specific prior written permission.
-;
-; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-; "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-; A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-; OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-; SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-; LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-; OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-
-====================BSD-3-Clause====================
-ISA-L is licensed using a BSD 3-clause [license]. All code submitted to
-
-
-====================BSD-3-Clause AND BSD-3-Clause AND BSD-3-Clause====================
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions
- are met:
- * Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in
- the documentation and/or other materials provided with the
- distribution.
- * Neither the name of Arm Corporation nor the names of its
- contributors may be used to endorse or promote products derived
- from this software without specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-
-====================COPYRIGHT====================
- Copyright(c) 2011-2013 Intel Corporation All rights reserved.
-
-
-====================COPYRIGHT====================
- Copyright(c) 2011-2017 Intel Corporation All rights reserved.
-
-
-====================COPYRIGHT====================
-# Copyright(c) 2011-2015 Intel Corporation All rights reserved.
-
-
-====================COPYRIGHT====================
-# Copyright(c) 2011-2016 Intel Corporation All rights reserved.
-
-
-====================COPYRIGHT====================
-# Copyright(c) 2011-2018 Intel Corporation All rights reserved.
-
-
-====================COPYRIGHT====================
-# Copyright(c) 2019 Arm Corporation All rights reserved.
-
-
-====================COPYRIGHT====================
-; Copyright(c) 2011-2019 Intel Corporation All rights reserved.
diff --git a/contrib/libs/isa-l/erasure_code/ut/gf_3vect_dot_prod_sse_test/ya.make b/contrib/libs/isa-l/erasure_code/ut/gf_3vect_dot_prod_sse_test/ya.make
deleted file mode 100644
index c4b11b139e..0000000000
--- a/contrib/libs/isa-l/erasure_code/ut/gf_3vect_dot_prod_sse_test/ya.make
+++ /dev/null
@@ -1,29 +0,0 @@
-PROGRAM()
-
-VERSION(2.28)
-
-LICENSE(BSD-3-Clause)
-
-LICENSE_TEXTS(.yandex_meta/licenses.list.txt)
-
-NO_UTIL()
-
-SUBSCRIBER(
- akozhikhov
- g:base
- g:yt
-)
-
-ADDINCL(contrib/libs/isa-l/include)
-
-NO_COMPILER_WARNINGS()
-
-SRCS(
- ../../gf_3vect_dot_prod_sse_test.c
-)
-
-PEERDIR(
- contrib/libs/isa-l/erasure_code
-)
-
-END()
diff --git a/contrib/libs/isa-l/erasure_code/ut/gf_4vect_dot_prod_sse_test/.yandex_meta/licenses.list.txt b/contrib/libs/isa-l/erasure_code/ut/gf_4vect_dot_prod_sse_test/.yandex_meta/licenses.list.txt
deleted file mode 100644
index 8f218b47cb..0000000000
--- a/contrib/libs/isa-l/erasure_code/ut/gf_4vect_dot_prod_sse_test/.yandex_meta/licenses.list.txt
+++ /dev/null
@@ -1,164 +0,0 @@
-====================BSD-3-Clause====================
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions
- are met:
- * Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in
- the documentation and/or other materials provided with the
- distribution.
- * Neither the name of Intel Corporation nor the names of its
- contributors may be used to endorse or promote products derived
- from this software without specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-====================BSD-3-Clause====================
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above copyright
-# notice, this list of conditions and the following disclaimer in
-# the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Arm Corporation nor the names of its
-# contributors may be used to endorse or promote products derived
-# from this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-
-====================BSD-3-Clause====================
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above copyright
-# notice, this list of conditions and the following disclaimer in
-# the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Intel Corporation nor the names of its
-# contributors may be used to endorse or promote products derived
-# from this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-
-====================BSD-3-Clause====================
-; Redistribution and use in source and binary forms, with or without
-; modification, are permitted provided that the following conditions
-; are met:
-; * Redistributions of source code must retain the above copyright
-; notice, this list of conditions and the following disclaimer.
-; * Redistributions in binary form must reproduce the above copyright
-; notice, this list of conditions and the following disclaimer in
-; the documentation and/or other materials provided with the
-; distribution.
-; * Neither the name of Intel Corporation nor the names of its
-; contributors may be used to endorse or promote products derived
-; from this software without specific prior written permission.
-;
-; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-; "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-; A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-; OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-; SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-; LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-; OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-
-====================BSD-3-Clause====================
-ISA-L is licensed using a BSD 3-clause [license]. All code submitted to
-
-
-====================BSD-3-Clause AND BSD-3-Clause AND BSD-3-Clause====================
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions
- are met:
- * Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in
- the documentation and/or other materials provided with the
- distribution.
- * Neither the name of Arm Corporation nor the names of its
- contributors may be used to endorse or promote products derived
- from this software without specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-
-====================COPYRIGHT====================
- Copyright(c) 2011-2013 Intel Corporation All rights reserved.
-
-
-====================COPYRIGHT====================
- Copyright(c) 2011-2017 Intel Corporation All rights reserved.
-
-
-====================COPYRIGHT====================
-# Copyright(c) 2011-2015 Intel Corporation All rights reserved.
-
-
-====================COPYRIGHT====================
-# Copyright(c) 2011-2016 Intel Corporation All rights reserved.
-
-
-====================COPYRIGHT====================
-# Copyright(c) 2011-2018 Intel Corporation All rights reserved.
-
-
-====================COPYRIGHT====================
-# Copyright(c) 2019 Arm Corporation All rights reserved.
-
-
-====================COPYRIGHT====================
-; Copyright(c) 2011-2019 Intel Corporation All rights reserved.
diff --git a/contrib/libs/isa-l/erasure_code/ut/gf_4vect_dot_prod_sse_test/ya.make b/contrib/libs/isa-l/erasure_code/ut/gf_4vect_dot_prod_sse_test/ya.make
deleted file mode 100644
index 758e7463a1..0000000000
--- a/contrib/libs/isa-l/erasure_code/ut/gf_4vect_dot_prod_sse_test/ya.make
+++ /dev/null
@@ -1,29 +0,0 @@
-PROGRAM()
-
-VERSION(2.28)
-
-LICENSE(BSD-3-Clause)
-
-LICENSE_TEXTS(.yandex_meta/licenses.list.txt)
-
-NO_UTIL()
-
-SUBSCRIBER(
- akozhikhov
- g:base
- g:yt
-)
-
-ADDINCL(contrib/libs/isa-l/include)
-
-NO_COMPILER_WARNINGS()
-
-SRCS(
- ../../gf_4vect_dot_prod_sse_test.c
-)
-
-PEERDIR(
- contrib/libs/isa-l/erasure_code
-)
-
-END()
diff --git a/contrib/libs/isa-l/erasure_code/ut/gf_5vect_dot_prod_sse_test/.yandex_meta/licenses.list.txt b/contrib/libs/isa-l/erasure_code/ut/gf_5vect_dot_prod_sse_test/.yandex_meta/licenses.list.txt
deleted file mode 100644
index 8f218b47cb..0000000000
--- a/contrib/libs/isa-l/erasure_code/ut/gf_5vect_dot_prod_sse_test/.yandex_meta/licenses.list.txt
+++ /dev/null
@@ -1,164 +0,0 @@
-====================BSD-3-Clause====================
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions
- are met:
- * Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in
- the documentation and/or other materials provided with the
- distribution.
- * Neither the name of Intel Corporation nor the names of its
- contributors may be used to endorse or promote products derived
- from this software without specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-====================BSD-3-Clause====================
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above copyright
-# notice, this list of conditions and the following disclaimer in
-# the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Arm Corporation nor the names of its
-# contributors may be used to endorse or promote products derived
-# from this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-
-====================BSD-3-Clause====================
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above copyright
-# notice, this list of conditions and the following disclaimer in
-# the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Intel Corporation nor the names of its
-# contributors may be used to endorse or promote products derived
-# from this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-
-====================BSD-3-Clause====================
-; Redistribution and use in source and binary forms, with or without
-; modification, are permitted provided that the following conditions
-; are met:
-; * Redistributions of source code must retain the above copyright
-; notice, this list of conditions and the following disclaimer.
-; * Redistributions in binary form must reproduce the above copyright
-; notice, this list of conditions and the following disclaimer in
-; the documentation and/or other materials provided with the
-; distribution.
-; * Neither the name of Intel Corporation nor the names of its
-; contributors may be used to endorse or promote products derived
-; from this software without specific prior written permission.
-;
-; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-; "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-; A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-; OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-; SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-; LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-; OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-
-====================BSD-3-Clause====================
-ISA-L is licensed using a BSD 3-clause [license]. All code submitted to
-
-
-====================BSD-3-Clause AND BSD-3-Clause AND BSD-3-Clause====================
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions
- are met:
- * Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in
- the documentation and/or other materials provided with the
- distribution.
- * Neither the name of Arm Corporation nor the names of its
- contributors may be used to endorse or promote products derived
- from this software without specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-
-====================COPYRIGHT====================
- Copyright(c) 2011-2013 Intel Corporation All rights reserved.
-
-
-====================COPYRIGHT====================
- Copyright(c) 2011-2017 Intel Corporation All rights reserved.
-
-
-====================COPYRIGHT====================
-# Copyright(c) 2011-2015 Intel Corporation All rights reserved.
-
-
-====================COPYRIGHT====================
-# Copyright(c) 2011-2016 Intel Corporation All rights reserved.
-
-
-====================COPYRIGHT====================
-# Copyright(c) 2011-2018 Intel Corporation All rights reserved.
-
-
-====================COPYRIGHT====================
-# Copyright(c) 2019 Arm Corporation All rights reserved.
-
-
-====================COPYRIGHT====================
-; Copyright(c) 2011-2019 Intel Corporation All rights reserved.
diff --git a/contrib/libs/isa-l/erasure_code/ut/gf_5vect_dot_prod_sse_test/ya.make b/contrib/libs/isa-l/erasure_code/ut/gf_5vect_dot_prod_sse_test/ya.make
deleted file mode 100644
index 4c389b8188..0000000000
--- a/contrib/libs/isa-l/erasure_code/ut/gf_5vect_dot_prod_sse_test/ya.make
+++ /dev/null
@@ -1,29 +0,0 @@
-PROGRAM()
-
-VERSION(2.28)
-
-LICENSE(BSD-3-Clause)
-
-LICENSE_TEXTS(.yandex_meta/licenses.list.txt)
-
-NO_UTIL()
-
-SUBSCRIBER(
- akozhikhov
- g:base
- g:yt
-)
-
-ADDINCL(contrib/libs/isa-l/include)
-
-NO_COMPILER_WARNINGS()
-
-SRCS(
- ../../gf_5vect_dot_prod_sse_test.c
-)
-
-PEERDIR(
- contrib/libs/isa-l/erasure_code
-)
-
-END()
diff --git a/contrib/libs/isa-l/erasure_code/ut/gf_6vect_dot_prod_sse_test/.yandex_meta/licenses.list.txt b/contrib/libs/isa-l/erasure_code/ut/gf_6vect_dot_prod_sse_test/.yandex_meta/licenses.list.txt
deleted file mode 100644
index 8f218b47cb..0000000000
--- a/contrib/libs/isa-l/erasure_code/ut/gf_6vect_dot_prod_sse_test/.yandex_meta/licenses.list.txt
+++ /dev/null
@@ -1,164 +0,0 @@
-====================BSD-3-Clause====================
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions
- are met:
- * Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in
- the documentation and/or other materials provided with the
- distribution.
- * Neither the name of Intel Corporation nor the names of its
- contributors may be used to endorse or promote products derived
- from this software without specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-====================BSD-3-Clause====================
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above copyright
-# notice, this list of conditions and the following disclaimer in
-# the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Arm Corporation nor the names of its
-# contributors may be used to endorse or promote products derived
-# from this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-
-====================BSD-3-Clause====================
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above copyright
-# notice, this list of conditions and the following disclaimer in
-# the documentation and/or other materials provided with the
-# distribution.
-# * Neither the name of Intel Corporation nor the names of its
-# contributors may be used to endorse or promote products derived
-# from this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-
-====================BSD-3-Clause====================
-; Redistribution and use in source and binary forms, with or without
-; modification, are permitted provided that the following conditions
-; are met:
-; * Redistributions of source code must retain the above copyright
-; notice, this list of conditions and the following disclaimer.
-; * Redistributions in binary form must reproduce the above copyright
-; notice, this list of conditions and the following disclaimer in
-; the documentation and/or other materials provided with the
-; distribution.
-; * Neither the name of Intel Corporation nor the names of its
-; contributors may be used to endorse or promote products derived
-; from this software without specific prior written permission.
-;
-; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-; "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-; A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-; OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-; SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-; LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-; OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-
-====================BSD-3-Clause====================
-ISA-L is licensed using a BSD 3-clause [license]. All code submitted to
-
-
-====================BSD-3-Clause AND BSD-3-Clause AND BSD-3-Clause====================
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions
- are met:
- * Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in
- the documentation and/or other materials provided with the
- distribution.
- * Neither the name of Arm Corporation nor the names of its
- contributors may be used to endorse or promote products derived
- from this software without specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-
-====================COPYRIGHT====================
- Copyright(c) 2011-2013 Intel Corporation All rights reserved.
-
-
-====================COPYRIGHT====================
- Copyright(c) 2011-2017 Intel Corporation All rights reserved.
-
-
-====================COPYRIGHT====================
-# Copyright(c) 2011-2015 Intel Corporation All rights reserved.
-
-
-====================COPYRIGHT====================
-# Copyright(c) 2011-2016 Intel Corporation All rights reserved.
-
-
-====================COPYRIGHT====================
-# Copyright(c) 2011-2018 Intel Corporation All rights reserved.
-
-
-====================COPYRIGHT====================
-# Copyright(c) 2019 Arm Corporation All rights reserved.
-
-
-====================COPYRIGHT====================
-; Copyright(c) 2011-2019 Intel Corporation All rights reserved.
diff --git a/contrib/libs/isa-l/erasure_code/ut/gf_6vect_dot_prod_sse_test/ya.make b/contrib/libs/isa-l/erasure_code/ut/gf_6vect_dot_prod_sse_test/ya.make
deleted file mode 100644
index 09f782f76a..0000000000
--- a/contrib/libs/isa-l/erasure_code/ut/gf_6vect_dot_prod_sse_test/ya.make
+++ /dev/null
@@ -1,29 +0,0 @@
-PROGRAM()
-
-VERSION(2.28)
-
-LICENSE(BSD-3-Clause)
-
-LICENSE_TEXTS(.yandex_meta/licenses.list.txt)
-
-NO_UTIL()
-
-SUBSCRIBER(
- akozhikhov
- g:base
- g:yt
-)
-
-ADDINCL(contrib/libs/isa-l/include)
-
-NO_COMPILER_WARNINGS()
-
-SRCS(
- ../../gf_6vect_dot_prod_sse_test.c
-)
-
-PEERDIR(
- contrib/libs/isa-l/erasure_code
-)
-
-END()
diff --git a/contrib/libs/isa-l/erasure_code/ut/gf_inverse_test/ya.make b/contrib/libs/isa-l/erasure_code/ut/gf_inverse_test/ya.make
index dc59e7e3d3..fc897ca8a2 100644
--- a/contrib/libs/isa-l/erasure_code/ut/gf_inverse_test/ya.make
+++ b/contrib/libs/isa-l/erasure_code/ut/gf_inverse_test/ya.make
@@ -1,6 +1,6 @@
PROGRAM()
-VERSION(2.28)
+VERSION(2.31)
LICENSE(BSD-3-Clause)
diff --git a/contrib/libs/isa-l/erasure_code/ut/gf_vect_dot_prod_base_test/ya.make b/contrib/libs/isa-l/erasure_code/ut/gf_vect_dot_prod_base_test/ya.make
index 89d263fa19..e396b42fdf 100644
--- a/contrib/libs/isa-l/erasure_code/ut/gf_vect_dot_prod_base_test/ya.make
+++ b/contrib/libs/isa-l/erasure_code/ut/gf_vect_dot_prod_base_test/ya.make
@@ -1,6 +1,6 @@
PROGRAM()
-VERSION(2.28)
+VERSION(2.31)
LICENSE(BSD-3-Clause)
diff --git a/contrib/libs/isa-l/erasure_code/ut/gf_vect_dot_prod_test/ya.make b/contrib/libs/isa-l/erasure_code/ut/gf_vect_dot_prod_test/ya.make
index 4767c00d3a..20897781ea 100644
--- a/contrib/libs/isa-l/erasure_code/ut/gf_vect_dot_prod_test/ya.make
+++ b/contrib/libs/isa-l/erasure_code/ut/gf_vect_dot_prod_test/ya.make
@@ -1,6 +1,6 @@
PROGRAM()
-VERSION(2.28)
+VERSION(2.31)
LICENSE(BSD-3-Clause)
diff --git a/contrib/libs/isa-l/erasure_code/ut/gf_vect_mad_test/ya.make b/contrib/libs/isa-l/erasure_code/ut/gf_vect_mad_test/ya.make
index 2d776e53f4..0bd839954d 100644
--- a/contrib/libs/isa-l/erasure_code/ut/gf_vect_mad_test/ya.make
+++ b/contrib/libs/isa-l/erasure_code/ut/gf_vect_mad_test/ya.make
@@ -1,6 +1,6 @@
PROGRAM()
-VERSION(2.28)
+VERSION(2.31)
LICENSE(BSD-3-Clause)
diff --git a/contrib/libs/isa-l/erasure_code/ut/gf_vect_mul_base_test/ya.make b/contrib/libs/isa-l/erasure_code/ut/gf_vect_mul_base_test/ya.make
index 2725cbf67e..37f0606713 100644
--- a/contrib/libs/isa-l/erasure_code/ut/gf_vect_mul_base_test/ya.make
+++ b/contrib/libs/isa-l/erasure_code/ut/gf_vect_mul_base_test/ya.make
@@ -1,6 +1,6 @@
PROGRAM()
-VERSION(2.28)
+VERSION(2.31)
LICENSE(BSD-3-Clause)
diff --git a/contrib/libs/isa-l/erasure_code/ut/gf_vect_mul_test/ya.make b/contrib/libs/isa-l/erasure_code/ut/gf_vect_mul_test/ya.make
index 614ceddd89..c22dd39c6d 100644
--- a/contrib/libs/isa-l/erasure_code/ut/gf_vect_mul_test/ya.make
+++ b/contrib/libs/isa-l/erasure_code/ut/gf_vect_mul_test/ya.make
@@ -1,6 +1,6 @@
PROGRAM()
-VERSION(2.28)
+VERSION(2.31)
LICENSE(BSD-3-Clause)
diff --git a/contrib/libs/isa-l/erasure_code/ut/ya.make b/contrib/libs/isa-l/erasure_code/ut/ya.make
index 637eac1966..7bc4eff15e 100644
--- a/contrib/libs/isa-l/erasure_code/ut/ya.make
+++ b/contrib/libs/isa-l/erasure_code/ut/ya.make
@@ -5,7 +5,7 @@ SUBSCRIBER(
EXECTEST()
-VERSION(2.28)
+VERSION(2.31)
LICENSE(BSD-3-Clause)
@@ -19,16 +19,6 @@ RUN(erasure_code_base_test)
RUN(erasure_code_update_test)
-RUN(gf_2vect_dot_prod_sse_test)
-
-RUN(gf_3vect_dot_prod_sse_test)
-
-RUN(gf_4vect_dot_prod_sse_test)
-
-RUN(gf_5vect_dot_prod_sse_test)
-
-RUN(gf_6vect_dot_prod_sse_test)
-
RUN(gf_inverse_test)
RUN(gf_vect_dot_prod_base_test)
@@ -45,11 +35,6 @@ DEPENDS(
contrib/libs/isa-l/erasure_code/ut/erasure_code_test
contrib/libs/isa-l/erasure_code/ut/erasure_code_base_test
contrib/libs/isa-l/erasure_code/ut/erasure_code_update_test
- contrib/libs/isa-l/erasure_code/ut/gf_2vect_dot_prod_sse_test
- contrib/libs/isa-l/erasure_code/ut/gf_3vect_dot_prod_sse_test
- contrib/libs/isa-l/erasure_code/ut/gf_4vect_dot_prod_sse_test
- contrib/libs/isa-l/erasure_code/ut/gf_5vect_dot_prod_sse_test
- contrib/libs/isa-l/erasure_code/ut/gf_6vect_dot_prod_sse_test
contrib/libs/isa-l/erasure_code/ut/gf_inverse_test
contrib/libs/isa-l/erasure_code/ut/gf_vect_dot_prod_base_test
contrib/libs/isa-l/erasure_code/ut/gf_vect_dot_prod_test
@@ -64,11 +49,6 @@ RECURSE_FOR_TESTS(
erasure_code_test
erasure_code_base_test
erasure_code_update_test
- gf_2vect_dot_prod_sse_test
- gf_3vect_dot_prod_sse_test
- gf_4vect_dot_prod_sse_test
- gf_5vect_dot_prod_sse_test
- gf_6vect_dot_prod_sse_test
gf_inverse_test
gf_vect_dot_prod_base_test
gf_vect_dot_prod_test
diff --git a/contrib/libs/isa-l/erasure_code/ya.make b/contrib/libs/isa-l/erasure_code/ya.make
index a1c30ae5be..0f2c15a27f 100644
--- a/contrib/libs/isa-l/erasure_code/ya.make
+++ b/contrib/libs/isa-l/erasure_code/ya.make
@@ -4,7 +4,7 @@ LICENSE(BSD-3-Clause)
LICENSE_TEXTS(.yandex_meta/licenses.list.txt)
-VERSION(2.28)
+VERSION(2.31)
NO_UTIL()
@@ -17,11 +17,6 @@ ADDINCL(
contrib/libs/isa-l/include
)
-SRCS(
- ec_base.c
- ec_highlevel_func.c
-)
-
IF (ARCH_X86_64)
IF (OS_DARWIN)
SRCS(
@@ -34,52 +29,88 @@ ELSE()
ENDIF()
SRCS(
- gf_vect_mul_sse.asm
- gf_vect_mul_avx.asm
- gf_vect_dot_prod_sse.asm
- gf_vect_dot_prod_avx.asm
- gf_vect_dot_prod_avx2.asm
- gf_vect_dot_prod_avx512.asm
- gf_2vect_dot_prod_sse.asm
- gf_2vect_dot_prod_avx.asm
+ ec_base.c
+ ec_highlevel_func.c
gf_2vect_dot_prod_avx2.asm
+ gf_2vect_dot_prod_avx2_gfni.asm
gf_2vect_dot_prod_avx512.asm
- gf_3vect_dot_prod_sse.asm
- gf_3vect_dot_prod_avx.asm
- gf_3vect_dot_prod_avx2.asm
- gf_3vect_dot_prod_avx512.asm
- gf_4vect_dot_prod_sse.asm
- gf_4vect_dot_prod_avx.asm
- gf_4vect_dot_prod_avx2.asm
- gf_4vect_dot_prod_avx512.asm
- gf_5vect_dot_prod_sse.asm
- gf_5vect_dot_prod_avx.asm
- gf_5vect_dot_prod_avx2.asm
- gf_6vect_dot_prod_sse.asm
- gf_6vect_dot_prod_avx.asm
- gf_6vect_dot_prod_avx2.asm
- gf_vect_mad_sse.asm
- gf_vect_mad_avx.asm
- gf_vect_mad_avx2.asm
- gf_vect_mad_avx512.asm
- gf_2vect_mad_sse.asm
- gf_2vect_mad_avx.asm
+ gf_2vect_dot_prod_avx512_gfni.asm
+ gf_2vect_dot_prod_avx.asm
+ gf_2vect_dot_prod_sse.asm
gf_2vect_mad_avx2.asm
+ gf_2vect_mad_avx2_gfni.asm
gf_2vect_mad_avx512.asm
- gf_3vect_mad_sse.asm
- gf_3vect_mad_avx.asm
+ gf_2vect_mad_avx512_gfni.asm
+ gf_2vect_mad_avx.asm
+ gf_2vect_mad_sse.asm
+ gf_3vect_dot_prod_avx2.asm
+ gf_3vect_dot_prod_avx2_gfni.asm
+ gf_3vect_dot_prod_avx512.asm
+ gf_3vect_dot_prod_avx512_gfni.asm
+ gf_3vect_dot_prod_avx.asm
+ gf_3vect_dot_prod_sse.asm
gf_3vect_mad_avx2.asm
+ gf_3vect_mad_avx2_gfni.asm
gf_3vect_mad_avx512.asm
- gf_4vect_mad_sse.asm
- gf_4vect_mad_avx.asm
+ gf_3vect_mad_avx512_gfni.asm
+ gf_3vect_mad_avx.asm
+ gf_3vect_mad_sse.asm
+ gf_4vect_dot_prod_avx2.asm
+ gf_4vect_dot_prod_avx512.asm
+ gf_4vect_dot_prod_avx512_gfni.asm
+ gf_4vect_dot_prod_avx.asm
+ gf_4vect_dot_prod_sse.asm
gf_4vect_mad_avx2.asm
+ gf_4vect_mad_avx2_gfni.asm
gf_4vect_mad_avx512.asm
- gf_5vect_mad_sse.asm
- gf_5vect_mad_avx.asm
+ gf_4vect_mad_avx512_gfni.asm
+ gf_4vect_mad_avx.asm
+ gf_4vect_mad_sse.asm
+ gf_5vect_dot_prod_avx2.asm
+ gf_5vect_dot_prod_avx512.asm
+ gf_5vect_dot_prod_avx512_gfni.asm
+ gf_5vect_dot_prod_avx.asm
+ gf_5vect_dot_prod_sse.asm
gf_5vect_mad_avx2.asm
- gf_6vect_mad_sse.asm
- gf_6vect_mad_avx.asm
+ gf_5vect_mad_avx2_gfni.asm
+ gf_5vect_mad_avx512.asm
+ gf_5vect_mad_avx512_gfni.asm
+ gf_5vect_mad_avx.asm
+ gf_5vect_mad_sse.asm
+ gf_6vect_dot_prod_avx2.asm
+ gf_6vect_dot_prod_avx512.asm
+ gf_6vect_dot_prod_avx512_gfni.asm
+ gf_6vect_dot_prod_avx.asm
+ gf_6vect_dot_prod_sse.asm
gf_6vect_mad_avx2.asm
+ gf_6vect_mad_avx512.asm
+ gf_6vect_mad_avx512_gfni.asm
+ gf_6vect_mad_avx.asm
+ gf_6vect_mad_sse.asm
+ gf_vect_dot_prod_avx2.asm
+ gf_vect_dot_prod_avx2_gfni.asm
+ gf_vect_dot_prod_avx512.asm
+ gf_vect_dot_prod_avx512_gfni.asm
+ gf_vect_dot_prod_avx.asm
+ gf_vect_dot_prod_sse.asm
+ gf_vect_mad_avx2.asm
+ gf_vect_mad_avx2_gfni.asm
+ gf_vect_mad_avx512.asm
+ gf_vect_mad_avx512_gfni.asm
+ gf_vect_mad_avx.asm
+ gf_vect_mad_sse.asm
+ gf_vect_mul_avx.asm
+ gf_vect_mul_sse.asm
+)
+ELSEIF(ARCH_AARCH64)
+SRCS(
+ ec_base.c
+ aarch64/ec_aarch64_dispatcher.c
+ aarch64/ec_aarch64_highlevel_func.c
+)
+
+PEERDIR(
+ contrib/libs/isa-l/erasure_code/aarch64
)
ENDIF()
diff --git a/contrib/libs/isa-l/include/aarch64_label.h b/contrib/libs/isa-l/include/aarch64_label.h
new file mode 100644
index 0000000000..a4e6d0609c
--- /dev/null
+++ b/contrib/libs/isa-l/include/aarch64_label.h
@@ -0,0 +1,18 @@
+#ifndef __AARCH64_LABEL_H__
+#define __AARCH64_LABEL_H__
+
+#ifdef __USER_LABEL_PREFIX__
+#define CONCAT1(a, b) CONCAT2(a, b)
+#define CONCAT2(a, b) a ## b
+#define cdecl(x) CONCAT1 (__USER_LABEL_PREFIX__, x)
+#else
+#define cdecl(x) x
+#endif
+
+#ifdef __APPLE__
+#define ASM_DEF_RODATA .section __TEXT,__const
+#else
+#define ASM_DEF_RODATA .section .rodata
+#endif
+
+#endif
diff --git a/contrib/libs/isa-l/include/aarch64_multibinary.h b/contrib/libs/isa-l/include/aarch64_multibinary.h
new file mode 100644
index 0000000000..6c77665fd6
--- /dev/null
+++ b/contrib/libs/isa-l/include/aarch64_multibinary.h
@@ -0,0 +1,347 @@
+/**********************************************************************
+ Copyright(c) 2020 Arm Corporation All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name of Arm Corporation nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+**********************************************************************/
+#ifndef __AARCH64_MULTIBINARY_H__
+#define __AARCH64_MULTIBINARY_H__
+#ifndef __aarch64__
+#error "This file is for aarch64 only"
+#endif
+#include "aarch64_label.h"
+#ifdef __ASSEMBLY__
+/**
+ * # mbin_interface : the wrapper layer for isal-l api
+ *
+ * ## references:
+ * * https://sourceware.org/git/gitweb.cgi?p=glibc.git;a=blob;f=sysdeps/aarch64/dl-trampoline.S
+ * * http://infocenter.arm.com/help/topic/com.arm.doc.ihi0055b/IHI0055B_aapcs64.pdf
+ * * https://static.docs.arm.com/ihi0057/b/IHI0057B_aadwarf64.pdf?_ga=2.80574487.1870739014.1564969896-1634778941.1548729310
+ *
+ * ## Usage:
+ * 1. Define dispather function
+ * 2. name must be \name\()_dispatcher
+ * 3. Prototype should be *"void * \name\()_dispatcher"*
+ * 4. The dispather should return the right function pointer , revision and a string information .
+ **/
+.macro mbin_interface name:req
+ .extern cdecl(\name\()_dispatcher)
+ .data
+ .balign 8
+ .global cdecl(\name\()_dispatcher_info)
+#ifndef __APPLE__
+ .type \name\()_dispatcher_info,%object
+#endif
+ cdecl(\name\()_dispatcher_info):
+ .quad \name\()_mbinit //func_entry
+#ifndef __APPLE__
+ .size \name\()_dispatcher_info,. - \name\()_dispatcher_info
+#endif
+ .balign 8
+ .text
+ \name\()_mbinit:
+ //save lp fp, sub sp
+ .cfi_startproc
+ stp x29, x30, [sp, -224]!
+
+ //add cfi directive to avoid GDB bt cmds error
+ //set cfi(Call Frame Information)
+ .cfi_def_cfa_offset 224
+ .cfi_offset 29, -224
+ .cfi_offset 30, -216
+
+ //save parameter/result/indirect result registers
+ stp x8, x9, [sp, 16]
+ .cfi_offset 8, -208
+ .cfi_offset 9, -200
+ stp x0, x1, [sp, 32]
+ .cfi_offset 0, -192
+ .cfi_offset 1, -184
+ stp x2, x3, [sp, 48]
+ .cfi_offset 2, -176
+ .cfi_offset 3, -168
+ stp x4, x5, [sp, 64]
+ .cfi_offset 4, -160
+ .cfi_offset 5, -152
+ stp x6, x7, [sp, 80]
+ .cfi_offset 6, -144
+ .cfi_offset 7, -136
+ stp q0, q1, [sp, 96]
+ .cfi_offset 64, -128
+ .cfi_offset 65, -112
+ stp q2, q3, [sp, 128]
+ .cfi_offset 66, -96
+ .cfi_offset 67, -80
+ stp q4, q5, [sp, 160]
+ .cfi_offset 68, -64
+ .cfi_offset 69, -48
+ stp q6, q7, [sp, 192]
+ .cfi_offset 70, -32
+ .cfi_offset 71, -16
+
+ /**
+ * The dispatcher functions have the following prototype:
+ * void * function_dispatcher(void)
+ * As the dispatcher is returning a struct, by the AAPCS,
+ */
+
+
+ bl cdecl(\name\()_dispatcher)
+ //restore temp/indirect result registers
+ ldp x8, x9, [sp, 16]
+ .cfi_restore 8
+ .cfi_restore 9
+
+ // save function entry
+ str x0, [x9]
+
+ //restore parameter/result registers
+ ldp x0, x1, [sp, 32]
+ .cfi_restore 0
+ .cfi_restore 1
+ ldp x2, x3, [sp, 48]
+ .cfi_restore 2
+ .cfi_restore 3
+ ldp x4, x5, [sp, 64]
+ .cfi_restore 4
+ .cfi_restore 5
+ ldp x6, x7, [sp, 80]
+ .cfi_restore 6
+ .cfi_restore 7
+ ldp q0, q1, [sp, 96]
+ .cfi_restore 64
+ .cfi_restore 65
+ ldp q2, q3, [sp, 128]
+ .cfi_restore 66
+ .cfi_restore 67
+ ldp q4, q5, [sp, 160]
+ .cfi_restore 68
+ .cfi_restore 69
+ ldp q6, q7, [sp, 192]
+ .cfi_restore 70
+ .cfi_restore 71
+ //save lp fp and sp
+ ldp x29, x30, [sp], 224
+ //restore cfi setting
+ .cfi_restore 30
+ .cfi_restore 29
+ .cfi_def_cfa_offset 0
+ .cfi_endproc
+
+ .global cdecl(\name)
+#ifndef __APPLE__
+ .type \name,%function
+#endif
+ .align 2
+ cdecl(\name\()):
+#ifndef __APPLE__
+ adrp x9, :got:\name\()_dispatcher_info
+ ldr x9, [x9, #:got_lo12:\name\()_dispatcher_info]
+#else
+ adrp x9, cdecl(\name\()_dispatcher_info)@GOTPAGE
+ ldr x9, [x9, #cdecl(\name\()_dispatcher_info)@GOTPAGEOFF]
+#endif
+ ldr x10,[x9]
+ br x10
+#ifndef __APPLE__
+ .size \name,. - \name
+#endif
+.endm
+
+/**
+ * mbin_interface_base is used for the interfaces which have only
+ * noarch implementation
+ */
+.macro mbin_interface_base name:req, base:req
+ .extern \base
+ .data
+ .balign 8
+ .global cdecl(\name\()_dispatcher_info)
+#ifndef __APPLE__
+ .type \name\()_dispatcher_info,%object
+#endif
+ cdecl(\name\()_dispatcher_info):
+ .quad \base //func_entry
+#ifndef __APPLE__
+ .size \name\()_dispatcher_info,. - \name\()_dispatcher_info
+#endif
+ .balign 8
+ .text
+ .global cdecl(\name)
+#ifndef __APPLE__
+ .type \name,%function
+#endif
+ .align 2
+ cdecl(\name\()):
+#ifndef __APPLE__
+ adrp x9, :got:cdecl(_\name\()_dispatcher_info)
+ ldr x9, [x9, #:got_lo12:cdecl(_\name\()_dispatcher_info)]
+#else
+ adrp x9, cdecl(_\name\()_dispatcher_info)@GOTPAGE
+ ldr x9, [x9, #cdecl(_\name\()_dispatcher_info)@GOTPAGEOFF]
+#endif
+ ldr x10,[x9]
+ br x10
+#ifndef __APPLE__
+ .size \name,. - \name
+#endif
+.endm
+
+#else /* __ASSEMBLY__ */
+#include <stdint.h>
+#if defined(__linux__)
+#include <sys/auxv.h>
+#include <asm/hwcap.h>
+#elif defined(__APPLE__)
+#define SYSCTL_PMULL_KEY "hw.optional.arm.FEAT_PMULL" // from macOS 12 FEAT_* sysctl infos are available
+#define SYSCTL_CRC32_KEY "hw.optional.armv8_crc32"
+#define SYSCTL_SVE_KEY "hw.optional.arm.FEAT_SVE" // this one is just a guess and need to check macOS update
+#include <sys/sysctl.h>
+#include <stddef.h>
+static inline int sysctlEnabled(const char* name){
+ int enabled;
+ size_t size = sizeof(enabled);
+ int status = sysctlbyname(name, &enabled, &size, NULL, 0);
+ return status ? 0 : enabled;
+}
+#endif
+
+
+#define DEFINE_INTERFACE_DISPATCHER(name) \
+ void * name##_dispatcher(void)
+
+#define PROVIDER_BASIC(name) \
+ PROVIDER_INFO(name##_base)
+
+#define DO_DIGNOSTIC(x) _Pragma GCC diagnostic ignored "-W"#x
+#define DO_PRAGMA(x) _Pragma (#x)
+#define DIGNOSTIC_IGNORE(x) DO_PRAGMA(GCC diagnostic ignored #x)
+#define DIGNOSTIC_PUSH() DO_PRAGMA(GCC diagnostic push)
+#define DIGNOSTIC_POP() DO_PRAGMA(GCC diagnostic pop)
+
+
+#define PROVIDER_INFO(_func_entry) \
+ ({ DIGNOSTIC_PUSH() \
+ DIGNOSTIC_IGNORE(-Wnested-externs) \
+ extern void _func_entry(void); \
+ DIGNOSTIC_POP() \
+ _func_entry; \
+ })
+
+/**
+ * Micro-Architector definitions
+ * Reference: https://developer.arm.com/docs/ddi0595/f/aarch64-system-registers/midr_el1
+ */
+
+#define CPU_IMPLEMENTER_RESERVE 0x00
+#define CPU_IMPLEMENTER_ARM 0x41
+
+
+#define CPU_PART_CORTEX_A57 0xD07
+#define CPU_PART_CORTEX_A72 0xD08
+#define CPU_PART_NEOVERSE_N1 0xD0C
+
+#define MICRO_ARCH_ID(imp,part) \
+ (((CPU_IMPLEMENTER_##imp&0xff)<<24)|((CPU_PART_##part&0xfff)<<4))
+
+#ifndef HWCAP_CPUID
+#define HWCAP_CPUID (1<<11)
+#endif
+
+/**
+ * @brief get_micro_arch_id
+ *
+ * read micro-architector register instruction if possible.This function
+ * provides microarchitecture information and make microarchitecture optimization
+ * possible.
+ *
+ * Read system registers(MRS) is forbidden in userspace. If executed, it
+ * will raise illegal instruction error. Kernel provides a solution for
+ * this issue. The solution depends on HWCAP_CPUID flags. Reference(1)
+ * describes how to use it. It provides a "illegal insstruction" handler
+ * in kernel space, the handler will execute MRS and return the correct
+ * value to userspace.
+ *
+ * To avoid too many kernel trap, this function MUST be only called in
+ * dispatcher. And HWCAP must be match,That will make sure there are no
+ * illegal instruction errors. HWCAP_CPUID should be available to get the
+ * best performance.
+ *
+ * NOTICE:
+ * - HWCAP_CPUID should be available. Otherwise it returns reserve value
+ * - It MUST be called inside dispather.
+ * - It MUST meet the HWCAP requirements
+ *
+ * Example:
+ * DEFINE_INTERFACE_DISPATCHER(crc32_iscsi)
+ * {
+ * unsigned long auxval = getauxval(AT_HWCAP);
+ * // MUST do the judgement is MUST.
+ * if ((HWCAP_CRC32 | HWCAP_PMULL) == (auxval & (HWCAP_CRC32 | HWCAP_PMULL))) {
+ * switch (get_micro_arch_id()) {
+ * case MICRO_ARCH_ID(ARM, CORTEX_A57):
+ * return PROVIDER_INFO(crc32_pmull_crc_for_a57);
+ * case MICRO_ARCH_ID(ARM, CORTEX_A72):
+ * return PROVIDER_INFO(crc32_pmull_crc_for_a72);
+ * case MICRO_ARCH_ID(ARM, NEOVERSE_N1):
+ * return PROVIDER_INFO(crc32_pmull_crc_for_n1);
+ * case default:
+ * return PROVIDER_INFO(crc32_pmull_crc_for_others);
+ * }
+ * }
+ * return PROVIDER_BASIC(crc32_iscsi);
+ * }
+ * KNOWN ISSUE:
+ * On a heterogeneous system (big.LITTLE), it will work but the performance
+ * might not be the best one as expected.
+ *
+ * If this function is called on the big core, it will return the function
+ * optimized for the big core.
+ *
+ * If execution is then scheduled to the little core. It will still work (1),
+ * but the function won't be optimized for the little core, thus the performance
+ * won't be as expected.
+ *
+ * References:
+ * - [CPU Feature detection](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/arm64/cpu-feature-registers.rst?h=v5.5)
+ *
+ */
+static inline uint32_t get_micro_arch_id(void)
+{
+ uint32_t id=CPU_IMPLEMENTER_RESERVE;
+#ifndef __APPLE__
+ if ((getauxval(AT_HWCAP) & HWCAP_CPUID)) {
+ /** Here will trap into kernel space */
+ asm("mrs %0, MIDR_EL1 " : "=r" (id));
+ }
+#endif
+ return id&0xff00fff0;
+}
+
+
+
+#endif /* __ASSEMBLY__ */
+#endif
diff --git a/contrib/libs/isa-l/include/erasure_code.h b/contrib/libs/isa-l/include/erasure_code.h
index 04fdfb1bc2..e361d7f4bb 100644
--- a/contrib/libs/isa-l/include/erasure_code.h
+++ b/contrib/libs/isa-l/include/erasure_code.h
@@ -74,6 +74,14 @@ extern "C" {
void ec_init_tables(int k, int rows, unsigned char* a, unsigned char* gftbls);
/**
+ * @brief Initialize tables for fast Erasure Code encode and decode, runs baseline version.
+ *
+ * Baseline version of ec_encode_data() with same parameters.
+ */
+
+void ec_init_tables_base(int k, int rows, unsigned char* a, unsigned char* gftbls);
+
+/**
* @brief Generate or decode erasure codes on blocks of data, runs appropriate version.
*
* Given a list of source data blocks, generate one or multiple blocks of
@@ -926,7 +934,10 @@ void gf_gen_cauchy1_matrix(unsigned char *a, int m, int k);
/**
* @brief Invert a matrix in GF(2^8)
*
- * @param in input matrix
+ * Attempts to construct an n x n inverse of the input matrix. Returns non-zero
+ * if singular. Will always destroy input matrix in process.
+ *
+ * @param in input matrix, destroyed by invert process
* @param out output matrix such that [in] x [out] = [I] - identity matrix
* @param n size of matrix [nxn]
* @returns 0 successful, other fail on singular input matrix
diff --git a/contrib/libs/isa-l/include/gf_vect_mul.h b/contrib/libs/isa-l/include/gf_vect_mul.h
index 70a0ab2ed3..7cd954452e 100644
--- a/contrib/libs/isa-l/include/gf_vect_mul.h
+++ b/contrib/libs/isa-l/include/gf_vect_mul.h
@@ -140,10 +140,11 @@ void gf_vect_mul_init(unsigned char c, unsigned char* gftbl);
* only use 2nd element is used.
* @param src Pointer to src data array. Must be aligned to 32B.
* @param dest Pointer to destination data array. Must be aligned to 32B.
+ * @returns 0 pass, other fail
*/
-void gf_vect_mul_base(int len, unsigned char *a, unsigned char *src,
- unsigned char *dest);
+int gf_vect_mul_base(int len, unsigned char *a, unsigned char *src,
+ unsigned char *dest);
#ifdef __cplusplus
}
diff --git a/contrib/libs/isa-l/include/memcpy.asm b/contrib/libs/isa-l/include/memcpy.asm
new file mode 100644
index 0000000000..8ce39cc28b
--- /dev/null
+++ b/contrib/libs/isa-l/include/memcpy.asm
@@ -0,0 +1,769 @@
+;;
+;; Copyright (c) 2023, Intel Corporation
+;;
+;; Redistribution and use in source and binary forms, with or without
+;; modification, are permitted provided that the following conditions are met:
+;;
+;; * Redistributions of source code must retain the above copyright notice,
+;; this list of conditions and the following disclaimer.
+;; * Redistributions in binary form must reproduce the above copyright
+;; notice, this list of conditions and the following disclaimer in the
+;; documentation and/or other materials provided with the distribution.
+;; * Neither the name of Intel Corporation nor the names of its contributors
+;; may be used to endorse or promote products derived from this software
+;; without specific prior written permission.
+;;
+;; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+;; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+;; IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+;; DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+;; FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+;; DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+;; SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+;; CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+;; OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+;; OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+;;
+
+%ifndef __MEMCPY_INC__
+%define __MEMCPY_INC__
+
+%include "reg_sizes.asm"
+
+; This section defines a series of macros to copy small to medium amounts
+; of data from memory to memory, where the size is variable but limited.
+;
+; The macros are all called as:
+; memcpy DST, SRC, SIZE, TMP0, TMP1, XTMP0, XTMP1, XTMP2, XTMP3
+; with the parameters defined as:
+; DST : register: pointer to dst (not modified)
+; SRC : register: pointer to src (not modified)
+; SIZE : register: length in bytes (not modified)
+; TMP0 : 64-bit temp GPR (clobbered)
+; TMP1 : 64-bit temp GPR (clobbered)
+; XTMP0 : temp XMM (clobbered)
+; XTMP1 : temp XMM (clobbered)
+; XTMP2 : temp XMM (clobbered)
+; XTMP3 : temp XMM (clobbered)
+;
+; The name indicates the options. The name is of the form:
+; memcpy_<VEC>_<SZ><ZERO><RET>
+; where:
+; <VEC> is either "sse" or "avx" or "avx2"
+; <SZ> is either "64" or "128" and defines largest value of SIZE
+; <ZERO> is blank or "_1". If "_1" then the min SIZE is 1 (otherwise 0)
+; <RET> is blank or "_ret". If blank, the code falls through. If "ret"
+; it does a "ret" at the end
+;
+; For the avx2 versions, the temp XMM registers need to be YMM registers
+; If the SZ is 64, then only two YMM temps are needed, i.e. it is called as:
+; memcpy_avx2_64 DST, SRC, SIZE, TMP0, TMP1, YTMP0, YTMP1
+; memcpy_avx2_128 DST, SRC, SIZE, TMP0, TMP1, YTMP0, YTMP1, YTMP2, YTMP3
+;
+; For example:
+; memcpy_sse_64 : SSE, 0 <= size < 64, falls through
+; memcpy_avx_64_1 : AVX1, 1 <= size < 64, falls through
+; memcpy_sse_128_ret : SSE, 0 <= size < 128, ends with ret
+; mempcy_avx_128_1_ret : AVX1, 1 <= size < 128, ends with ret
+;
+
+%macro memcpy_sse_64 9
+ __memcpy_int %1,%2,%3,%4,%5,%6,%7,%8,%9, 0, 64, 0, 0
+%endm
+
+%macro memcpy_sse_64_1 9
+ __memcpy_int %1,%2,%3,%4,%5,%6,%7,%8,%9, 1, 64, 0, 0
+%endm
+
+%macro memcpy_sse_128 9
+ __memcpy_int %1,%2,%3,%4,%5,%6,%7,%8,%9, 0, 128, 0, 0
+%endm
+
+%macro memcpy_sse_128_1 9
+ __memcpy_int %1,%2,%3,%4,%5,%6,%7,%8,%9, 1, 128, 0, 0
+%endm
+
+%macro memcpy_sse_64_ret 9
+ __memcpy_int %1,%2,%3,%4,%5,%6,%7,%8,%9, 0, 64, 1, 0
+%endm
+
+%macro memcpy_sse_64_1_ret 9
+ __memcpy_int %1,%2,%3,%4,%5,%6,%7,%8,%9, 1, 64, 1, 0
+%endm
+
+%macro memcpy_sse_128_ret 9
+ __memcpy_int %1,%2,%3,%4,%5,%6,%7,%8,%9, 0, 128, 1, 0
+%endm
+
+%macro memcpy_sse_128_1_ret 9
+ __memcpy_int %1,%2,%3,%4,%5,%6,%7,%8,%9, 1, 128, 1, 0
+%endm
+
+%macro memcpy_sse_16 5
+ __memcpy_int %1,%2,%3,%4,%5,,,,, 0, 16, 0, 0
+%endm
+
+%macro memcpy_sse_16_1 5
+ __memcpy_int %1,%2,%3,%4,%5,,,,, 1, 16, 0, 0
+%endm
+
+ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+%macro memcpy_avx_64 9
+ __memcpy_int %1,%2,%3,%4,%5,%6,%7,%8,%9, 0, 64, 0, 1
+%endm
+
+%macro memcpy_avx_64_1 9
+ __memcpy_int %1,%2,%3,%4,%5,%6,%7,%8,%9, 1, 64, 0, 1
+%endm
+
+%macro memcpy_avx_128 9
+ __memcpy_int %1,%2,%3,%4,%5,%6,%7,%8,%9, 0, 128, 0, 1
+%endm
+
+%macro memcpy_avx_128_1 9
+ __memcpy_int %1,%2,%3,%4,%5,%6,%7,%8,%9, 1, 128, 0, 1
+%endm
+
+%macro memcpy_avx_64_ret 9
+ __memcpy_int %1,%2,%3,%4,%5,%6,%7,%8,%9, 0, 64, 1, 1
+%endm
+
+%macro memcpy_avx_64_1_ret 9
+ __memcpy_int %1,%2,%3,%4,%5,%6,%7,%8,%9, 1, 64, 1, 1
+%endm
+
+%macro memcpy_avx_128_ret 9
+ __memcpy_int %1,%2,%3,%4,%5,%6,%7,%8,%9, 0, 128, 1, 1
+%endm
+
+%macro memcpy_avx_128_1_ret 9
+ __memcpy_int %1,%2,%3,%4,%5,%6,%7,%8,%9, 1, 128, 1, 1
+%endm
+
+%macro memcpy_avx_16 5
+ __memcpy_int %1,%2,%3,%4,%5,,,,, 0, 16, 0, 1
+%endm
+
+%macro memcpy_avx_16_1 5
+ __memcpy_int %1,%2,%3,%4,%5,,,,, 1, 16, 0, 1
+%endm
+
+ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+%macro memcpy_avx2_64 7
+ __memcpy_int %1,%2,%3,%4,%5,%6,%7,--,--, 0, 64, 0, 2
+%endm
+
+%macro memcpy_avx2_64_1 7
+ __memcpy_int %1,%2,%3,%4,%5,%6,%7,--,--, 1, 64, 0, 2
+%endm
+
+%macro memcpy_avx2_128 9
+ __memcpy_int %1,%2,%3,%4,%5,%6,%7, %8, %9, 0, 128, 0, 2
+%endm
+
+%macro memcpy_avx2_128_1 9
+ __memcpy_int %1,%2,%3,%4,%5,%6,%7, %8, %9, 1, 128, 0, 2
+%endm
+
+%macro memcpy_avx2_64_ret 7
+ __memcpy_int %1,%2,%3,%4,%5,%6,%7,--,--, 0, 64, 1, 2
+%endm
+
+%macro memcpy_avx2_64_1_ret 7
+ __memcpy_int %1,%2,%3,%4,%5,%6,%7,--,--, 1, 64, 1, 2
+%endm
+
+%macro memcpy_avx2_128_ret 9
+ __memcpy_int %1,%2,%3,%4,%5,%6,%7,%8,%9, 0, 128, 1, 2
+%endm
+
+%macro memcpy_avx2_128_1_ret 9
+ __memcpy_int %1,%2,%3,%4,%5,%6,%7,%8,%9, 1, 128, 1, 2
+%endm
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+%macro __memcpy_int 13
+%define %%DST %1 ; register: pointer to dst (not modified)
+%define %%SRC %2 ; register: pointer to src (not modified)
+%define %%SIZE %3 ; register: length in bytes (not modified)
+%define %%TMP0 %4 ; 64-bit temp GPR (clobbered)
+%define %%TMP1 %5 ; 64-bit temp GPR (clobbered)
+%define %%XTMP0 %6 ; temp XMM (clobbered)
+%define %%XTMP1 %7 ; temp XMM (clobbered)
+%define %%XTMP2 %8 ; temp XMM (clobbered)
+%define %%XTMP3 %9 ; temp XMM (clobbered)
+%define %%NOT0 %10 ; if not 0, then assume size cannot be zero
+%define %%MAXSIZE %11 ; 128, 64, etc
+%define %%USERET %12 ; if not 0, use "ret" at end
+%define %%USEAVX %13 ; 0 = SSE, 1 = AVX1, 2 = AVX2
+
+%if (%%USERET != 0)
+ %define %%DONE ret
+%else
+ %define %%DONE jmp %%end
+%endif
+
+%if (%%USEAVX != 0)
+ %define %%MOVDQU vmovdqu
+%else
+ %define %%MOVDQU movdqu
+%endif
+
+%if (%%MAXSIZE >= 128)
+ test %%SIZE, 64
+ jz %%lt64
+ %if (%%USEAVX >= 2)
+ %%MOVDQU %%XTMP0, [%%SRC + 0*32]
+ %%MOVDQU %%XTMP1, [%%SRC + 1*32]
+ %%MOVDQU %%XTMP2, [%%SRC + %%SIZE - 2*32]
+ %%MOVDQU %%XTMP3, [%%SRC + %%SIZE - 1*32]
+
+ %%MOVDQU [%%DST + 0*32], %%XTMP0
+ %%MOVDQU [%%DST + 1*32], %%XTMP1
+ %%MOVDQU [%%DST + %%SIZE - 2*32], %%XTMP2
+ %%MOVDQU [%%DST + %%SIZE - 1*32], %%XTMP3
+ %else
+ %%MOVDQU %%XTMP0, [%%SRC + 0*16]
+ %%MOVDQU %%XTMP1, [%%SRC + 1*16]
+ %%MOVDQU %%XTMP2, [%%SRC + 2*16]
+ %%MOVDQU %%XTMP3, [%%SRC + 3*16]
+ %%MOVDQU [%%DST + 0*16], %%XTMP0
+ %%MOVDQU [%%DST + 1*16], %%XTMP1
+ %%MOVDQU [%%DST + 2*16], %%XTMP2
+ %%MOVDQU [%%DST + 3*16], %%XTMP3
+
+ %%MOVDQU %%XTMP0, [%%SRC + %%SIZE - 4*16]
+ %%MOVDQU %%XTMP1, [%%SRC + %%SIZE - 3*16]
+ %%MOVDQU %%XTMP2, [%%SRC + %%SIZE - 2*16]
+ %%MOVDQU %%XTMP3, [%%SRC + %%SIZE - 1*16]
+ %%MOVDQU [%%DST + %%SIZE - 4*16], %%XTMP0
+ %%MOVDQU [%%DST + %%SIZE - 3*16], %%XTMP1
+ %%MOVDQU [%%DST + %%SIZE - 2*16], %%XTMP2
+ %%MOVDQU [%%DST + %%SIZE - 1*16], %%XTMP3
+ %endif
+ %%DONE
+%endif
+
+%if (%%MAXSIZE >= 64)
+%%lt64:
+ test %%SIZE, 32
+ jz %%lt32
+ %if (%%USEAVX >= 2)
+ %%MOVDQU %%XTMP0, [%%SRC + 0*32]
+ %%MOVDQU %%XTMP1, [%%SRC + %%SIZE - 1*32]
+ %%MOVDQU [%%DST + 0*32], %%XTMP0
+ %%MOVDQU [%%DST + %%SIZE - 1*32], %%XTMP1
+ %else
+ %%MOVDQU %%XTMP0, [%%SRC + 0*16]
+ %%MOVDQU %%XTMP1, [%%SRC + 1*16]
+ %%MOVDQU %%XTMP2, [%%SRC + %%SIZE - 2*16]
+ %%MOVDQU %%XTMP3, [%%SRC + %%SIZE - 1*16]
+ %%MOVDQU [%%DST + 0*16], %%XTMP0
+ %%MOVDQU [%%DST + 1*16], %%XTMP1
+ %%MOVDQU [%%DST + %%SIZE - 2*16], %%XTMP2
+ %%MOVDQU [%%DST + %%SIZE - 1*16], %%XTMP3
+ %endif
+ %%DONE
+%endif
+
+%if (%%MAXSIZE >= 32)
+%%lt32:
+ test %%SIZE, 16
+ jz %%lt16
+ %if (%%USEAVX >= 2)
+ %%MOVDQU XWORD(%%XTMP0), [%%SRC + 0*16]
+ %%MOVDQU XWORD(%%XTMP1), [%%SRC + %%SIZE - 1*16]
+ %%MOVDQU [%%DST + 0*16], XWORD(%%XTMP0)
+ %%MOVDQU [%%DST + %%SIZE - 1*16], XWORD(%%XTMP1)
+ %else
+ %%MOVDQU %%XTMP0, [%%SRC + 0*16]
+ %%MOVDQU %%XTMP1, [%%SRC + %%SIZE - 1*16]
+ %%MOVDQU [%%DST + 0*16], %%XTMP0
+ %%MOVDQU [%%DST + %%SIZE - 1*16], %%XTMP1
+ %endif
+ %%DONE
+%endif
+
+%if (%%MAXSIZE >= 16)
+ test %%SIZE, 16
+ jz %%lt16
+ mov %%TMP0, [%%SRC]
+ mov %%TMP1, [%%SRC + 8]
+ mov [%%DST], %%TMP0
+ mov [%%DST + 8], %%TMP1
+%%lt16:
+ test %%SIZE, 8
+ jz %%lt8
+ mov %%TMP0, [%%SRC]
+ mov %%TMP1, [%%SRC + %%SIZE - 8]
+ mov [%%DST], %%TMP0
+ mov [%%DST + %%SIZE - 8], %%TMP1
+ %%DONE
+%endif
+
+%if (%%MAXSIZE >= 8)
+%%lt8:
+ test %%SIZE, 4
+ jz %%lt4
+ mov DWORD(%%TMP0), [%%SRC]
+ mov DWORD(%%TMP1), [%%SRC + %%SIZE - 4]
+ mov [%%DST], DWORD(%%TMP0)
+ mov [%%DST + %%SIZE - 4], DWORD(%%TMP1)
+ %%DONE
+%endif
+
+%if (%%MAXSIZE >= 4)
+%%lt4:
+ test %%SIZE, 2
+ jz %%lt2
+ movzx DWORD(%%TMP0), word [%%SRC]
+ movzx DWORD(%%TMP1), byte [%%SRC + %%SIZE - 1]
+ mov [%%DST], WORD(%%TMP0)
+ mov [%%DST + %%SIZE - 1], BYTE(%%TMP1)
+ %%DONE
+%endif
+
+%%lt2:
+%if (%%NOT0 == 0)
+ test %%SIZE, 1
+ jz %%end
+%endif
+ movzx DWORD(%%TMP0), byte [%%SRC]
+ mov [%%DST], BYTE(%%TMP0)
+%%end:
+%if (%%USERET != 0)
+ ret
+%endif
+%endm
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; Utility macro to assist with SIMD shifting
+%macro _PSRLDQ 3
+%define %%VEC %1
+%define %%REG %2
+%define %%IMM %3
+
+%ifidn %%VEC, SSE
+ psrldq %%REG, %%IMM
+%else
+ vpsrldq %%REG, %%REG, %%IMM
+%endif
+%endm
+
+ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; This section defines a series of macros to store small to medium amounts
+; of data from SIMD registers to memory, where the size is variable but limited.
+;
+; The macros are all called as:
+; memcpy DST, SRC, SIZE, TMP, IDX
+; with the parameters defined as:
+; DST : register: pointer to dst (not modified)
+; SRC : register: src data (clobbered)
+; SIZE : register: length in bytes (not modified)
+; TMP : 64-bit temp GPR (clobbered)
+; IDX : 64-bit GPR to store dst index/offset (clobbered)
+; OFFSET ; Offset to be applied to destination pointer (optional)
+;
+; The name indicates the options. The name is of the form:
+; simd_store_<VEC>
+; where <VEC> is the SIMD instruction type e.g. "sse" or "avx"
+
+%macro simd_store_sse 5-6
+%if %0 == 6
+ __simd_store %1,%2,%3,%4,%5,SSE,16,%6
+%else
+ __simd_store %1,%2,%3,%4,%5,SSE,16
+%endif
+%endm
+
+%macro simd_store_avx 5-6
+%if %0 == 6
+ __simd_store %1,%2,%3,%4,%5,AVX,16,%6
+%else
+ __simd_store %1,%2,%3,%4,%5,AVX,16
+%endif
+%endm
+
+%macro simd_store_sse_15 5-6
+%if %0 == 6
+ __simd_store %1,%2,%3,%4,%5,SSE,15,%6
+%else
+ __simd_store %1,%2,%3,%4,%5,SSE,15
+%endif
+%endm
+
+%macro simd_store_avx_15 5-6
+%if %0 == 6
+ __simd_store %1,%2,%3,%4,%5,AVX,15,%6
+%else
+ __simd_store %1,%2,%3,%4,%5,AVX,15
+%endif
+%endm
+
+%macro __simd_store 7-8
+%define %%DST %1 ; register: pointer to dst (not modified)
+%define %%SRC %2 ; register: src data (clobbered)
+%define %%SIZE %3 ; register: length in bytes (not modified)
+%define %%TMP %4 ; 64-bit temp GPR (clobbered)
+%define %%IDX %5 ; 64-bit temp GPR to store dst idx (clobbered)
+%define %%SIMDTYPE %6 ; "SSE" or "AVX"
+%define %%MAX_LEN %7 ; maximum length to be stored
+%define %%OFFSET %8 ; offset to be applied to destination pointer
+
+%define %%PSRLDQ _PSRLDQ %%SIMDTYPE,
+
+%ifidn %%SIMDTYPE, SSE
+ %define %%MOVDQU movdqu
+ %define %%MOVQ movq
+%else
+ %define %%MOVDQU vmovdqu
+ %define %%MOVQ vmovq
+%endif
+
+;; determine max byte size for store operation
+%assign max_length_to_store %%MAX_LEN
+
+%if max_length_to_store > 16
+%error "__simd_store macro invoked with MAX_LEN bigger than 16!"
+%endif
+
+%if %0 == 8
+ mov %%IDX, %%OFFSET
+%else
+ xor %%IDX, %%IDX ; zero idx
+%endif
+
+%if max_length_to_store == 16
+ test %%SIZE, 16
+ jz %%lt16
+ %%MOVDQU [%%DST + %%IDX], %%SRC
+ jmp %%end
+%%lt16:
+%endif
+
+%if max_length_to_store >= 8
+ test %%SIZE, 8
+ jz %%lt8
+ %%MOVQ [%%DST + %%IDX], %%SRC
+ %%PSRLDQ %%SRC, 8
+ add %%IDX, 8
+%%lt8:
+%endif
+
+ %%MOVQ %%TMP, %%SRC ; use GPR from now on
+
+%if max_length_to_store >= 4
+ test %%SIZE, 4
+ jz %%lt4
+ mov [%%DST + %%IDX], DWORD(%%TMP)
+ shr %%TMP, 32
+ add %%IDX, 4
+%%lt4:
+%endif
+
+ test %%SIZE, 2
+ jz %%lt2
+ mov [%%DST + %%IDX], WORD(%%TMP)
+ shr %%TMP, 16
+ add %%IDX, 2
+%%lt2:
+ test %%SIZE, 1
+ jz %%end
+ mov [%%DST + %%IDX], BYTE(%%TMP)
+%%end:
+%endm
+
+; This section defines a series of macros to load small to medium amounts
+; (from 0 to 16 bytes) of data from memory to SIMD registers,
+; where the size is variable but limited.
+;
+; The macros are all called as:
+; simd_load DST, SRC, SIZE
+; with the parameters defined as:
+; DST : register: destination XMM register
+; SRC : register: pointer to src data (not modified)
+; SIZE : register: length in bytes (not modified)
+;
+; The name indicates the options. The name is of the form:
+; simd_load_<VEC>_<SZ><ZERO>
+; where:
+; <VEC> is either "sse" or "avx"
+; <SZ> is either "15" or "16" and defines largest value of SIZE
+; <ZERO> is blank or "_1". If "_1" then the min SIZE is 1 (otherwise 0)
+;
+; For example:
+; simd_load_sse_16 : SSE, 0 <= size <= 16
+; simd_load_avx_15_1 : AVX, 1 <= size <= 15
+
+%macro simd_load_sse_15_1 3
+ __simd_load %1,%2,%3,0,0,SSE
+%endm
+%macro simd_load_sse_15 3
+ __simd_load %1,%2,%3,1,0,SSE
+%endm
+%macro simd_load_sse_16_1 3
+ __simd_load %1,%2,%3,0,1,SSE
+%endm
+%macro simd_load_sse_16 3
+ __simd_load %1,%2,%3,1,1,SSE
+%endm
+
+%macro simd_load_avx_15_1 3
+ __simd_load %1,%2,%3,0,0,AVX
+%endm
+%macro simd_load_avx_15 3
+ __simd_load %1,%2,%3,1,0,AVX
+%endm
+%macro simd_load_avx_16_1 3
+ __simd_load %1,%2,%3,0,1,AVX
+%endm
+%macro simd_load_avx_16 3
+ __simd_load %1,%2,%3,1,1,AVX
+%endm
+
+%macro __simd_load 6
+%define %%DST %1 ; [out] destination XMM register
+%define %%SRC %2 ; [in] pointer to src data
+%define %%SIZE %3 ; [in] length in bytes (0-16 bytes)
+%define %%ACCEPT_0 %4 ; 0 = min length = 1, 1 = min length = 0
+%define %%ACCEPT_16 %5 ; 0 = max length = 15 , 1 = max length = 16
+%define %%SIMDTYPE %6 ; "SSE" or "AVX"
+
+%ifidn %%SIMDTYPE, SSE
+ %define %%MOVDQU movdqu
+ %define %%PINSRB pinsrb
+ %define %%PINSRQ pinsrq
+ %define %%PXOR pxor
+%else
+ %define %%MOVDQU vmovdqu
+ %define %%PINSRB vpinsrb
+ %define %%PINSRQ vpinsrq
+ %define %%PXOR vpxor
+%endif
+
+%if (%%ACCEPT_16 != 0)
+ test %%SIZE, 16
+ jz %%_skip_16
+ %%MOVDQU %%DST, [%%SRC]
+ jmp %%end_load
+
+%%_skip_16:
+%endif
+ %%PXOR %%DST, %%DST ; clear XMM register
+%if (%%ACCEPT_0 != 0)
+ or %%SIZE, %%SIZE
+ je %%end_load
+%endif
+ cmp %%SIZE, 2
+ jb %%_size_1
+ je %%_size_2
+ cmp %%SIZE, 4
+ jb %%_size_3
+ je %%_size_4
+ cmp %%SIZE, 6
+ jb %%_size_5
+ je %%_size_6
+ cmp %%SIZE, 8
+ jb %%_size_7
+ je %%_size_8
+ cmp %%SIZE, 10
+ jb %%_size_9
+ je %%_size_10
+ cmp %%SIZE, 12
+ jb %%_size_11
+ je %%_size_12
+ cmp %%SIZE, 14
+ jb %%_size_13
+ je %%_size_14
+
+%%_size_15:
+ %%PINSRB %%DST, [%%SRC + 14], 14
+%%_size_14:
+ %%PINSRB %%DST, [%%SRC + 13], 13
+%%_size_13:
+ %%PINSRB %%DST, [%%SRC + 12], 12
+%%_size_12:
+ %%PINSRB %%DST, [%%SRC + 11], 11
+%%_size_11:
+ %%PINSRB %%DST, [%%SRC + 10], 10
+%%_size_10:
+ %%PINSRB %%DST, [%%SRC + 9], 9
+%%_size_9:
+ %%PINSRB %%DST, [%%SRC + 8], 8
+%%_size_8:
+ %%PINSRQ %%DST, [%%SRC], 0
+ jmp %%end_load
+%%_size_7:
+ %%PINSRB %%DST, [%%SRC + 6], 6
+%%_size_6:
+ %%PINSRB %%DST, [%%SRC + 5], 5
+%%_size_5:
+ %%PINSRB %%DST, [%%SRC + 4], 4
+%%_size_4:
+ %%PINSRB %%DST, [%%SRC + 3], 3
+%%_size_3:
+ %%PINSRB %%DST, [%%SRC + 2], 2
+%%_size_2:
+ %%PINSRB %%DST, [%%SRC + 1], 1
+%%_size_1:
+ %%PINSRB %%DST, [%%SRC + 0], 0
+%%end_load:
+%endm
+
+%macro simd_load_avx2 5
+%define %%DST %1 ; [out] destination YMM register
+%define %%SRC %2 ; [in] pointer to src data
+%define %%SIZE %3 ; [in] length in bytes (0-32 bytes)
+%define %%IDX %4 ; [clobbered] Temp GP register to store src idx
+%define %%TMP %5 ; [clobbered] Temp GP register
+
+ test %%SIZE, 32
+ jz %%_skip_32
+ vmovdqu %%DST, [%%SRC]
+ jmp %%end_load
+
+%%_skip_32:
+ vpxor %%DST, %%DST ; clear YMM register
+ or %%SIZE, %%SIZE
+ je %%end_load
+
+ lea %%IDX, [%%SRC]
+ mov %%TMP, %%SIZE
+ cmp %%SIZE, 16
+ jle %%_check_size
+
+ add %%IDX, 16
+ sub %%TMP, 16
+
+%%_check_size:
+ cmp %%TMP, 2
+ jb %%_size_1
+ je %%_size_2
+ cmp %%TMP, 4
+ jb %%_size_3
+ je %%_size_4
+ cmp %%TMP, 6
+ jb %%_size_5
+ je %%_size_6
+ cmp %%TMP, 8
+ jb %%_size_7
+ je %%_size_8
+ cmp %%TMP, 10
+ jb %%_size_9
+ je %%_size_10
+ cmp %%TMP, 12
+ jb %%_size_11
+ je %%_size_12
+ cmp %%TMP, 14
+ jb %%_size_13
+ je %%_size_14
+ cmp %%TMP, 15
+ je %%_size_15
+
+%%_size_16:
+ vmovdqu XWORD(%%DST), [%%IDX]
+ jmp %%end_load
+%%_size_15:
+ vpinsrb XWORD(%%DST), [%%IDX + 14], 14
+%%_size_14:
+ vpinsrb XWORD(%%DST), [%%IDX + 13], 13
+%%_size_13:
+ vpinsrb XWORD(%%DST), [%%IDX + 12], 12
+%%_size_12:
+ vpinsrb XWORD(%%DST), [%%IDX + 11], 11
+%%_size_11:
+ vpinsrb XWORD(%%DST), [%%IDX + 10], 10
+%%_size_10:
+ vpinsrb XWORD(%%DST), [%%IDX + 9], 9
+%%_size_9:
+ vpinsrb XWORD(%%DST), [%%IDX + 8], 8
+%%_size_8:
+ vpinsrq XWORD(%%DST), [%%IDX], 0
+ jmp %%_check_higher_16
+%%_size_7:
+ vpinsrb XWORD(%%DST), [%%IDX + 6], 6
+%%_size_6:
+ vpinsrb XWORD(%%DST), [%%IDX + 5], 5
+%%_size_5:
+ vpinsrb XWORD(%%DST), [%%IDX + 4], 4
+%%_size_4:
+ vpinsrb XWORD(%%DST), [%%IDX + 3], 3
+%%_size_3:
+ vpinsrb XWORD(%%DST), [%%IDX + 2], 2
+%%_size_2:
+ vpinsrb XWORD(%%DST), [%%IDX + 1], 1
+%%_size_1:
+ vpinsrb XWORD(%%DST), [%%IDX + 0], 0
+%%_check_higher_16:
+ test %%SIZE, 16
+ jz %%end_load
+
+ ; Move last bytes loaded to upper half and load 16 bytes in lower half
+ vinserti128 %%DST, XWORD(%%DST), 1
+ vinserti128 %%DST, [%%SRC], 0
+%%end_load:
+%endm
+
+%macro simd_store_avx2 5
+%define %%DST %1 ; register: pointer to dst (not modified)
+%define %%SRC %2 ; register: src data (clobbered)
+%define %%SIZE %3 ; register: length in bytes (not modified)
+%define %%TMP %4 ; 64-bit temp GPR (clobbered)
+%define %%IDX %5 ; 64-bit temp GPR to store dst idx (clobbered)
+
+ xor %%IDX, %%IDX ; zero idx
+
+ test %%SIZE, 32
+ jz %%lt32
+ vmovdqu [%%DST], %%SRC
+ jmp %%end
+%%lt32:
+
+ test %%SIZE, 16
+ jz %%lt16
+ vmovdqu [%%DST], XWORD(%%SRC)
+ ; Move upper half to lower half for further stores
+ vperm2i128 %%SRC, %%SRC, %%SRC, 0x81
+ add %%IDX, 16
+%%lt16:
+
+ test %%SIZE, 8
+ jz %%lt8
+ vmovq [%%DST + %%IDX], XWORD(%%SRC)
+ vpsrldq XWORD(%%SRC), 8
+ add %%IDX, 8
+%%lt8:
+
+ vmovq %%TMP, XWORD(%%SRC) ; use GPR from now on
+
+ test %%SIZE, 4
+ jz %%lt4
+ mov [%%DST + %%IDX], DWORD(%%TMP)
+ shr %%TMP, 32
+ add %%IDX, 4
+%%lt4:
+
+ test %%SIZE, 2
+ jz %%lt2
+ mov [%%DST + %%IDX], WORD(%%TMP)
+ shr %%TMP, 16
+ add %%IDX, 2
+%%lt2:
+ test %%SIZE, 1
+ jz %%end
+ mov [%%DST + %%IDX], BYTE(%%TMP)
+%%end:
+%endm
+
+%endif ; ifndef __MEMCPY_INC__
diff --git a/contrib/libs/isa-l/include/multibinary.asm b/contrib/libs/isa-l/include/multibinary.asm
index 2cad1c51be..1a861a0376 100644
--- a/contrib/libs/isa-l/include/multibinary.asm
+++ b/contrib/libs/isa-l/include/multibinary.asm
@@ -69,12 +69,14 @@
mbin_def_ptr %1_mbinit
section .text
- global %1:ISAL_SYM_TYPE_FUNCTION
+ global %1, function
%1_mbinit:
+ endbranch
;;; only called the first time to setup hardware match
call %1_dispatch_init
;;; falls thru to execute the hw optimized code
%1:
+ endbranch
jmp mbin_ptr_sz [%1_dispatched]
%endmacro
@@ -152,8 +154,10 @@
; 1-> function name
; 2-> base function
; 3-> SSE4_1 and CLMUL optimized function
+; 4-> AVX/02 opt func
+; 5-> AVX512/10 opt func
;;;;;
-%macro mbin_dispatch_init_clmul 3
+%macro mbin_dispatch_init_clmul 5
section .text
%1_dispatch_init:
push mbin_rsi
@@ -161,18 +165,55 @@
push mbin_rbx
push mbin_rcx
push mbin_rdx
+ push mbin_rdi
lea mbin_rsi, [%2 WRT_OPT] ; Default - use base function
mov eax, 1
cpuid
- lea mbin_rbx, [%3 WRT_OPT] ; SSE opt func
-
- ; Test for SSE4.2
+ mov ebx, ecx ; save cpuid1.ecx
test ecx, FLAG_CPUID1_ECX_SSE4_1
jz _%1_init_done
test ecx, FLAG_CPUID1_ECX_CLMUL
- cmovne mbin_rsi, mbin_rbx
+ jz _%1_init_done
+ lea mbin_rsi, [%3 WRT_OPT] ; SSE possible so use 00/01 opt
+
+ ;; Test for XMM_YMM support/AVX
+ test ecx, FLAG_CPUID1_ECX_OSXSAVE
+ je _%1_init_done
+ xor ecx, ecx
+ xgetbv ; xcr -> edx:eax
+ mov edi, eax ; save xgetvb.eax
+
+ and eax, FLAG_XGETBV_EAX_XMM_YMM
+ cmp eax, FLAG_XGETBV_EAX_XMM_YMM
+ jne _%1_init_done
+ test ebx, FLAG_CPUID1_ECX_AVX
+ je _%1_init_done
+ lea mbin_rsi, [%4 WRT_OPT] ; AVX/02 opt
+
+%if AS_FEATURE_LEVEL >= 10
+ ;; Test for AVX2
+ xor ecx, ecx
+ mov eax, 7
+ cpuid
+ test ebx, FLAG_CPUID7_EBX_AVX2
+ je _%1_init_done ; No AVX2 possible
+
+ ;; Test for AVX512
+ and edi, FLAG_XGETBV_EAX_ZMM_OPM
+ cmp edi, FLAG_XGETBV_EAX_ZMM_OPM
+ jne _%1_init_done ; No AVX512 possible
+ and ebx, FLAGS_CPUID7_EBX_AVX512_G1
+ cmp ebx, FLAGS_CPUID7_EBX_AVX512_G1
+ jne _%1_init_done
+
+ and ecx, FLAGS_CPUID7_ECX_AVX512_G2
+ cmp ecx, FLAGS_CPUID7_ECX_AVX512_G2
+ lea mbin_rbx, [%5 WRT_OPT] ; AVX512/10 opt
+ cmove mbin_rsi, mbin_rbx
+%endif
_%1_init_done:
+ pop mbin_rdi
pop mbin_rdx
pop mbin_rcx
pop mbin_rbx
@@ -390,10 +431,97 @@
pop mbin_rsi
ret
%endmacro
+
+;;;;;
+; mbin_dispatch_init8 parameters
+; 1-> function name
+; 2-> base function
+; 3-> SSE4_2 or 00/01 optimized function
+; 4-> AVX/02 opt func
+; 5-> AVX2/04 opt func
+; 6-> AVX512/06 opt func
+; 7-> AVX2 Update/07 opt func
+; 8-> AVX512 Update/10 opt func
+;;;;;
+%macro mbin_dispatch_init8 8
+ section .text
+ %1_dispatch_init:
+ push mbin_rsi
+ push mbin_rax
+ push mbin_rbx
+ push mbin_rcx
+ push mbin_rdx
+ push mbin_rdi
+ lea mbin_rsi, [%2 WRT_OPT] ; Default - use base function
+
+ mov eax, 1
+ cpuid
+ mov ebx, ecx ; save cpuid1.ecx
+ test ecx, FLAG_CPUID1_ECX_SSE4_2
+ je _%1_init_done ; Use base function if no SSE4_2
+ lea mbin_rsi, [%3 WRT_OPT] ; SSE possible so use 00/01 opt
+
+ ;; Test for XMM_YMM support/AVX
+ test ecx, FLAG_CPUID1_ECX_OSXSAVE
+ je _%1_init_done
+ xor ecx, ecx
+ xgetbv ; xcr -> edx:eax
+ mov edi, eax ; save xgetvb.eax
+
+ and eax, FLAG_XGETBV_EAX_XMM_YMM
+ cmp eax, FLAG_XGETBV_EAX_XMM_YMM
+ jne _%1_init_done
+ test ebx, FLAG_CPUID1_ECX_AVX
+ je _%1_init_done
+ lea mbin_rsi, [%4 WRT_OPT] ; AVX/02 opt
+
+ ;; Test for AVX2
+ xor ecx, ecx
+ mov eax, 7
+ cpuid
+ test ebx, FLAG_CPUID7_EBX_AVX2
+ je _%1_init_done ; No AVX2 possible
+ lea mbin_rsi, [%5 WRT_OPT] ; AVX2/04 opt func
+
+ ;; Test for AVX512
+ and edi, FLAG_XGETBV_EAX_ZMM_OPM
+ cmp edi, FLAG_XGETBV_EAX_ZMM_OPM
+ jne _%1_check_avx2_g2 ; No AVX512 possible
+ and ebx, FLAGS_CPUID7_EBX_AVX512_G1
+ cmp ebx, FLAGS_CPUID7_EBX_AVX512_G1
+ lea mbin_rbx, [%6 WRT_OPT] ; AVX512/06 opt
+ cmove mbin_rsi, mbin_rbx
+
+ and ecx, FLAGS_CPUID7_ECX_AVX512_G2
+ cmp ecx, FLAGS_CPUID7_ECX_AVX512_G2
+ lea mbin_rbx, [%8 WRT_OPT] ; AVX512/10 opt
+ cmove mbin_rsi, mbin_rbx
+ jmp _%1_init_done
+
+ _%1_check_avx2_g2:
+ ;; Test for AVX2 Gen 2
+ and ecx, FLAGS_CPUID7_ECX_AVX2_G2
+ cmp ecx, FLAGS_CPUID7_ECX_AVX2_G2
+ lea mbin_rbx, [%7 WRT_OPT] ; AVX2/7 opt
+ cmove mbin_rsi, mbin_rbx
+
+ _%1_init_done:
+ pop mbin_rdi
+ pop mbin_rdx
+ pop mbin_rcx
+ pop mbin_rbx
+ pop mbin_rax
+ mov [%1_dispatched], mbin_rsi
+ pop mbin_rsi
+ ret
+%endmacro
%else
%macro mbin_dispatch_init7 7
mbin_dispatch_init6 %1, %2, %3, %4, %5, %6
%endmacro
+%macro mbin_dispatch_init8 8
+ mbin_dispatch_init6 %1, %2, %3, %4, %5, %6
+%endmacro
%endif
%endif ; ifndef _MULTIBINARY_ASM_
diff --git a/contrib/libs/isa-l/include/reg_sizes.asm b/contrib/libs/isa-l/include/reg_sizes.asm
index fec6a8aafb..983f8b421d 100644
--- a/contrib/libs/isa-l/include/reg_sizes.asm
+++ b/contrib/libs/isa-l/include/reg_sizes.asm
@@ -30,14 +30,6 @@
%ifndef _REG_SIZES_ASM_
%define _REG_SIZES_ASM_
-%ifdef __NASM_VER__
-%ifidn __OUTPUT_FORMAT__, win64
-%error nasm not supported in windows
-%else
-%define endproc_frame
-%endif
-%endif
-
%ifndef AS_FEATURE_LEVEL
%define AS_FEATURE_LEVEL 4
%endif
@@ -75,6 +67,7 @@
%define FLAGS_CPUID7_EBX_AVX512_G1 (FLAG_CPUID7_EBX_AVX512F | FLAG_CPUID7_EBX_AVX512VL | FLAG_CPUID7_EBX_AVX512BW | FLAG_CPUID7_EBX_AVX512CD | FLAG_CPUID7_EBX_AVX512DQ)
%define FLAGS_CPUID7_ECX_AVX512_G2 (FLAG_CPUID7_ECX_AVX512VBMI2 | FLAG_CPUID7_ECX_GFNI | FLAG_CPUID7_ECX_VAES | FLAG_CPUID7_ECX_VPCLMULQDQ | FLAG_CPUID7_ECX_VNNI | FLAG_CPUID7_ECX_BITALG | FLAG_CPUID7_ECX_VPOPCNTDQ)
+%define FLAGS_CPUID7_ECX_AVX2_G2 (FLAG_CPUID7_ECX_GFNI | FLAG_CPUID7_ECX_VAES | FLAG_CPUID7_ECX_VPCLMULQDQ)
%define FLAG_XGETBV_EAX_XMM (1<<1)
%define FLAG_XGETBV_EAX_YMM (1<<2)
@@ -203,14 +196,44 @@
%define XWORD(reg) reg %+ x
+%ifdef INTEL_CET_ENABLED
+ %ifdef __NASM_VER__
+ %if AS_FEATURE_LEVEL >= 10
+ %ifidn __OUTPUT_FORMAT__,elf32
+section .note.gnu.property note alloc noexec align=4
+DD 0x00000004,0x0000000c,0x00000005,0x00554e47
+DD 0xc0000002,0x00000004,0x00000003
+ %endif
+ %ifidn __OUTPUT_FORMAT__,elf64
+section .note.gnu.property note alloc noexec align=8
+DD 0x00000004,0x00000010,0x00000005,0x00554e47
+DD 0xc0000002,0x00000004,0x00000003,0x00000000
+ %endif
+ %endif
+ %endif
+%endif
+
%ifidn __OUTPUT_FORMAT__,elf32
section .note.GNU-stack noalloc noexec nowrite progbits
section .text
%endif
%ifidn __OUTPUT_FORMAT__,elf64
+ %define __x86_64__
section .note.GNU-stack noalloc noexec nowrite progbits
section .text
%endif
+%ifidn __OUTPUT_FORMAT__,win64
+ %define __x86_64__
+%endif
+%ifidn __OUTPUT_FORMAT__,macho64
+ %define __x86_64__
+%endif
+
+%ifdef __x86_64__
+ %define endbranch db 0xf3, 0x0f, 0x1e, 0xfa
+%else
+ %define endbranch db 0xf3, 0x0f, 0x1e, 0xfb
+%endif
%ifdef REL_TEXT
%define WRT_OPT
@@ -220,29 +243,56 @@ section .text
%define WRT_OPT
%endif
+%macro mk_global 1-3
+ %ifdef __NASM_VER__
+ %ifidn __OUTPUT_FORMAT__, macho64
+ global %1
+ %elifidn __OUTPUT_FORMAT__, win64
+ global %1
+ %else
+ global %1:%2 %3
+ %endif
+ %else
+ global %1:%2 %3
+ %endif
+%endmacro
+
+
+; Fixes for nasm lack of MS proc helpers
+%ifdef __NASM_VER__
+ %ifidn __OUTPUT_FORMAT__, win64
+ %macro alloc_stack 1
+ sub rsp, %1
+ %endmacro
+
+ %macro proc_frame 1
+ %1:
+ %endmacro
+
+ %macro save_xmm128 2
+ movdqa [rsp + %2], %1
+ %endmacro
+
+ %macro save_reg 2
+ mov [rsp + %2], %1
+ %endmacro
+
+ %macro rex_push_reg 1
+ push %1
+ %endmacro
+
+ %macro push_reg 1
+ push %1
+ %endmacro
+
+ %define end_prolog
+ %endif
+
+ %define endproc_frame
+%endif
+
%ifidn __OUTPUT_FORMAT__, macho64
%define elf64 macho64
mac_equ equ 1
- %ifdef __NASM_VER__
- %define ISAL_SYM_TYPE_FUNCTION
- %define ISAL_SYM_TYPE_DATA_INTERNAL
- %else
- %define ISAL_SYM_TYPE_FUNCTION function
- %define ISAL_SYM_TYPE_DATA_INTERNAL data internal
- %endif
-%else
- %define ISAL_SYM_TYPE_FUNCTION function
- %define ISAL_SYM_TYPE_DATA_INTERNAL data internal
%endif
-
-%macro slversion 4
- section .text
- global %1_slver_%2%3%4
- global %1_slver
- %1_slver:
- %1_slver_%2%3%4:
- dw 0x%4
- db 0x%3, 0x%2
-%endmacro
-
%endif ; ifndef _REG_SIZES_ASM_
diff --git a/contrib/libs/jinja2cpp/.yandex_meta/devtools.copyrights.report b/contrib/libs/jinja2cpp/.yandex_meta/devtools.copyrights.report
new file mode 100644
index 0000000000..f1ac2b9dae
--- /dev/null
+++ b/contrib/libs/jinja2cpp/.yandex_meta/devtools.copyrights.report
@@ -0,0 +1,52 @@
+# File format ($ symbol means the beginning of a line):
+#
+# $ # this message
+# $ # =======================
+# $ # comments (all commentaries should starts with some number of spaces and # symbol)
+# ${action} {license id} {license text hash}
+# $BELONGS ./ya/make/file/relative/path/1/ya.make ./ya/make/2/ya.make
+# ${all_file_action} filename
+# $ # user commentaries (many lines)
+# $ generated description - files with this license, license text... (some number of lines that starts with some number of spaces, do not modify)
+# ${action} {license spdx} {license text hash}
+# $BELONGS ./ya/make/file/relative/path/3/ya.make
+# ${all_file_action} filename
+# $ # user commentaries
+# $ generated description
+# $ ...
+#
+# You can modify action, all_file_action and add commentaries
+# Available actions:
+# keep - keep license in contrib and use in credits
+# skip - skip license
+# remove - remove all files with this license
+# rename - save license text/links into licenses texts file, but not store SPDX into LINCENSE macro. You should store correct license id into devtools.license.spdx.txt file
+#
+# {all file action} records will be generated when license text contains filename that exists on filesystem (in contrib directory)
+# We suppose that that files can contain some license info
+# Available all file actions:
+# FILE_IGNORE - ignore file (do nothing)
+# FILE_INCLUDE - include all file data into licenses text file
+# =======================
+
+KEEP COPYRIGHT_SERVICE_LABEL 097cfbf1153a4f7ed38e64fd7e2e3993
+BELONGS ya.make
+ License text:
+ Copyright (c) 2016 Jonathan B. Coe
+ Scancode info:
+ Original SPDX id: COPYRIGHT_SERVICE_LABEL
+ Score : 100.00
+ Match type : COPYRIGHT
+ Files with this license:
+ include/jinja2cpp/polymorphic_value.h [3:3]
+
+KEEP COPYRIGHT_SERVICE_LABEL b64d8f4e77f6cb007626437192f93d68
+BELONGS ya.make
+ License text:
+ // Copyright (c) 2018-2021 Martin Ankerl <http://martin.ankerl.com>
+ Scancode info:
+ Original SPDX id: COPYRIGHT_SERVICE_LABEL
+ Score : 100.00
+ Match type : COPYRIGHT
+ Files with this license:
+ src/robin_hood.h [13:13]
diff --git a/contrib/libs/jinja2cpp/.yandex_meta/devtools.licenses.report b/contrib/libs/jinja2cpp/.yandex_meta/devtools.licenses.report
new file mode 100644
index 0000000000..c548c28d7b
--- /dev/null
+++ b/contrib/libs/jinja2cpp/.yandex_meta/devtools.licenses.report
@@ -0,0 +1,125 @@
+# File format ($ symbol means the beginning of a line):
+#
+# $ # this message
+# $ # =======================
+# $ # comments (all commentaries should starts with some number of spaces and # symbol)
+# ${action} {license spdx} {license text hash}
+# $BELONGS ./ya/make/file/relative/path/1/ya.make ./ya/make/2/ya.make
+# ${all_file_action} filename
+# $ # user commentaries (many lines)
+# $ generated description - files with this license, license text... (some number of lines that starts with some number of spaces, do not modify)
+# ${action} {license spdx} {license text hash}
+# $BELONGS ./ya/make/file/relative/path/3/ya.make
+# ${all_file_action} filename
+# $ # user commentaries
+# $ generated description
+# $ ...
+#
+# You can modify action, all_file_action and add commentaries
+# Available actions:
+# keep - keep license in contrib and use in credits
+# skip - skip license
+# remove - remove all files with this license
+# rename - save license text/links into licenses texts file, but not store SPDX into LINCENSE macro. You should store correct license id into devtools.license.spdx.txt file
+#
+# {all file action} records will be generated when license text contains filename that exists on filesystem (in contrib directory)
+# We suppose that that files can contain some license info
+# Available all file actions:
+# FILE_IGNORE - ignore file (do nothing)
+# FILE_INCLUDE - include all file data into licenses text file
+# =======================
+
+KEEP MIT 4dfb1f9f7c68ff4156bccff8f3de1b60
+BELONGS ya.make
+ License text:
+ [![GitHub License](https://img.shields.io/badge/license-Mozilla-blue.svg)](https://raw.githubusercontent.com/jinja2cpp/Jinja2Cpp/master/LICENSE)
+ Scancode info:
+ Original SPDX id: MIT
+ Score : 85.71
+ Match type : TAG
+ Links : http://opensource.org/licenses/mit-license.php, https://spdx.org/licenses/MIT
+ Files with this license:
+ README.md [12:12]
+
+KEEP MIT 6b45d159c11839114dfda208e6140eda
+BELONGS ya.make
+ Note: matched license text is too long. Read it in the source files.
+ Scancode info:
+ Original SPDX id: MIT
+ Score : 100.00
+ Match type : TEXT
+ Links : http://opensource.org/licenses/mit-license.php, https://spdx.org/licenses/MIT
+ Files with this license:
+ src/robin_hood.h [15:31]
+
+KEEP MPL-2.0 81bec2692a2a04ebc459d6dca672caf4
+BELONGS ya.make
+FILE_INCLUDE LICENSE found in files: LICENSE at line 363
+ Note: matched license text is too long. Read it in the source files.
+ Scancode info:
+ Original SPDX id: MPL-2.0
+ Score : 100.00
+ Match type : TEXT
+ Links : http://mpl.mozilla.org/2012/01/03/announcing-mpl-2-0/, http://www.mozilla.com/MPL/2.0/, https://spdx.org/licenses/MPL-2.0
+ Files with this license:
+ LICENSE [1:373]
+
+KEEP MIT 8384d75c38c570f3edb87cf9f64f2ec2
+BELONGS ya.make
+ License text:
+ // SPDX-License-Identifier: MIT
+ Scancode info:
+ Original SPDX id: MIT
+ Score : 100.00
+ Match type : TAG
+ Links : http://opensource.org/licenses/mit-license.php, https://spdx.org/licenses/MIT
+ Files with this license:
+ src/robin_hood.h [12:12]
+
+KEEP MIT a6e9f2d79eb73e6e422759b53da6152a
+BELONGS ya.make
+ Note: matched license text is too long. Read it in the source files.
+ Scancode info:
+ Original SPDX id: MIT
+ Score : 100.00
+ Match type : TEXT
+ Links : http://opensource.org/licenses/mit-license.php, https://spdx.org/licenses/MIT
+ Files with this license:
+ include/jinja2cpp/polymorphic_value.h [5:20]
+
+KEEP MIT b6657f1432f3f3405667101097117109
+BELONGS ya.make
+ License text:
+ // Licensed under the MIT License <http://opensource.org/licenses/MIT>.
+ Scancode info:
+ Original SPDX id: MIT
+ Score : 100.00
+ Match type : NOTICE
+ Links : http://opensource.org/licenses/mit-license.php, https://spdx.org/licenses/MIT
+ Files with this license:
+ src/robin_hood.h [11:11]
+
+KEEP MPL-1.1 bbcc868f743e472bc5bc01c0a6b359a5
+BELONGS ya.make
+ License text:
+ [![GitHub License](https://img.shields.io/badge/license-Mozilla-blue.svg)](https://raw.githubusercontent.com/jinja2cpp/Jinja2Cpp/master/LICENSE)
+ Scancode info:
+ Original SPDX id: MPL-1.1
+ Score : 90.00
+ Match type : TAG
+ Links : http://www.mozilla.com/MPL/1.1/index.html, http://www.mozilla.org/MPL/MPL-1.1.html, https://spdx.org/licenses/MPL-1.1
+ Files with this license:
+ README.md [12:12]
+
+KEEP MIT e7fc849ec7d035354afc7a26365b817d
+BELONGS ya.make
+ License text:
+ * under the guidelines and in accordance with the MIT License. *
+ * http://www.opensource.org/licenses/MIT *
+ Scancode info:
+ Original SPDX id: MIT
+ Score : 81.82
+ Match type : REFERENCE
+ Links : http://opensource.org/licenses/mit-license.php, https://spdx.org/licenses/MIT
+ Files with this license:
+ src/lexertk.h [11:12]
diff --git a/contrib/libs/jinja2cpp/.yandex_meta/licenses.list.txt b/contrib/libs/jinja2cpp/.yandex_meta/licenses.list.txt
new file mode 100644
index 0000000000..c054605553
--- /dev/null
+++ b/contrib/libs/jinja2cpp/.yandex_meta/licenses.list.txt
@@ -0,0 +1,818 @@
+====================COPYRIGHT====================
+// Copyright (c) 2018-2021 Martin Ankerl <http://martin.ankerl.com>
+
+
+====================COPYRIGHT====================
+Copyright (c) 2016 Jonathan B. Coe
+
+
+====================File: LICENSE====================
+Mozilla Public License Version 2.0
+==================================
+
+1. Definitions
+--------------
+
+1.1. "Contributor"
+ means each individual or legal entity that creates, contributes to
+ the creation of, or owns Covered Software.
+
+1.2. "Contributor Version"
+ means the combination of the Contributions of others (if any) used
+ by a Contributor and that particular Contributor's Contribution.
+
+1.3. "Contribution"
+ means Covered Software of a particular Contributor.
+
+1.4. "Covered Software"
+ means Source Code Form to which the initial Contributor has attached
+ the notice in Exhibit A, the Executable Form of such Source Code
+ Form, and Modifications of such Source Code Form, in each case
+ including portions thereof.
+
+1.5. "Incompatible With Secondary Licenses"
+ means
+
+ (a) that the initial Contributor has attached the notice described
+ in Exhibit B to the Covered Software; or
+
+ (b) that the Covered Software was made available under the terms of
+ version 1.1 or earlier of the License, but not also under the
+ terms of a Secondary License.
+
+1.6. "Executable Form"
+ means any form of the work other than Source Code Form.
+
+1.7. "Larger Work"
+ means a work that combines Covered Software with other material, in
+ a separate file or files, that is not Covered Software.
+
+1.8. "License"
+ means this document.
+
+1.9. "Licensable"
+ means having the right to grant, to the maximum extent possible,
+ whether at the time of the initial grant or subsequently, any and
+ all of the rights conveyed by this License.
+
+1.10. "Modifications"
+ means any of the following:
+
+ (a) any file in Source Code Form that results from an addition to,
+ deletion from, or modification of the contents of Covered
+ Software; or
+
+ (b) any new file in Source Code Form that contains any Covered
+ Software.
+
+1.11. "Patent Claims" of a Contributor
+ means any patent claim(s), including without limitation, method,
+ process, and apparatus claims, in any patent Licensable by such
+ Contributor that would be infringed, but for the grant of the
+ License, by the making, using, selling, offering for sale, having
+ made, import, or transfer of either its Contributions or its
+ Contributor Version.
+
+1.12. "Secondary License"
+ means either the GNU General Public License, Version 2.0, the GNU
+ Lesser General Public License, Version 2.1, the GNU Affero General
+ Public License, Version 3.0, or any later versions of those
+ licenses.
+
+1.13. "Source Code Form"
+ means the form of the work preferred for making modifications.
+
+1.14. "You" (or "Your")
+ means an individual or a legal entity exercising rights under this
+ License. For legal entities, "You" includes any entity that
+ controls, is controlled by, or is under common control with You. For
+ purposes of this definition, "control" means (a) the power, direct
+ or indirect, to cause the direction or management of such entity,
+ whether by contract or otherwise, or (b) ownership of more than
+ fifty percent (50%) of the outstanding shares or beneficial
+ ownership of such entity.
+
+2. License Grants and Conditions
+--------------------------------
+
+2.1. Grants
+
+Each Contributor hereby grants You a world-wide, royalty-free,
+non-exclusive license:
+
+(a) under intellectual property rights (other than patent or trademark)
+ Licensable by such Contributor to use, reproduce, make available,
+ modify, display, perform, distribute, and otherwise exploit its
+ Contributions, either on an unmodified basis, with Modifications, or
+ as part of a Larger Work; and
+
+(b) under Patent Claims of such Contributor to make, use, sell, offer
+ for sale, have made, import, and otherwise transfer either its
+ Contributions or its Contributor Version.
+
+2.2. Effective Date
+
+The licenses granted in Section 2.1 with respect to any Contribution
+become effective for each Contribution on the date the Contributor first
+distributes such Contribution.
+
+2.3. Limitations on Grant Scope
+
+The licenses granted in this Section 2 are the only rights granted under
+this License. No additional rights or licenses will be implied from the
+distribution or licensing of Covered Software under this License.
+Notwithstanding Section 2.1(b) above, no patent license is granted by a
+Contributor:
+
+(a) for any code that a Contributor has removed from Covered Software;
+ or
+
+(b) for infringements caused by: (i) Your and any other third party's
+ modifications of Covered Software, or (ii) the combination of its
+ Contributions with other software (except as part of its Contributor
+ Version); or
+
+(c) under Patent Claims infringed by Covered Software in the absence of
+ its Contributions.
+
+This License does not grant any rights in the trademarks, service marks,
+or logos of any Contributor (except as may be necessary to comply with
+the notice requirements in Section 3.4).
+
+2.4. Subsequent Licenses
+
+No Contributor makes additional grants as a result of Your choice to
+distribute the Covered Software under a subsequent version of this
+License (see Section 10.2) or under the terms of a Secondary License (if
+permitted under the terms of Section 3.3).
+
+2.5. Representation
+
+Each Contributor represents that the Contributor believes its
+Contributions are its original creation(s) or it has sufficient rights
+to grant the rights to its Contributions conveyed by this License.
+
+2.6. Fair Use
+
+This License is not intended to limit any rights You have under
+applicable copyright doctrines of fair use, fair dealing, or other
+equivalents.
+
+2.7. Conditions
+
+Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
+in Section 2.1.
+
+3. Responsibilities
+-------------------
+
+3.1. Distribution of Source Form
+
+All distribution of Covered Software in Source Code Form, including any
+Modifications that You create or to which You contribute, must be under
+the terms of this License. You must inform recipients that the Source
+Code Form of the Covered Software is governed by the terms of this
+License, and how they can obtain a copy of this License. You may not
+attempt to alter or restrict the recipients' rights in the Source Code
+Form.
+
+3.2. Distribution of Executable Form
+
+If You distribute Covered Software in Executable Form then:
+
+(a) such Covered Software must also be made available in Source Code
+ Form, as described in Section 3.1, and You must inform recipients of
+ the Executable Form how they can obtain a copy of such Source Code
+ Form by reasonable means in a timely manner, at a charge no more
+ than the cost of distribution to the recipient; and
+
+(b) You may distribute such Executable Form under the terms of this
+ License, or sublicense it under different terms, provided that the
+ license for the Executable Form does not attempt to limit or alter
+ the recipients' rights in the Source Code Form under this License.
+
+3.3. Distribution of a Larger Work
+
+You may create and distribute a Larger Work under terms of Your choice,
+provided that You also comply with the requirements of this License for
+the Covered Software. If the Larger Work is a combination of Covered
+Software with a work governed by one or more Secondary Licenses, and the
+Covered Software is not Incompatible With Secondary Licenses, this
+License permits You to additionally distribute such Covered Software
+under the terms of such Secondary License(s), so that the recipient of
+the Larger Work may, at their option, further distribute the Covered
+Software under the terms of either this License or such Secondary
+License(s).
+
+3.4. Notices
+
+You may not remove or alter the substance of any license notices
+(including copyright notices, patent notices, disclaimers of warranty,
+or limitations of liability) contained within the Source Code Form of
+the Covered Software, except that You may alter any license notices to
+the extent required to remedy known factual inaccuracies.
+
+3.5. Application of Additional Terms
+
+You may choose to offer, and to charge a fee for, warranty, support,
+indemnity or liability obligations to one or more recipients of Covered
+Software. However, You may do so only on Your own behalf, and not on
+behalf of any Contributor. You must make it absolutely clear that any
+such warranty, support, indemnity, or liability obligation is offered by
+You alone, and You hereby agree to indemnify every Contributor for any
+liability incurred by such Contributor as a result of warranty, support,
+indemnity or liability terms You offer. You may include additional
+disclaimers of warranty and limitations of liability specific to any
+jurisdiction.
+
+4. Inability to Comply Due to Statute or Regulation
+---------------------------------------------------
+
+If it is impossible for You to comply with any of the terms of this
+License with respect to some or all of the Covered Software due to
+statute, judicial order, or regulation then You must: (a) comply with
+the terms of this License to the maximum extent possible; and (b)
+describe the limitations and the code they affect. Such description must
+be placed in a text file included with all distributions of the Covered
+Software under this License. Except to the extent prohibited by statute
+or regulation, such description must be sufficiently detailed for a
+recipient of ordinary skill to be able to understand it.
+
+5. Termination
+--------------
+
+5.1. The rights granted under this License will terminate automatically
+if You fail to comply with any of its terms. However, if You become
+compliant, then the rights granted under this License from a particular
+Contributor are reinstated (a) provisionally, unless and until such
+Contributor explicitly and finally terminates Your grants, and (b) on an
+ongoing basis, if such Contributor fails to notify You of the
+non-compliance by some reasonable means prior to 60 days after You have
+come back into compliance. Moreover, Your grants from a particular
+Contributor are reinstated on an ongoing basis if such Contributor
+notifies You of the non-compliance by some reasonable means, this is the
+first time You have received notice of non-compliance with this License
+from such Contributor, and You become compliant prior to 30 days after
+Your receipt of the notice.
+
+5.2. If You initiate litigation against any entity by asserting a patent
+infringement claim (excluding declaratory judgment actions,
+counter-claims, and cross-claims) alleging that a Contributor Version
+directly or indirectly infringes any patent, then the rights granted to
+You by any and all Contributors for the Covered Software under Section
+2.1 of this License shall terminate.
+
+5.3. In the event of termination under Sections 5.1 or 5.2 above, all
+end user license agreements (excluding distributors and resellers) which
+have been validly granted by You or Your distributors under this License
+prior to termination shall survive termination.
+
+************************************************************************
+* *
+* 6. Disclaimer of Warranty *
+* ------------------------- *
+* *
+* Covered Software is provided under this License on an "as is" *
+* basis, without warranty of any kind, either expressed, implied, or *
+* statutory, including, without limitation, warranties that the *
+* Covered Software is free of defects, merchantable, fit for a *
+* particular purpose or non-infringing. The entire risk as to the *
+* quality and performance of the Covered Software is with You. *
+* Should any Covered Software prove defective in any respect, You *
+* (not any Contributor) assume the cost of any necessary servicing, *
+* repair, or correction. This disclaimer of warranty constitutes an *
+* essential part of this License. No use of any Covered Software is *
+* authorized under this License except under this disclaimer. *
+* *
+************************************************************************
+
+************************************************************************
+* *
+* 7. Limitation of Liability *
+* -------------------------- *
+* *
+* Under no circumstances and under no legal theory, whether tort *
+* (including negligence), contract, or otherwise, shall any *
+* Contributor, or anyone who distributes Covered Software as *
+* permitted above, be liable to You for any direct, indirect, *
+* special, incidental, or consequential damages of any character *
+* including, without limitation, damages for lost profits, loss of *
+* goodwill, work stoppage, computer failure or malfunction, or any *
+* and all other commercial damages or losses, even if such party *
+* shall have been informed of the possibility of such damages. This *
+* limitation of liability shall not apply to liability for death or *
+* personal injury resulting from such party's negligence to the *
+* extent applicable law prohibits such limitation. Some *
+* jurisdictions do not allow the exclusion or limitation of *
+* incidental or consequential damages, so this exclusion and *
+* limitation may not apply to You. *
+* *
+************************************************************************
+
+8. Litigation
+-------------
+
+Any litigation relating to this License may be brought only in the
+courts of a jurisdiction where the defendant maintains its principal
+place of business and such litigation shall be governed by laws of that
+jurisdiction, without reference to its conflict-of-law provisions.
+Nothing in this Section shall prevent a party's ability to bring
+cross-claims or counter-claims.
+
+9. Miscellaneous
+----------------
+
+This License represents the complete agreement concerning the subject
+matter hereof. If any provision of this License is held to be
+unenforceable, such provision shall be reformed only to the extent
+necessary to make it enforceable. Any law or regulation which provides
+that the language of a contract shall be construed against the drafter
+shall not be used to construe this License against a Contributor.
+
+10. Versions of the License
+---------------------------
+
+10.1. New Versions
+
+Mozilla Foundation is the license steward. Except as provided in Section
+10.3, no one other than the license steward has the right to modify or
+publish new versions of this License. Each version will be given a
+distinguishing version number.
+
+10.2. Effect of New Versions
+
+You may distribute the Covered Software under the terms of the version
+of the License under which You originally received the Covered Software,
+or under the terms of any subsequent version published by the license
+steward.
+
+10.3. Modified Versions
+
+If you create software not governed by this License, and you want to
+create a new license for such software, you may create and use a
+modified version of this License if you rename the license and remove
+any references to the name of the license steward (except to note that
+such modified license differs from this License).
+
+10.4. Distributing Source Code Form that is Incompatible With Secondary
+Licenses
+
+If You choose to distribute Source Code Form that is Incompatible With
+Secondary Licenses under the terms of this version of the License, the
+notice described in Exhibit B of this License must be attached.
+
+Exhibit A - Source Code Form License Notice
+-------------------------------------------
+
+ This Source Code Form is subject to the terms of the Mozilla Public
+ License, v. 2.0. If a copy of the MPL was not distributed with this
+ file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+If it is not possible or desirable to put the notice in a particular
+file, then You may include the notice in a location (such as a LICENSE
+file in a relevant directory) where a recipient would be likely to look
+for such a notice.
+
+You may add additional accurate notices of copyright ownership.
+
+Exhibit B - "Incompatible With Secondary Licenses" Notice
+---------------------------------------------------------
+
+ This Source Code Form is "Incompatible With Secondary Licenses", as
+ defined by the Mozilla Public License, v. 2.0.
+
+
+====================MIT====================
+ * under the guidelines and in accordance with the MIT License. *
+ * http://www.opensource.org/licenses/MIT *
+
+
+====================MIT====================
+// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
+
+
+====================MIT====================
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+
+====================MIT====================
+// SPDX-License-Identifier: MIT
+
+
+====================MIT====================
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+
+====================MIT====================
+[![GitHub License](https://img.shields.io/badge/license-Mozilla-blue.svg)](https://raw.githubusercontent.com/jinja2cpp/Jinja2Cpp/master/LICENSE)
+
+
+====================MPL-1.1====================
+[![GitHub License](https://img.shields.io/badge/license-Mozilla-blue.svg)](https://raw.githubusercontent.com/jinja2cpp/Jinja2Cpp/master/LICENSE)
+
+
+====================MPL-2.0====================
+Mozilla Public License Version 2.0
+==================================
+
+1. Definitions
+--------------
+
+1.1. "Contributor"
+ means each individual or legal entity that creates, contributes to
+ the creation of, or owns Covered Software.
+
+1.2. "Contributor Version"
+ means the combination of the Contributions of others (if any) used
+ by a Contributor and that particular Contributor's Contribution.
+
+1.3. "Contribution"
+ means Covered Software of a particular Contributor.
+
+1.4. "Covered Software"
+ means Source Code Form to which the initial Contributor has attached
+ the notice in Exhibit A, the Executable Form of such Source Code
+ Form, and Modifications of such Source Code Form, in each case
+ including portions thereof.
+
+1.5. "Incompatible With Secondary Licenses"
+ means
+
+ (a) that the initial Contributor has attached the notice described
+ in Exhibit B to the Covered Software; or
+
+ (b) that the Covered Software was made available under the terms of
+ version 1.1 or earlier of the License, but not also under the
+ terms of a Secondary License.
+
+1.6. "Executable Form"
+ means any form of the work other than Source Code Form.
+
+1.7. "Larger Work"
+ means a work that combines Covered Software with other material, in
+ a separate file or files, that is not Covered Software.
+
+1.8. "License"
+ means this document.
+
+1.9. "Licensable"
+ means having the right to grant, to the maximum extent possible,
+ whether at the time of the initial grant or subsequently, any and
+ all of the rights conveyed by this License.
+
+1.10. "Modifications"
+ means any of the following:
+
+ (a) any file in Source Code Form that results from an addition to,
+ deletion from, or modification of the contents of Covered
+ Software; or
+
+ (b) any new file in Source Code Form that contains any Covered
+ Software.
+
+1.11. "Patent Claims" of a Contributor
+ means any patent claim(s), including without limitation, method,
+ process, and apparatus claims, in any patent Licensable by such
+ Contributor that would be infringed, but for the grant of the
+ License, by the making, using, selling, offering for sale, having
+ made, import, or transfer of either its Contributions or its
+ Contributor Version.
+
+1.12. "Secondary License"
+ means either the GNU General Public License, Version 2.0, the GNU
+ Lesser General Public License, Version 2.1, the GNU Affero General
+ Public License, Version 3.0, or any later versions of those
+ licenses.
+
+1.13. "Source Code Form"
+ means the form of the work preferred for making modifications.
+
+1.14. "You" (or "Your")
+ means an individual or a legal entity exercising rights under this
+ License. For legal entities, "You" includes any entity that
+ controls, is controlled by, or is under common control with You. For
+ purposes of this definition, "control" means (a) the power, direct
+ or indirect, to cause the direction or management of such entity,
+ whether by contract or otherwise, or (b) ownership of more than
+ fifty percent (50%) of the outstanding shares or beneficial
+ ownership of such entity.
+
+2. License Grants and Conditions
+--------------------------------
+
+2.1. Grants
+
+Each Contributor hereby grants You a world-wide, royalty-free,
+non-exclusive license:
+
+(a) under intellectual property rights (other than patent or trademark)
+ Licensable by such Contributor to use, reproduce, make available,
+ modify, display, perform, distribute, and otherwise exploit its
+ Contributions, either on an unmodified basis, with Modifications, or
+ as part of a Larger Work; and
+
+(b) under Patent Claims of such Contributor to make, use, sell, offer
+ for sale, have made, import, and otherwise transfer either its
+ Contributions or its Contributor Version.
+
+2.2. Effective Date
+
+The licenses granted in Section 2.1 with respect to any Contribution
+become effective for each Contribution on the date the Contributor first
+distributes such Contribution.
+
+2.3. Limitations on Grant Scope
+
+The licenses granted in this Section 2 are the only rights granted under
+this License. No additional rights or licenses will be implied from the
+distribution or licensing of Covered Software under this License.
+Notwithstanding Section 2.1(b) above, no patent license is granted by a
+Contributor:
+
+(a) for any code that a Contributor has removed from Covered Software;
+ or
+
+(b) for infringements caused by: (i) Your and any other third party's
+ modifications of Covered Software, or (ii) the combination of its
+ Contributions with other software (except as part of its Contributor
+ Version); or
+
+(c) under Patent Claims infringed by Covered Software in the absence of
+ its Contributions.
+
+This License does not grant any rights in the trademarks, service marks,
+or logos of any Contributor (except as may be necessary to comply with
+the notice requirements in Section 3.4).
+
+2.4. Subsequent Licenses
+
+No Contributor makes additional grants as a result of Your choice to
+distribute the Covered Software under a subsequent version of this
+License (see Section 10.2) or under the terms of a Secondary License (if
+permitted under the terms of Section 3.3).
+
+2.5. Representation
+
+Each Contributor represents that the Contributor believes its
+Contributions are its original creation(s) or it has sufficient rights
+to grant the rights to its Contributions conveyed by this License.
+
+2.6. Fair Use
+
+This License is not intended to limit any rights You have under
+applicable copyright doctrines of fair use, fair dealing, or other
+equivalents.
+
+2.7. Conditions
+
+Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
+in Section 2.1.
+
+3. Responsibilities
+-------------------
+
+3.1. Distribution of Source Form
+
+All distribution of Covered Software in Source Code Form, including any
+Modifications that You create or to which You contribute, must be under
+the terms of this License. You must inform recipients that the Source
+Code Form of the Covered Software is governed by the terms of this
+License, and how they can obtain a copy of this License. You may not
+attempt to alter or restrict the recipients' rights in the Source Code
+Form.
+
+3.2. Distribution of Executable Form
+
+If You distribute Covered Software in Executable Form then:
+
+(a) such Covered Software must also be made available in Source Code
+ Form, as described in Section 3.1, and You must inform recipients of
+ the Executable Form how they can obtain a copy of such Source Code
+ Form by reasonable means in a timely manner, at a charge no more
+ than the cost of distribution to the recipient; and
+
+(b) You may distribute such Executable Form under the terms of this
+ License, or sublicense it under different terms, provided that the
+ license for the Executable Form does not attempt to limit or alter
+ the recipients' rights in the Source Code Form under this License.
+
+3.3. Distribution of a Larger Work
+
+You may create and distribute a Larger Work under terms of Your choice,
+provided that You also comply with the requirements of this License for
+the Covered Software. If the Larger Work is a combination of Covered
+Software with a work governed by one or more Secondary Licenses, and the
+Covered Software is not Incompatible With Secondary Licenses, this
+License permits You to additionally distribute such Covered Software
+under the terms of such Secondary License(s), so that the recipient of
+the Larger Work may, at their option, further distribute the Covered
+Software under the terms of either this License or such Secondary
+License(s).
+
+3.4. Notices
+
+You may not remove or alter the substance of any license notices
+(including copyright notices, patent notices, disclaimers of warranty,
+or limitations of liability) contained within the Source Code Form of
+the Covered Software, except that You may alter any license notices to
+the extent required to remedy known factual inaccuracies.
+
+3.5. Application of Additional Terms
+
+You may choose to offer, and to charge a fee for, warranty, support,
+indemnity or liability obligations to one or more recipients of Covered
+Software. However, You may do so only on Your own behalf, and not on
+behalf of any Contributor. You must make it absolutely clear that any
+such warranty, support, indemnity, or liability obligation is offered by
+You alone, and You hereby agree to indemnify every Contributor for any
+liability incurred by such Contributor as a result of warranty, support,
+indemnity or liability terms You offer. You may include additional
+disclaimers of warranty and limitations of liability specific to any
+jurisdiction.
+
+4. Inability to Comply Due to Statute or Regulation
+---------------------------------------------------
+
+If it is impossible for You to comply with any of the terms of this
+License with respect to some or all of the Covered Software due to
+statute, judicial order, or regulation then You must: (a) comply with
+the terms of this License to the maximum extent possible; and (b)
+describe the limitations and the code they affect. Such description must
+be placed in a text file included with all distributions of the Covered
+Software under this License. Except to the extent prohibited by statute
+or regulation, such description must be sufficiently detailed for a
+recipient of ordinary skill to be able to understand it.
+
+5. Termination
+--------------
+
+5.1. The rights granted under this License will terminate automatically
+if You fail to comply with any of its terms. However, if You become
+compliant, then the rights granted under this License from a particular
+Contributor are reinstated (a) provisionally, unless and until such
+Contributor explicitly and finally terminates Your grants, and (b) on an
+ongoing basis, if such Contributor fails to notify You of the
+non-compliance by some reasonable means prior to 60 days after You have
+come back into compliance. Moreover, Your grants from a particular
+Contributor are reinstated on an ongoing basis if such Contributor
+notifies You of the non-compliance by some reasonable means, this is the
+first time You have received notice of non-compliance with this License
+from such Contributor, and You become compliant prior to 30 days after
+Your receipt of the notice.
+
+5.2. If You initiate litigation against any entity by asserting a patent
+infringement claim (excluding declaratory judgment actions,
+counter-claims, and cross-claims) alleging that a Contributor Version
+directly or indirectly infringes any patent, then the rights granted to
+You by any and all Contributors for the Covered Software under Section
+2.1 of this License shall terminate.
+
+5.3. In the event of termination under Sections 5.1 or 5.2 above, all
+end user license agreements (excluding distributors and resellers) which
+have been validly granted by You or Your distributors under this License
+prior to termination shall survive termination.
+
+************************************************************************
+* *
+* 6. Disclaimer of Warranty *
+* ------------------------- *
+* *
+* Covered Software is provided under this License on an "as is" *
+* basis, without warranty of any kind, either expressed, implied, or *
+* statutory, including, without limitation, warranties that the *
+* Covered Software is free of defects, merchantable, fit for a *
+* particular purpose or non-infringing. The entire risk as to the *
+* quality and performance of the Covered Software is with You. *
+* Should any Covered Software prove defective in any respect, You *
+* (not any Contributor) assume the cost of any necessary servicing, *
+* repair, or correction. This disclaimer of warranty constitutes an *
+* essential part of this License. No use of any Covered Software is *
+* authorized under this License except under this disclaimer. *
+* *
+************************************************************************
+
+************************************************************************
+* *
+* 7. Limitation of Liability *
+* -------------------------- *
+* *
+* Under no circumstances and under no legal theory, whether tort *
+* (including negligence), contract, or otherwise, shall any *
+* Contributor, or anyone who distributes Covered Software as *
+* permitted above, be liable to You for any direct, indirect, *
+* special, incidental, or consequential damages of any character *
+* including, without limitation, damages for lost profits, loss of *
+* goodwill, work stoppage, computer failure or malfunction, or any *
+* and all other commercial damages or losses, even if such party *
+* shall have been informed of the possibility of such damages. This *
+* limitation of liability shall not apply to liability for death or *
+* personal injury resulting from such party's negligence to the *
+* extent applicable law prohibits such limitation. Some *
+* jurisdictions do not allow the exclusion or limitation of *
+* incidental or consequential damages, so this exclusion and *
+* limitation may not apply to You. *
+* *
+************************************************************************
+
+8. Litigation
+-------------
+
+Any litigation relating to this License may be brought only in the
+courts of a jurisdiction where the defendant maintains its principal
+place of business and such litigation shall be governed by laws of that
+jurisdiction, without reference to its conflict-of-law provisions.
+Nothing in this Section shall prevent a party's ability to bring
+cross-claims or counter-claims.
+
+9. Miscellaneous
+----------------
+
+This License represents the complete agreement concerning the subject
+matter hereof. If any provision of this License is held to be
+unenforceable, such provision shall be reformed only to the extent
+necessary to make it enforceable. Any law or regulation which provides
+that the language of a contract shall be construed against the drafter
+shall not be used to construe this License against a Contributor.
+
+10. Versions of the License
+---------------------------
+
+10.1. New Versions
+
+Mozilla Foundation is the license steward. Except as provided in Section
+10.3, no one other than the license steward has the right to modify or
+publish new versions of this License. Each version will be given a
+distinguishing version number.
+
+10.2. Effect of New Versions
+
+You may distribute the Covered Software under the terms of the version
+of the License under which You originally received the Covered Software,
+or under the terms of any subsequent version published by the license
+steward.
+
+10.3. Modified Versions
+
+If you create software not governed by this License, and you want to
+create a new license for such software, you may create and use a
+modified version of this License if you rename the license and remove
+any references to the name of the license steward (except to note that
+such modified license differs from this License).
+
+10.4. Distributing Source Code Form that is Incompatible With Secondary
+Licenses
+
+If You choose to distribute Source Code Form that is Incompatible With
+Secondary Licenses under the terms of this version of the License, the
+notice described in Exhibit B of this License must be attached.
+
+Exhibit A - Source Code Form License Notice
+-------------------------------------------
+
+ This Source Code Form is subject to the terms of the Mozilla Public
+ License, v. 2.0. If a copy of the MPL was not distributed with this
+ file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+If it is not possible or desirable to put the notice in a particular
+file, then You may include the notice in a location (such as a LICENSE
+file in a relevant directory) where a recipient would be likely to look
+for such a notice.
+
+You may add additional accurate notices of copyright ownership.
+
+Exhibit B - "Incompatible With Secondary Licenses" Notice
+---------------------------------------------------------
+
+ This Source Code Form is "Incompatible With Secondary Licenses", as
+ defined by the Mozilla Public License, v. 2.0. \ No newline at end of file
diff --git a/contrib/libs/jinja2cpp/LICENSE b/contrib/libs/jinja2cpp/LICENSE
new file mode 100644
index 0000000000..a612ad9813
--- /dev/null
+++ b/contrib/libs/jinja2cpp/LICENSE
@@ -0,0 +1,373 @@
+Mozilla Public License Version 2.0
+==================================
+
+1. Definitions
+--------------
+
+1.1. "Contributor"
+ means each individual or legal entity that creates, contributes to
+ the creation of, or owns Covered Software.
+
+1.2. "Contributor Version"
+ means the combination of the Contributions of others (if any) used
+ by a Contributor and that particular Contributor's Contribution.
+
+1.3. "Contribution"
+ means Covered Software of a particular Contributor.
+
+1.4. "Covered Software"
+ means Source Code Form to which the initial Contributor has attached
+ the notice in Exhibit A, the Executable Form of such Source Code
+ Form, and Modifications of such Source Code Form, in each case
+ including portions thereof.
+
+1.5. "Incompatible With Secondary Licenses"
+ means
+
+ (a) that the initial Contributor has attached the notice described
+ in Exhibit B to the Covered Software; or
+
+ (b) that the Covered Software was made available under the terms of
+ version 1.1 or earlier of the License, but not also under the
+ terms of a Secondary License.
+
+1.6. "Executable Form"
+ means any form of the work other than Source Code Form.
+
+1.7. "Larger Work"
+ means a work that combines Covered Software with other material, in
+ a separate file or files, that is not Covered Software.
+
+1.8. "License"
+ means this document.
+
+1.9. "Licensable"
+ means having the right to grant, to the maximum extent possible,
+ whether at the time of the initial grant or subsequently, any and
+ all of the rights conveyed by this License.
+
+1.10. "Modifications"
+ means any of the following:
+
+ (a) any file in Source Code Form that results from an addition to,
+ deletion from, or modification of the contents of Covered
+ Software; or
+
+ (b) any new file in Source Code Form that contains any Covered
+ Software.
+
+1.11. "Patent Claims" of a Contributor
+ means any patent claim(s), including without limitation, method,
+ process, and apparatus claims, in any patent Licensable by such
+ Contributor that would be infringed, but for the grant of the
+ License, by the making, using, selling, offering for sale, having
+ made, import, or transfer of either its Contributions or its
+ Contributor Version.
+
+1.12. "Secondary License"
+ means either the GNU General Public License, Version 2.0, the GNU
+ Lesser General Public License, Version 2.1, the GNU Affero General
+ Public License, Version 3.0, or any later versions of those
+ licenses.
+
+1.13. "Source Code Form"
+ means the form of the work preferred for making modifications.
+
+1.14. "You" (or "Your")
+ means an individual or a legal entity exercising rights under this
+ License. For legal entities, "You" includes any entity that
+ controls, is controlled by, or is under common control with You. For
+ purposes of this definition, "control" means (a) the power, direct
+ or indirect, to cause the direction or management of such entity,
+ whether by contract or otherwise, or (b) ownership of more than
+ fifty percent (50%) of the outstanding shares or beneficial
+ ownership of such entity.
+
+2. License Grants and Conditions
+--------------------------------
+
+2.1. Grants
+
+Each Contributor hereby grants You a world-wide, royalty-free,
+non-exclusive license:
+
+(a) under intellectual property rights (other than patent or trademark)
+ Licensable by such Contributor to use, reproduce, make available,
+ modify, display, perform, distribute, and otherwise exploit its
+ Contributions, either on an unmodified basis, with Modifications, or
+ as part of a Larger Work; and
+
+(b) under Patent Claims of such Contributor to make, use, sell, offer
+ for sale, have made, import, and otherwise transfer either its
+ Contributions or its Contributor Version.
+
+2.2. Effective Date
+
+The licenses granted in Section 2.1 with respect to any Contribution
+become effective for each Contribution on the date the Contributor first
+distributes such Contribution.
+
+2.3. Limitations on Grant Scope
+
+The licenses granted in this Section 2 are the only rights granted under
+this License. No additional rights or licenses will be implied from the
+distribution or licensing of Covered Software under this License.
+Notwithstanding Section 2.1(b) above, no patent license is granted by a
+Contributor:
+
+(a) for any code that a Contributor has removed from Covered Software;
+ or
+
+(b) for infringements caused by: (i) Your and any other third party's
+ modifications of Covered Software, or (ii) the combination of its
+ Contributions with other software (except as part of its Contributor
+ Version); or
+
+(c) under Patent Claims infringed by Covered Software in the absence of
+ its Contributions.
+
+This License does not grant any rights in the trademarks, service marks,
+or logos of any Contributor (except as may be necessary to comply with
+the notice requirements in Section 3.4).
+
+2.4. Subsequent Licenses
+
+No Contributor makes additional grants as a result of Your choice to
+distribute the Covered Software under a subsequent version of this
+License (see Section 10.2) or under the terms of a Secondary License (if
+permitted under the terms of Section 3.3).
+
+2.5. Representation
+
+Each Contributor represents that the Contributor believes its
+Contributions are its original creation(s) or it has sufficient rights
+to grant the rights to its Contributions conveyed by this License.
+
+2.6. Fair Use
+
+This License is not intended to limit any rights You have under
+applicable copyright doctrines of fair use, fair dealing, or other
+equivalents.
+
+2.7. Conditions
+
+Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
+in Section 2.1.
+
+3. Responsibilities
+-------------------
+
+3.1. Distribution of Source Form
+
+All distribution of Covered Software in Source Code Form, including any
+Modifications that You create or to which You contribute, must be under
+the terms of this License. You must inform recipients that the Source
+Code Form of the Covered Software is governed by the terms of this
+License, and how they can obtain a copy of this License. You may not
+attempt to alter or restrict the recipients' rights in the Source Code
+Form.
+
+3.2. Distribution of Executable Form
+
+If You distribute Covered Software in Executable Form then:
+
+(a) such Covered Software must also be made available in Source Code
+ Form, as described in Section 3.1, and You must inform recipients of
+ the Executable Form how they can obtain a copy of such Source Code
+ Form by reasonable means in a timely manner, at a charge no more
+ than the cost of distribution to the recipient; and
+
+(b) You may distribute such Executable Form under the terms of this
+ License, or sublicense it under different terms, provided that the
+ license for the Executable Form does not attempt to limit or alter
+ the recipients' rights in the Source Code Form under this License.
+
+3.3. Distribution of a Larger Work
+
+You may create and distribute a Larger Work under terms of Your choice,
+provided that You also comply with the requirements of this License for
+the Covered Software. If the Larger Work is a combination of Covered
+Software with a work governed by one or more Secondary Licenses, and the
+Covered Software is not Incompatible With Secondary Licenses, this
+License permits You to additionally distribute such Covered Software
+under the terms of such Secondary License(s), so that the recipient of
+the Larger Work may, at their option, further distribute the Covered
+Software under the terms of either this License or such Secondary
+License(s).
+
+3.4. Notices
+
+You may not remove or alter the substance of any license notices
+(including copyright notices, patent notices, disclaimers of warranty,
+or limitations of liability) contained within the Source Code Form of
+the Covered Software, except that You may alter any license notices to
+the extent required to remedy known factual inaccuracies.
+
+3.5. Application of Additional Terms
+
+You may choose to offer, and to charge a fee for, warranty, support,
+indemnity or liability obligations to one or more recipients of Covered
+Software. However, You may do so only on Your own behalf, and not on
+behalf of any Contributor. You must make it absolutely clear that any
+such warranty, support, indemnity, or liability obligation is offered by
+You alone, and You hereby agree to indemnify every Contributor for any
+liability incurred by such Contributor as a result of warranty, support,
+indemnity or liability terms You offer. You may include additional
+disclaimers of warranty and limitations of liability specific to any
+jurisdiction.
+
+4. Inability to Comply Due to Statute or Regulation
+---------------------------------------------------
+
+If it is impossible for You to comply with any of the terms of this
+License with respect to some or all of the Covered Software due to
+statute, judicial order, or regulation then You must: (a) comply with
+the terms of this License to the maximum extent possible; and (b)
+describe the limitations and the code they affect. Such description must
+be placed in a text file included with all distributions of the Covered
+Software under this License. Except to the extent prohibited by statute
+or regulation, such description must be sufficiently detailed for a
+recipient of ordinary skill to be able to understand it.
+
+5. Termination
+--------------
+
+5.1. The rights granted under this License will terminate automatically
+if You fail to comply with any of its terms. However, if You become
+compliant, then the rights granted under this License from a particular
+Contributor are reinstated (a) provisionally, unless and until such
+Contributor explicitly and finally terminates Your grants, and (b) on an
+ongoing basis, if such Contributor fails to notify You of the
+non-compliance by some reasonable means prior to 60 days after You have
+come back into compliance. Moreover, Your grants from a particular
+Contributor are reinstated on an ongoing basis if such Contributor
+notifies You of the non-compliance by some reasonable means, this is the
+first time You have received notice of non-compliance with this License
+from such Contributor, and You become compliant prior to 30 days after
+Your receipt of the notice.
+
+5.2. If You initiate litigation against any entity by asserting a patent
+infringement claim (excluding declaratory judgment actions,
+counter-claims, and cross-claims) alleging that a Contributor Version
+directly or indirectly infringes any patent, then the rights granted to
+You by any and all Contributors for the Covered Software under Section
+2.1 of this License shall terminate.
+
+5.3. In the event of termination under Sections 5.1 or 5.2 above, all
+end user license agreements (excluding distributors and resellers) which
+have been validly granted by You or Your distributors under this License
+prior to termination shall survive termination.
+
+************************************************************************
+* *
+* 6. Disclaimer of Warranty *
+* ------------------------- *
+* *
+* Covered Software is provided under this License on an "as is" *
+* basis, without warranty of any kind, either expressed, implied, or *
+* statutory, including, without limitation, warranties that the *
+* Covered Software is free of defects, merchantable, fit for a *
+* particular purpose or non-infringing. The entire risk as to the *
+* quality and performance of the Covered Software is with You. *
+* Should any Covered Software prove defective in any respect, You *
+* (not any Contributor) assume the cost of any necessary servicing, *
+* repair, or correction. This disclaimer of warranty constitutes an *
+* essential part of this License. No use of any Covered Software is *
+* authorized under this License except under this disclaimer. *
+* *
+************************************************************************
+
+************************************************************************
+* *
+* 7. Limitation of Liability *
+* -------------------------- *
+* *
+* Under no circumstances and under no legal theory, whether tort *
+* (including negligence), contract, or otherwise, shall any *
+* Contributor, or anyone who distributes Covered Software as *
+* permitted above, be liable to You for any direct, indirect, *
+* special, incidental, or consequential damages of any character *
+* including, without limitation, damages for lost profits, loss of *
+* goodwill, work stoppage, computer failure or malfunction, or any *
+* and all other commercial damages or losses, even if such party *
+* shall have been informed of the possibility of such damages. This *
+* limitation of liability shall not apply to liability for death or *
+* personal injury resulting from such party's negligence to the *
+* extent applicable law prohibits such limitation. Some *
+* jurisdictions do not allow the exclusion or limitation of *
+* incidental or consequential damages, so this exclusion and *
+* limitation may not apply to You. *
+* *
+************************************************************************
+
+8. Litigation
+-------------
+
+Any litigation relating to this License may be brought only in the
+courts of a jurisdiction where the defendant maintains its principal
+place of business and such litigation shall be governed by laws of that
+jurisdiction, without reference to its conflict-of-law provisions.
+Nothing in this Section shall prevent a party's ability to bring
+cross-claims or counter-claims.
+
+9. Miscellaneous
+----------------
+
+This License represents the complete agreement concerning the subject
+matter hereof. If any provision of this License is held to be
+unenforceable, such provision shall be reformed only to the extent
+necessary to make it enforceable. Any law or regulation which provides
+that the language of a contract shall be construed against the drafter
+shall not be used to construe this License against a Contributor.
+
+10. Versions of the License
+---------------------------
+
+10.1. New Versions
+
+Mozilla Foundation is the license steward. Except as provided in Section
+10.3, no one other than the license steward has the right to modify or
+publish new versions of this License. Each version will be given a
+distinguishing version number.
+
+10.2. Effect of New Versions
+
+You may distribute the Covered Software under the terms of the version
+of the License under which You originally received the Covered Software,
+or under the terms of any subsequent version published by the license
+steward.
+
+10.3. Modified Versions
+
+If you create software not governed by this License, and you want to
+create a new license for such software, you may create and use a
+modified version of this License if you rename the license and remove
+any references to the name of the license steward (except to note that
+such modified license differs from this License).
+
+10.4. Distributing Source Code Form that is Incompatible With Secondary
+Licenses
+
+If You choose to distribute Source Code Form that is Incompatible With
+Secondary Licenses under the terms of this version of the License, the
+notice described in Exhibit B of this License must be attached.
+
+Exhibit A - Source Code Form License Notice
+-------------------------------------------
+
+ This Source Code Form is subject to the terms of the Mozilla Public
+ License, v. 2.0. If a copy of the MPL was not distributed with this
+ file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+If it is not possible or desirable to put the notice in a particular
+file, then You may include the notice in a location (such as a LICENSE
+file in a relevant directory) where a recipient would be likely to look
+for such a notice.
+
+You may add additional accurate notices of copyright ownership.
+
+Exhibit B - "Incompatible With Secondary Licenses" Notice
+---------------------------------------------------------
+
+ This Source Code Form is "Incompatible With Secondary Licenses", as
+ defined by the Mozilla Public License, v. 2.0.
diff --git a/contrib/libs/jinja2cpp/README.md b/contrib/libs/jinja2cpp/README.md
new file mode 100644
index 0000000000..2fc58e46ac
--- /dev/null
+++ b/contrib/libs/jinja2cpp/README.md
@@ -0,0 +1,384 @@
+<div align="center"><img width="200" src="https://avatars0.githubusercontent.com/u/49841676?s=200&v=4"></div>
+
+# Jinja2С++
+
+[![Language](https://img.shields.io/badge/language-C++-blue.svg)](https://isocpp.org/)
+[![Standard](https://img.shields.io/badge/c%2B%2B-14-blue.svg)](https://en.wikipedia.org/wiki/C%2B%2B#Standardization)
+[![Standard](https://img.shields.io/badge/c%2B%2B-17-blue.svg)](https://en.wikipedia.org/wiki/C%2B%2B#Standardization)
+[![Standard](https://img.shields.io/badge/c%2B%2B-20-blue.svg)](https://en.wikipedia.org/wiki/C%2B%2B#Standardization)
+[![Coverage Status](https://codecov.io/gh/jinja2cpp/Jinja2Cpp/branch/master/graph/badge.svg)](https://codecov.io/gh/jinja2cpp/Jinja2Cpp)
+[![Github Releases](https://img.shields.io/github/release/jinja2cpp/Jinja2Cpp/all.svg)](https://github.com/jinja2cpp/Jinja2Cpp/releases)
+[![Github Issues](https://img.shields.io/github/issues/jinja2cpp/Jinja2Cpp.svg)](http://github.com/jinja2cpp/Jinja2Cpp/issues)
+[![GitHub License](https://img.shields.io/badge/license-Mozilla-blue.svg)](https://raw.githubusercontent.com/jinja2cpp/Jinja2Cpp/master/LICENSE)
+[![conan.io](https://api.bintray.com/packages/conan/conan-center/jinja2cpp%3A_/images/download.svg?version=1.2.1%3A_) ](https://conan.io/center/jinja2cpp)
+[![Gitter Chat](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/Jinja2Cpp/Lobby)
+
+C++ implementation of the Jinja2 Python template engine. This library brings support of powerful Jinja2 template features into the C++ world, reports dynamic HTML pages and source code generation.
+
+## Introduction
+
+Main features of Jinja2C++:
+- Easy-to-use public interface. Just load templates and render them.
+- Conformance to [Jinja2 specification](http://jinja.pocoo.org/docs/2.10/)
+- Full support of narrow- and wide-character strings both for templates and parameters.
+- Built-in reflection for the common C++ types, nlohmann and rapid JSON libraries.
+- Powerful full-featured Jinja2 expressions with filtering (via '|' operator) and 'if'-expressions.
+- Control statements (`set`, `for`, `if`, `filter`, `do`, `with`).
+- Templates extension, including and importing
+- Macros
+- Rich error reporting.
+- Shared template environment with templates cache support
+
+For instance, this simple code:
+
+```c++
+#include <jinja2cpp/template.h>
+
+std::string source = R"(
+{{ ("Hello", 'world') | join }}!!!
+{{ ("Hello", 'world') | join(', ') }}!!!
+{{ ("Hello", 'world') | join(d = '; ') }}!!!
+{{ ("Hello", 'world') | join(d = '; ') | lower }}!!!
+)";
+
+Template tpl;
+tpl.Load(source);
+
+std::string result = tpl.RenderAsString({}).value();
+```
+
+produces the result string:
+
+```
+Helloworld!!!
+Hello, world!!!
+Hello; world!!!
+hello; world!!!
+```
+
+## Getting started
+
+To use Jinja2C++ in your project you have to:
+* Clone the Jinja2C++ repository
+* Build it according to the [instructions](https://jinja2cpp.github.io/docs/build_and_install.html)
+* Link to your project.
+
+Usage of Jinja2C++ in the code is pretty simple:
+1. Declare the jinja2::Template object:
+
+```c++
+jinja2::Template tpl;
+```
+
+2. Populate it with template:
+
+```c++
+tpl.Load("{{ 'Hello World' }}!!!");
+```
+
+3. Render the template:
+
+```c++
+std::cout << tpl.RenderAsString({}).value() << std::endl;
+```
+
+and get:
+
+`
+Hello World!!!
+`
+
+That's all!
+
+More detailed examples and features description can be found in the documentation: [https://jinja2cpp.github.io/docs/usage](https://jinja2cpp.github.io/docs/usage)
+
+## Current Jinja2 support
+Currently, Jinja2C++ supports the limited number of Jinja2 features. By the way, Jinja2C++ is planned to be a fully [jinja2 specification](http://jinja.pocoo.org/docs/2.10/templates/)-conformant. The current support is limited to:
+- expressions. You can use almost every expression style: simple, filtered, conditional, and so on.
+- the big number of filters (**sort, default, first, last, length, max, min, reverse, unique, sum, attr, map, reject, rejectattr, select, selectattr, pprint, dictsort, abs, float, int, list, round, random, trim, title, upper, wordcount, replace, truncate, groupby, urlencode, capitalize, escape, tojson, striptags, center, xmlattr**)
+- the big number of testers (**eq, defined, ge, gt, iterable, le, lt, mapping, ne, number, sequence, string, undefined, in, even, odd, lower, upper**)
+- the number of functions (**range**, **loop.cycle**)
+- 'if' statement (with 'elif' and 'else' branches)
+- 'for' statement (with 'else' branch and 'if' part support)
+- 'include' statement
+- 'import'/'from' statements
+- 'set' statement (both line and block)
+- 'filter' statement
+- 'extends'/'block' statements
+- 'macro'/'call' statements
+- 'with' statement
+- 'do' extension statement
+- recursive loops
+- space control and 'raw'/'endraw' blocks
+
+Full information about Jinja2 specification support and compatibility table can be found here: [https://jinja2cpp.github.io/docs/j2_compatibility.html](https://jinja2cpp.github.io/docs/j2_compatibility.html).
+
+## Supported compilers
+Compilation of Jinja2C++ tested on the following compilers (with C++14 and C++17 enabled features):
+- Linux gcc 5.5 - 9.0
+- Linux clang 5.0 - 9
+- MacOS X-Code 9
+- MacOS X-Code 10
+- MacOS X-Code 11 (C++14 in default build, C++17 with externally-provided boost)
+- Microsoft Visual Studio 2015 - 2019 x86, x64
+- MinGW gcc compiler 7.3
+- MinGW gcc compiler 8.1
+
+**Note:** Support of gcc version >= 9.x or clang version >= 8.0 depends on the version of the Boost library provided.
+
+### Build status
+
+| Compiler | Status |
+|---------|---------:|
+| **MSVC** 2015 (x86, x64), **MinGW** 7 (x64), **MinGW** 8 (x64) | [![Build status](https://ci.appveyor.com/api/projects/status/vu59lw4r67n8jdxl/branch/master?svg=true)](https://ci.appveyor.com/project/flexferrum/jinja2cpp-n5hjm/branch/master) |
+| **X-Code** 9, 10, 11 | [![Build Status](https://travis-ci.org/jinja2cpp/Jinja2Cpp.svg?branch=master)](https://travis-ci.org/jinja2cpp/Jinja2Cpp) |
+| **MSVC** 2017 (x86, x64), **MSVC** 2019 (x86, x64), C++14/C++17 | [![](https://github.com/jinja2cpp/Jinja2Cpp/workflows/CI-windows-build/badge.svg)](https://github.com/jinja2cpp/Jinja2Cpp/actions?query=workflow%3ACI-windows-build) |
+| **g++** 5, 6, 7, 8, 9, 10, 11 **clang** 5, 6, 7, 8, 9, 10, 11, 12 C++14/C++17/C++20 | [![](https://github.com/jinja2cpp/Jinja2Cpp/workflows/CI-linux-build/badge.svg)](https://github.com/jinja2cpp/Jinja2Cpp/actions?query=workflow%3ACI-linux-build) |
+
+## Build and install
+Jinja2C++ has several external dependencies:
+- `boost` library (at least version 1.65)
+- `nonstd::expected-lite` [https://github.com/martinmoene/expected-lite](https://github.com/martinmoene/expected-lite)
+- `nonstd::variant-lite` [https://github.com/martinmoene/variant-lite](https://github.com/martinmoene/variant-lite)
+- `nonstd::optional-lite` [https://github.com/martinmoene/optional-lite](https://github.com/martinmoene/optional-lite)
+- `nonstd::string-view-lite` [https://github.com/martinmoene/string-view-lite](https://github.com/martinmoene/string-view-lite)
+- `fmtlib::fmt` [https://github.com/fmtlib/fmt](https://github.com/fmtlib/fmt)
+
+Examples of build scripts and different build configurations could be found here: [https://github.com/jinja2cpp/examples-build](https://github.com/jinja2cpp/examples-build)
+
+In simplest case to compile Jinja2C++ you need:
+
+1. Install CMake build system (at least version 3.0)
+2. Clone jinja2cpp repository:
+
+```
+> git clone https://github.com/flexferrum/Jinja2Cpp.git
+```
+
+3. Create build directory:
+
+```
+> cd Jinja2Cpp
+> mkdir build
+```
+
+4. Run CMake and build the library:
+
+```
+> cd build
+> cmake .. -DCMAKE_INSTALL_PREFIX=<path to install folder>
+> cmake --build . --target all
+```
+"Path to install folder" here is a path to the folder where you want to install Jinja2C++ lib.
+
+5. Install library:
+
+```
+> cmake --build . --target install
+```
+
+In this case, Jinja2C++ will be built with internally-shipped dependencies and install them respectively. But Jinja2C++ supports builds with externally-provided deps.
+### Usage with conan.io dependency manager
+Jinja2C++ can be used as conan.io package. In this case, you should do the following steps:
+
+1. Install conan.io according to the documentation ( https://docs.conan.io/en/latest/installation.html )
+2. Add a reference to Jinja2C++ package (`jinja2cpp/1.2.1`) to your conanfile.txt, conanfile.py or CMakeLists.txt. For instance, with the usage of `conan-cmake` integration it could be written this way:
+
+```cmake
+
+cmake_minimum_required(VERSION 3.24)
+project(Jinja2CppSampleConan CXX)
+
+list(APPEND CMAKE_MODULE_PATH ${CMAKE_BINARY_DIR})
+list(APPEND CMAKE_PREFIX_PATH ${CMAKE_BINARY_DIR})
+
+add_definitions("-std=c++14")
+
+if(NOT EXISTS "${CMAKE_BINARY_DIR}/conan.cmake")
+ message(STATUS "Downloading conan.cmake from https://github.com/conan-io/cmake-conan")
+ file(DOWNLOAD "https://raw.githubusercontent.com/conan-io/cmake-conan/0.18.1/conan.cmake"
+ "${CMAKE_BINARY_DIR}/conan.cmake"
+ TLS_VERIFY ON)
+endif()
+include(${CMAKE_BINARY_DIR}/conan.cmake)
+
+conan_cmake_autodetect(settings)
+conan_cmake_run(REQUIRES
+ jinja2cpp/1.1.0
+ gtest/1.14.0
+ BASIC_SETUP
+ ${CONAN_SETTINGS}
+ OPTIONS
+ jinja2cpp/*:shared=False
+ gtest/*:shared=False
+ BUILD missing)
+
+set (TARGET_NAME jinja2cpp_build_test)
+
+add_executable (${TARGET_NAME} main.cpp)
+
+target_link_libraries (${TARGET_NAME} ${CONAN_LIBS})
+set_target_properties (${TARGET_NAME} PROPERTIES
+ CXX_STANDARD 14
+ CXX_STANDARD_REQUIRED ON)
+
+```
+
+
+### Additional CMake build flags
+You can define (via -D command-line CMake option) the following build flags:
+
+- **JINJA2CPP_BUILD_TESTS** (default TRUE) - to build or not to Jinja2C++ tests.
+- **JINJA2CPP_STRICT_WARNINGS** (default TRUE) - Enable strict mode compile-warnings(-Wall -Werror, etc).
+- **JINJA2CPP_MSVC_RUNTIME_TYPE** (default /MD) - MSVC runtime type to link with (if you use Microsoft Visual Studio compiler).
+- **JINJA2CPP_DEPS_MODE** (default "internal") - modes for dependency handling. Following values possible:
+ - `internal` In this mode Jinja2C++ build script uses dependencies (include `boost`) shipped as subprojects. Nothing needs to be provided externally.
+ - `external-boost` In this mode Jinja2C++ build script uses only `boost` as an externally-provided dependency. All other dependencies are taken from subprojects.
+ - `external` In this mode all dependencies should be provided externally. Paths to `boost`, `nonstd-*` libs, etc. should be specified via standard CMake variables (like `CMAKE_PREFIX_PATH` or libname_DIR)
+ - `conan-build` Special mode for building Jinja2C++ via conan recipe.
+
+
+### Build with C++17 standard enabled
+Jinja2C++ tries to use standard versions of `std::variant`, `std::string_view` and `std::optional` if possible.
+
+## Acknowledgments
+Thanks to **@flexferrum** for creating this library, for being one of the brightest minds in software engineering community. Rest in peace, friend.
+
+Thanks to **@manu343726** for CMake scripts improvement, bug hunting, and fixing and conan.io packaging.
+
+Thanks to **@martinmoene** for the perfectly implemented xxx-lite libraries.
+
+Thanks to **@vitaut** for the amazing text formatting library.
+
+Thanks to **@martinus** for the fast hash maps implementation.
+
+
+## Changelog
+
+
+### Version 1.3.1
+
+#### Changes and improvements
+- bump deps versions
+- add new json binding - boost::json
+- speedup regex parsing by switching to boost::regex(std::regex extremely slow)
+ - templates are now loading faster
+
+#### Fixed bugs
+- small fixes across code base
+
+#### Breaking changes
+- internal deps now used through cmake fetch_content
+- default json serializer/deserializer is switched to boost::json
+
+### Version 1.2.1
+
+#### Changes and improvements
+- bump deps versions
+- support modern compilers(up to Clang 12) and standards(C++20)
+- tiny code style cleanup
+
+#### Fixed bugs
+- small fixes across code base
+
+#### Breaking changes
+- internal deps point to make based boost build
+
+### Version 1.1.0
+#### Changes and improvements
+- `batch` filter added
+- `slice` filter added
+- `format` filter added
+- `tojson` filter added
+- `striptags` filter added
+- `center` filter added
+- `xmlattr` filter added
+- `raw`/`endraw` tags added
+- repeat string operator added (e. g. `'a' * 5` will produce `'aaaaa'`)
+- support for templates metadata (`meta`/`endmeta` tags) added
+- `-fPIC` flag added to Linux build configuration
+
+#### Fixed bugs
+- Fix behavior of lstripblock/trimblocks global settings. Now it fully corresponds to the origina jinja2
+- Fix bug with rendering parent `block` content if child doesn't override this block
+- Fix compilation issues with user-defined callables with number of arguments more than 2
+- Fix access to global Jinja2 functions from included/extended templates
+- Fix point of evaluation of macro params
+- Fix looping over the strings
+- Cleanup warnings
+
+#### Breaking changes
+- From now with C++17 standard enabled Jinja2C++ uses standard versions of types `variant`, `string_view` and `optional`
+
+### Version 1.0.0
+#### Changes and improvements
+- `default` attribute added to the `map` filter (#48)
+- escape sequences support added to the string literals (#49)
+- arbitrary ranges, generated sequences, input iterators, etc. now can be used with `GenericList` type (#66)
+- nonstd::string_view is now one of the possible types for the `Value`
+- `filter` tag support added to the template parser (#44)
+- `escape` filter support added to the template parser (#140)
+- `capitalize` filter support added to the template parser (#137)
+- the multiline version of `set` tag added to the parser (#45)
+- added built-in reflection for nlohmann JSON and RapidJSON libraries (#78)
+- `loop.depth` and `loop.depth0` variables support added
+- {fmt} is now used as a formatting library instead of iostreams
+- robin hood hash map is now used for internal value storage
+- rendering performance improvements
+- template cache implemented in `TemplateEnv`
+- user-defined callables now can accept global context via `*context` special param
+- MinGW, clang >= 7.0, XCode >= 9, gcc >= 7.0 are now officially supported as a target compilers (#79)
+
+#### Fixed bugs
+- Fixed pipe (`|`) operator precedence (#47)
+- Fixed bug in internal char <-> wchar_t converter on Windows
+- Fixed crash in parsing `endblock` tag
+- Fixed scope control for `include` and `for` tags
+- Fixed bug with macros call within expression context
+
+#### Breaking changes
+- MSVC runtime type is now defined by `JINJA2CPP_MSVC_RUNTIME_TYPE` CMake variable
+
+### Version 0.9.2
+#### Major changes
+- User-defined callables implemented. Now you can define your own callable objects, pass them as input parameters and use them inside templates as regular (global) functions, filters or testers. See details here: https://jinja2cpp.github.io/docs/usage/ud_callables.html
+- Now you can define global (template environment-wide) parameters that are accessible for all templates bound to this environment.
+- `include`, `import` and `from` statements implemented. Now it's possible to include other templates and use macros from other templates.
+- `with` statement implemented
+- `do` statement implemented
+- Sample build projects for various Jinja2C++ usage variants created: https://github.com/jinja2cpp/examples-build](https://github.com/jinja2cpp/examples-build)
+- Documentation site created for Jinja2C++: https://jinja2cpp.github.io
+
+#### Minor changes
+- Render-time error handling added
+- Dependency management mode added to the build script
+- Fix bugs with error reporting during the parse time
+- Upgraded versions of external dependencies
+
+#### Breaking changes
+- `RenderAsString` method now returns `nonstd::expected` instead of regular `std::string`
+- Templates with `import`, `extends` and `include` generate errors if parsed without `TemplateEnv` set
+- Release bundles (archives) are configured with `external` dependency management mode by default
+
+### Version 0.9.1
+- `applymacro` filter added which allows applying arbitrary macro as a filter
+- dependencies to boost removed from the public interface
+- CMake scripts improved
+- Various bugs fixed
+- Improve reflection
+- Warnings cleanup
+
+### Version 0.9
+- Support of 'extents'/'block' statements
+- Support of 'macro'/'call' statements
+- Rich error reporting
+- Support for recursive loops
+- Support for space control before and after control blocks
+- Improve reflection
+
+### Version 0.6
+- A lot of filters have been implemented. Full set of supported filters listed here: [https://github.com/flexferrum/Jinja2Cpp/issues/7](https://github.com/flexferrum/Jinja2Cpp/issues/7)
+- A lot of testers have been implemented. Full set of supported testers listed here: [https://github.com/flexferrum/Jinja2Cpp/issues/8](https://github.com/flexferrum/Jinja2Cpp/issues/8)
+- 'Concatenate as string' operator ('~') has been implemented
+- For-loop with 'if' condition has been implemented
+- Fixed some bugs in parser
diff --git a/contrib/libs/jinja2cpp/include/jinja2cpp/binding/rapid_json.h b/contrib/libs/jinja2cpp/include/jinja2cpp/binding/rapid_json.h
new file mode 100644
index 0000000000..2d9bc47c1b
--- /dev/null
+++ b/contrib/libs/jinja2cpp/include/jinja2cpp/binding/rapid_json.h
@@ -0,0 +1,201 @@
+#ifndef JINJA2CPP_BINDING_RAPID_JSON_H
+#define JINJA2CPP_BINDING_RAPID_JSON_H
+
+#include <jinja2cpp/reflected_value.h>
+#include <jinja2cpp/string_helpers.h>
+
+#include <rapidjson/document.h>
+#include <rapidjson/rapidjson.h>
+
+namespace jinja2
+{
+namespace detail
+{
+
+template<typename CharT>
+struct RapidJsonNameConverter;
+
+template<>
+struct RapidJsonNameConverter<char>
+{
+ static const std::string& GetName(const std::string& str) { return str; }
+};
+
+template<>
+struct RapidJsonNameConverter<wchar_t>
+{
+ static std::wstring GetName(const std::string& str) { return ConvertString<std::wstring>(str); }
+};
+
+template<typename T>
+class RapidJsonObjectAccessor : public IMapItemAccessor, public ReflectedDataHolder<T, false>
+{
+public:
+ using ReflectedDataHolder<T, false>::ReflectedDataHolder;
+ using NameCvt = RapidJsonNameConverter<typename T::Ch>;
+ using ThisType = RapidJsonObjectAccessor<T>;
+ ~RapidJsonObjectAccessor() override = default;
+
+ size_t GetSize() const override
+ {
+ auto j = this->GetValue();
+ return j ? j->MemberCount() : 0ULL;
+ }
+
+ bool HasValue(const std::string& name) const override
+ {
+ auto j = this->GetValue();
+ return j ? j->HasMember(NameCvt::GetName(name).c_str()) : false;
+ }
+
+ Value GetValueByName(const std::string& nameOrig) const override
+ {
+ auto j = this->GetValue();
+ const auto& name = NameCvt::GetName(nameOrig);
+ if (!j || !j->HasMember(name.c_str()))
+ return Value();
+
+ return Reflect(&(*j)[name.c_str()]);
+ }
+
+ std::vector<std::string> GetKeys() const override
+ {
+ auto j = this->GetValue();
+ if (!j)
+ return {};
+
+ std::vector<std::string> result;
+ result.reserve(j->MemberCount());
+ for (auto it = j->MemberBegin(); it != j->MemberEnd(); ++ it)
+ {
+ result.emplace_back(ConvertString<std::string>(std::basic_string_view<typename T::Ch>(it->name.GetString())));
+ }
+ return result;
+ }
+
+ bool IsEqual(const IComparable& other) const override
+ {
+ auto* val = dynamic_cast<const ThisType*>(&other);
+ if (!val)
+ return false;
+ auto enumerator = this->GetValue();
+ auto otherEnum = val->GetValue();
+ if (enumerator && otherEnum && enumerator != otherEnum)
+ return false;
+ if ((enumerator && !otherEnum) || (!enumerator && otherEnum))
+ return false;
+ return true;
+ }
+};
+
+template<typename Enc>
+struct RapidJsonArrayAccessor
+ : IListItemAccessor
+ , IIndexBasedAccessor
+ , ReflectedDataHolder<rapidjson::GenericValue<Enc>, false>
+{
+ using ReflectedDataHolder<rapidjson::GenericValue<Enc>, false>::ReflectedDataHolder;
+ using ThisType = RapidJsonArrayAccessor<Enc>;
+
+ std::optional<size_t> GetSize() const override
+ {
+ auto j = this->GetValue();
+ return j ? j->Size() : std::optional<size_t>();
+ }
+
+ const IIndexBasedAccessor* GetIndexer() const override
+ {
+ return this;
+ }
+
+ ListEnumeratorPtr CreateEnumerator() const override
+ {
+ using Enum = Enumerator<typename rapidjson::GenericValue<Enc>::ConstValueIterator>;
+ auto j = this->GetValue();
+ if (!j)
+ return jinja2::ListEnumeratorPtr();
+
+ return jinja2::ListEnumeratorPtr(new Enum(j->Begin(), j->End()));
+ }
+
+ Value GetItemByIndex(int64_t idx) const override
+ {
+ auto j = this->GetValue();
+ if (!j)
+ return Value();
+
+ return Reflect((*j)[static_cast<rapidjson::SizeType>(idx)]);
+ }
+
+ bool IsEqual(const IComparable& other) const override
+ {
+ auto* val = dynamic_cast<const ThisType*>(&other);
+ if (!val)
+ return false;
+ auto enumerator = this->GetValue();
+ auto otherEnum = val->GetValue();
+ if (enumerator && otherEnum && enumerator != otherEnum)
+ return false;
+ if ((enumerator && !otherEnum) || (!enumerator && otherEnum))
+ return false;
+ return true;
+ }
+};
+
+template<typename Enc>
+struct Reflector<rapidjson::GenericValue<Enc>>
+{
+ static Value CreateFromPtr(const rapidjson::GenericValue<Enc>* val)
+ {
+ Value result;
+ switch (val->GetType())
+ {
+ case rapidjson::kNullType:
+ break;
+ case rapidjson::kFalseType:
+ result = Value(false);
+ break;
+ case rapidjson::kTrueType:
+ result = Value(true);
+ break;
+ case rapidjson::kObjectType:
+ result = GenericMap([accessor = RapidJsonObjectAccessor<rapidjson::GenericValue<Enc>>(val)]() { return &accessor; });
+ break;
+ case rapidjson::kArrayType:
+ result = GenericList([accessor = RapidJsonArrayAccessor<Enc>(val)]() { return &accessor; });
+ break;
+ case rapidjson::kStringType:
+ result = std::basic_string<typename Enc::Ch>(val->GetString(), val->GetStringLength());
+ break;
+ case rapidjson::kNumberType:
+ if (val->IsInt64() || val->IsUint64())
+ result = val->GetInt64();
+ else if (val->IsInt() || val->IsUint())
+ result = val->GetInt();
+ else
+ result = val->GetDouble();
+ break;
+ }
+ return result;
+ }
+
+};
+
+template<typename Enc>
+struct Reflector<rapidjson::GenericDocument<Enc>>
+{
+ static Value Create(const rapidjson::GenericDocument<Enc>& val)
+ {
+ return GenericMap([accessor = RapidJsonObjectAccessor<rapidjson::GenericDocument<Enc>>(&val)]() { return &accessor; });
+ }
+
+ static Value CreateFromPtr(const rapidjson::GenericDocument<Enc>* val)
+ {
+ return GenericMap([accessor = RapidJsonObjectAccessor<rapidjson::GenericDocument<Enc>>(val)]() { return &accessor; });
+ }
+
+};
+} // namespace detail
+} // namespace jinja2
+
+#endif // JINJA2CPP_BINDING_RAPID_JSON_H
diff --git a/contrib/libs/jinja2cpp/include/jinja2cpp/config.h b/contrib/libs/jinja2cpp/include/jinja2cpp/config.h
new file mode 100644
index 0000000000..23d53ab33d
--- /dev/null
+++ b/contrib/libs/jinja2cpp/include/jinja2cpp/config.h
@@ -0,0 +1,27 @@
+#ifndef JINJA2CPP_CONFIG_H
+#define JINJA2CPP_CONFIG_H
+
+// The Jinja2C++ library version in the form major * 10000 + minor * 100 + patch.
+#define JINJA2CPP_VERSION 10100
+
+#ifdef _WIN32
+#define JINJA2_DECLSPEC(S) __declspec(S)
+#if _MSC_VER
+#pragma warning(disable : 4251)
+#endif
+#else
+#define JINJA2_DECLSPEC(S)
+#endif
+
+#ifdef JINJA2CPP_BUILD_AS_SHARED
+#define JINJA2CPP_EXPORT JINJA2_DECLSPEC(dllexport)
+#define JINJA2CPP_SHARED_LIB
+#elif JINJA2CPP_LINK_AS_SHARED
+#define JINJA2CPP_EXPORT JINJA2_DECLSPEC(dllimport)
+#define JINJA2CPP_SHARED_LIB
+#else
+#define JINJA2CPP_EXPORT
+#define JINJA2CPP_STATIC_LIB
+#endif
+
+#endif // JINJA2CPP_CONFIG_H
diff --git a/contrib/libs/jinja2cpp/include/jinja2cpp/error_info.h b/contrib/libs/jinja2cpp/include/jinja2cpp/error_info.h
new file mode 100644
index 0000000000..d4c2f88d96
--- /dev/null
+++ b/contrib/libs/jinja2cpp/include/jinja2cpp/error_info.h
@@ -0,0 +1,185 @@
+#ifndef JINJA2CPP_ERROR_INFO_H
+#define JINJA2CPP_ERROR_INFO_H
+
+#include "config.h"
+#include "value.h"
+
+#include <iostream>
+#include <type_traits>
+#include <vector>
+
+namespace jinja2
+{
+/*!
+ * \brief Type of the error
+ */
+enum class ErrorCode
+{
+ Unspecified = 0, //!< Error is unspecified
+ UnexpectedException = 1, //!< Generic exception occurred during template parsing or execution. ExtraParams[0] contains `what()` string of the exception
+ YetUnsupported, //!< Feature of the jinja2 specification which yet not supported
+ FileNotFound, //!< Requested file was not found. ExtraParams[0] contains name of the file
+ ExtensionDisabled, //!< Particular jinja2 extension disabled in the settings
+ TemplateEnvAbsent, //!< Template uses `extend`, `import`, `from` or `include` features but it's loaded without the template environment set
+ TemplateNotFound, //!< Template with the specified name was not found. ExtraParams[0] contains name of the file
+ TemplateNotParsed, //!< Template was not parsed
+ InvalidValueType, //!< Invalid type of the value in the particular context
+ InvalidTemplateName, //!< Invalid name of the template. ExtraParams[0] contains the name
+ MetadataParseError, //!< Invalid name of the template. ExtraParams[0] contains the name
+ ExpectedStringLiteral = 1001, //!< String literal expected
+ ExpectedIdentifier, //!< Identifier expected
+ ExpectedSquareBracket, //!< ']' expected
+ ExpectedRoundBracket, //!< ')' expected
+ ExpectedCurlyBracket, //!< '}' expected
+ ExpectedToken, //!< Specific token(s) expected. ExtraParams[0] contains the actual token, rest of ExtraParams contain set of expected tokens
+ ExpectedExpression, //!< Expression expected
+ ExpectedEndOfStatement, //!< End of statement expected. ExtraParams[0] contains the expected end of statement tag
+ ExpectedRawEnd, //!< {% endraw %} expected
+ ExpectedMetaEnd, //!< {% endmeta %} expected
+ UnexpectedToken, //!< Unexpected token. ExtraParams[0] contains the invalid token
+ UnexpectedStatement, //!< Unexpected statement. ExtraParams[0] contains the invalid statement tag
+ UnexpectedCommentBegin, //!< Unexpected comment block begin (`{#`)
+ UnexpectedCommentEnd, //!< Unexpected comment block end (`#}`)
+ UnexpectedExprBegin, //!< Unexpected expression block begin (`{{`)
+ UnexpectedExprEnd, //!< Unexpected expression block end (`}}`)
+ UnexpectedStmtBegin, //!< Unexpected statement block begin (`{%`)
+ UnexpectedStmtEnd, //!< Unexpected statement block end (`%}`)
+ UnexpectedRawBegin, //!< Unexpected raw block begin {% raw %}
+ UnexpectedRawEnd, //!< Unexpected raw block end {% endraw %}
+ UnexpectedMetaBegin, //!< Unexpected meta block begin {% meta %}
+ UnexpectedMetaEnd, //!< Unexpected meta block end {% endmeta %}
+};
+
+/*!
+ * \brief Information about the source location of the error
+ */
+struct SourceLocation
+{
+ //! Name of the file
+ std::string fileName;
+ //! Line number (1-based)
+ unsigned line = 0;
+ //! Column number (1-based)
+ unsigned col = 0;
+};
+
+template<typename CharT>
+/*!
+ * \brief Detailed information about the parse-time or render-time error
+ *
+ * If template parsing or rendering fails the detailed error information is provided. Exact specialization of ErrorInfoTpl is an object which contains
+ * this information. Type of specialization depends on type of the template object: \ref ErrorInfo for \ref Template and \ref ErrorInfoW for \ref TemplateW.
+ *
+ * Detailed information about an error contains:
+ * - Error code
+ * - Error location
+ * - Other locations related to the error
+ * - Description of the location
+ * - Extra parameters of the error
+ *
+ * @tparam CharT Character type which was used in template parser
+ */
+class ErrorInfoTpl
+{
+public:
+ struct Data
+ {
+ ErrorCode code = ErrorCode::Unspecified;
+ SourceLocation srcLoc;
+ std::vector<SourceLocation> relatedLocs;
+ std::vector<Value> extraParams;
+ std::basic_string<CharT> locationDescr;
+ };
+
+ //! Default constructor
+ ErrorInfoTpl() = default;
+ //! Initializing constructor from error description
+ explicit ErrorInfoTpl(Data data)
+ : m_errorData(std::move(data))
+ {}
+
+ //! Copy constructor
+ ErrorInfoTpl(const ErrorInfoTpl<CharT>&) = default;
+ //! Move constructor
+ ErrorInfoTpl(ErrorInfoTpl<CharT>&& val) noexcept
+ : m_errorData(std::move(val.m_errorData))
+ { }
+
+ //! Destructor
+ ~ErrorInfoTpl() noexcept = default;
+
+ //! Copy-assignment operator
+ ErrorInfoTpl& operator =(const ErrorInfoTpl<CharT>&) = default;
+ //! Move-assignment operator
+ ErrorInfoTpl& operator =(ErrorInfoTpl<CharT>&& val) noexcept
+ {
+ if (this == &val)
+ return *this;
+
+ std::swap(m_errorData.code, val.m_errorData.code);
+ std::swap(m_errorData.srcLoc, val.m_errorData.srcLoc);
+ std::swap(m_errorData.relatedLocs, val.m_errorData.relatedLocs);
+ std::swap(m_errorData.extraParams, val.m_errorData.extraParams);
+ std::swap(m_errorData.locationDescr, val.m_errorData.locationDescr);
+
+ return *this;
+ }
+
+ //! Return code of the error
+ ErrorCode GetCode() const
+ {
+ return m_errorData.code;
+ }
+
+ //! Return error location in the template file
+ auto& GetErrorLocation() const
+ {
+ return m_errorData.srcLoc;
+ }
+
+ //! Return locations, related to the main error location
+ auto& GetRelatedLocations() const
+ {
+ return m_errorData.relatedLocs;
+ }
+
+ /*!
+ * \brief Return location description
+ *
+ * Return string of two lines. First line is contents of the line with error. Second highlight the exact position within line. For instance:
+ * ```
+ * {% for i in range(10) endfor%}
+ * ---^-------
+ * ```
+ *
+ * @return Location description
+ */
+ const std::basic_string<CharT>& GetLocationDescr() const
+ {
+ return m_errorData.locationDescr;
+ }
+
+ /*!
+ * \brief Return extra params of the error
+ *
+ * Extra params is a additional details assiciated with the error. For instance, name of the file which wasn't opened
+ *
+ * @return Vector with extra error params
+ */
+ auto& GetExtraParams() const { return m_errorData.extraParams; }
+
+ //! Convert error to the detailed string representation
+ JINJA2CPP_EXPORT std::basic_string<CharT> ToString() const;
+
+private:
+ Data m_errorData;
+};
+
+using ErrorInfo = ErrorInfoTpl<char>;
+using ErrorInfoW = ErrorInfoTpl<wchar_t>;
+
+JINJA2CPP_EXPORT std::ostream& operator<<(std::ostream& os, const ErrorInfo& res);
+JINJA2CPP_EXPORT std::wostream& operator<<(std::wostream& os, const ErrorInfoW& res);
+} // namespace jinja2
+
+#endif // JINJA2CPP_ERROR_INFO_H
diff --git a/contrib/libs/jinja2cpp/include/jinja2cpp/filesystem_handler.h b/contrib/libs/jinja2cpp/include/jinja2cpp/filesystem_handler.h
new file mode 100644
index 0000000000..c33b4c9121
--- /dev/null
+++ b/contrib/libs/jinja2cpp/include/jinja2cpp/filesystem_handler.h
@@ -0,0 +1,201 @@
+#ifndef JINJA2CPP_FILESYSTEM_HANDLER_H
+#define JINJA2CPP_FILESYSTEM_HANDLER_H
+
+#include "config.h"
+
+#include <jinja2cpp/utils/i_comparable.h>
+
+#include <optional>
+#include <variant>
+
+#include <chrono>
+#include <iostream>
+#include <memory>
+#include <string>
+#include <unordered_map>
+
+namespace jinja2
+{
+
+template<typename CharT>
+using FileStreamPtr = std::unique_ptr<std::basic_istream<CharT>, void (*)(std::basic_istream<CharT>*)>;
+using CharFileStreamPtr = FileStreamPtr<char>;
+using WCharFileStreamPtr = FileStreamPtr<wchar_t>;
+
+/*!
+ * \brief Generic interface to filesystem handlers (loaders)
+ *
+ * This interface should be implemented in order to provide custom file system handler. Interface provides most-common methods which are called by
+ * the template environment to load the particular template. `OpenStream` methods return the unique pointer to the generic `istream` object implementation.
+ * So, the exact type (ex. `ifstream`, `istringstream` etc.) of input stream is unspecified. In order to delete stream object correctly returned pointer
+ * provide the custom deleter which should properly delete the stream object.
+ */
+class JINJA2CPP_EXPORT IFilesystemHandler : public IComparable
+{
+public:
+ //! Destructor
+ virtual ~IFilesystemHandler() = default;
+
+ /*!
+ * \brief Method is called to open the file with the specified name in 'narrow-char' mode.
+ *
+ * Method should return unique pointer to the std::istream object with custom deleter (\ref CharFileStreamPtr) . Deleter should properly delete pointee
+ * stream object.
+ *
+ * @param name Name of the file to open
+ * @return Opened stream object or empty pointer in case of any error
+ */
+ virtual CharFileStreamPtr OpenStream(const std::string& name) const = 0;
+ /*!
+ * \brief Method is called to open the file with the specified name in 'wide-char' mode.
+ *
+ * Method should return unique pointer to the std::wistream object with custom deleter (\ref WCharFileStreamPtr) . Deleter should properly delete pointee
+ * stream object.
+ *
+ * @param name Name of the file to open
+ * @return Opened stream object or empty pointer in case of any error
+ */
+ virtual WCharFileStreamPtr OpenWStream(const std::string& name) const = 0;
+ /*!
+ * \brief Method is called to obtain the modification date of the specified file (if applicable)
+ *
+ * If the underlaying filesystem supports retrival of the last modification date of the file this method should return this date when called. In other
+ * case it should return the empty optional object. Main purpose of this method is to help templates loader to determine the necessity of cached template
+ * reload
+ *
+ * @param name Name of the file to get the last modification date
+ * @return Last modification date (if applicable) or empty optional object otherwise
+ */
+ virtual std::optional<std::chrono::system_clock::time_point> GetLastModificationDate(const std::string& name) const = 0;
+};
+
+using FilesystemHandlerPtr = std::shared_ptr<IFilesystemHandler>;
+
+/*!
+ * \brief Filesystem handler for files stored in memory
+ *
+ * This filesystem handler implements the simple dictionary object which maps name of the file to it's content. New files can be added by \ref AddFile
+ * methods. Content of the files automatically converted to narrow/wide strings representation if necessary.
+ */
+class JINJA2CPP_EXPORT MemoryFileSystem : public IFilesystemHandler
+{
+public:
+ /*!
+ * \brief Add new narrow-char "file" to the filesystem handler
+ *
+ * Adds new file entry to the internal dictionary object or overwrite the existing one. New entry contains the specified content of the file
+ *
+ * @param fileName Name of the file to add
+ * @param fileContent Content of the file to add
+ */
+ void AddFile(std::string fileName, std::string fileContent);
+ /*!
+ * \brief Add new wide-char "file" to the filesystem handler
+ *
+ * Adds new file entry to the internal dictionary object or overwrite the existing one. New entry contains the specified content of the file
+ *
+ * @param fileName Name of the file to add
+ * @param fileContent Content of the file to add
+ */
+ void AddFile(std::string fileName, std::wstring fileContent);
+
+ CharFileStreamPtr OpenStream(const std::string& name) const override;
+ WCharFileStreamPtr OpenWStream(const std::string& name) const override;
+ std::optional<std::chrono::system_clock::time_point> GetLastModificationDate(const std::string& name) const override;
+
+ /*!
+ * \brief Compares to an object of the same type
+ *
+ * return true if equal
+ */
+ bool IsEqual(const IComparable& other) const override;
+private:
+ struct FileContent
+ {
+ std::optional<std::string> narrowContent;
+ std::optional<std::wstring> wideContent;
+ bool operator==(const FileContent& other) const
+ {
+ if (narrowContent != other.narrowContent)
+ return false;
+ return wideContent == other.wideContent;
+ }
+ bool operator!=(const FileContent& other) const
+ {
+ return !(*this == other);
+ }
+ };
+ mutable std::unordered_map<std::string, FileContent> m_filesMap;
+};
+
+/*!
+ * \brief Filesystem handler for files stored on the filesystem
+ *
+ * This filesystem handler is an interface to the real file system. Root directory for file name mapping provided as a constructor argument. Each name (path) of
+ * the file to open is appended to the root directory path and then passed to the stream open methods.
+ */
+class JINJA2CPP_EXPORT RealFileSystem : public IFilesystemHandler
+{
+public:
+ /*!
+ * \brief Initializing/default constructor
+ *
+ * @param rootFolder Path to the root folder. This path is used as a root for every opened file
+ */
+ explicit RealFileSystem(std::string rootFolder = ".");
+
+ /*!
+ * \brief Reset path to the root folder to the new value
+ *
+ * @param newRoot New path to the root folder
+ */
+ void SetRootFolder(std::string newRoot)
+ {
+ m_rootFolder = std::move(newRoot);
+ }
+
+ /*!
+ * \brief Get path to the current root folder
+ *
+ * @return
+ */
+ const std::string& GetRootFolder() const
+ {
+ return m_rootFolder;
+ }
+ /*!
+ * \brief Get full path to the specified file.
+ *
+ * Appends specified name of the file to the current root folder and returns it
+ *
+ * @param name Name of the file to get path to
+ * @return Full path to the file
+ */
+ std::string GetFullFilePath(const std::string& name) const;
+
+ CharFileStreamPtr OpenStream(const std::string& name) const override;
+ WCharFileStreamPtr OpenWStream(const std::string& name) const override;
+ /*!
+ * \brief Open the specified file as a binary stream
+ *
+ * Opens the specified file in the binary mode (instead of text).
+ *
+ * @param name Name of the file to get the last modification date
+ * @return Last modification date (if applicable) or empty optional object otherwise
+ */
+ CharFileStreamPtr OpenByteStream(const std::string& name) const;
+ std::optional<std::chrono::system_clock::time_point> GetLastModificationDate(const std::string& name) const override;
+
+ /*!
+ * \brief Compares to an object of the same type
+ *
+ * return true if equal
+ */
+ bool IsEqual(const IComparable& other) const override;
+
+private:
+ std::string m_rootFolder;
+};
+} // namespace jinja2
+
+#endif // JINJA2CPP_FILESYSTEM_HANDLER_H
diff --git a/contrib/libs/jinja2cpp/include/jinja2cpp/generic_list.h b/contrib/libs/jinja2cpp/include/jinja2cpp/generic_list.h
new file mode 100644
index 0000000000..ae70aa8e3e
--- /dev/null
+++ b/contrib/libs/jinja2cpp/include/jinja2cpp/generic_list.h
@@ -0,0 +1,287 @@
+#ifndef JINJA2CPP_GENERIC_LIST_H
+#define JINJA2CPP_GENERIC_LIST_H
+
+#include <jinja2cpp/utils/i_comparable.h>
+#include <jinja2cpp/value_ptr.h>
+
+#include <optional>
+
+#include <functional>
+#include <iterator>
+#include <memory>
+
+namespace jinja2
+{
+class Value;
+
+/*!
+ * \brief Interface for accessing items in list by the indexes
+ *
+ * This interface should provided by the particular list implementation in case of support index-based access to the items.
+ */
+struct IIndexBasedAccessor : virtual IComparable
+{
+ virtual ~IIndexBasedAccessor() = default;
+ /*!
+ * \brief This method is called to get the item by the specified index
+ *
+ * @param idx Index of item to get
+ *
+ * @return requested item
+ */
+ virtual Value GetItemByIndex(int64_t idx) const = 0;
+};
+
+struct IListEnumerator;
+using ListEnumeratorPtr = types::ValuePtr<IListEnumerator>;
+
+inline auto MakeEmptyListEnumeratorPtr()
+{
+ return ListEnumeratorPtr();
+}
+
+/*!
+ * \brief Generic list enumerator interface
+ *
+ * This interface should be implemented by the lists of any type. Interface is used to enumerate the list contents item by item.
+ *
+ * Implementation notes: Initial state of the enumerator should be "before the first item". So, the first call of \ref MoveNext method either moves the
+ * enumerator to the first element end returns `true` or moves enumerator to the end and returns `false` in case of empty list. Each call of \ref GetCurrent
+ * method should return the current enumerable item.
+ */
+struct IListEnumerator : virtual IComparable
+{
+ //! Destructor
+ virtual ~IListEnumerator() = default;
+
+ /*!
+ * \brief Method is called to reset enumerator to the initial state ('before the first element') if applicable.
+ *
+ * For the sequences which allow multi-pass iteration this method should reset enumerator to the initial state. For the single-pass sequences method
+ * can do nothing.
+ */
+ virtual void Reset() = 0;
+
+ /*!
+ * \brief Method is called to move the enumerator to the next item (if any)
+ *
+ * @return `true` if enumerator successfully moved and `false` if enumerator reaches the end of the sequence.
+ */
+ virtual bool MoveNext() = 0;
+
+ /*!
+ * \brief Method is called to get the current item value. Can be called multiply times
+ *
+ * @return Value of the item if the current item is valid item and empty value otherwise
+ */
+ virtual Value GetCurrent() const = 0;
+
+ /*!
+ * \brief Method is called to make a deep **copy** of the current enumerator state if possible
+ *
+ * @return New enumerator object with copy of the current enumerator state or empty pointer if copying is not applicable to the enumerator
+ */
+ virtual ListEnumeratorPtr Clone() const = 0;
+
+ /*!
+ * \brief Method is called to transfer current enumerator state to the new object
+ *
+ * State of the enumerator after successful creation of the new object is unspecified by there is a guarantee that there will no calls to the 'moved'
+ * enumerator. Destruction of the moved enumerator shouldn't affect the newly created object.
+ *
+ * @return New enumerator object which holds and owns the current enumerator state
+ */
+ virtual ListEnumeratorPtr Move() = 0;
+};
+
+/*!
+ * \brief Generic list implementation interface
+ *
+ * Every list implementation should implement this interface for providing access to the items of the list. There are several types of lists and implementation
+ * notes for every of them:
+ * - **Single-pass sequences** . For instance, input-stream iterators, generator-based sequences. This type of generic lists should provide no size and no indexer. Enumerator of such sequence supports should be moveable but non-copyable and non-resetable.
+ * - **Forward sequences** . For instance, single-linked lists. This type of lists should provide no size and indexer. Enumerator should be moveable, copyable and resetable.
+ * - **Bidirectional sequences**. Have got the same implementation requirements as forward sequences.
+ * - **Random-access sequences**. Such as arrays or vectors. Should provide valid size (number of stored items), valid indexer implementation and moveable,
+ * copyable and resetable enumerator.
+ *
+ * It's assumed that indexer interface is a part of list implementation.
+ */
+struct IListItemAccessor : virtual IComparable
+{
+ virtual ~IListItemAccessor() = default;
+
+ /*!
+ * \brief Called to get pointer to indexer interface implementation (if applicable)
+ *
+ * See implementation notes for the interface. This method should return pointer to the valid indexer interface if (and only if) list implementation
+ * supports random access to the items.
+ *
+ * Method can be called several times from the different threads.
+ *
+ * @return Pointer to the indexer interface implementation or null if indexing isn't supported for the list
+ */
+ virtual const IIndexBasedAccessor* GetIndexer() const = 0;
+
+ /*!
+ * \brief Called to get enumerator of the particular list
+ *
+ * See implementation notes for the interface. This method should return unique pointer (with custom deleter) to the ListEnumerator interface implementation. Enumerator implementation should follow the requirements for the particular list type implementation.
+ *
+ * Method can be called several times from the different threads.
+ *
+ * @return Pointer to the enumerator of the list
+ */
+ virtual ListEnumeratorPtr CreateEnumerator() const = 0;
+
+ /*!
+ * \brief Called to get size of the list if applicable.
+ *
+ * See implementation notes for the interface. This method should return valid (non-empty) size only for random-access sequences. In other cases this
+ * method should return empty optional.
+ *
+ * Method can be called several times from the different threads.
+ *
+ * @return Non-empty optional with the valid size of the list or empty optional in case of non-random sequence implementation
+ */
+ virtual std::optional<size_t> GetSize() const = 0;
+
+ /*!
+ * \brief Helper factory method of particular enumerator implementation
+ *
+ * @tparam T Type of enumerator to create
+ * @tparam Args Type of enumerator construct args
+ * @param args Actual enumerator constructor args
+ * @return Unique pointer to the enumerator
+ */
+ template<typename T, typename... Args>
+ static ListEnumeratorPtr MakeEnumerator(Args&&... args);
+};
+
+
+namespace detail
+{
+class GenericListIterator;
+} // namespace detail
+
+/*!
+ * \brief Facade class for generic lists
+ *
+ * This class holds the implementation of particular generic list interface and provides friendly access to it's method. Also this class is used to hold
+ * the particular list. Pointer to the generic list interface implementation is held inside std::function object which provides access to the pointer to the interface.
+ *
+ * You can use \ref MakeGenericList method to create instances of the GenericList:
+ * ```
+ * std::array<int, 9> sampleList{10, 20, 30, 40, 50, 60, 70, 80, 90};
+ *
+ * ValuesMap params = {
+ * {"input", jinja2::MakeGenericList(begin(sampleList), end(sampleList)) }
+ * };
+ * ```
+ */
+class JINJA2CPP_EXPORT GenericList
+{
+public:
+ //! Default constructor
+ GenericList() = default;
+
+ /*!
+ * \brief Initializing constructor
+ *
+ * This constructor is only one way to create the valid GenericList object. `accessor` is a functional object which provides access to the \ref IListItemAccessor
+ * interface. The most common way of GenericList creation is to initialize it with lambda which simultaniously holds and and provide access to the
+ * generic list implementation:
+ *
+ * ```
+ * auto MakeGeneratedList(ListGenerator&& fn)
+ * {
+ * return GenericList([accessor = GeneratedListAccessor(std::move(fn))]() {return &accessor;});
+ * }
+ * ```
+ *
+ * @param accessor Functional object which provides access to the particular generic list implementation
+ */
+ explicit GenericList(std::function<const IListItemAccessor*()> accessor)
+ : m_accessor(std::move(accessor))
+ {
+ }
+
+ /*!
+ * \brief Get size of the list
+ *
+ * @return Actual size of the generic list or empty optional object if not applicable
+ */
+ std::optional<size_t> GetSize() const
+ {
+ return m_accessor ? m_accessor()->GetSize() : std::optional<size_t>();
+ }
+
+ /*!
+ * \brief Get pointer to the list accessor interface implementation
+ *
+ * @return Pointer to the list accessor interface or nullptr in case of non-initialized GenericList object
+ */
+ auto GetAccessor() const
+ {
+ return m_accessor ? m_accessor() : nullptr;
+ }
+
+ /*!
+ * \brief Check the GenericList object state
+ *
+ * @return true if GenericList object is valid (initialize) or false otherwize
+ */
+ bool IsValid() const
+ {
+ return !(!m_accessor);
+ }
+
+ /*!
+ * \brief Get interator to the first element of the list
+ *
+ * @return Iterator to the first element of the generic list or iterator equal to the `end()` if list is empty or not initialized
+ */
+ detail::GenericListIterator begin() const;
+ /*!
+ * \brief Get the end iterator
+ *
+ * @return 'end' iterator of the generic list
+ */
+ detail::GenericListIterator end() const;
+
+ /*!
+ * \brief Get interator to the first element of the list
+ *
+ * @return Iterator to the first element of the generic list or iterator equal to the `end()` if list is empty or not initialized
+ */
+ auto cbegin() const;
+ /*!
+ * \brief Get the end iterator
+ *
+ * @return 'end' iterator of the generic list
+ */
+ auto cend() const;
+
+ /*!
+ * \brief Compares with the objects of same type
+ *
+ * @return true if equal
+ */
+ bool IsEqual(const GenericList& rhs) const;
+
+private:
+ std::function<const IListItemAccessor*()> m_accessor;
+};
+
+bool operator==(const GenericList& lhs, const GenericList& rhs);
+bool operator!=(const GenericList& lhs, const GenericList& rhs);
+
+template<typename T, typename ...Args>
+inline ListEnumeratorPtr IListItemAccessor::MakeEnumerator(Args&& ...args)
+{
+ return ListEnumeratorPtr(types::MakeValuePtr<T>(std::forward<Args>(args)...));
+}
+} // namespace jinja2
+
+
+#endif // JINJA2CPP_GENERIC_LIST_H
diff --git a/contrib/libs/jinja2cpp/include/jinja2cpp/generic_list_iterator.h b/contrib/libs/jinja2cpp/include/jinja2cpp/generic_list_iterator.h
new file mode 100644
index 0000000000..7af469f8a3
--- /dev/null
+++ b/contrib/libs/jinja2cpp/include/jinja2cpp/generic_list_iterator.h
@@ -0,0 +1,104 @@
+#ifndef JINJA2CPP_GENERIC_LIST_ITERATOR_H
+#define JINJA2CPP_GENERIC_LIST_ITERATOR_H
+
+#include "generic_list.h"
+#include "value.h"
+#include "value_ptr.h"
+
+namespace jinja2
+{
+namespace detail
+{
+class JINJA2CPP_EXPORT GenericListIterator
+{
+public:
+ using iterator_category = std::input_iterator_tag;
+ using value_type = const Value;
+ using difference_type = std::ptrdiff_t;
+ using reference = const Value&;
+ using pointer = const Value*;
+ using EnumeratorPtr = types::ValuePtr<IListEnumerator>;
+
+ GenericListIterator() = default;
+
+ GenericListIterator(ListEnumeratorPtr enumerator)
+ : m_enumerator(types::ValuePtr<IListEnumerator>(enumerator))
+ {
+ if (m_enumerator)
+ m_hasValue = m_enumerator->MoveNext();
+
+ if (m_hasValue)
+ m_current = m_enumerator->GetCurrent();
+ }
+
+ bool operator == (const GenericListIterator& other) const
+ {
+ if (m_hasValue != other.m_hasValue)
+ return false;
+ if (!m_enumerator && !other.m_enumerator)
+ return true;
+ if (this->m_enumerator && other.m_enumerator && !m_enumerator->IsEqual(*other.m_enumerator))
+ return false;
+ if ((m_enumerator && !other.m_enumerator) || (!m_enumerator && other.m_enumerator))
+ return false;
+ if (m_current != other.m_current)
+ return false;
+ return true;
+ }
+
+ bool operator != (const GenericListIterator& other) const
+ {
+ return !(*this == other);
+ }
+
+ reference operator *() const
+ {
+ return m_current;
+ }
+
+ GenericListIterator& operator ++()
+ {
+ if (!m_enumerator)
+ return *this;
+ m_hasValue = m_enumerator->MoveNext();
+ if (m_hasValue)
+ {
+ m_current = m_enumerator->GetCurrent();
+ }
+ else
+ {
+ EnumeratorPtr temp;
+ Value tempVal;
+ using std::swap;
+ swap(m_enumerator, temp);
+ swap(m_current, tempVal);
+ }
+
+ return *this;
+ }
+
+ GenericListIterator operator++(int)
+ {
+ GenericListIterator result(std::move(m_current));
+
+ this->operator++();
+ return result;
+ }
+private:
+ explicit GenericListIterator(Value&& val)
+ : m_hasValue(true)
+ , m_current(std::move(val))
+ {
+
+ }
+
+private:
+ EnumeratorPtr m_enumerator;
+ bool m_hasValue = false;
+ Value m_current;
+};
+
+} // namespace detail
+} // namespace jinja2
+
+#endif // JINJA2CPP_GENERIC_LIST_ITERATOR_H
diff --git a/contrib/libs/jinja2cpp/include/jinja2cpp/polymorphic_value.h b/contrib/libs/jinja2cpp/include/jinja2cpp/polymorphic_value.h
new file mode 100644
index 0000000000..69663d859f
--- /dev/null
+++ b/contrib/libs/jinja2cpp/include/jinja2cpp/polymorphic_value.h
@@ -0,0 +1,447 @@
+/*
+
+Copyright (c) 2016 Jonathan B. Coe
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+*/
+
+#ifndef ISOCPP_P0201_POLYMORPHIC_VALUE_H_INCLUDED
+#define ISOCPP_P0201_POLYMORPHIC_VALUE_H_INCLUDED
+
+#include <cassert>
+#include <exception>
+#include <memory>
+#include <type_traits>
+#include <typeinfo>
+#include <utility>
+
+
+//
+// in_place: code duplicated in any-lite, expected-lite, optional-lite, value-ptr-lite, variant-lite:
+//
+
+#ifndef nonstd_lite_HAVE_IN_PLACE_TYPES
+#define nonstd_lite_HAVE_IN_PLACE_TYPES 1
+
+// C++17 std::in_place in <utility>:
+
+#if variant_CPP17_OR_GREATER
+
+#include <utility>
+
+namespace nonstd {
+
+using std::in_place;
+using std::in_place_type;
+using std::in_place_index;
+using std::in_place_t;
+using std::in_place_type_t;
+using std::in_place_index_t;
+
+#define nonstd_lite_in_place_t( T) std::in_place_t
+#define nonstd_lite_in_place_type_t( T) std::in_place_type_t<T>
+#define nonstd_lite_in_place_index_t(K) std::in_place_index_t<K>
+
+#define nonstd_lite_in_place( T) std::in_place_t{}
+#define nonstd_lite_in_place_type( T) std::in_place_type_t<T>{}
+#define nonstd_lite_in_place_index(K) std::in_place_index_t<K>{}
+
+} // namespace nonstd
+
+#else // variant_CPP17_OR_GREATER
+
+#include <cstddef>
+
+namespace nonstd {
+namespace detail {
+
+template< class T >
+struct in_place_type_tag {};
+
+template< std::size_t K >
+struct in_place_index_tag {};
+
+} // namespace detail
+
+struct in_place_t {};
+
+template< class T >
+inline in_place_t in_place( detail::in_place_type_tag<T> = detail::in_place_type_tag<T>() )
+{
+ return in_place_t();
+}
+
+template< std::size_t K >
+inline in_place_t in_place( detail::in_place_index_tag<K> = detail::in_place_index_tag<K>() )
+{
+ return in_place_t();
+}
+
+template< class T >
+inline in_place_t in_place_type( detail::in_place_type_tag<T> = detail::in_place_type_tag<T>() )
+{
+ return in_place_t();
+}
+
+template< std::size_t K >
+inline in_place_t in_place_index( detail::in_place_index_tag<K> = detail::in_place_index_tag<K>() )
+{
+ return in_place_t();
+}
+
+// mimic templated typedef:
+
+#define nonstd_lite_in_place_t( T) nonstd::in_place_t(&)( nonstd::detail::in_place_type_tag<T> )
+#define nonstd_lite_in_place_type_t( T) nonstd::in_place_t(&)( nonstd::detail::in_place_type_tag<T> )
+#define nonstd_lite_in_place_index_t(K) nonstd::in_place_t(&)( nonstd::detail::in_place_index_tag<K> )
+
+#define nonstd_lite_in_place( T) nonstd::in_place_type<T>
+#define nonstd_lite_in_place_type( T) nonstd::in_place_type<T>
+#define nonstd_lite_in_place_index(K) nonstd::in_place_index<K>
+
+} // namespace nonstd
+
+#endif // variant_CPP17_OR_GREATER
+#endif // nonstd_lite_HAVE_IN_PLACE_TYPES
+
+namespace isocpp_p0201 {
+
+namespace detail {
+
+////////////////////////////////////////////////////////////////////////////
+// Implementation detail classes
+////////////////////////////////////////////////////////////////////////////
+
+template <class T>
+struct default_copy {
+ T* operator()(const T& t) const { return new T(t); }
+};
+
+template <class T>
+struct default_delete {
+ void operator()(const T* t) const { delete t; }
+};
+
+template <class T>
+struct control_block {
+ virtual ~control_block() = default;
+
+ virtual std::unique_ptr<control_block> clone() const = 0;
+
+ virtual T* ptr() = 0;
+};
+
+template <class T, class U = T>
+class direct_control_block : public control_block<T> {
+ static_assert(!std::is_reference<U>::value, "");
+ U u_;
+
+ public:
+ template <class... Ts>
+ explicit direct_control_block(Ts&&... ts) : u_(U(std::forward<Ts>(ts)...)) {}
+
+ std::unique_ptr<control_block<T>> clone() const override {
+ return std::make_unique<direct_control_block>(*this);
+ }
+
+ T* ptr() override { return std::addressof(u_); }
+};
+
+template <class T, class U, class C = default_copy<U>,
+ class D = default_delete<U>>
+class pointer_control_block : public control_block<T>, public C {
+ std::unique_ptr<U, D> p_;
+
+ public:
+ explicit pointer_control_block(U* u, C c = C{}, D d = D{})
+ : C(std::move(c)), p_(u, std::move(d)) {}
+
+ explicit pointer_control_block(std::unique_ptr<U, D> p, C c = C{})
+ : C(std::move(c)), p_(std::move(p)) {}
+
+ std::unique_ptr<control_block<T>> clone() const override {
+ assert(p_);
+ return std::make_unique<pointer_control_block>(
+ C::operator()(*p_), static_cast<const C&>(*this), p_.get_deleter());
+ }
+
+ T* ptr() override { return p_.get(); }
+};
+
+template <class T, class U>
+class delegating_control_block : public control_block<T> {
+ std::unique_ptr<control_block<U>> delegate_;
+
+ public:
+ explicit delegating_control_block(std::unique_ptr<control_block<U>> b)
+ : delegate_(std::move(b)) {}
+
+ std::unique_ptr<control_block<T>> clone() const override {
+ return std::make_unique<delegating_control_block>(delegate_->clone());
+ }
+
+ T* ptr() override { return delegate_->ptr(); }
+};
+
+} // end namespace detail
+
+class bad_polymorphic_value_construction : public std::exception {
+ public:
+ bad_polymorphic_value_construction() noexcept = default;
+
+ const char* what() const noexcept override {
+ return "Dynamic and static type mismatch in polymorphic_value "
+ "construction";
+ }
+};
+
+template <class T>
+class polymorphic_value;
+
+template <class T>
+struct is_polymorphic_value : std::false_type {};
+
+template <class T>
+struct is_polymorphic_value<polymorphic_value<T>> : std::true_type {};
+
+////////////////////////////////////////////////////////////////////////////////
+// `polymorphic_value` class definition
+////////////////////////////////////////////////////////////////////////////////
+
+template <class T>
+class polymorphic_value {
+ static_assert(!std::is_union<T>::value, "");
+ static_assert(std::is_class<T>::value, "");
+
+ template <class U>
+ friend class polymorphic_value;
+
+ template <class T_, class U, class... Ts>
+ friend polymorphic_value<T_> make_polymorphic_value(Ts&&... ts);
+ template <class T_, class... Ts>
+ friend polymorphic_value<T_> make_polymorphic_value(Ts&&... ts);
+
+ T* ptr_ = nullptr;
+ std::unique_ptr<detail::control_block<T>> cb_;
+
+ public:
+ //
+ // Destructor
+ //
+
+ ~polymorphic_value() = default;
+
+ //
+ // Constructors
+ //
+
+ polymorphic_value() {}
+
+ template <class U, class C = detail::default_copy<U>,
+ class D = detail::default_delete<U>,
+ class V = std::enable_if_t<std::is_convertible<U*, T*>::value>>
+ explicit polymorphic_value(U* u, C copier = C{}, D deleter = D{}) {
+ if (!u) {
+ return;
+ }
+
+#ifndef ISOCPP_P0201_POLYMORPHIC_VALUE_NO_RTTI
+ if (std::is_same<D, detail::default_delete<U>>::value &&
+ std::is_same<C, detail::default_copy<U>>::value &&
+ typeid(*u) != typeid(U))
+ throw bad_polymorphic_value_construction();
+#endif
+ std::unique_ptr<U, D> p(u, std::move(deleter));
+
+ cb_ = std::make_unique<detail::pointer_control_block<T, U, C, D>>(
+ std::move(p), std::move(copier));
+ ptr_ = u;
+ }
+
+ //
+ // Copy-constructors
+ //
+
+ polymorphic_value(const polymorphic_value& p) {
+ if (!p) {
+ return;
+ }
+ auto tmp_cb = p.cb_->clone();
+ ptr_ = tmp_cb->ptr();
+ cb_ = std::move(tmp_cb);
+ }
+
+ //
+ // Move-constructors
+ //
+
+ polymorphic_value(polymorphic_value&& p) noexcept {
+ ptr_ = p.ptr_;
+ cb_ = std::move(p.cb_);
+ p.ptr_ = nullptr;
+ }
+
+ //
+ // Converting constructors
+ //
+
+ template <class U,
+ class V = std::enable_if_t<!std::is_same<T, U>::value &&
+ std::is_convertible<U*, T*>::value>>
+ explicit polymorphic_value(const polymorphic_value<U>& p) {
+ polymorphic_value<U> tmp(p);
+ ptr_ = tmp.ptr_;
+ cb_ = std::make_unique<detail::delegating_control_block<T, U>>(
+ std::move(tmp.cb_));
+ }
+
+ template <class U,
+ class V = std::enable_if_t<!std::is_same<T, U>::value &&
+ std::is_convertible<U*, T*>::value>>
+ explicit polymorphic_value(polymorphic_value<U>&& p) {
+ ptr_ = p.ptr_;
+ cb_ = std::make_unique<detail::delegating_control_block<T, U>>(
+ std::move(p.cb_));
+ p.ptr_ = nullptr;
+ }
+
+#if __cplusplus < 201703L
+
+#endif
+ //
+ // In-place constructor
+ //
+
+ template <class U,
+ class V = std::enable_if_t<
+ std::is_convertible<std::decay_t<U>*, T*>::value &&
+ !is_polymorphic_value<std::decay_t<U>>::value>,
+ class... Ts>
+ explicit polymorphic_value(nonstd_lite_in_place_type_t(U), Ts&&... ts)
+// explicit polymorphic_value(std::in_place_type_t<U>, Ts&&... ts)
+ : cb_(std::make_unique<detail::direct_control_block<T, U>>(
+ std::forward<Ts>(ts)...)) {
+ ptr_ = cb_->ptr();
+ }
+
+
+ //
+ // Assignment
+ //
+
+ polymorphic_value& operator=(const polymorphic_value& p) {
+ if (std::addressof(p) == this) {
+ return *this;
+ }
+
+ if (!p) {
+ cb_.reset();
+ ptr_ = nullptr;
+ return *this;
+ }
+
+ auto tmp_cb = p.cb_->clone();
+ ptr_ = tmp_cb->ptr();
+ cb_ = std::move(tmp_cb);
+ return *this;
+ }
+
+ //
+ // Move-assignment
+ //
+
+ polymorphic_value& operator=(polymorphic_value&& p) noexcept {
+ if (std::addressof(p) == this) {
+ return *this;
+ }
+
+ cb_ = std::move(p.cb_);
+ ptr_ = p.ptr_;
+ p.ptr_ = nullptr;
+ return *this;
+ }
+
+ //
+ // Modifiers
+ //
+
+ void swap(polymorphic_value& p) noexcept {
+ using std::swap;
+ swap(ptr_, p.ptr_);
+ swap(cb_, p.cb_);
+ }
+
+ //
+ // Observers
+ //
+
+ explicit operator bool() const { return bool(cb_); }
+
+ const T* operator->() const {
+ assert(ptr_);
+ return ptr_;
+ }
+
+ const T& operator*() const {
+ assert(*this);
+ return *ptr_;
+ }
+
+ T* operator->() {
+ assert(*this);
+ return ptr_;
+ }
+
+ T& operator*() {
+ assert(*this);
+ return *ptr_;
+ }
+};
+
+//
+// polymorphic_value creation
+//
+template <class T, class... Ts>
+polymorphic_value<T> make_polymorphic_value(Ts&&... ts) {
+ polymorphic_value<T> p;
+ p.cb_ = std::make_unique<detail::direct_control_block<T, T>>(
+ std::forward<Ts>(ts)...);
+ p.ptr_ = p.cb_->ptr();
+ return p;
+}
+template <class T, class U, class... Ts>
+polymorphic_value<T> make_polymorphic_value(Ts&&... ts) {
+ polymorphic_value<T> p;
+ p.cb_ = std::make_unique<detail::direct_control_block<T, U>>(
+ std::forward<Ts>(ts)...);
+ p.ptr_ = p.cb_->ptr();
+ return p;
+}
+
+//
+// non-member swap
+//
+template <class T>
+void swap(polymorphic_value<T>& t, polymorphic_value<T>& u) noexcept {
+ t.swap(u);
+}
+
+} // namespace isocpp_p0201
+
+#endif // ISOCPP_P0201_POLYMORPHIC_VALUE_H_INCLUDED
diff --git a/contrib/libs/jinja2cpp/include/jinja2cpp/reflected_value.h b/contrib/libs/jinja2cpp/include/jinja2cpp/reflected_value.h
new file mode 100644
index 0000000000..fcb99a8031
--- /dev/null
+++ b/contrib/libs/jinja2cpp/include/jinja2cpp/reflected_value.h
@@ -0,0 +1,601 @@
+#ifndef JINJA2CPP_REFLECTED_VALUE_H
+#define JINJA2CPP_REFLECTED_VALUE_H
+
+#include "value.h"
+
+#include <optional>
+
+#include <cstddef>
+#include <memory>
+#include <set>
+#include <string>
+#include <type_traits>
+#include <vector>
+
+namespace jinja2
+{
+
+/*!
+ * \brief Reflect the arbitrary C++ type to the Jinja2C++ engine
+ *
+ * Generic method which reflects arbitrary C++ type to the Jinja2C++ template engine. The way of reflection depends on the actual reflected type and could be
+ * - Reflect as an exact value if the type is basic type (such as `char`, `int`, `double`, `std::string` etc.)
+ * - Reflect as a GenericList/GenericMap for standard containers respectively
+ * - Reflect as a GenericMap for the user types
+ * Also pointers/shared pointers to the types could be reflected.
+ *
+ * Reflected value takes ownership on the object, passed to the `Reflect` method by r-value reference or value. Actually, such object is moved. For const
+ * references or pointers reflected value holds the pointer to the reflected object. So, it's necessary to be sure that life time of the reflected object is
+ * longer than it's usage within the template.
+ *
+ * In order to reflect custom (user) the \ref jinja2::TypeReflection template should be specialized in the following way:
+ * ```c++
+ * struct jinja2::TypeReflection<TestStruct> : jinja2::TypeReflected<TestStruct>
+ * {
+ * using FieldAccessor = typename jinja2::TypeReflected<TestStruct>::FieldAccessor;
+ * static auto& GetAccessors()
+ * {
+ * static std::unordered_map<std::string, FieldAccessor> accessors = {
+ * {"intValue", [](const TestStruct& obj) {assert(obj.isAlive); return jinja2::Reflect(obj.intValue);}},
+ * {"intEvenValue", [](const TestStruct& obj) -> Value
+ * {
+ * assert(obj.isAlive);
+ * if (obj.intValue % 2)
+ * return {};
+ * return {obj.intValue};
+ * }},
+ * };
+ *
+ * return accessors;
+ * }
+ * };
+ *
+ * `TestStruct` here is a type which should be reflected. Specialization of the \ref TypeReflection template should derived from \ref TypeReflected template
+ * and define only one method: `GetAccessors`. This method returns the unordered map object which maps field name (as a string) to the corresponded field
+ * accessor. And field accessor here is a lambda object which takes the reflected object reference and returns the value of the field from it.
+ *
+ * @tparam T Type of value to reflect
+ * @param val Value to reflect
+ *
+ * @return jinja2::Value which contains the reflected value or the empty one
+ */
+template<typename T>
+Value Reflect(T&& val);
+
+template<typename T, bool val>
+struct TypeReflectedImpl : std::integral_constant<bool, val>
+{
+};
+
+template<typename T>
+using FieldAccessor = std::function<Value(const T&)>;
+
+template<typename T>
+struct TypeReflected : TypeReflectedImpl<T, true>
+{
+ using FieldAccessor = jinja2::FieldAccessor<T>;
+};
+
+
+
+template<typename T, typename = void>
+struct TypeReflection : TypeReflectedImpl<T, false>
+{
+};
+
+#ifndef JINJA2CPP_NO_DOXYGEN
+template<typename Derived>
+class ReflectedMapImplBase : public IMapItemAccessor
+{
+public:
+ bool HasValue(const std::string& name) const override
+ {
+ return Derived::GetAccessors().count(name) != 0;
+ }
+ Value GetValueByName(const std::string& name) const override
+ {
+ const auto& accessors = Derived::GetAccessors();
+ auto p = accessors.find(name);
+ if (p == accessors.end())
+ throw std::runtime_error("Invalid field access");
+
+ return static_cast<const Derived*>(this)->GetField(p->second);
+ }
+ std::vector<std::string> GetKeys() const override
+ {
+ std::vector<std::string> result;
+ const auto& accessors = Derived::GetAccessors();
+ for (auto& i : accessors)
+ result.push_back(i.first);
+
+ return result;
+ }
+ size_t GetSize() const override
+ {
+ return Derived::GetAccessors().size();
+ }
+};
+
+template<typename T, bool byValue = true>
+class ReflectedDataHolder;
+
+template<typename T>
+class ReflectedDataHolder<T, true>
+{
+public:
+ explicit ReflectedDataHolder(T val) : m_value(std::move(val)) {}
+ explicit ReflectedDataHolder(const T* val) : m_valuePtr(val) {}
+
+protected:
+ const T* GetValue() const
+ {
+ return m_valuePtr ? m_valuePtr : (m_value ? &m_value.value() : nullptr);
+ }
+
+private:
+ std::optional<T> m_value;
+ const T* m_valuePtr = nullptr;
+};
+
+template<typename T>
+class ReflectedDataHolder<T, false>
+{
+public:
+ explicit ReflectedDataHolder(const T* val) : m_valuePtr(val) {}
+
+protected:
+ const T* GetValue() const
+ {
+ return m_valuePtr;
+ }
+
+private:
+ const T* m_valuePtr = nullptr;
+};
+
+template<typename T>
+class ReflectedMapImpl : public ReflectedMapImplBase<ReflectedMapImpl<T>>, public ReflectedDataHolder<T>
+{
+public:
+ using ReflectedDataHolder<T>::ReflectedDataHolder;
+ using ThisType = ReflectedMapImpl<T>;
+
+ static auto GetAccessors() {return TypeReflection<T>::GetAccessors();}
+ template<typename Fn>
+ Value GetField(Fn&& accessor) const
+ {
+ auto v = this->GetValue();
+ if (!v)
+ return Value();
+ return accessor(*v);
+ }
+
+ bool IsEqual(const IComparable& other) const override
+ {
+ auto* val = dynamic_cast<const ThisType*>(&other);
+ if (!val)
+ return false;
+
+ return this->GetValue() == val->GetValue();
+ }
+};
+
+namespace detail
+{
+template<typename T, typename Tag = void>
+struct Reflector;
+
+template<typename T>
+using IsReflectedType = std::enable_if_t<TypeReflection<T>::value>;
+
+template<typename It>
+struct Enumerator : public IListEnumerator
+{
+ using ThisType = Enumerator<It>;
+ It m_begin;
+ It m_cur;
+ It m_end;
+ bool m_justInited = true;
+
+ Enumerator(It begin, It end)
+ : m_begin(begin)
+ , m_cur(end)
+ , m_end(end)
+ {}
+
+ void Reset() override
+ {
+ m_justInited = true;
+ }
+
+ bool MoveNext() override
+ {
+ if (m_justInited)
+ {
+ m_cur = m_begin;
+ m_justInited = false;
+ }
+ else
+ {
+ ++ m_cur;
+ }
+
+ return m_cur != m_end;
+ }
+
+ Value GetCurrent() const override
+ {
+ return Reflect(*m_cur);
+ }
+
+ ListEnumeratorPtr Clone() const override
+ {
+ auto result = std::make_unique<Enumerator<It>>(m_begin, m_end);
+ result->m_cur = m_cur;
+ result->m_justInited = m_justInited;
+ return jinja2::ListEnumeratorPtr(result.release()); //, Deleter);
+ }
+
+ ListEnumeratorPtr Move() override
+ {
+ auto result = std::make_unique<Enumerator<It>>(m_begin, m_end);
+ result->m_cur = std::move(m_cur);
+ result->m_justInited = m_justInited;
+ this->m_justInited = true;
+ return jinja2::ListEnumeratorPtr(result.release()); //, Deleter);
+ }
+
+ bool IsEqual(const IComparable& other) const override
+ {
+ auto* val = dynamic_cast<const ThisType*>(&other);
+ if (!val)
+ return false;
+ if (m_begin != val->m_begin)
+ return false;
+ if (m_cur != val->m_cur)
+ return false;
+ if (m_end != val->m_end)
+ return false;
+ if (m_justInited != val->m_justInited)
+ return false;
+ return true;
+ }
+
+ /*
+ It m_begin;
+ It m_cur;
+ It m_end;
+ bool m_justInited = true;
+*/
+/*
+ static void Deleter(IListEnumerator* e)
+ {
+ delete static_cast<Enumerator<It>*>(e);
+ }
+ */
+};
+
+struct ContainerReflector
+{
+ template<typename T>
+ struct ValueItemAccessor : IListItemAccessor, IIndexBasedAccessor
+ {
+ using ThisType = ValueItemAccessor<T>;
+
+ T m_value;
+
+ explicit ValueItemAccessor(T&& cont) noexcept
+ : m_value(std::move(cont))
+ {
+ }
+
+ std::optional<size_t> GetSize() const override
+ {
+ return m_value.size();
+ }
+
+ const IIndexBasedAccessor* GetIndexer() const override
+ {
+ return this;
+ }
+
+ ListEnumeratorPtr CreateEnumerator() const override
+ {
+ using Enum = Enumerator<typename T::const_iterator>;
+ return jinja2::ListEnumeratorPtr(new Enum(m_value.begin(), m_value.end()));//, Enum::Deleter);
+ }
+
+ Value GetItemByIndex(int64_t idx) const override
+ {
+ auto p = m_value.begin();
+ std::advance(p, static_cast<size_t>(idx));
+ return Reflect(*p);
+ }
+
+ bool IsEqual(const IComparable& other) const override
+ {
+ auto* val = dynamic_cast<const ThisType*>(&other);
+ if (!val)
+ return false;
+ auto enumerator = CreateEnumerator();
+ auto otherEnum = val->CreateEnumerator();
+ if (enumerator && otherEnum && !enumerator->IsEqual(*otherEnum))
+ return false;
+ return true;
+ }
+ };
+
+ template<typename T>
+ struct PtrItemAccessor : IListItemAccessor, IIndexBasedAccessor
+ {
+ using ThisType = PtrItemAccessor<T>;
+
+ const T* m_value{};
+
+ explicit PtrItemAccessor(const T* ptr)
+ : m_value(ptr)
+ {
+ }
+ std::optional<size_t> GetSize() const override
+ {
+ return m_value->size();
+ }
+ const IIndexBasedAccessor* GetIndexer() const override
+ {
+ return this;
+ }
+
+ ListEnumeratorPtr CreateEnumerator() const override
+ {
+ using Enum = Enumerator<typename T::const_iterator>;
+ return jinja2::ListEnumeratorPtr(new Enum(m_value->begin(), m_value->end()));//, Enum::Deleter);
+ }
+
+ Value GetItemByIndex(int64_t idx) const override
+ {
+ auto p = m_value->begin();
+ std::advance(p, static_cast<size_t>(idx));
+ return Reflect(*p);
+ }
+
+ bool IsEqual(const IComparable& other) const override
+ {
+ auto* val = dynamic_cast<const ThisType*>(&other);
+ if (!val)
+ return false;
+ auto enumerator = CreateEnumerator();
+ auto otherEnum = val->CreateEnumerator();
+ if (enumerator && otherEnum && !enumerator->IsEqual(*otherEnum))
+ return false;
+ return true;
+ }
+ };
+
+ template<typename T>
+ static Value CreateFromValue(T&& cont)
+ {
+ return GenericList([accessor = ValueItemAccessor<T>(std::forward<T>(cont))]() {return &accessor;});
+ }
+
+ template<typename T>
+ static Value CreateFromPtr(const T* cont)
+ {
+ return GenericList([accessor = PtrItemAccessor<T>(cont)]() {return &accessor;});
+ }
+
+ template<typename T>
+ static Value CreateFromPtr(std::shared_ptr<T> cont)
+ {
+ return GenericList([ptr = std::move(cont), accessor = PtrItemAccessor<T>(cont.get())]() {return &accessor;});
+ }
+};
+
+template<typename T>
+struct Reflector<std::set<T>>
+{
+ static auto Create(std::set<T> val)
+ {
+ return ContainerReflector::CreateFromValue(std::move(val));
+ }
+ static auto CreateFromPtr(const std::set<T>* val)
+ {
+ return ContainerReflector::CreateFromPtr(val);
+ }
+};
+
+template<typename T>
+struct Reflector<std::vector<T>>
+{
+ static auto Create(std::vector<T> val)
+ {
+ return ContainerReflector::CreateFromValue(std::move(val));
+ }
+ template<typename U>
+ static auto CreateFromPtr(U&& val)
+ {
+ return ContainerReflector::CreateFromPtr(std::forward<U>(val));
+ }
+};
+
+template<typename T>
+struct Reflector<T, IsReflectedType<T>>
+{
+ static auto Create(const T& val)
+ {
+ return GenericMap([accessor = ReflectedMapImpl<T>(val)]() {return &accessor;});
+ }
+
+ static auto CreateFromPtr(const T* val)
+ {
+ return GenericMap([accessor = ReflectedMapImpl<T>(static_cast<const T*>(val))]() {return &accessor;});
+ }
+
+ static auto CreateFromPtr(std::shared_ptr<T> val)
+ {
+ return GenericMap([ptr = val, accessor = ReflectedMapImpl<T>(val.get())]() {return &accessor;});
+ }
+};
+
+template<typename T>
+struct Reflector<const T&>
+{
+ static auto Create(const T& val)
+ {
+ return Reflector<T>::CreateFromPtr(&val);
+ }
+ static auto Create(const T*& val)
+ {
+ return Reflector<T>::CreateFromPtr(val);
+ }
+};
+
+template<typename T>
+struct Reflector<const T*&>
+{
+ static auto Create(const T*& val)
+ {
+ return Reflector<T>::CreateFromPtr(val);
+ }
+
+};
+
+template<typename T>
+struct Reflector<const T*const&>
+{
+ static auto Create(const T*const& val)
+ {
+ return Reflector<T>::CreateFromPtr(val);
+ }
+
+};
+
+template<typename T>
+struct Reflector<const std::shared_ptr<T>&>
+{
+ static auto Create(const std::shared_ptr<T>& val)
+ {
+ return Reflector<T>::CreateFromPtr(val.get());
+ }
+};
+
+template<typename T>
+struct Reflector<T&>
+{
+ static auto Create(T& val)
+ {
+ return Reflector<T>::Create(val);
+ }
+};
+
+template<typename T>
+struct Reflector<const T*>
+{
+ static auto Create(const T* val)
+ {
+ return Reflector<T>::CreateFromPtr(val);
+ }
+ static auto CreateFromPtr(const T* val)
+ {
+ return Reflector<T>::CreateFromPtr(val);
+ }
+};
+
+template<typename T>
+struct Reflector<T*>
+{
+ static auto Create(T* val)
+ {
+ return Reflector<T>::CreateFromPtr(val);
+ }
+};
+
+template<typename T>
+struct Reflector<std::shared_ptr<T>>
+{
+ static auto Create(std::shared_ptr<T> val)
+ {
+ return Reflector<T>::CreateFromPtr(val);
+ }
+};
+
+template<typename CharT>
+struct Reflector<std::basic_string<CharT>>
+{
+ static auto Create(std::basic_string<CharT> str) {
+ return Value(std::move(str));
+ }
+ static auto CreateFromPtr(const std::basic_string<CharT>* str) {
+ return Value(*str);
+ }
+};
+
+template<typename CharT>
+struct Reflector<std::basic_string_view<CharT>>
+{
+ static auto Create(std::basic_string_view<CharT> str) { return Value(std::move(str)); }
+ static auto CreateFromPtr(const std::basic_string_view<CharT>* str) { return Value(*str); }
+};
+
+template<>
+struct Reflector<bool>
+{
+ static auto Create(bool val)
+ {
+ return Value(val);
+ }
+ static auto CreateFromPtr(const bool* val)
+ {
+ return Value(*val);
+ }
+};
+
+template<>
+struct Reflector<float>
+{
+ static auto Create(double val) { return Value(val); }
+ static auto CreateFromPtr(const float* val) { return Value(static_cast<double>(*val)); }
+};
+
+template<>
+struct Reflector<double>
+{
+ static auto Create(double val) { return Value(val); }
+ static auto CreateFromPtr(const double* val) { return Value(*val); }
+};
+
+#define JINJA2_INT_REFLECTOR(Type) \
+template<> \
+struct Reflector<Type> \
+{ \
+ static auto Create(Type val) \
+ { \
+ return Value(static_cast<int64_t>(val)); \
+ } \
+ static auto CreateFromPtr(const Type* val) \
+ { \
+ return Value(static_cast<int64_t>(*val)); \
+ } \
+}
+
+JINJA2_INT_REFLECTOR(char);
+JINJA2_INT_REFLECTOR(wchar_t);
+JINJA2_INT_REFLECTOR(int8_t);
+JINJA2_INT_REFLECTOR(uint8_t);
+JINJA2_INT_REFLECTOR(int16_t);
+JINJA2_INT_REFLECTOR(uint16_t);
+JINJA2_INT_REFLECTOR(int32_t);
+JINJA2_INT_REFLECTOR(uint32_t);
+JINJA2_INT_REFLECTOR(int64_t);
+JINJA2_INT_REFLECTOR(uint64_t);
+} // namespace detail
+#endif
+
+template<typename T>
+Value Reflect(T&& val)
+{
+ return detail::Reflector<T>::Create(std::forward<T>(val));
+}
+
+} // namespace jinja2
+
+#endif // JINJA2CPP_REFLECTED_VALUE_H
diff --git a/contrib/libs/jinja2cpp/include/jinja2cpp/string_helpers.h b/contrib/libs/jinja2cpp/include/jinja2cpp/string_helpers.h
new file mode 100644
index 0000000000..b2bb68872c
--- /dev/null
+++ b/contrib/libs/jinja2cpp/include/jinja2cpp/string_helpers.h
@@ -0,0 +1,296 @@
+#ifndef JINJA2CPP_STRING_HELPERS_H
+#define JINJA2CPP_STRING_HELPERS_H
+
+#include "value.h"
+
+#include <string_view>
+
+#include <cwchar>
+#include <string>
+#include <type_traits>
+
+namespace jinja2
+{
+namespace detail
+{
+ template<typename Src, typename Dst>
+ struct StringConverter;
+
+ template<typename Src>
+ struct StringConverter<Src, Src>
+ {
+ static Src DoConvert(const std::basic_string_view<typename Src::value_type>& from)
+ {
+ return Src(from.begin(), from.end());
+ }
+ };
+
+ template<>
+ struct StringConverter<std::wstring, std::string>
+ {
+ static std::string DoConvert(const std::wstring_view& from)
+ {
+ std::mbstate_t state = std::mbstate_t();
+ auto srcPtr = from.data();
+ std::size_t srcSize = from.size();
+ std::size_t destBytes = 0;
+
+#ifndef _MSC_VER
+ destBytes = std::wcsrtombs(nullptr, &srcPtr, srcSize, &state);
+ if (destBytes == static_cast<std::size_t>(-1))
+ return std::string();
+#else
+ auto err = wcsrtombs_s(&destBytes, nullptr, 0, &srcPtr, srcSize, &state);
+ if (err != 0)
+ return std::string();
+#endif
+ std::string result;
+#ifndef _MSC_VER
+ result.resize(destBytes + 1);
+ auto converted = std::wcsrtombs(&result[0], &srcPtr, srcSize, &state);
+ if (converted == static_cast<std::size_t>(-1))
+ return std::string();
+ result.resize(converted);
+#else
+ result.resize(destBytes);
+ wcsrtombs_s(&destBytes, &result[0], destBytes, &srcPtr, srcSize, &state);
+ result.resize(destBytes - 1);
+#endif
+ return result;
+ }
+ };
+
+ template<>
+ struct StringConverter<std::string, std::wstring>
+ {
+ static std::wstring DoConvert(const std::string_view& from)
+ {
+ std::mbstate_t state = std::mbstate_t();
+ auto srcPtr = from.data();
+ std::size_t srcSize = from.size();
+ std::size_t destBytes = 0;
+
+#ifndef _MSC_VER
+ destBytes = std::mbsrtowcs(nullptr, &srcPtr, srcSize, &state);
+ if (destBytes == static_cast<std::size_t>(-1))
+ return std::wstring();
+#else
+ auto err = mbsrtowcs_s(&destBytes, nullptr, 0, &srcPtr, srcSize, &state);
+ if (err != 0)
+ return std::wstring();
+#endif
+ std::wstring result;
+#ifndef _MSC_VER
+ result.resize(destBytes + 1);
+ srcPtr = from.data();
+ auto converted = std::mbsrtowcs(&result[0], &srcPtr, srcSize, &state);
+ if (converted == static_cast<std::size_t>(-1))
+ return std::wstring();
+ result.resize(converted);
+#else
+ result.resize(destBytes);
+ mbsrtowcs_s(&destBytes, &result[0], destBytes, &srcPtr, srcSize, &state);
+ result.resize(destBytes - 1);
+#endif
+ return result;
+ }
+ };
+
+ template<typename CharT, typename T>
+ struct StringConverter<std::basic_string_view<CharT>, T> : public StringConverter<std::basic_string<CharT>, T> {};
+
+} // namespace detail
+
+/*!
+ * \brief Convert string objects from one representation or another
+ *
+ * Converts string or string views to string objects with possible char conversion (char -> wchar_t or wchar_t -> char).
+ * This function should be used when exact type of string is needed.
+ *
+ * @tparam Dst Destination string type. Mandatory. Can be std::string or std::wstring
+ * @tparam Src Source string type. Auto detected. Can be either std::basic_string<CharT> or std::string_view<CharT>
+ *
+ * @param from Source string object which should be converted
+ * @return Destination string object of the specified type
+ */
+template<typename Dst, typename Src>
+Dst ConvertString(Src&& from)
+{
+ using src_t = std::decay_t<Src>;
+ return detail::StringConverter<src_t, std::decay_t<Dst>>::DoConvert(std::basic_string_view<typename src_t::value_type>(from));
+}
+
+/*!
+ * \brief Gets std::string from std::string
+ *
+ * Helper method for use in template context which gets std::string from the other possible string objects (std::string in this case)
+ *
+ * @param str Source string
+ * @return Copy of the source string
+ */
+inline const std::string AsString(const std::string& str)
+{
+ return str;
+}
+/*!
+ * \brief Gets std::string from std::wstring
+ *
+ * Helper method for use in template context which gets std::string from the other possible string objects (std::wstring in this case)
+ * Conversion wchar_t -> char is performing
+ *
+ * @param str Source string
+ * @return Converted source string
+ */
+inline std::string AsString(const std::wstring& str)
+{
+ return ConvertString<std::string>(str);
+}
+/*!
+ * \brief Gets std::string from std::string_view
+ *
+ * Helper method for use in template context which gets std::string from the other possible string objects (std::string_view in this case)
+ *
+ * @param str Source string
+ * @return Copy of the source string
+ */
+inline std::string AsString(const std::string_view& str)
+{
+ return std::string(str.begin(), str.end());
+}
+/*!
+ * \brief Gets std::string from std::wstring_view
+ *
+ * Helper method for use in template context which gets std::string from the other possible string objects (std::wstring_view in this case)
+ * Conversion wchar_t -> char is performing
+ *
+ * @param str Source string
+ * @return Converted source string
+ */
+inline std::string AsString(const std::wstring_view& str)
+{
+ return ConvertString<std::string>(str);
+}
+/*!
+ * \brief Gets std::wstring from std::wstring
+ *
+ * Helper method for use in template context which gets std::wstring from the other possible string objects (std::wstring in this case)
+ *
+ * @param str Source string
+ * @return Copy of the source string
+ */
+inline const std::wstring AsWString(const std::wstring& str)
+{
+ return str;
+}
+/*!
+ * \brief Gets std::wstring from std::string
+ *
+ * Helper method for use in template context which gets std::wstring from the other possible string objects (std::string in this case)
+ * Conversion char -> wchar_t is performing
+ *
+ * @param str Source string
+ * @return Converted source string
+ */
+inline std::wstring AsWString(const std::string& str)
+{
+ return ConvertString<std::wstring>(str);
+}
+/*!
+ * \brief Gets std::wstring from std::wstring_view
+ *
+ * Helper method for use in template context which gets std::wstring from the other possible string objects (std::wstring_view in this case)
+ *
+ * @param str Source string
+ * @return Copy of the source string
+ */
+inline std::wstring AsWString(const std::wstring_view& str)
+{
+ return std::wstring(str.begin(), str.end());
+}
+/*!
+ * \brief Gets std::wstring from std::string_view
+ *
+ * Helper method for use in template context which gets std::wstring from the other possible string objects (std::string_view in this case)
+ * Conversion char -> wchar_t is performing
+ *
+ * @param str Source string
+ * @return Converted source string
+ */
+inline std::wstring AsWString(const std::string_view& str)
+{
+ return ConvertString<std::wstring>(str);
+}
+
+namespace detail
+{
+struct StringGetter
+{
+ template<typename CharT>
+ std::string operator()(const std::basic_string<CharT>& str) const
+ {
+ return AsString(str);
+ }
+ template<typename CharT>
+ std::string operator()(const std::basic_string_view<CharT>& str) const
+ {
+ return AsString(str);
+ }
+
+ template<typename T>
+ std::string operator()(T&&) const
+ {
+ return std::string();
+ }
+};
+
+struct WStringGetter
+{
+ template<typename CharT>
+ std::wstring operator()(const std::basic_string<CharT>& str) const
+ {
+ return AsWString(str);
+ }
+ template<typename CharT>
+ std::wstring operator()(const std::basic_string_view<CharT>& str) const
+ {
+ return AsWString(str);
+ }
+
+ template<typename T>
+ std::wstring operator()(T&&) const
+ {
+ return std::wstring();
+ }
+};
+} // namespace detail
+/*!
+ * \brief Gets std::string from the arbitrary \ref Value
+ *
+ * Helper method for use in template context which gets std::string from the other possible string objects (Value in this case).
+ * Conversion wchar_t -> char is performing if needed. In case of non-string object actually stored in the \ref Value
+ * empty string is returned.
+ *
+ * @param val Source string
+ * @return Extracted or empty string
+ */
+inline std::string AsString(const Value& val)
+{
+ return std::visit(detail::StringGetter(), val.data());
+}
+/*!
+ * \brief Gets std::wstring from the arbitrary \ref Value
+ *
+ * Helper method for use in template context which gets std::wstring from the other possible string objects (Value in this case).
+ * Conversion char -> wchar_t is performing if needed. In case of non-string object actually stored in the \ref Value
+ * empty string is returned.
+ *
+ * @param val Source string
+ * @return Extracted or empty string
+ */
+inline std::wstring AsWString(const Value& val)
+{
+ return std::visit(detail::WStringGetter(), val.data());
+}
+} // namespace jinja2
+
+#endif // JINJA2CPP_STRING_HELPERS_H
diff --git a/contrib/libs/jinja2cpp/include/jinja2cpp/template.h b/contrib/libs/jinja2cpp/include/jinja2cpp/template.h
new file mode 100644
index 0000000000..889dbd2ae3
--- /dev/null
+++ b/contrib/libs/jinja2cpp/include/jinja2cpp/template.h
@@ -0,0 +1,305 @@
+#ifndef JINJA2CPP_TEMPLATE_H
+#define JINJA2CPP_TEMPLATE_H
+
+#include "config.h"
+#include "error_info.h"
+#include "value.h"
+
+#include <contrib/restricted/expected-lite/include/nonstd/expected.hpp>
+
+#include <iostream>
+#include <memory>
+#include <string>
+
+namespace jinja2
+{
+class JINJA2CPP_EXPORT ITemplateImpl;
+class JINJA2CPP_EXPORT TemplateEnv;
+template<typename CharT>
+class TemplateImpl;
+template<typename U>
+using Result = nonstd::expected<U, ErrorInfo>;
+template<typename U>
+using ResultW = nonstd::expected<U, ErrorInfoW>;
+
+template<typename CharT>
+struct MetadataInfo
+{
+ std::string metadataType;
+ std::basic_string_view<CharT> metadata;
+ SourceLocation location;
+};
+
+/*!
+ * \brief Template object which is used to render narrow char templates
+ *
+ * This class is a main class for rendering narrow char templates. It can be used independently or together with
+ * \ref TemplateEnv. In the second case it's possible to use templates inheritance and extension.
+ *
+ * Basic usage of Template class:
+ * ```c++
+ * std::string source = "Hello World from Parser!";
+ *
+ * jinja2::Template tpl;
+ * tpl.Load(source);
+ * std::string result = tpl.RenderAsString(ValuesMap{}).value();
+ * ```
+ */
+class JINJA2CPP_EXPORT Template
+{
+public:
+ /*!
+ * \brief Default constructor
+ */
+ Template()
+ : Template(nullptr)
+ {
+ }
+ /*!
+ * \brief Initializing constructor
+ *
+ * Creates instance of the template with the specified template environment object
+ *
+ * @param env Template environment object which created template should refer to
+ */
+ explicit Template(TemplateEnv* env);
+ /*!
+ * Destructor
+ */
+ ~Template();
+
+ /*!
+ * \brief Load template from the zero-terminated narrow char string
+ *
+ * Takes specified narrow char string and parses it as a Jinja2 template. In case of error returns detailed
+ * diagnostic
+ *
+ * @param tpl Zero-terminated narrow char string with template description
+ * @param tplName Optional name of the template (for the error reporting purposes)
+ *
+ * @return Either noting or instance of \ref ErrorInfoTpl as an error
+ */
+ Result<void> Load(const char* tpl, std::string tplName = std::string());
+ /*!
+ * \brief Load template from the std::string
+ *
+ * Takes specified std::string object and parses it as a Jinja2 template. In case of error returns detailed
+ * diagnostic
+ *
+ * @param str std::string object with template description
+ * @param tplName Optional name of the template (for the error reporting purposes)
+ *
+ * @return Either noting or instance of \ref ErrorInfoTpl as an error
+ */
+ Result<void> Load(const std::string& str, std::string tplName = std::string());
+ /*!
+ * \brief Load template from the stream
+ *
+ * Takes specified stream object and parses it as a source of Jinja2 template. In case of error returns detailed
+ * diagnostic
+ *
+ * @param stream Stream object with template description
+ * @param tplName Optional name of the template (for the error reporting purposes)
+ *
+ * @return Either noting or instance of \ref ErrorInfoTpl as an error
+ */
+ Result<void> Load(std::istream& stream, std::string tplName = std::string());
+ /*!
+ * \brief Load template from the specified file
+ *
+ * Loads file with the specified name and parses it as a source of Jinja2 template. In case of error returns
+ * detailed diagnostic
+ *
+ * @param fileName Name of the file to load
+ *
+ * @return Either noting or instance of \ref ErrorInfoTpl as an error
+ */
+ Result<void> LoadFromFile(const std::string& fileName);
+
+ /*!
+ * \brief Render previously loaded template to the narrow char stream
+ *
+ * Renders previously loaded template to the specified narrow char stream and specified set of params.
+ *
+ * @param os Stream to render template to
+ * @param params Set of params which should be passed to the template engine and can be used within the template
+ *
+ * @return Either noting or instance of \ref ErrorInfoTpl as an error
+ */
+ Result<void> Render(std::ostream& os, const ValuesMap& params);
+ /*!
+ * \brief Render previously loaded template to the narrow char string
+ *
+ * Renders previously loaded template as a narrow char string and with specified set of params.
+ *
+ * @param params Set of params which should be passed to the template engine and can be used within the template
+ *
+ * @return Either rendered string or instance of \ref ErrorInfoTpl as an error
+ */
+ Result<std::string> RenderAsString(const ValuesMap& params);
+ /*!
+ * \brief Get metadata, provided in the {% meta %} tag
+ *
+ * @return Parsed metadata as a generic map value or instance of \ref ErrorInfoTpl as an error
+ */
+ Result<GenericMap> GetMetadata();
+ /*!
+ * \brief Get non-parsed metadata, provided in the {% meta %} tag
+ *
+ * @return Non-parsed metadata information or instance of \ref ErrorInfoTpl as an error
+ */
+ Result<MetadataInfo<char>> GetMetadataRaw();
+
+ /* !
+ * \brief compares to an other object of the same type
+ *
+ * @return true if equal
+ */
+ bool IsEqual(const Template& other) const;
+
+private:
+ std::shared_ptr<ITemplateImpl> m_impl;
+ friend class TemplateImpl<char>;
+};
+
+bool operator==(const Template& lhs, const Template& rhs);
+bool operator!=(const Template& lhs, const Template& rhs);
+
+/*!
+ * \brief Template object which is used to render wide char templates
+ *
+ * This class is a main class for rendering wide char templates. It can be used independently or together with
+ * \ref TemplateEnv. In the second case it's possible to use templates inheritance and extension.
+ *
+ * Basic usage of Template class:
+ * ```c++
+ * std::string source = "Hello World from Parser!";
+ *
+ * jinja2::Template tpl;
+ * tpl.Load(source);
+ * std::string result = tpl.RenderAsString(ValuesMap{}).value();
+ * ```
+*/
+class JINJA2CPP_EXPORT TemplateW
+{
+public:
+ /*!
+ * \brief Default constructor
+ */
+ TemplateW()
+ : TemplateW(nullptr)
+ {
+ }
+ /*!
+ * \brief Initializing constructor
+ *
+ * Creates instance of the template with the specified template environment object
+ *
+ * @param env Template environment object which created template should refer to
+ */
+ explicit TemplateW(TemplateEnv* env);
+ /*!
+ * Destructor
+ */
+ ~TemplateW();
+
+ /*!
+ * \brief Load template from the zero-terminated wide char string
+ *
+ * Takes specified wide char string and parses it as a Jinja2 template. In case of error returns detailed
+ * diagnostic
+ *
+ * @param tpl Zero-terminated wide char string with template description
+ * @param tplName Optional name of the template (for the error reporting purposes)
+ *
+ * @return Either noting or instance of \ref ErrorInfoTpl as an error
+ */
+ ResultW<void> Load(const wchar_t* tpl, std::string tplName = std::string());
+ /*!
+ * \brief Load template from the std::wstring
+ *
+ * Takes specified std::wstring object and parses it as a Jinja2 template. In case of error returns detailed
+ * diagnostic
+ *
+ * @param str std::wstring object with template description
+ * @param tplName Optional name of the template (for the error reporting purposes)
+ *
+ * @return Either noting or instance of \ref ErrorInfoTpl as an error
+ */
+ ResultW<void> Load(const std::wstring& str, std::string tplName = std::string());
+ /*!
+ * \brief Load template from the stream
+ *
+ * Takes specified stream object and parses it as a source of Jinja2 template. In case of error returns detailed
+ * diagnostic
+ *
+ * @param stream Stream object with template description
+ * @param tplName Optional name of the template (for the error reporting purposes)
+ *
+ * @return Either noting or instance of \ref ErrorInfoTpl as an error
+ */
+ ResultW<void> Load(std::wistream& stream, std::string tplName = std::string());
+ /*!
+ * \brief Load template from the specified file
+ *
+ * Loads file with the specified name and parses it as a source of Jinja2 template. In case of error returns
+ * detailed diagnostic
+ *
+ * @param fileName Name of the file to load
+ *
+ * @return Either noting or instance of \ref ErrorInfoTpl as an error
+ */
+ ResultW<void> LoadFromFile(const std::string& fileName);
+
+ /*!
+ * \brief Render previously loaded template to the wide char stream
+ *
+ * Renders previously loaded template to the specified wide char stream and specified set of params.
+ *
+ * @param os Stream to render template to
+ * @param params Set of params which should be passed to the template engine and can be used within the template
+ *
+ * @return Either noting or instance of \ref ErrorInfoTpl as an error
+ */
+ ResultW<void> Render(std::wostream& os, const ValuesMap& params);
+ /*!
+ * \brief Render previously loaded template to the wide char string
+ *
+ * Renders previously loaded template as a wide char string and with specified set of params.
+ *
+ * @param params Set of params which should be passed to the template engine and can be used within the template
+ *
+ * @return Either rendered string or instance of \ref ErrorInfoTpl as an error
+ */
+ ResultW<std::wstring> RenderAsString(const ValuesMap& params);
+ /*!
+ * \brief Get metadata, provided in the {% meta %} tag
+ *
+ * @return Parsed metadata as a generic map value or instance of \ref ErrorInfoTpl as an error
+ */
+ ResultW<GenericMap> GetMetadata();
+ /*!
+ * \brief Get non-parsed metadata, provided in the {% meta %} tag
+ *
+ * @return Non-parsed metadata information or instance of \ref ErrorInfoTpl as an error
+ */
+ ResultW<MetadataInfo<wchar_t>> GetMetadataRaw();
+
+ /* !
+ * \brief compares to an other object of the same type
+ *
+ * @return true if equal
+ */
+ bool IsEqual(const TemplateW& other) const;
+
+private:
+ std::shared_ptr<ITemplateImpl> m_impl;
+ friend class TemplateImpl<wchar_t>;
+};
+
+bool operator==(const TemplateW& lhs, const TemplateW& rhs);
+bool operator!=(const TemplateW& lhs, const TemplateW& rhs);
+
+} // namespace jinja2
+
+#endif // JINJA2CPP_TEMPLATE_H
diff --git a/contrib/libs/jinja2cpp/include/jinja2cpp/template_env.h b/contrib/libs/jinja2cpp/include/jinja2cpp/template_env.h
new file mode 100644
index 0000000000..80dcecc1ec
--- /dev/null
+++ b/contrib/libs/jinja2cpp/include/jinja2cpp/template_env.h
@@ -0,0 +1,320 @@
+#ifndef JINJA2CPP_TEMPLATE_ENV_H
+#define JINJA2CPP_TEMPLATE_ENV_H
+
+#include "config.h"
+#include "error_info.h"
+#include "filesystem_handler.h"
+#include "template.h"
+
+#include <mutex>
+#include <shared_mutex>
+#include <unordered_map>
+
+namespace jinja2
+{
+
+class IErrorHandler;
+class IFilesystemHandler;
+
+//! Compatibility mode for jinja2c++ engine
+enum class Jinja2CompatMode
+{
+ None, //!< Default mode
+ Vesrsion_2_10, //!< Compatibility with Jinja2 v.2.10 specification
+};
+
+//! Global template environment settings
+struct Settings
+{
+ /// Extensions set which should be supported
+ struct Extensions
+ {
+ bool Do = false; //!< Enable use of `do` statement
+ };
+
+ //! Enables use of line statements (yet not supported)
+ bool useLineStatements = false;
+ //! Enables blocks trimming the same way as it does python Jinja2 engine
+ bool trimBlocks = false;
+ //! Enables blocks stripping (from the left) the same way as it does python Jinja2 engine
+ bool lstripBlocks = false;
+ //! Templates cache size
+ int cacheSize = 400;
+ //! If auto_reload is set to true (default) every time a template is requested the loader checks if the source changed and if yes, it will reload the template
+ bool autoReload = true;
+ //! Extensions set enabled for templates
+ Extensions extensions;
+ //! Controls Jinja2 compatibility mode
+ Jinja2CompatMode jinja2CompatMode = Jinja2CompatMode::None;
+ //! Default format for metadata block in the templates
+ std::string m_defaultMetadataType = "json";
+};
+
+inline bool operator==(const Settings& lhs, const Settings& rhs)
+{
+ auto lhsTie = std::tie(lhs.useLineStatements, lhs.trimBlocks, lhs.lstripBlocks, lhs.cacheSize, lhs.autoReload, lhs.extensions.Do, lhs.jinja2CompatMode, lhs.m_defaultMetadataType);
+ auto rhsTie = std::tie(rhs.useLineStatements, rhs.trimBlocks, rhs.lstripBlocks, rhs.cacheSize, rhs.autoReload, rhs.extensions.Do, rhs.jinja2CompatMode, rhs.m_defaultMetadataType);
+ return lhsTie == rhsTie;
+}
+inline bool operator!=(const Settings& lhs, const Settings& rhs)
+{
+ return !(lhs == rhs);
+}
+
+/*!
+ * \brief Global template environment which controls behaviour of the different \ref Template instances
+ *
+ * This class is used for fine tuning of the templates behaviour and for state sharing between them. With this class
+ * it's possible to control template loading, provide template sources, set global variables, use template inheritance
+ * and inclusion.
+ *
+ * It's possible to load templates from the environment via \ref LoadTemplate or \ref LoadTemplateW methods
+ * or to pass instance of the environment directly to the \ref Template via constructor.
+ */
+class JINJA2CPP_EXPORT TemplateEnv
+{
+public:
+ using TimePoint = std::chrono::system_clock::time_point;
+ using TimeStamp = std::chrono::steady_clock::time_point;
+
+ /*!
+ * \brief Returns global settings for the environment
+ *
+ * @return Constant reference to the global settings
+ */
+ const Settings& GetSettings() const {return m_settings;}
+ /*!
+ * \brief Returns global settings for the environment available for modification
+ *
+ * @return Reference to the global settings
+ */
+ Settings& GetSettings() {return m_settings;}
+
+ /*!
+ * \brief Replace global settings for the environment with the new ones
+ *
+ * @param setts New settings
+ */
+ void SetSettings(const Settings& setts) {m_settings = setts;}
+
+ /*!
+ * \brief Add pointer to file system handler with the specified prefix
+ *
+ * Adds filesystem handler which provides access to the external source of templates. With added handlers it's
+ * possible to load templates from the `import`, `extends` and `include` jinja2 tags. Prefix is used for
+ * distinguish one templates source from another. \ref LoadTemplate or \ref LoadTemplateW methods use
+ * handlers to load templates with the specified name.
+ * Method is thread-unsafe. It's dangerous to add new filesystem handlers and load templates simultaneously.
+ *
+ * Basic usage:
+ * ```c++
+ * jinja2::TemplateEnv env;
+ *
+ * auto fs = std::make_shared<jinja2::MemoryFileSystem>();
+ * env.AddFilesystemHandler(std::string(), fs);
+ * fs->AddFile("base.j2tpl", "Hello World!");
+ * ```
+ *
+ * @param prefix Optional prefix of the handler's filesystem. Prefix is a part of the file name and passed to the handler's \ref IFilesystemHandler::OpenStream method
+ * @param h Shared pointer to the handler
+ */
+ void AddFilesystemHandler(std::string prefix, FilesystemHandlerPtr h)
+ {
+ m_filesystemHandlers.push_back(FsHandler{std::move(prefix), std::move(h)});
+ }
+ /*!
+ * \brief Add reference to file system handler with the specified prefix
+ *
+ * Adds filesystem handler which provides access to the external source of templates. With added handlers it's
+ * possible to load templates from the `import`, `extends` and `include` jinja2 tags. Prefix is used for
+ * distinguish one templates source from another. \ref LoadTemplate or \ref LoadTemplateW methods use
+ * handlers to load templates with the specified name.
+ * Method is thread-unsafe. It's dangerous to add new filesystem handlers and load templates simultaneously.
+ *
+ * Basic usage:
+ * ```c++
+ * jinja2::TemplateEnv env;
+ *
+ * MemoryFileSystem fs;
+ * env.AddFilesystemHandler(std::string(), fs);
+ * fs.AddFile("base.j2tpl", "Hello World!");
+ * ```
+ *
+ * @param prefix Optional prefix of the handler's filesystem. Prefix is a part of the file name and passed to the handler's \ref IFilesystemHandler::OpenStream method
+ * @param h Reference to the handler. It's assumed that lifetime of the handler is controlled externally
+ */
+ void AddFilesystemHandler(std::string prefix, IFilesystemHandler& h)
+ {
+ m_filesystemHandlers.push_back(FsHandler{std::move(prefix), std::shared_ptr<IFilesystemHandler>(&h, [](auto*) {})});
+ }
+ /*!
+ * \brief Load narrow char template with the specified name via registered file handlers
+ *
+ * In case of specified file present in any of the registered handlers, template is loaded and parsed. If any
+ * error occurred during the loading or parsing detailed diagnostic will be returned.
+ * Method is thread-unsafe. It's dangerous to add new filesystem handlers and load templates simultaneously.
+ *
+ * @param fileName Template name to load
+ *
+ * @return Either loaded template or load/parse error. See \ref ErrorInfoTpl
+ */
+ nonstd::expected<Template, ErrorInfo> LoadTemplate(std::string fileName);
+ /*!
+ * \brief Load wide char template with the specified name via registered file handlers
+ *
+ * In case of specified file present in any of the registered handlers, template is loaded and parsed. If any
+ * error occurred during the loading or parsing detailed diagnostic will be returned.
+ * Method is thread-unsafe. It's dangerous to add new filesystem handlers and load templates simultaneously.
+ *
+ * @param fileName Template name to load
+ *
+ * @return Either loaded template or load/parse error. See \ref ErrorInfoTpl
+ */
+ nonstd::expected<TemplateW, ErrorInfoW> LoadTemplateW(std::string fileName);
+
+ /*!
+ * \brief Add global variable to the environment
+ *
+ * Adds global variable which can be referred in any template which is loaded within this environment object.
+ * Method is thread-safe.
+ *
+ * @param name Name of the variable
+ * @param val Value of the variable
+ */
+ void AddGlobal(std::string name, Value val)
+ {
+ std::unique_lock<std::shared_timed_mutex> l(m_guard);
+ m_globalValues[std::move(name)] = std::move(val);
+ }
+ /*!
+ * \brief Remove global variable from the environment
+ *
+ * Removes global variable from the environment.
+ * Method is thread-safe.
+ *
+ * @param name Name of the variable
+ */
+ void RemoveGlobal(const std::string& name)
+ {
+ std::unique_lock<std::shared_timed_mutex> l(m_guard);
+ m_globalValues.erase(name);
+ }
+
+ /*!
+ * \brief Call the specified function with the current set of global variables under the internal lock
+ *
+ * Main purpose of this method is to help external code to enumerate global variables thread-safely. Provided functional object is called under the
+ * internal lock with the current set of global variables as an argument.
+ *
+ * @tparam Fn Type of the functional object to call
+ * @param fn Functional object to call
+ */
+ template<typename Fn>
+ void ApplyGlobals(Fn&& fn)
+ {
+ std::shared_lock<std::shared_timed_mutex> l(m_guard);
+ fn(m_globalValues);
+ }
+
+ bool IsEqual(const TemplateEnv& other) const
+ {
+ if (m_filesystemHandlers != other.m_filesystemHandlers)
+ return false;
+ if (m_settings != other.m_settings)
+ return false;
+ if (m_globalValues != other.m_globalValues)
+ return false;
+ if (m_templateCache != other.m_templateCache)
+ return false;
+ if (m_templateWCache != other.m_templateWCache)
+ return false;
+
+ return true;
+ }
+
+private:
+ template<typename CharT, typename T, typename Cache>
+ auto LoadTemplateImpl(TemplateEnv* env, std::string fileName, const T& filesystemHandlers, Cache& cache);
+
+
+private:
+ struct FsHandler
+ {
+ std::string prefix;
+ FilesystemHandlerPtr handler;
+ bool operator==(const FsHandler& rhs) const
+ {
+ if (prefix != rhs.prefix)
+ return false;
+ if (handler && rhs.handler && !handler->IsEqual(*rhs.handler))
+ return false;
+ if ((!handler && rhs.handler) || (handler && !rhs.handler))
+ return false;
+ return true;
+ }
+ bool operator!=(const FsHandler& rhs) const
+ {
+ return !(*this == rhs);
+ }
+ };
+
+ struct BaseTemplateInfo
+ {
+ std::optional<TimePoint> lastModification;
+ TimeStamp lastAccessTime;
+ FilesystemHandlerPtr handler;
+ bool operator==(const BaseTemplateInfo& other) const
+ {
+ if (lastModification != other.lastModification)
+ return false;
+ if (lastAccessTime != other.lastAccessTime)
+ return false;
+ if (handler && other.handler && !handler->IsEqual(*other.handler))
+ return false;
+ if ((!handler && other.handler) || (handler && !other.handler))
+ return false;
+ return true;
+ }
+ bool operator!=(const BaseTemplateInfo& other) const
+ {
+ return !(*this == other);
+ }
+ };
+
+ struct TemplateCacheEntry : public BaseTemplateInfo
+ {
+ Template tpl;
+ bool operator==(const TemplateCacheEntry& other) const
+ {
+ return BaseTemplateInfo::operator==(other) && tpl == other.tpl;
+ }
+ bool operator!=(const TemplateCacheEntry& other) const
+ {
+ return !(*this == other);
+ }
+ };
+
+ struct TemplateWCacheEntry : public BaseTemplateInfo
+ {
+ TemplateW tpl;
+ bool operator==(const TemplateWCacheEntry& other) const
+ {
+ return BaseTemplateInfo::operator==(other) && tpl == other.tpl;
+ }
+ bool operator!=(const TemplateWCacheEntry& other) const
+ {
+ return !(*this == other);
+ }
+ };
+
+ std::vector<FsHandler> m_filesystemHandlers;
+ Settings m_settings;
+ ValuesMap m_globalValues;
+ std::shared_timed_mutex m_guard;
+ std::unordered_map<std::string, TemplateCacheEntry> m_templateCache;
+ std::unordered_map<std::string, TemplateWCacheEntry> m_templateWCache;
+};
+
+} // namespace jinja2
+
+#endif // JINJA2CPP_TEMPLATE_ENV_H
diff --git a/contrib/libs/jinja2cpp/include/jinja2cpp/utils/i_comparable.h b/contrib/libs/jinja2cpp/include/jinja2cpp/utils/i_comparable.h
new file mode 100644
index 0000000000..76f58d5c88
--- /dev/null
+++ b/contrib/libs/jinja2cpp/include/jinja2cpp/utils/i_comparable.h
@@ -0,0 +1,16 @@
+#ifndef JINJA2CPP_ICOMPARABLE_H
+#define JINJA2CPP_ICOMPARABLE_H
+
+#include <jinja2cpp/config.h>
+
+namespace jinja2 {
+
+struct JINJA2CPP_EXPORT IComparable
+{
+ virtual ~IComparable() {}
+ virtual bool IsEqual(const IComparable& other) const = 0;
+};
+
+} // namespace jinja2
+
+#endif // JINJA2CPP_ICOMPARABLE_H
diff --git a/contrib/libs/jinja2cpp/include/jinja2cpp/value.h b/contrib/libs/jinja2cpp/include/jinja2cpp/value.h
new file mode 100644
index 0000000000..545294fcd5
--- /dev/null
+++ b/contrib/libs/jinja2cpp/include/jinja2cpp/value.h
@@ -0,0 +1,763 @@
+#ifndef JINJA2CPP_VALUE_H
+#define JINJA2CPP_VALUE_H
+
+#include <jinja2cpp/generic_list.h>
+#include <jinja2cpp/utils/i_comparable.h>
+#include <jinja2cpp/value_ptr.h>
+
+#include <variant>
+#include <optional>
+#include <string_view>
+
+#include <atomic>
+#include <vector>
+#include <unordered_map>
+#include <string>
+#include <functional>
+#include <type_traits>
+#include <utility>
+
+namespace jinja2
+{
+//! Empty value container
+struct EmptyValue
+{
+ template<typename T>
+ operator T() const {return T{};}
+};
+
+inline bool operator==(const EmptyValue& lhs, const EmptyValue& rhs)
+{
+ (void)lhs;
+ (void)rhs;
+ return true;
+}
+
+class Value;
+
+/*!
+ * \brief Interface to the generic dictionary type which maps string to some value
+ */
+struct IMapItemAccessor : IComparable
+{
+ //! Destructor
+ virtual ~IMapItemAccessor() = default;
+
+ //! Method is called to obtain number of items in the dictionary. Maximum possible size_t value means non-calculable size
+ virtual size_t GetSize() const = 0;
+
+ /*!
+ * \brief Method is called to check presence of the item in the dictionary
+ *
+ * @param name Name of the item
+ *
+ * @return true if item is present and false otherwise.
+ */
+ virtual bool HasValue(const std::string& name) const = 0;
+ /*!
+ * \brief Method is called for retrieving the value by specified name
+ *
+ * @param name Name of the value to retrieve
+ *
+ * @return Requestd value or empty \ref Value if item is absent
+ */
+ virtual Value GetValueByName(const std::string& name) const = 0;
+ /*!
+ * \brief Method is called for retrieving collection of keys in the dictionary
+ *
+ * @return Collection of keys if any. Ordering of keys is unspecified.
+ */
+ virtual std::vector<std::string> GetKeys() const = 0;
+
+ /*!
+ * \brief Compares to object of the same type
+ *
+ * @return true if equal
+ */
+// virtual bool IsEqual(const IMapItemAccessor& rhs) const = 0;
+};
+
+/*!
+ * \brief Helper class for accessing maps specified by the \ref IMapItemAccessor interface
+ *
+ * In the \ref Value type can be stored either ValuesMap instance or GenericMap instance. ValuesMap is a simple
+ * dictionary object based on std::unordered_map. Rather than GenericMap is a more robust object which can provide
+ * access to the different types of dictionary entities. GenericMap takes the \ref IMapItemAccessor interface instance
+ * and uses it to access particular items in the dictionaries.
+ */
+class GenericMap
+{
+public:
+ //! Default constructor
+ GenericMap() = default;
+
+ /*!
+ * \brief Initializing constructor
+ *
+ * The only one way to get valid non-empty GeneridMap is to construct it with the specified \ref IMapItemAccessor
+ * implementation provider. This provider is a functional object which returns pointer to the interface instance.
+ *
+ * @param accessor Functional object which returns pointer to the \ref IMapItemAccessor interface
+ */
+ explicit GenericMap(std::function<const IMapItemAccessor* ()> accessor)
+ : m_accessor(std::move(accessor))
+ {
+ }
+
+ /*!
+ * \brief Check the presence the specific item in the dictionary
+ *
+ * @param name Name of the the item
+ *
+ * @return true of item is present and false otherwise
+ */
+ bool HasValue(const std::string& name) const
+ {
+ return m_accessor ? m_accessor()->HasValue(name) : false;
+ }
+
+ /*!
+ * \brief Get specific item from the dictionary
+ *
+ * @param name Name of the item to get
+ *
+ * @return Value of the item or empty \ref Value if no item
+ */
+ Value GetValueByName(const std::string& name) const;
+ /*!
+ * \brief Get size of the dictionary
+ *
+ * @return Size of the dictionary
+ */
+ size_t GetSize() const
+ {
+ return m_accessor ? m_accessor()->GetSize() : 0;
+ }
+ /*!
+ * \brief Get collection of keys from the dictionary
+ *
+ * @return Collection of the keys or empty collection if no keys
+ */
+ auto GetKeys() const
+ {
+ return m_accessor ? m_accessor()->GetKeys() : std::vector<std::string>();
+ }
+ /*!
+ * \brief Get the underlying access interface to the dictionary
+ *
+ * @return Pointer to the underlying interface or nullptr if no
+ */
+ auto GetAccessor() const
+ {
+ return m_accessor();
+ }
+
+ auto operator[](const std::string& name) const;
+
+private:
+ std::function<const IMapItemAccessor* ()> m_accessor;
+};
+
+bool operator==(const GenericMap& lhs, const GenericMap& rhs);
+bool operator!=(const GenericMap& lhs, const GenericMap& rhs);
+
+using ValuesList = std::vector<Value>;
+struct ValuesMap;
+struct UserCallableArgs;
+struct ParamInfo;
+struct UserCallable;
+
+template<typename T>
+using RecWrapper = types::ValuePtr<T>;
+
+/*!
+ * \brief Generic value class
+ *
+ * Variant-based class which is used for passing values to and from Jinja2C++ template engine. This class store the
+ * following types of values:
+ *
+ * - EmptyValue. In this case instance of this class threated as 'empty'
+ * - Boolean value.
+ * - String value.
+ * - Wide string value
+ * - String view value (std::string_view)
+ * - Wide string view value (std::wstring_view)
+ * - integer (int64_t) value
+ * - floating point (double) value
+ * - Simple list of other values (\ref ValuesList)
+ * - Simple map of other values (\ref ValuesMap)
+ * - Generic list of other values (\ref GenericList)
+ * - Generic map of other values (\ref GenericMap)
+ * - User-defined callable (\ref UserCallable)
+ *
+ * Exact value can be accessed via std::visit method applied to the result of the Value::data() call or any of
+ * asXXX method (ex. \ref Value::asString). In case of string retrieval it's better to use \ref AsString or \ref
+ * AsWString functions. Thay hide all nececcary transformations between various types of strings (or string views).
+ */
+class Value
+{
+public:
+ using ValueData = std::variant<
+ EmptyValue,
+ bool,
+ std::string,
+ std::wstring,
+ std::string_view,
+ std::wstring_view,
+ int64_t,
+ double,
+ RecWrapper<ValuesList>,
+ RecWrapper<ValuesMap>,
+ GenericList,
+ GenericMap,
+ RecWrapper<UserCallable>
+ >;
+
+ template<typename T, typename ... L>
+ struct AnyOf : public std::false_type {};
+
+ template<typename T, typename H, typename ... L>
+ struct AnyOf<T, H, L...> : public std::integral_constant<bool, std::is_same<std::decay_t<T>, H>::value || AnyOf<T, L...>::value> {};
+
+ //! Default constructor
+ Value();
+ //! Copy constructor
+ Value(const Value& val);
+ //! Move constructor
+ Value(Value&& val) noexcept;
+ //! Desctructor
+ // ~Value();
+ ~Value();
+
+ //! Assignment operator
+ Value& operator=(const Value&);
+ //! Move assignment operator
+ Value& operator=(Value&&) noexcept;
+ /*!
+ * \brief Generic initializing constructor
+ *
+ * Creates \ref Value from the arbitrary type which is compatible with types listed in \ref Value::ValueData
+ *
+ * @tparam T Type of value to create \ref Value instance from
+ * @param val Value which should be used to initialize \ref Value instance
+ */
+ template<typename T>
+ Value(T&& val, typename std::enable_if<!AnyOf<T, Value, ValuesList, ValuesMap, UserCallable>::value>::type* = nullptr)
+ : m_data(std::forward<T>(val))
+ {
+ }
+ /*!
+ * \brief Initializing constructor from pointer to the null-terminated narrow string
+ *
+ * @param val Null-terminated string which should be used to initialize \ref Value instance
+ */
+ Value(const char* val)
+ : m_data(std::string(val))
+ {
+ }
+ /*!
+ * \brief Initializing constructor from pointer to the null-terminated wide string
+ *
+ * @param val Null-terminated string which should be used to initialize \ref Value instance
+ */
+ Value(const wchar_t* val)
+ : m_data(std::wstring(val))
+ {
+ }
+ /*!
+ * \brief Initializing constructor from the narrow string literal
+ *
+ * @param val String literal which should be used to initialize \ref Value instance
+ */
+ template<size_t N>
+ Value(char (&val)[N])
+ : m_data(std::string(val))
+ {
+ }
+ /*!
+ * \brief Initializing constructor from the wide string literal
+ *
+ * @param val String literal which should be used to initialize \ref Value instance
+ */
+ template<size_t N>
+ Value(wchar_t (&val)[N])
+ : m_data(std::wstring(val))
+ {
+ }
+ /*!
+ * \brief Initializing constructor from the int value
+ *
+ * @param val Integer value which should be used to initialize \ref Value instance
+ */
+ Value(int val)
+ : m_data(static_cast<int64_t>(val))
+ {
+ }
+ /*!
+ * \brief Initializing constructor from the \ref ValuesList
+ *
+ * @param list List of values which should be used to initialize \ref Value instance
+ */
+ Value(const ValuesList& list);
+ /*!
+ * \brief Initializing constructor from the \ref ValuesMap
+ *
+ * @param map Map of values which should be used to initialize \ref Value instance
+ */
+ Value(const ValuesMap& map);
+ /*!
+ * \brief Initializing constructor from the \ref UserCallable
+ *
+ * @param callable UserCallable which should be used to initialize \ref Value instance
+ */
+ Value(const UserCallable& callable);
+ /*!
+ * \brief Initializing move constructor from the \ref ValuesList
+ *
+ * @param list List of values which should be used to initialize \ref Value instance
+ */
+ Value(ValuesList&& list) noexcept;
+ /*!
+ * \brief Initializing move constructor from the \ref ValuesMap
+ *
+ * @param map Map of values which should be used to initialize \ref Value instance
+ */
+ Value(ValuesMap&& map) noexcept;
+ /*!
+ * \brief Initializing move constructor from the \ref UserCallable
+ *
+ * @param callable UserCallable which should be used to initialize \ref Value instance
+ */
+ Value(UserCallable&& callable);
+
+ /*!
+ * \brief Get the non-mutable stored data object
+ *
+ * Returns the stored data object in order to get the typed value from it. For instance:
+ * ```c++
+ * inline std::string AsString(const jinja2::Value& val)
+ * {
+ * return std::visit(StringGetter(), val.data());
+ * }
+ * ```
+ *
+ * @return Non-mutable stored data object
+ */
+ const ValueData& data() const {return m_data;}
+ /*!
+ * \brief Get the mutable stored data object
+ *
+ * Returns the stored data object in order to get the typed value from it. For instance:
+ * ```c++
+ * inline std::string AsString(Value& val)
+ * {
+ * return std::visit(StringGetter(), val.data());
+ * }
+ * ```
+ *
+ * @return Mutable stored data object
+ */
+ ValueData& data() {return m_data;}
+
+ //! Test Value for containing std::string object
+ bool isString() const
+ {
+ return std::get_if<std::string>(&m_data) != nullptr;
+ }
+ /*!
+ * \brief Returns mutable containing std::string object
+ *
+ * Returns containing std::string object. Appropriate exception is thrown in case non-string containing value
+ *
+ * @return Mutable containing std::string object
+ */
+ auto& asString()
+ {
+ return std::get<std::string>(m_data);
+ }
+ /*!
+ * \brief Returns non-mutable containing std::string object
+ *
+ * Returns containing std::string object. Appropriate exception is thrown in case of non-string containing value
+ *
+ * @return Non-mutable containing std::string object
+ */
+ auto& asString() const
+ {
+ return std::get<std::string>(m_data);
+ }
+
+ //! Test Value for containing std::wstring object
+ bool isWString() const
+ {
+ return std::get_if<std::wstring>(&m_data) != nullptr;
+ }
+ /*!
+ * \brief Returns mutable containing std::wstring object
+ *
+ * Returns containing std::wstring object. Appropriate exception is thrown in case of non-wstring containing value
+ *
+ * @return Mutable containing std::wstring object
+ */
+ auto& asWString()
+ {
+ return std::get<std::wstring>(m_data);
+ }
+ /*!
+ * \brief Returns non-mutable containing std::wstring object
+ *
+ * Returns containing std::wstring object. Appropriate exception is thrown in case of non-wstring containing value
+ *
+ * @return Non-mutable containing std::wstring object
+ */
+ auto& asWString() const
+ {
+ return std::get<std::wstring>(m_data);
+ }
+
+ //! Test Value for containing jinja2::ValuesList object
+ bool isList() const
+ {
+ return std::get_if<RecWrapper<ValuesList>>(&m_data) != nullptr || std::get_if<GenericList>(&m_data) != nullptr;
+ }
+ /*!
+ * \brief Returns mutable containing jinja2::ValuesList object
+ *
+ * Returns containing jinja2::ValuesList object. Appropriate exception is thrown in case of non-Valueslist containing value
+ *
+ * @return Mutable containing jinja2::ValuesList object
+ */
+ auto& asList()
+ {
+ return *std::get<RecWrapper<ValuesList>>(m_data);
+ }
+ /*!
+ * \brief Returns non-mutable containing jinja2::ValuesList object
+ *
+ * Returns containing jinja2::ValuesList object. Appropriate exception is thrown in case of non-Valueslist containing value
+ *
+ * @return Non-mutable containing jinja2::ValuesList object
+ */
+ auto& asList() const
+ {
+ return *std::get<RecWrapper<ValuesList>>(m_data);
+ }
+ //! Test Value for containing jinja2::ValuesMap object
+ bool isMap() const
+ {
+ return std::get_if<RecWrapper<ValuesMap>>(&m_data) != nullptr || std::get_if<GenericMap>(&m_data) != nullptr;
+ }
+ /*!
+ * \brief Returns mutable containing jinja2::ValuesMap object
+ *
+ * Returns containing jinja2::ValuesMap object. Appropriate exception is thrown in case of non-ValuesMap containing value
+ *
+ * @return Mutable containing jinja2::ValuesMap object
+ */
+ auto& asMap()
+ {
+ return *std::get<RecWrapper<ValuesMap>>(m_data);
+ }
+ /*!
+ * \brief Returns non-mutable containing jinja2::ValuesMap object
+ *
+ * Returns containing jinja2::ValuesMap object. Appropriate exception is thrown in case of non-ValuesMap containing value
+ *
+ * @return Non-mutable containing jinja2::ValuesMap object
+ */
+ auto& asMap() const
+ {
+ return *std::get<RecWrapper<ValuesMap>>(m_data);
+ }
+
+ template<typename T>
+ auto get()
+ {
+ return std::get<T>(m_data);
+ }
+
+ template<typename T>
+ auto get() const
+ {
+ return std::get<T>(m_data);
+ }
+
+ template<typename T>
+ auto getPtr()
+ {
+ return std::get_if<T>(&m_data); // m_data.index() == ValueData::template index_of<T>() ? &m_data.get<T>() : nullptr;
+ }
+
+ template<typename T>
+ auto getPtr() const
+ {
+ return std::get_if<T>(&m_data); // m_data.index() == ValueData::template index_of<T>() ? &m_data.get<T>() : nullptr;
+ }
+
+ //! Test Value for emptyness
+ bool isEmpty() const
+ {
+ return std::get_if<EmptyValue>(&m_data) != nullptr;
+ }
+
+ bool IsEqual(const Value& rhs) const;
+
+private:
+ ValueData m_data;
+};
+
+JINJA2CPP_EXPORT bool operator==(const Value& lhs, const Value& rhs);
+JINJA2CPP_EXPORT bool operator!=(const Value& lhs, const Value& rhs);
+bool operator==(const types::ValuePtr<Value>& lhs, const types::ValuePtr<Value>& rhs);
+bool operator!=(const types::ValuePtr<Value>& lhs, const types::ValuePtr<Value>& rhs);
+bool operator==(const types::ValuePtr<std::vector<Value>>& lhs, const types::ValuePtr<std::vector<Value>>& rhs);
+bool operator!=(const types::ValuePtr<std::vector<Value>>& lhs, const types::ValuePtr<std::vector<Value>>& rhs);
+
+struct ValuesMap : std::unordered_map<std::string, Value>
+{
+ using unordered_map::unordered_map;
+};
+
+bool operator==(const types::ValuePtr<ValuesMap>& lhs, const types::ValuePtr<ValuesMap>& rhs);
+bool operator!=(const types::ValuePtr<ValuesMap>& lhs, const types::ValuePtr<ValuesMap>& rhs);
+
+/*!
+ * \brief Information about user-callable parameters passed from Jinja2 call context
+ *
+ * This structure prepared by the Jinja2C++ engine and filled by information about call parameters gathered from the
+ * call context. See documentation for \ref UserCallable for detailed information
+ *
+ */
+struct UserCallableParams
+{
+ //! Values of parameters mapped according to \ref UserCallable::argsInfo
+ ValuesMap args;
+ //! Values of extra positional args got from the call expression
+ Value extraPosArgs;
+ //! Values of extra named args got from the call expression
+ Value extraKwArgs;
+ //! Context object which provides access to the current variables set of the template
+ Value context;
+ bool paramsParsed = false;
+
+ Value operator[](const std::string& paramName) const
+ {
+ auto p = args.find(paramName);
+ if (p == args.end())
+ return Value();
+
+ return p->second;
+ }
+};
+
+/*!
+ * \brief Information about one argument of the user-defined callable
+ *
+ * This structure is used as a description of the user-callable argument. Information from this structure is used
+ * by the Jinja2C++ engine to map actual call parameters to the expected ones by the user-defined callable.
+ */
+struct ArgInfo
+{
+ //! Name of the argument
+ std::string paramName;
+ //! Mandatory flag
+ bool isMandatory;
+ //! Default value for the argument
+ Value defValue;
+
+ ArgInfo(std::string name, bool isMandat = false, Value defVal = Value())
+ : paramName(std::move(name))
+ , isMandatory(isMandat)
+ , defValue(std::move(defVal)) {}
+};
+
+inline bool operator==(const ArgInfo& lhs, const ArgInfo& rhs)
+{
+ if (lhs.paramName != rhs.paramName)
+ return false;
+ if (lhs.isMandatory != rhs.isMandatory)
+ return false;
+ return lhs.defValue == rhs.defValue;
+}
+
+inline bool operator!=(const ArgInfo& lhs, const ArgInfo& rhs)
+{
+ return !(lhs == rhs);
+}
+
+template<typename T>
+struct ArgInfoT : public ArgInfo
+{
+ using type = T;
+
+ using ArgInfo::ArgInfo;
+ ArgInfoT(const ArgInfo& info)
+ : ArgInfo(info)
+ {
+ }
+ ArgInfoT(ArgInfo&& info) noexcept
+ : ArgInfo(std::move(info))
+ {
+ }
+};
+
+/*!
+ * \brief User-callable descriptor
+ *
+ * This descriptor is used for description of the user-defined callables passed to the Jinja2C++ engine. Information
+ * from this descriptor is used by the engine to properly parse and prepare of the call parameters and pass it to the
+ * user-callable. For instance, such kind of user-defined callable passed as a parameter:
+ * ```c++
+ * jinja2::UserCallable uc;
+ * uc.callable = [](auto& params)->jinja2::Value {
+ * auto str1 = params["str1"];
+ * auto str2 = params["str2"];
+ *
+ * if (str1.isString())
+ * return str1.asString() + " " + str2.asString();
+ *
+ * return str1.asWString() + L" " + str2.asWString();
+ * };
+ * uc.argsInfo = {{"str1", true}, {"str2", true}};
+ * params["test"] = std::move(uc);
+ * ```
+ * This declaration defines user-defined callable which takes two named parameters: `str1` and `str2`. Further, it's
+ * possible to call this user-defined callable from the Jinja2 template this way:
+ * ```jinja2
+ * {{ test('Hello', 'World!') }}
+ * ```
+ * or:
+ * ```
+ * {{ test(str2='World!', str1='Hello') }}
+ * ```
+ * Jinja2C++ engine maps actual call parameters according the information from \ref UserCallable::argsInfo field and
+ * pass them as a \ref UserCallableParams structure. Every named param (explicitly defined in the call or it's default value)
+ * passed throught \ref UserCallableParams::args field. Every extra positional param mentoined in call passed as \ref
+ * UserCallableParams::extraPosArgs. Every extra named param mentoined in call passed as \ref
+ * UserCallableParams::extraKwArgs.
+ *
+ * If any of argument, marked as `mandatory` in the \ref UserCallable::argsInfo field is missed in the point of the
+ * user-defined call the call is failed.
+ */
+struct JINJA2CPP_EXPORT UserCallable
+{
+ using UserCallableFunctionPtr = std::function<Value (const UserCallableParams&)>;
+ UserCallable() : m_counter(++m_gen) {}
+ UserCallable(const UserCallableFunctionPtr& fptr, const std::vector<ArgInfo>& argsInfos)
+ : callable(fptr)
+ , argsInfo(argsInfos)
+ , m_counter(++m_gen)
+ {
+ }
+ UserCallable(const UserCallable& other)
+ : callable(other.callable)
+ , argsInfo(other.argsInfo)
+ , m_counter(other.m_counter)
+ {
+ }
+ UserCallable& operator=(const UserCallable& other)
+ {
+ if (*this == other)
+ return *this;
+ UserCallable temp(other);
+
+ using std::swap;
+ swap(callable, temp.callable);
+ swap(argsInfo, temp.argsInfo);
+ swap(m_counter, temp.m_counter);
+
+ return *this;
+ }
+
+ UserCallable(UserCallable&& other) noexcept
+ : callable(std::move(other.callable))
+ , argsInfo(std::move(other.argsInfo))
+ , m_counter(other.m_counter)
+ {
+ }
+
+ UserCallable& operator=(UserCallable&& other) noexcept
+ {
+ callable = std::move(other.callable);
+ argsInfo = std::move(other.argsInfo);
+ m_counter = other.m_counter;
+
+ return *this;
+ }
+
+ bool IsEqual(const UserCallable& other) const
+ {
+ return m_counter == other.m_counter;
+ }
+
+ //! Functional object which is actually handle the call
+ UserCallableFunctionPtr callable;
+ //! Information about arguments of the user-defined callable
+ std::vector<ArgInfo> argsInfo;
+
+private:
+ static std::atomic_uint64_t m_gen;
+ uint64_t m_counter{};
+};
+
+bool operator==(const UserCallable& lhs, const UserCallable& rhs);
+bool operator!=(const UserCallable& lhs, const UserCallable& rhs);
+bool operator==(const types::ValuePtr<UserCallable>& lhs, const types::ValuePtr<UserCallable>& rhs);
+bool operator!=(const types::ValuePtr<UserCallable>& lhs, const types::ValuePtr<UserCallable>& rhs);
+
+
+inline Value::Value(const UserCallable& callable)
+ : m_data(types::MakeValuePtr<UserCallable>(callable))
+{
+}
+
+inline Value::Value(UserCallable&& callable)
+ : m_data(types::MakeValuePtr<UserCallable>(std::move(callable)))
+{
+}
+
+inline Value GenericMap::GetValueByName(const std::string& name) const
+{
+ return m_accessor ? m_accessor()->GetValueByName(name) : Value();
+}
+inline auto GenericMap::operator[](const std::string& name) const
+{
+ return GetValueByName(name);
+}
+
+inline Value::Value() = default;
+inline Value::Value(const Value& val) = default;
+inline Value::Value(Value&& val) noexcept
+ : m_data(std::move(val.m_data))
+{
+}
+inline Value::~Value() = default;
+inline Value& Value::operator=(const Value&) = default;
+inline Value& Value::operator=(Value&& val) noexcept
+{
+ if (this == &val)
+ return *this;
+
+ m_data.swap(val.m_data);
+ return *this;
+}
+inline Value::Value(const ValuesMap& map)
+ : m_data(types::MakeValuePtr<ValuesMap>(map))
+{
+}
+inline Value::Value(const ValuesList& list)
+ : m_data(types::MakeValuePtr<ValuesList>(list))
+{
+}
+inline Value::Value(ValuesList&& list) noexcept
+ : m_data(types::MakeValuePtr<ValuesList>(std::move(list)))
+{
+}
+inline Value::Value(ValuesMap&& map) noexcept
+ : m_data(types::MakeValuePtr<ValuesMap>(std::move(map)))
+{
+}
+
+} // namespace jinja2
+
+#endif // JINJA2CPP_VALUE_H
diff --git a/contrib/libs/jinja2cpp/include/jinja2cpp/value_ptr.h b/contrib/libs/jinja2cpp/include/jinja2cpp/value_ptr.h
new file mode 100644
index 0000000000..26eee6b6bb
--- /dev/null
+++ b/contrib/libs/jinja2cpp/include/jinja2cpp/value_ptr.h
@@ -0,0 +1,29 @@
+#ifndef JINJA2CPP_VALUE_PTR_H
+#define JINJA2CPP_VALUE_PTR_H
+
+#include "polymorphic_value.h"
+
+namespace jinja2 {
+namespace types {
+
+using namespace isocpp_p0201;
+
+template<typename T>
+using ValuePtr = polymorphic_value<T>;
+
+template<class T, class... Ts>
+ValuePtr<T> MakeValuePtr(Ts&&... ts)
+{
+ return make_polymorphic_value<T>(std::forward<Ts&&>(ts)...);
+}
+
+template<class T, class U, class... Ts>
+ValuePtr<T> MakeValuePtr(Ts&&... ts)
+{
+ return make_polymorphic_value<T, U>(std::forward<Ts>(ts)...);
+}
+
+} // namespace types
+} // namespace jinja2
+
+#endif // JINJA2CPP_VALUE_PTR_H
diff --git a/contrib/libs/jinja2cpp/src/ast_visitor.h b/contrib/libs/jinja2cpp/src/ast_visitor.h
new file mode 100644
index 0000000000..01b519829b
--- /dev/null
+++ b/contrib/libs/jinja2cpp/src/ast_visitor.h
@@ -0,0 +1,117 @@
+#ifndef JINJA2CPP_SRC_AST_VISITOR_H
+#define JINJA2CPP_SRC_AST_VISITOR_H
+
+namespace jinja2
+{
+class IRendererBase;
+class ExpressionEvaluatorBase;
+class Statement;
+class ForStatement;
+class IfStatement;
+class ElseBranchStatement;
+class SetStatement;
+class ParentBlockStatement;
+class BlockStatement;
+class ExtendsStatement;
+class IncludeStatement;
+class ImportStatement;
+class MacroStatement;
+class MacroCallStatement;
+class ComposedRenderer;
+class RawTextRenderer;
+class ExpressionRenderer;
+
+class StatementVisitor;
+
+class VisitableStatement
+{
+public:
+ virtual ~VisitableStatement() = default;
+
+ virtual void ApplyVisitor(StatementVisitor* visitor) = 0;
+ virtual void ApplyVisitor(StatementVisitor* visitor) const = 0;
+};
+
+#define VISITABLE_STATEMENT() \
+ void ApplyVisitor(StatementVisitor* visitor) override {visitor->DoVisit(this);} \
+ void ApplyVisitor(StatementVisitor* visitor) const override {visitor->DoVisit(this);} \
+
+namespace detail
+{
+template<typename Base, typename Type>
+class VisitorIfaceImpl : public Base
+{
+public:
+ using Base::DoVisit;
+
+ virtual void DoVisit(Type*) {}
+ virtual void DoVisit(const Type*) {}
+};
+
+template<typename Type>
+class VisitorIfaceImpl<void, Type>
+{
+public:
+ virtual void DoVisit(Type*) {}
+ virtual void DoVisit(const Type*) {}
+};
+
+template<typename Base, typename ... Types>
+struct VisitorBaseImpl;
+
+template<typename Base, typename T, typename ... Types>
+struct VisitorBaseImpl<Base, T, Types...>
+{
+ using current_base = VisitorIfaceImpl<Base, T>;
+ using base_type = typename VisitorBaseImpl<current_base, Types...>::base_type;
+};
+
+template<typename Base, typename T>
+struct VisitorBaseImpl<Base, T>
+{
+ using base_type = VisitorIfaceImpl<Base, T>;
+};
+
+
+template<typename ... Types>
+struct VisitorBase
+{
+ using type = typename VisitorBaseImpl<void, Types ...>::base_type;
+};
+} // namespace detail
+
+template<typename ... Types>
+using VisitorBase = typename detail::VisitorBase<Types...>::type;
+
+class StatementVisitor : public VisitorBase<
+ IRendererBase,
+ Statement,
+ ForStatement,
+ IfStatement,
+ ElseBranchStatement,
+ SetStatement,
+ ParentBlockStatement,
+ BlockStatement,
+ ExtendsStatement,
+ IncludeStatement,
+ ImportStatement,
+ MacroStatement,
+ MacroCallStatement,
+ ComposedRenderer,
+ RawTextRenderer,
+ ExpressionRenderer>
+{
+public:
+ void Visit(VisitableStatement* stmt)
+ {
+ stmt->ApplyVisitor(this);
+ }
+ void Visit(const VisitableStatement* stmt)
+ {
+ stmt->ApplyVisitor(this);
+ }
+};
+} // namespace jinja2
+
+
+#endif
diff --git a/contrib/libs/jinja2cpp/src/binding/rapid_json_serializer.cpp b/contrib/libs/jinja2cpp/src/binding/rapid_json_serializer.cpp
new file mode 100644
index 0000000000..1234759d27
--- /dev/null
+++ b/contrib/libs/jinja2cpp/src/binding/rapid_json_serializer.cpp
@@ -0,0 +1,127 @@
+#include "rapid_json_serializer.h"
+
+#include "../value_visitors.h"
+
+#include <rapidjson/prettywriter.h>
+
+namespace jinja2
+{
+namespace rapidjson_serializer
+{
+namespace
+{
+struct JsonInserter : visitors::BaseVisitor<rapidjson::Value>
+{
+ using BaseVisitor::operator();
+
+ explicit JsonInserter(rapidjson::Document::AllocatorType& allocator)
+ : m_allocator(allocator)
+ {
+ }
+
+ rapidjson::Value operator()(const ListAdapter& list) const
+ {
+ rapidjson::Value listValue(rapidjson::kArrayType);
+
+ for (auto& v : list)
+ {
+ listValue.PushBack(Apply<JsonInserter>(v, m_allocator), m_allocator);
+ }
+ return listValue;
+ }
+
+ rapidjson::Value operator()(const MapAdapter& map) const
+ {
+ rapidjson::Value mapNode(rapidjson::kObjectType);
+
+ const auto& keys = map.GetKeys();
+ for (auto& k : keys)
+ {
+ mapNode.AddMember(rapidjson::Value(k.c_str(), m_allocator), Apply<JsonInserter>(map.GetValueByName(k), m_allocator), m_allocator);
+ }
+
+ return mapNode;
+ }
+
+ rapidjson::Value operator()(const KeyValuePair& kwPair) const
+ {
+ rapidjson::Value pairNode(rapidjson::kObjectType);
+ pairNode.AddMember(rapidjson::Value(kwPair.key.c_str(), m_allocator), Apply<JsonInserter>(kwPair.value, m_allocator), m_allocator);
+
+ return pairNode;
+ }
+
+ rapidjson::Value operator()(const std::string& str) const { return rapidjson::Value(str.c_str(), m_allocator); }
+
+ rapidjson::Value operator()(const std::string_view& str) const
+ {
+ return rapidjson::Value(str.data(), static_cast<rapidjson::SizeType>(str.size()), m_allocator);
+ }
+
+ rapidjson::Value operator()(const std::wstring& str) const
+ {
+ auto s = ConvertString<std::string>(str);
+ return rapidjson::Value(s.c_str(), m_allocator);
+ }
+
+ rapidjson::Value operator()(const std::wstring_view& str) const
+ {
+ auto s = ConvertString<std::string>(str);
+ return rapidjson::Value(s.c_str(), m_allocator);
+ }
+
+ rapidjson::Value operator()(bool val) const { return rapidjson::Value(val); }
+
+ rapidjson::Value operator()(EmptyValue) const { return rapidjson::Value(); }
+
+ rapidjson::Value operator()(const Callable&) const { return rapidjson::Value("<callable>"); }
+
+ rapidjson::Value operator()(double val) const { return rapidjson::Value(val); }
+
+ rapidjson::Value operator()(int64_t val) const { return rapidjson::Value(val); }
+
+ rapidjson::Document::AllocatorType& m_allocator;
+};
+} // namespace
+
+DocumentWrapper::DocumentWrapper()
+ : m_document(std::make_shared<rapidjson::Document>())
+{
+}
+
+ValueWrapper DocumentWrapper::CreateValue(const InternalValue& value) const
+{
+ auto v = Apply<JsonInserter>(value, m_document->GetAllocator());
+ return ValueWrapper(std::move(v), m_document);
+}
+
+ValueWrapper::ValueWrapper(rapidjson::Value&& value, std::shared_ptr<rapidjson::Document> document)
+ : m_value(std::move(value))
+ , m_document(document)
+{
+}
+
+std::string ValueWrapper::AsString(const uint8_t indent) const
+{
+ using Writer = rapidjson::Writer<rapidjson::StringBuffer, rapidjson::Document::EncodingType, rapidjson::UTF8<>>;
+ using PrettyWriter = rapidjson::PrettyWriter<rapidjson::StringBuffer, rapidjson::Document::EncodingType, rapidjson::UTF8<>>;
+
+ rapidjson::StringBuffer buffer;
+ if (indent == 0)
+ {
+ Writer writer(buffer);
+ m_value.Accept(writer);
+ }
+ else
+ {
+ PrettyWriter writer(buffer);
+ writer.SetIndent(' ', indent);
+ writer.SetFormatOptions(rapidjson::kFormatSingleLineArray);
+ m_value.Accept(writer);
+ }
+
+ return buffer.GetString();
+}
+
+} // namespace rapidjson_serializer
+} // namespace jinja2
diff --git a/contrib/libs/jinja2cpp/src/binding/rapid_json_serializer.h b/contrib/libs/jinja2cpp/src/binding/rapid_json_serializer.h
new file mode 100644
index 0000000000..66e26c14da
--- /dev/null
+++ b/contrib/libs/jinja2cpp/src/binding/rapid_json_serializer.h
@@ -0,0 +1,50 @@
+#ifndef JINJA2CPP_SRC_RAPID_JSON_SERIALIZER_H
+#define JINJA2CPP_SRC_RAPID_JSON_SERIALIZER_H
+
+#include "../internal_value.h"
+
+#include <rapidjson/document.h>
+#include <rapidjson/rapidjson.h>
+
+#include <memory>
+
+namespace jinja2
+{
+namespace rapidjson_serializer
+{
+
+class ValueWrapper
+{
+ friend class DocumentWrapper;
+
+public:
+ ValueWrapper(ValueWrapper&&) = default;
+ ValueWrapper& operator=(ValueWrapper&&) = default;
+
+ std::string AsString(uint8_t indent = 0) const;
+
+private:
+ ValueWrapper(rapidjson::Value&& value, std::shared_ptr<rapidjson::Document> document);
+
+ rapidjson::Value m_value;
+ std::shared_ptr<rapidjson::Document> m_document;
+};
+
+class DocumentWrapper
+{
+public:
+ DocumentWrapper();
+
+ DocumentWrapper(DocumentWrapper&&) = default;
+ DocumentWrapper& operator=(DocumentWrapper&&) = default;
+
+ ValueWrapper CreateValue(const InternalValue& value) const;
+
+private:
+ std::shared_ptr<rapidjson::Document> m_document;
+};
+
+} // namespace rapidjson_serializer
+} // namespace jinja2
+
+#endif // JINJA2CPP_SRC_RAPID_JSON_SERIALIZER_H
diff --git a/contrib/libs/jinja2cpp/src/error_handling.h b/contrib/libs/jinja2cpp/src/error_handling.h
new file mode 100644
index 0000000000..db0f02ce52
--- /dev/null
+++ b/contrib/libs/jinja2cpp/src/error_handling.h
@@ -0,0 +1,63 @@
+#ifndef JINJA2CPP_SRC_ERROR_HANDLING_H
+#define JINJA2CPP_SRC_ERROR_HANDLING_H
+
+#include "lexer.h"
+#include <jinja2cpp/error_info.h>
+#include <contrib/restricted/expected-lite/include/nonstd/expected.hpp>
+
+#include <initializer_list>
+#include <vector>
+
+namespace jinja2
+{
+
+struct ParseError
+{
+ ParseError() = default;
+ ParseError(ErrorCode code, Token tok)
+ : errorCode(code)
+ , errorToken(tok)
+ {}
+
+ ParseError(ErrorCode code, Token tok, std::initializer_list<Token> toks)
+ : errorCode(code)
+ , errorToken(tok)
+ , relatedTokens(toks)
+ {}
+ ParseError(const ParseError&) = default;
+ ParseError(ParseError&& other) noexcept(true)
+ : errorCode(std::move(other.errorCode))
+ , errorToken(std::move(other.errorToken))
+ , relatedTokens(std::move(other.relatedTokens))
+ {}
+
+ ParseError& operator =(const ParseError&) = default;
+ ParseError& operator =(ParseError&& error) noexcept
+ {
+ if (this == &error)
+ return *this;
+
+ std::swap(errorCode, error.errorCode);
+ std::swap(errorToken, error.errorToken);
+ std::swap(relatedTokens, error.relatedTokens);
+
+ return *this;
+ }
+
+ ErrorCode errorCode;
+ Token errorToken;
+ std::vector<Token> relatedTokens;
+};
+
+inline auto MakeParseError(ErrorCode code, Token tok)
+{
+ return nonstd::make_unexpected(ParseError{code, tok});
+}
+
+inline auto MakeParseError(ErrorCode code, Token tok, std::initializer_list<Token> toks)
+{
+ return nonstd::make_unexpected(ParseError{code, tok, toks});
+}
+
+} // namespace jinja2
+#endif // JINJA2CPP_SRC_ERROR_HANDLING_H
diff --git a/contrib/libs/jinja2cpp/src/error_info.cpp b/contrib/libs/jinja2cpp/src/error_info.cpp
new file mode 100644
index 0000000000..25ff5dfee7
--- /dev/null
+++ b/contrib/libs/jinja2cpp/src/error_info.cpp
@@ -0,0 +1,289 @@
+#include "helpers.h"
+
+#include <fmt/format.h>
+#include <fmt/xchar.h>
+#include <jinja2cpp/error_info.h>
+#include <iterator>
+
+namespace
+{
+template<typename FmtCtx>
+struct ValueRenderer
+{
+ using CharT = typename FmtCtx::char_type;
+ FmtCtx* ctx;
+
+ explicit ValueRenderer(FmtCtx* c)
+ : ctx(c)
+ {
+ }
+
+ constexpr void operator()(bool val) const {
+ fmt::format_to(
+ ctx->out(),
+ UNIVERSAL_STR("{}").GetValue<CharT>(),
+ (val ? UNIVERSAL_STR("True").GetValue<CharT>(): UNIVERSAL_STR("False").GetValue<CharT>()));
+ }
+ void operator()(const jinja2::EmptyValue&) const { fmt::format_to(ctx->out(), UNIVERSAL_STR("").GetValue<CharT>()); }
+ template<typename CharU>
+ void operator()(const std::basic_string<CharU>& val) const
+ {
+ fmt::format_to(ctx->out(), UNIVERSAL_STR("{}").GetValue<CharT>(), jinja2::ConvertString<std::basic_string<CharT>>(val));
+ }
+
+ template<typename CharU>
+ void operator()(const std::basic_string_view<CharU>& val) const
+ {
+ fmt::format_to(ctx->out(), UNIVERSAL_STR("{}").GetValue<CharT>(), jinja2::ConvertString<std::basic_string<CharT>>(val));
+ }
+
+ void operator()(const jinja2::ValuesList& vals) const
+ {
+ fmt::format_to(ctx->out(), UNIVERSAL_STR("{{").GetValue<CharT>());
+ bool isFirst = true;
+ for (auto& val : vals)
+ {
+ if (isFirst)
+ isFirst = false;
+ else
+ fmt::format_to(ctx->out(), UNIVERSAL_STR(", ").GetValue<CharT>());
+ std::visit(ValueRenderer<FmtCtx>(ctx), val.data());
+ }
+ fmt::format_to(ctx->out(), UNIVERSAL_STR("}}").GetValue<CharT>());
+ }
+
+ void operator()(const jinja2::ValuesMap& vals) const
+ {
+ fmt::format_to(ctx->out(), UNIVERSAL_STR("{{").GetValue<CharT>());
+ bool isFirst = true;
+ for (auto& val : vals)
+ {
+ if (isFirst)
+ isFirst = false;
+ else
+ fmt::format_to(ctx->out(), UNIVERSAL_STR(", ").GetValue<CharT>());
+
+ fmt::format_to(ctx->out(), UNIVERSAL_STR("{{\"{}\",").GetValue<CharT>(), jinja2::ConvertString<std::basic_string<CharT>>(val.first));
+ std::visit(ValueRenderer<FmtCtx>(ctx), val.second.data());
+ fmt::format_to(ctx->out(), UNIVERSAL_STR("}}").GetValue<CharT>());
+ }
+ fmt::format_to(ctx->out(), UNIVERSAL_STR("}}").GetValue<CharT>());
+ }
+
+ template<typename T>
+ void operator()(const jinja2::RecWrapper<T>& val) const
+ {
+ this->operator()(const_cast<const T&>(*val));
+ }
+
+ void operator()(const jinja2::GenericMap& /*val*/) const {}
+
+ void operator()(const jinja2::GenericList& /*val*/) const {}
+
+ void operator()(const jinja2::UserCallable& /*val*/) const {}
+
+ template<typename T>
+ void operator()(const T& val) const
+ {
+ fmt::format_to(ctx->out(), UNIVERSAL_STR("{}").GetValue<CharT>(), val);
+ }
+};
+} // namespace
+
+namespace fmt
+{
+template<typename CharT>
+struct formatter<jinja2::Value, CharT>
+{
+ template<typename ParseContext>
+ constexpr auto parse(ParseContext& ctx)
+ {
+ return ctx.begin();
+ }
+
+ template<typename FormatContext>
+ auto format(const jinja2::Value& val, FormatContext& ctx)
+ {
+ std::visit(ValueRenderer<FormatContext>(&ctx), val.data());
+ return fmt::format_to(ctx.out(), UNIVERSAL_STR("").GetValue<CharT>());
+ }
+};
+} // namespace fmt
+
+namespace jinja2
+{
+
+template<typename CharT>
+void RenderErrorInfo(std::basic_string<CharT>& result, const ErrorInfoTpl<CharT>& errInfo)
+{
+ using string_t = std::basic_string<CharT>;
+ auto out = fmt::basic_memory_buffer<CharT>();
+
+ auto& loc = errInfo.GetErrorLocation();
+
+ fmt::format_to(std::back_inserter(out), UNIVERSAL_STR("{}:{}:{}: error: ").GetValue<CharT>(), ConvertString<string_t>(loc.fileName), loc.line, loc.col);
+ ErrorCode errCode = errInfo.GetCode();
+ switch (errCode)
+ {
+ case ErrorCode::Unspecified:
+ format_to(std::back_inserter(out), UNIVERSAL_STR("Parse error").GetValue<CharT>());
+ break;
+ case ErrorCode::UnexpectedException:
+ {
+ auto& extraParams = errInfo.GetExtraParams();
+ format_to(std::back_inserter(out), UNIVERSAL_STR("Unexpected exception occurred during template processing. Exception: {}").GetValue<CharT>(), extraParams[0]);
+ break;
+ }
+ case ErrorCode::MetadataParseError:
+ {
+ auto& extraParams = errInfo.GetExtraParams();
+ format_to(std::back_inserter(out), UNIVERSAL_STR("Error occurred during template metadata parsing. Error: {}").GetValue<CharT>(), extraParams[0]);
+ break;
+ }
+ case ErrorCode::YetUnsupported:
+ format_to(std::back_inserter(out), UNIVERSAL_STR("This feature has not been supported yet").GetValue<CharT>());
+ break;
+ case ErrorCode::FileNotFound:
+ format_to(std::back_inserter(out), UNIVERSAL_STR("File not found").GetValue<CharT>());
+ break;
+ case ErrorCode::ExpectedStringLiteral:
+ format_to(std::back_inserter(out), UNIVERSAL_STR("String expected").GetValue<CharT>());
+ break;
+ case ErrorCode::ExpectedIdentifier:
+ format_to(std::back_inserter(out), UNIVERSAL_STR("Identifier expected").GetValue<CharT>());
+ break;
+ case ErrorCode::ExpectedSquareBracket:
+ format_to(std::back_inserter(out), UNIVERSAL_STR("']' expected").GetValue<CharT>());
+ break;
+ case ErrorCode::ExpectedRoundBracket:
+ format_to(std::back_inserter(out), UNIVERSAL_STR("')' expected").GetValue<CharT>());
+ break;
+ case ErrorCode::ExpectedCurlyBracket:
+ format_to(std::back_inserter(out), UNIVERSAL_STR("'}}' expected").GetValue<CharT>());
+ break;
+ case ErrorCode::ExpectedToken:
+ {
+ auto& extraParams = errInfo.GetExtraParams();
+ format_to(std::back_inserter(out), UNIVERSAL_STR("Unexpected token '{}'").GetValue<CharT>(), extraParams[0]);
+ if (extraParams.size() > 1)
+ {
+ format_to(std::back_inserter(out), UNIVERSAL_STR(". Expected: ").GetValue<CharT>());
+ for (std::size_t i = 1; i < extraParams.size(); ++ i)
+ {
+ if (i != 1)
+ format_to(std::back_inserter(out), UNIVERSAL_STR(", ").GetValue<CharT>());
+ format_to(std::back_inserter(out), UNIVERSAL_STR("\'{}\'").GetValue<CharT>(), extraParams[i]);
+ }
+ }
+ break;
+ }
+ case ErrorCode::ExpectedExpression:
+ {
+ auto& extraParams = errInfo.GetExtraParams();
+ format_to(std::back_inserter(out), UNIVERSAL_STR("Expected expression, got: '{}'").GetValue<CharT>(), extraParams[0]);
+ break;
+ }
+ case ErrorCode::ExpectedEndOfStatement:
+ {
+ auto& extraParams = errInfo.GetExtraParams();
+ format_to(std::back_inserter(out), UNIVERSAL_STR("Expected end of statement, got: '{}'").GetValue<CharT>(), extraParams[0]);
+ break;
+ }
+ case ErrorCode::ExpectedRawEnd:
+ format_to(std::back_inserter(out), UNIVERSAL_STR("Expected end of raw block").GetValue<CharT>());
+ break;
+ case ErrorCode::ExpectedMetaEnd:
+ format_to(std::back_inserter(out), UNIVERSAL_STR("Expected end of meta block").GetValue<CharT>());
+ break;
+ case ErrorCode::UnexpectedToken:
+ {
+ auto& extraParams = errInfo.GetExtraParams();
+ format_to(std::back_inserter(out), UNIVERSAL_STR("Unexpected token: '{}'").GetValue<CharT>(), extraParams[0]);
+ break;
+ }
+ case ErrorCode::UnexpectedStatement:
+ {
+ auto& extraParams = errInfo.GetExtraParams();
+ format_to(std::back_inserter(out), UNIVERSAL_STR("Unexpected statement: '{}'").GetValue<CharT>(), extraParams[0]);
+ break;
+ }
+ case ErrorCode::UnexpectedCommentBegin:
+ format_to(std::back_inserter(out), UNIVERSAL_STR("Unexpected comment begin").GetValue<CharT>());
+ break;
+ case ErrorCode::UnexpectedCommentEnd:
+ format_to(std::back_inserter(out), UNIVERSAL_STR("Unexpected comment end").GetValue<CharT>());
+ break;
+ case ErrorCode::UnexpectedRawBegin:
+ format_to(std::back_inserter(out), UNIVERSAL_STR("Unexpected raw block begin").GetValue<CharT>());
+ break;
+ case ErrorCode::UnexpectedRawEnd:
+ format_to(std::back_inserter(out), UNIVERSAL_STR("Unexpected raw block end").GetValue<CharT>());
+ break;
+ case ErrorCode::UnexpectedMetaBegin:
+ format_to(std::back_inserter(out), UNIVERSAL_STR("Unexpected meta block begin").GetValue<CharT>());
+ break;
+ case ErrorCode::UnexpectedMetaEnd:
+ format_to(std::back_inserter(out), UNIVERSAL_STR("Unexpected meta block end").GetValue<CharT>());
+ break;
+ case ErrorCode::UnexpectedExprBegin:
+ format_to(std::back_inserter(out), UNIVERSAL_STR("Unexpected expression block begin").GetValue<CharT>());
+ break;
+ case ErrorCode::UnexpectedExprEnd:
+ format_to(std::back_inserter(out), UNIVERSAL_STR("Unexpected expression block end").GetValue<CharT>());
+ break;
+ case ErrorCode::UnexpectedStmtBegin:
+ format_to(std::back_inserter(out), UNIVERSAL_STR("Unexpected statement block begin").GetValue<CharT>());
+ break;
+ case ErrorCode::UnexpectedStmtEnd:
+ format_to(std::back_inserter(out), UNIVERSAL_STR("Unexpected statement block end").GetValue<CharT>());
+ break;
+ case ErrorCode::TemplateNotParsed:
+ format_to(std::back_inserter(out), UNIVERSAL_STR("Template not parsed").GetValue<CharT>());
+ break;
+ case ErrorCode::TemplateNotFound:
+ format_to(std::back_inserter(out), UNIVERSAL_STR("Template(s) not found: {}").GetValue<CharT>(), errInfo.GetExtraParams()[0]);
+ break;
+ case ErrorCode::InvalidTemplateName:
+ format_to(std::back_inserter(out), UNIVERSAL_STR("Invalid template name: {}").GetValue<CharT>(), errInfo.GetExtraParams()[0]);
+ break;
+ case ErrorCode::InvalidValueType:
+ format_to(std::back_inserter(out), UNIVERSAL_STR("Invalid value type").GetValue<CharT>());
+ break;
+ case ErrorCode::ExtensionDisabled:
+ format_to(std::back_inserter(out), UNIVERSAL_STR("Extension disabled").GetValue<CharT>());
+ break;
+ case ErrorCode::TemplateEnvAbsent:
+ format_to(std::back_inserter(out), UNIVERSAL_STR("Template environment doesn't set").GetValue<CharT>());
+ break;
+ }
+ format_to(std::back_inserter(out), UNIVERSAL_STR("\n{}").GetValue<CharT>(), errInfo.GetLocationDescr());
+ result = to_string(out);
+}
+
+template<>
+std::string ErrorInfoTpl<char>::ToString() const
+{
+ std::string result;
+ RenderErrorInfo(result, *this);
+ return result;
+}
+
+template<>
+std::wstring ErrorInfoTpl<wchar_t>::ToString() const
+{
+ std::wstring result;
+ RenderErrorInfo(result, *this);
+ return result;
+}
+
+std::ostream& operator << (std::ostream& os, const ErrorInfo& res)
+{
+ os << res.ToString();
+ return os;
+}
+std::wostream& operator << (std::wostream& os, const ErrorInfoW& res)
+{
+ os << res.ToString();
+ return os;
+}
+} // namespace jinja2
diff --git a/contrib/libs/jinja2cpp/src/expression_evaluator.cpp b/contrib/libs/jinja2cpp/src/expression_evaluator.cpp
new file mode 100644
index 0000000000..136e33d8fc
--- /dev/null
+++ b/contrib/libs/jinja2cpp/src/expression_evaluator.cpp
@@ -0,0 +1,602 @@
+#include "expression_evaluator.h"
+#include "filters.h"
+#include "generic_adapters.h"
+#include "internal_value.h"
+#include "out_stream.h"
+#include "testers.h"
+#include "value_visitors.h"
+
+#include <boost/algorithm/string/join.hpp>
+#include <boost/container/small_vector.hpp>
+
+#include <cmath>
+#include <stack>
+
+namespace jinja2
+{
+
+void ExpressionEvaluatorBase::Render(OutStream& stream, RenderContext& values)
+{
+ auto val = Evaluate(values);
+ stream.WriteValue(val);
+}
+
+
+InternalValue FullExpressionEvaluator::Evaluate(RenderContext& values)
+{
+ if (!m_expression)
+ return InternalValue();
+
+ auto result = m_expression->Evaluate(values);
+
+ if (m_tester && !m_tester->Evaluate(values))
+ return m_tester->EvaluateAltValue(values);
+
+ return result;
+}
+
+void FullExpressionEvaluator::Render(OutStream& stream, RenderContext& values)
+{
+ if (!m_tester)
+ m_expression->Render(stream, values);
+ else
+ Expression::Render(stream, values);
+}
+
+InternalValue ValueRefExpression::Evaluate(RenderContext& values)
+{
+ bool found = false;
+ auto p = values.FindValue(m_valueName, found);
+ if (found)
+ return p->second;
+
+ return InternalValue();
+}
+
+InternalValue SubscriptExpression::Evaluate(RenderContext& values)
+{
+ InternalValue cur = m_value->Evaluate(values);
+
+ for (auto idx : m_subscriptExprs)
+ {
+ auto subscript = idx->Evaluate(values);
+ auto newVal = Subscript(cur, subscript, &values);
+ if (cur.ShouldExtendLifetime())
+ newVal.SetParentData(cur);
+ std::swap(newVal, cur);
+ }
+
+ return cur;
+}
+
+InternalValue FilteredExpression::Evaluate(RenderContext& values)
+{
+ auto origResult = m_expression->Evaluate(values);
+ return m_filter->Evaluate(origResult, values);
+}
+
+InternalValue UnaryExpression::Evaluate(RenderContext& values)
+{
+ return Apply<visitors::UnaryOperation>(m_expr->Evaluate(values), m_oper);
+}
+
+BinaryExpression::BinaryExpression(BinaryExpression::Operation oper, ExpressionEvaluatorPtr<> leftExpr, ExpressionEvaluatorPtr<> rightExpr)
+ : m_oper(oper)
+ , m_leftExpr(leftExpr)
+ , m_rightExpr(rightExpr)
+{
+ if (m_oper == In)
+ {
+ CallParamsInfo params;
+ params.kwParams["seq"] = rightExpr;
+ m_inTester = CreateTester("in", params);
+ }
+}
+
+InternalValue BinaryExpression::Evaluate(RenderContext& context)
+{
+ InternalValue leftVal = m_leftExpr->Evaluate(context);
+ InternalValue rightVal = m_oper == In ? InternalValue() : m_rightExpr->Evaluate(context);
+ InternalValue result;
+
+ switch (m_oper)
+ {
+ case jinja2::BinaryExpression::LogicalAnd:
+ {
+ bool left = ConvertToBool(leftVal);
+ if (left)
+ left = ConvertToBool(rightVal);
+ result = static_cast<bool>(left);
+ break;
+ }
+ case jinja2::BinaryExpression::LogicalOr:
+ {
+ bool left = ConvertToBool(leftVal);
+ if (!left)
+ left = ConvertToBool(rightVal);
+ result = static_cast<bool>(left);
+ break;
+ }
+ case jinja2::BinaryExpression::LogicalEq:
+ case jinja2::BinaryExpression::LogicalNe:
+ case jinja2::BinaryExpression::LogicalGt:
+ case jinja2::BinaryExpression::LogicalLt:
+ case jinja2::BinaryExpression::LogicalGe:
+ case jinja2::BinaryExpression::LogicalLe:
+ case jinja2::BinaryExpression::Plus:
+ case jinja2::BinaryExpression::Minus:
+ case jinja2::BinaryExpression::Mul:
+ case jinja2::BinaryExpression::Div:
+ case jinja2::BinaryExpression::DivReminder:
+ case jinja2::BinaryExpression::DivInteger:
+ case jinja2::BinaryExpression::Pow:
+ result = Apply2<visitors::BinaryMathOperation>(leftVal, rightVal, m_oper);
+ break;
+ case jinja2::BinaryExpression::In:
+ {
+ result = m_inTester->Test(leftVal, context);
+ break;
+ }
+ case jinja2::BinaryExpression::StringConcat:
+ {
+ auto leftStr = context.GetRendererCallback()->GetAsTargetString(leftVal);
+ auto rightStr = context.GetRendererCallback()->GetAsTargetString(rightVal);
+ TargetString resultStr;
+ std::string* nleftStr = GetIf<std::string>(&leftStr);
+ if (nleftStr != nullptr)
+ {
+ auto* nrightStr = GetIf<std::string>(&rightStr);
+ resultStr = *nleftStr + *nrightStr;
+ }
+ else
+ {
+ auto* wleftStr = GetIf<std::wstring>(&leftStr);
+ auto* wrightStr = GetIf<std::wstring>(&rightStr);
+ resultStr = *wleftStr + *wrightStr;
+ }
+ result = InternalValue(std::move(resultStr));
+ break;
+ }
+ default:
+ break;
+ }
+ return result;
+}
+
+InternalValue TupleCreator::Evaluate(RenderContext& context)
+{
+ InternalValueList result;
+ for (auto& e : m_exprs)
+ {
+ result.push_back(e->Evaluate(context));
+ }
+
+ return ListAdapter::CreateAdapter(std::move(result));
+}
+
+InternalValue DictCreator::Evaluate(RenderContext& context)
+{
+ InternalValueMap result;
+ for (auto& e : m_exprs)
+ {
+ result[e.first] = e.second->Evaluate(context);
+ }
+
+ return CreateMapAdapter(std::move(result));;
+}
+
+ExpressionFilter::ExpressionFilter(const std::string& filterName, CallParamsInfo params)
+{
+ m_filter = CreateFilter(filterName, std::move(params));
+ if (!m_filter)
+ throw std::runtime_error("Can't find filter '" + filterName + "'");
+}
+
+InternalValue ExpressionFilter::Evaluate(const InternalValue& baseVal, RenderContext& context)
+{
+ if (m_parentFilter)
+ return m_filter->Filter(m_parentFilter->Evaluate(baseVal, context), context);
+
+ return m_filter->Filter(baseVal, context);
+}
+
+IsExpression::IsExpression(ExpressionEvaluatorPtr<> value, const std::string& tester, CallParamsInfo params)
+ : m_value(value)
+{
+ m_tester = CreateTester(tester, std::move(params));
+ if (!m_tester)
+ throw std::runtime_error("Can't find tester '" + tester + "'");
+}
+
+InternalValue IsExpression::Evaluate(RenderContext& context)
+{
+ return m_tester->Test(m_value->Evaluate(context), context);
+}
+
+bool IfExpression::Evaluate(RenderContext& context)
+{
+ return ConvertToBool(m_testExpr->Evaluate(context));
+}
+
+InternalValue IfExpression::EvaluateAltValue(RenderContext& context)
+{
+ return m_altValue ? m_altValue->Evaluate(context) : InternalValue();
+}
+
+/*
+InternalValue DictionaryCreator::Evaluate(RenderContext& context)
+{
+ ValuesMap result;
+ for (auto& i : m_items)
+ {
+ result[i.first] = i.second->Evaluate(context);
+ }
+
+ return result;
+}*/
+
+InternalValue CallExpression::Evaluate(RenderContext& values)
+{
+ auto fn = m_valueRef->Evaluate(values);
+
+ auto fnId = ConvertToInt(fn, InvalidFn);
+
+
+ switch (fnId)
+ {
+ case RangeFn:
+ return CallGlobalRange(values);
+ case LoopCycleFn:
+ return CallLoopCycle(values);
+ default:
+ return CallArbitraryFn(values);
+ }
+}
+
+void CallExpression::Render(OutStream& stream, RenderContext& values)
+{
+ auto fnVal = m_valueRef->Evaluate(values);
+ const Callable* callable = GetIf<Callable>(&fnVal);
+ if (callable == nullptr)
+ {
+ fnVal = Subscript(fnVal, std::string("operator()"), &values);
+ callable = GetIf<Callable>(&fnVal);
+ if (callable == nullptr)
+ {
+ Expression::Render(stream, values);
+ return;
+ }
+ }
+
+ auto callParams = helpers::EvaluateCallParams(m_params, values);
+
+ if (callable->GetType() == Callable::Type::Expression)
+ {
+ stream.WriteValue(callable->GetExpressionCallable()(callParams, values));
+ }
+ else
+ {
+ callable->GetStatementCallable()(callParams, stream, values);
+ }
+}
+
+InternalValue CallExpression::CallArbitraryFn(RenderContext& values)
+{
+ auto fnVal = m_valueRef->Evaluate(values);
+ Callable* callable = GetIf<Callable>(&fnVal);
+ if (callable == nullptr)
+ {
+ fnVal = Subscript(fnVal, std::string("operator()"), nullptr);
+ callable = GetIf<Callable>(&fnVal);
+ if (callable == nullptr)
+ return InternalValue();
+ }
+
+ auto kind = callable->GetKind();
+ if (kind != Callable::GlobalFunc && kind != Callable::UserCallable && kind != Callable::Macro)
+ return InternalValue();
+
+ auto callParams = helpers::EvaluateCallParams(m_params, values);
+
+ if (callable->GetType() == Callable::Type::Expression)
+ {
+ return callable->GetExpressionCallable()(callParams, values);
+ }
+
+ TargetString resultStr;
+ auto stream = values.GetRendererCallback()->GetStreamOnString(resultStr);
+ callable->GetStatementCallable()(callParams, stream, values);
+ return resultStr;
+}
+
+InternalValue CallExpression::CallGlobalRange(RenderContext& values)
+{
+ bool isArgsParsed = true;
+
+ auto args = helpers::ParseCallParamsInfo({ { "start" }, { "stop", true }, { "step" } }, m_params, isArgsParsed);
+ if (!isArgsParsed)
+ return InternalValue();
+
+
+ auto startExpr = args["start"];
+ auto stopExpr = args["stop"];
+ auto stepExpr = args["step"];
+
+ InternalValue startVal = startExpr ? startExpr->Evaluate(values) : InternalValue();
+ InternalValue stopVal = stopExpr ? stopExpr->Evaluate(values) : InternalValue();
+ InternalValue stepVal = stepExpr ? stepExpr->Evaluate(values) : InternalValue();
+
+ int64_t start = Apply<visitors::IntegerEvaluator>(startVal);
+ int64_t stop = Apply<visitors::IntegerEvaluator>(stopVal);
+ int64_t step = Apply<visitors::IntegerEvaluator>(stepVal);
+
+ if (!stepExpr)
+ {
+ step = 1;
+ }
+ else
+ {
+ if (step == 0)
+ return InternalValue();
+ }
+
+ auto distance = stop - start;
+ auto items_count = distance / step;
+ items_count = items_count < 0 ? 0 : static_cast<size_t>(items_count);
+
+ return ListAdapter::CreateAdapter(static_cast<size_t>(items_count),
+ [start, step](size_t idx) { return InternalValue(static_cast<int64_t>(start + step * idx)); });
+}
+
+InternalValue CallExpression::CallLoopCycle(RenderContext& values)
+{
+ bool loopFound = false;
+ auto loopValP = values.FindValue("loop", loopFound);
+ if (!loopFound)
+ return InternalValue();
+
+ auto loop = GetIf<MapAdapter>(&loopValP->second);
+ int64_t baseIdx = Apply<visitors::IntegerEvaluator>(loop->GetValueByName("index0"));
+ auto idx = static_cast<size_t>(baseIdx % m_params.posParams.size());
+ return m_params.posParams[idx]->Evaluate(values);
+}
+
+
+void SetupGlobals(InternalValueMap& globalParams)
+{
+ globalParams["range"] = InternalValue(static_cast<int64_t>(RangeFn));
+ // globalParams["loop"] = MapAdapter::CreateAdapter(InternalValueMap{{"cycle", InternalValue(static_cast<int64_t>(LoopCycleFn))}});
+}
+
+namespace helpers
+{
+enum ArgState
+{
+ NotFound,
+ NotFoundMandatory,
+ Keyword,
+ Positional,
+ Ignored
+};
+
+enum ParamState
+{
+ UnknownPos,
+ UnknownKw,
+ MappedPos,
+ MappedKw,
+};
+
+template<typename Result>
+struct ParsedArgumentDefaultValGetter;
+
+template<>
+struct ParsedArgumentDefaultValGetter<ParsedArguments>
+{
+ static auto Get(const InternalValue& val) { return val; }
+};
+
+template<>
+struct ParsedArgumentDefaultValGetter<ParsedArgumentsInfo>
+{
+ static auto Get(const InternalValue& val) { return std::make_shared<ConstantExpression>(val); }
+};
+
+template<typename Result, typename T, typename P>
+Result ParseCallParamsImpl(const T& args, const P& params, bool& isSucceeded)
+{
+ struct ArgInfo
+ {
+ ArgState state = NotFound;
+ int prevNotFound = -1;
+ int nextNotFound = -1;
+ const ArgumentInfo* info = nullptr;
+ };
+
+ boost::container::small_vector<ArgInfo, 8> argsInfo(args.size());
+ boost::container::small_vector<ParamState, 8> posParamsInfo(params.posParams.size());
+
+ isSucceeded = true;
+
+ Result result;
+
+ int argIdx = 0;
+ int firstMandatoryIdx = -1;
+ int prevNotFound = -1;
+ int foundKwArgs = 0;
+ (void)foundKwArgs; // extremely odd bug in clang warning
+ // Wunused-but-set-variable
+
+ // Find all provided keyword args
+ for (auto& argInfo : args)
+ {
+ argsInfo[argIdx].info = &argInfo;
+
+ if (argInfo.name == "*args" || argInfo.name=="**kwargs")
+ {
+ argsInfo[argIdx ++].state = Ignored;
+ continue;
+ }
+
+ auto p = params.kwParams.find(argInfo.name);
+ if (p != params.kwParams.end())
+ {
+ result.args[argInfo.name] = p->second;
+ argsInfo[argIdx].state = Keyword;
+ ++foundKwArgs;
+ }
+ else
+ {
+ if (argInfo.mandatory)
+ {
+ argsInfo[argIdx].state = NotFoundMandatory;
+ if (firstMandatoryIdx == -1)
+ firstMandatoryIdx = argIdx;
+ }
+ else
+ {
+ argsInfo[argIdx].state = NotFound;
+ }
+
+
+ if (prevNotFound != -1)
+ argsInfo[prevNotFound].nextNotFound = argIdx;
+
+ argsInfo[argIdx].prevNotFound = prevNotFound;
+ prevNotFound = argIdx;
+ }
+
+
+ ++ argIdx;
+ }
+
+ std::size_t startPosArg = firstMandatoryIdx == -1 ? 0 : firstMandatoryIdx;
+ std::size_t curPosArg = startPosArg;
+ std::size_t eatenPosArgs = 0;
+
+ // Determine the range for positional arguments scanning
+ bool isFirstTime = true;
+ for (; eatenPosArgs < posParamsInfo.size() && startPosArg < args.size(); eatenPosArgs = eatenPosArgs + (argsInfo[startPosArg].state == Ignored ? 0 : 1))
+ {
+ if (isFirstTime)
+ {
+ for (; startPosArg < args.size() && (argsInfo[startPosArg].state == Keyword || argsInfo[startPosArg].state == Positional); ++ startPosArg)
+ ;
+
+ isFirstTime = false;
+ if (startPosArg == args.size())
+ break;
+ continue;
+ }
+
+ prevNotFound = argsInfo[startPosArg].prevNotFound;
+ if (prevNotFound != -1)
+ {
+ startPosArg = static_cast<std::size_t>(prevNotFound);
+ }
+ else if (curPosArg == args.size())
+ {
+ break;
+ }
+ else
+ {
+ int nextPosArg = argsInfo[curPosArg].nextNotFound;
+ if (nextPosArg == -1)
+ break;
+ curPosArg = static_cast<std::size_t>(nextPosArg);
+ }
+ }
+
+ // Map positional params to the desired arguments
+ auto curArg = static_cast<int>(startPosArg);
+ for (std::size_t idx = 0; idx < eatenPosArgs && curArg != -1 && static_cast<size_t>(curArg) < argsInfo.size(); ++ idx, curArg = argsInfo[curArg].nextNotFound)
+ {
+ if (argsInfo[curArg].state == Ignored)
+ continue;
+
+ result.args[argsInfo[curArg].info->name] = params.posParams[idx];
+ argsInfo[curArg].state = Positional;
+ }
+
+ // Fill default arguments (if missing) and check for mandatory
+ for (std::size_t idx = 0; idx < argsInfo.size(); ++ idx)
+ {
+ auto& argInfo = argsInfo[idx];
+ switch (argInfo.state)
+ {
+ case Positional:
+ case Keyword:
+ case Ignored:
+ continue;
+ case NotFound:
+ {
+ if (!IsEmpty(argInfo.info->defaultVal))
+ {
+#if __cplusplus >= 201703L
+ if constexpr (std::is_same<Result, ParsedArgumentsInfo>::value)
+ result.args[argInfo.info->name] = std::make_shared<ConstantExpression>(argInfo.info->defaultVal);
+ else
+ result.args[argInfo.info->name] = argInfo.info->defaultVal;
+#else
+ result.args[argInfo.info->name] = ParsedArgumentDefaultValGetter<Result>::Get(argInfo.info->defaultVal);
+#endif
+ }
+ break;
+ }
+ case NotFoundMandatory:
+ isSucceeded = false;
+ break;
+ }
+ }
+
+ // Fill the extra positional and kw-args
+ for (auto& kw : params.kwParams)
+ {
+ if (result.args.find(kw.first) != result.args.end())
+ continue;
+
+ result.extraKwArgs[kw.first] = kw.second;
+ }
+
+ for (auto idx = eatenPosArgs; idx < params.posParams.size(); ++ idx)
+ result.extraPosArgs.push_back(params.posParams[idx]);
+
+
+ return result;
+}
+
+ParsedArguments ParseCallParams(const std::initializer_list<ArgumentInfo>& args, const CallParams& params, bool& isSucceeded)
+{
+ return ParseCallParamsImpl<ParsedArguments>(args, params, isSucceeded);
+}
+
+ParsedArguments ParseCallParams(const std::vector<ArgumentInfo>& args, const CallParams& params, bool& isSucceeded)
+{
+ return ParseCallParamsImpl<ParsedArguments>(args, params, isSucceeded);
+}
+
+ParsedArgumentsInfo ParseCallParamsInfo(const std::initializer_list<ArgumentInfo>& args, const CallParamsInfo& params, bool& isSucceeded)
+{
+ return ParseCallParamsImpl<ParsedArgumentsInfo>(args, params, isSucceeded);
+}
+
+ParsedArgumentsInfo ParseCallParamsInfo(const std::vector<ArgumentInfo>& args, const CallParamsInfo& params, bool& isSucceeded)
+{
+ return ParseCallParamsImpl<ParsedArgumentsInfo>(args, params, isSucceeded);
+}
+
+CallParams EvaluateCallParams(const CallParamsInfo& info, RenderContext& context)
+{
+ CallParams result;
+
+ for (auto& p : info.posParams)
+ result.posParams.push_back(p->Evaluate(context));
+
+ for (auto& kw : info.kwParams)
+ result.kwParams[kw.first] = kw.second->Evaluate(context);
+
+ return result;
+}
+
+} // namespace helpers
+} // namespace jinja2
diff --git a/contrib/libs/jinja2cpp/src/expression_evaluator.h b/contrib/libs/jinja2cpp/src/expression_evaluator.h
new file mode 100644
index 0000000000..06b1c40f60
--- /dev/null
+++ b/contrib/libs/jinja2cpp/src/expression_evaluator.h
@@ -0,0 +1,619 @@
+#ifndef JINJA2CPP_SRC_EXPRESSION_EVALUATOR_H
+#define JINJA2CPP_SRC_EXPRESSION_EVALUATOR_H
+
+#include "internal_value.h"
+#include "render_context.h"
+
+#include <jinja2cpp/utils/i_comparable.h>
+
+#include <memory>
+#include <limits>
+
+namespace jinja2
+{
+
+enum
+{
+ InvalidFn = -1,
+ RangeFn = 1,
+ LoopCycleFn = 2
+};
+
+class ExpressionEvaluatorBase : public IComparable
+{
+public:
+ virtual ~ExpressionEvaluatorBase() {}
+
+ virtual InternalValue Evaluate(RenderContext& values) = 0;
+ virtual void Render(OutStream& stream, RenderContext& values);
+};
+
+template<typename T = ExpressionEvaluatorBase>
+using ExpressionEvaluatorPtr = std::shared_ptr<T>;
+using Expression = ExpressionEvaluatorBase;
+
+inline bool operator==(const ExpressionEvaluatorPtr<>& lhs, const ExpressionEvaluatorPtr<>& rhs)
+{
+ if (lhs && rhs && !lhs->IsEqual(*rhs))
+ return false;
+ if ((lhs && !rhs) || (!lhs && rhs))
+ return false;
+ return true;
+}
+inline bool operator!=(const ExpressionEvaluatorPtr<>& lhs, const ExpressionEvaluatorPtr<>& rhs)
+{
+ return !(lhs == rhs);
+}
+
+struct CallParams
+{
+ std::unordered_map<std::string, InternalValue> kwParams;
+ std::vector<InternalValue> posParams;
+};
+
+inline bool operator==(const CallParams& lhs, const CallParams& rhs)
+{
+ if (lhs.kwParams != rhs.kwParams)
+ return false;
+ if (lhs.posParams != rhs.posParams)
+ return false;
+ return true;
+}
+
+inline bool operator!=(const CallParams& lhs, const CallParams& rhs)
+{
+ return !(lhs == rhs);
+}
+
+struct CallParamsInfo
+{
+ std::unordered_map<std::string, ExpressionEvaluatorPtr<>> kwParams;
+ std::vector<ExpressionEvaluatorPtr<>> posParams;
+};
+
+inline bool operator==(const CallParamsInfo& lhs, const CallParamsInfo& rhs)
+{
+ if (lhs.kwParams != rhs.kwParams)
+ return false;
+ if (lhs.posParams != rhs.posParams)
+ return false;
+ return true;
+}
+
+inline bool operator!=(const CallParamsInfo& lhs, const CallParamsInfo& rhs)
+{
+ return !(lhs == rhs);
+}
+
+struct ArgumentInfo
+{
+ std::string name;
+ bool mandatory = false;
+ InternalValue defaultVal;
+
+ ArgumentInfo(std::string argName, bool isMandatory = false, InternalValue def = InternalValue())
+ : name(std::move(argName))
+ , mandatory(isMandatory)
+ , defaultVal(std::move(def))
+ {
+ }
+};
+
+inline bool operator==(const ArgumentInfo& lhs, const ArgumentInfo& rhs)
+{
+ if (lhs.name != rhs.name)
+ return false;
+ if (lhs.mandatory != rhs.mandatory)
+ return false;
+ if (!(lhs.defaultVal == rhs.defaultVal))
+ return false;
+ return true;
+}
+
+inline bool operator!=(const ArgumentInfo& lhs, const ArgumentInfo& rhs)
+{
+ return !(lhs == rhs);
+}
+
+struct ParsedArgumentsInfo
+{
+ std::unordered_map<std::string, ExpressionEvaluatorPtr<>> args;
+ std::unordered_map<std::string, ExpressionEvaluatorPtr<>> extraKwArgs;
+ std::vector<ExpressionEvaluatorPtr<>> extraPosArgs;
+
+ ExpressionEvaluatorPtr<> operator[](const std::string& name) const
+ {
+ auto p = args.find(name);
+ if (p == args.end())
+ return ExpressionEvaluatorPtr<>();
+
+ return p->second;
+ }
+};
+
+inline bool operator==(const ParsedArgumentsInfo& lhs, const ParsedArgumentsInfo& rhs)
+{
+ if (lhs.args != rhs.args)
+ return false;
+ if (lhs.extraKwArgs != rhs.extraKwArgs)
+ return false;
+ if (lhs.extraPosArgs != rhs.extraPosArgs)
+ return false;
+ return true;
+}
+
+inline bool operator!=(const ParsedArgumentsInfo& lhs, const ParsedArgumentsInfo& rhs)
+{
+ return !(lhs == rhs);
+}
+
+struct ParsedArguments
+{
+ std::unordered_map<std::string, InternalValue> args;
+ std::unordered_map<std::string, InternalValue> extraKwArgs;
+ std::vector<InternalValue> extraPosArgs;
+
+ InternalValue operator[](const std::string& name) const
+ {
+ auto p = args.find(name);
+ if (p == args.end())
+ return InternalValue();
+
+ return p->second;
+ }
+};
+
+inline bool operator==(const ParsedArguments& lhs, const ParsedArguments& rhs)
+{
+ if (lhs.args != rhs.args)
+ return false;
+ if (lhs.extraKwArgs != rhs.extraKwArgs)
+ return false;
+ if (lhs.extraPosArgs != rhs.extraPosArgs)
+ return false;
+ return true;
+}
+
+inline bool operator!=(const ParsedArguments& lhs, const ParsedArguments& rhs)
+{
+ return !(lhs == rhs);
+}
+
+class ExpressionFilter;
+class IfExpression;
+
+class FullExpressionEvaluator : public ExpressionEvaluatorBase
+{
+public:
+ void SetExpression(ExpressionEvaluatorPtr<Expression> expr)
+ {
+ m_expression = std::move(expr);
+ }
+ void SetTester(ExpressionEvaluatorPtr<IfExpression> expr)
+ {
+ m_tester = std::move(expr);
+ }
+ InternalValue Evaluate(RenderContext& values) override;
+ void Render(OutStream &stream, RenderContext &values) override;
+
+ bool IsEqual(const IComparable& other) const override
+ {
+ const auto* eval = dynamic_cast<const FullExpressionEvaluator*>(&other);
+ if (!eval)
+ return false;
+ if (m_expression != eval->m_expression)
+ return false;
+ if (m_tester != eval->m_tester)
+ return false;
+ return true;
+ }
+private:
+ ExpressionEvaluatorPtr<Expression> m_expression;
+ ExpressionEvaluatorPtr<IfExpression> m_tester;
+};
+
+class ValueRefExpression : public Expression
+{
+public:
+ ValueRefExpression(std::string valueName)
+ : m_valueName(std::move(valueName))
+ {
+ }
+ InternalValue Evaluate(RenderContext& values) override;
+
+ bool IsEqual(const IComparable& other) const override
+ {
+ auto* value = dynamic_cast<const ValueRefExpression*>(&other);
+ if (!value)
+ return false;
+ return m_valueName != value->m_valueName;
+ }
+private:
+ std::string m_valueName;
+};
+
+class SubscriptExpression : public Expression
+{
+public:
+ SubscriptExpression(ExpressionEvaluatorPtr<Expression> value)
+ : m_value(value)
+ {
+ }
+ InternalValue Evaluate(RenderContext& values) override;
+ void AddIndex(ExpressionEvaluatorPtr<Expression> value)
+ {
+ m_subscriptExprs.push_back(value);
+ }
+
+ bool IsEqual(const IComparable& other) const override
+ {
+ auto* otherPtr = dynamic_cast<const SubscriptExpression*>(&other);
+ if (!otherPtr)
+ return false;
+ if (m_value != otherPtr->m_value)
+ return false;
+ if (m_subscriptExprs != otherPtr->m_subscriptExprs)
+ return false;
+ return true;
+ }
+
+private:
+ ExpressionEvaluatorPtr<Expression> m_value;
+ std::vector<ExpressionEvaluatorPtr<Expression>> m_subscriptExprs;
+};
+
+class FilteredExpression : public Expression
+{
+public:
+ explicit FilteredExpression(ExpressionEvaluatorPtr<Expression> expression, ExpressionEvaluatorPtr<ExpressionFilter> filter)
+ : m_expression(std::move(expression))
+ , m_filter(std::move(filter))
+ {
+ }
+ InternalValue Evaluate(RenderContext&) override;
+ bool IsEqual(const IComparable& other) const override
+ {
+ auto* otherPtr = dynamic_cast<const FilteredExpression*>(&other);
+ if (!otherPtr)
+ return false;
+ if (m_expression != otherPtr->m_expression)
+ return false;
+ if (m_filter != otherPtr->m_filter)
+ return false;
+ return true;
+ }
+
+private:
+ ExpressionEvaluatorPtr<Expression> m_expression;
+ ExpressionEvaluatorPtr<ExpressionFilter> m_filter;
+};
+
+class ConstantExpression : public Expression
+{
+public:
+ ConstantExpression(InternalValue constant)
+ : m_constant(constant)
+ {}
+ InternalValue Evaluate(RenderContext&) override
+ {
+ return m_constant;
+ }
+
+ bool IsEqual(const IComparable& other) const override
+ {
+ auto* otherVal = dynamic_cast<const ConstantExpression*>(&other);
+ if (!otherVal)
+ return false;
+ return m_constant == otherVal->m_constant;
+ }
+private:
+ InternalValue m_constant;
+};
+
+class TupleCreator : public Expression
+{
+public:
+ TupleCreator(std::vector<ExpressionEvaluatorPtr<>> exprs)
+ : m_exprs(std::move(exprs))
+ {
+ }
+
+ InternalValue Evaluate(RenderContext&) override;
+
+ bool IsEqual(const IComparable& other) const override
+ {
+ auto* val = dynamic_cast<const TupleCreator*>(&other);
+ if (!val)
+ return false;
+ return m_exprs == val->m_exprs;
+ }
+private:
+ std::vector<ExpressionEvaluatorPtr<>> m_exprs;
+};
+/*
+class DictionaryCreator : public Expression
+{
+public:
+ DictionaryCreator(std::unordered_map<std::string, ExpressionEvaluatorPtr<>> items)
+ : m_items(std::move(items))
+ {
+ }
+
+ InternalValue Evaluate(RenderContext&) override;
+
+private:
+ std::unordered_map<std::string, ExpressionEvaluatorPtr<>> m_items;
+};*/
+
+class DictCreator : public Expression
+{
+public:
+ DictCreator(std::unordered_map<std::string, ExpressionEvaluatorPtr<>> exprs)
+ : m_exprs(std::move(exprs))
+ {
+ }
+
+ InternalValue Evaluate(RenderContext&) override;
+
+ bool IsEqual(const IComparable& other) const override
+ {
+ auto* val = dynamic_cast<const DictCreator*>(&other);
+ if (!val)
+ return false;
+ return m_exprs == val->m_exprs;
+ }
+private:
+ std::unordered_map<std::string, ExpressionEvaluatorPtr<>> m_exprs;
+};
+
+class UnaryExpression : public Expression
+{
+public:
+ enum Operation
+ {
+ LogicalNot,
+ UnaryPlus,
+ UnaryMinus
+ };
+
+ UnaryExpression(Operation oper, ExpressionEvaluatorPtr<> expr)
+ : m_oper(oper)
+ , m_expr(expr)
+ {}
+ InternalValue Evaluate(RenderContext&) override;
+
+ bool IsEqual(const IComparable& other) const override
+ {
+ auto* val = dynamic_cast<const UnaryExpression*>(&other);
+ if (!val)
+ return false;
+ if (m_oper != val->m_oper)
+ return false;
+ if (m_expr != val->m_expr)
+ return false;
+ return true;
+ }
+
+private:
+ Operation m_oper;
+ ExpressionEvaluatorPtr<> m_expr;
+};
+
+class IsExpression : public Expression
+{
+public:
+ virtual ~IsExpression() {}
+
+ struct ITester : IComparable
+ {
+ virtual ~ITester() {}
+ virtual bool Test(const InternalValue& baseVal, RenderContext& context) = 0;
+ };
+ using TesterPtr = std::shared_ptr<ITester>;
+ using TesterFactoryFn = std::function<TesterPtr(CallParamsInfo params)>;
+
+ IsExpression(ExpressionEvaluatorPtr<> value, const std::string& tester, CallParamsInfo params);
+ InternalValue Evaluate(RenderContext& context) override;
+
+ bool IsEqual(const IComparable& other) const override
+ {
+ auto* val = dynamic_cast<const IsExpression*>(&other);
+ if (!val)
+ return false;
+ if (m_value != val->m_value)
+ return false;
+ if (m_tester != val->m_tester)
+ return false;
+ if (m_tester && val->m_tester && !m_tester->IsEqual(*val->m_tester))
+ return false;
+ return true;
+ }
+
+private:
+ ExpressionEvaluatorPtr<> m_value;
+ TesterPtr m_tester;
+};
+
+class BinaryExpression : public Expression
+{
+public:
+ enum Operation
+ {
+ LogicalAnd,
+ LogicalOr,
+ LogicalEq,
+ LogicalNe,
+ LogicalGt,
+ LogicalLt,
+ LogicalGe,
+ LogicalLe,
+ In,
+ Plus,
+ Minus,
+ Mul,
+ Div,
+ DivReminder,
+ DivInteger,
+ Pow,
+ StringConcat
+ };
+
+ enum CompareType
+ {
+ Undefined = 0,
+ CaseSensitive = 0,
+ CaseInsensitive = 1
+ };
+
+ BinaryExpression(Operation oper, ExpressionEvaluatorPtr<> leftExpr, ExpressionEvaluatorPtr<> rightExpr);
+ InternalValue Evaluate(RenderContext&) override;
+
+ bool IsEqual(const IComparable& other) const override
+ {
+ auto* val = dynamic_cast<const BinaryExpression*>(&other);
+ if (!val)
+ return false;
+ if (m_oper != val->m_oper)
+ return false;
+ if (m_leftExpr != val->m_leftExpr)
+ return false;
+ if (m_rightExpr != val->m_rightExpr)
+ return false;
+ if (m_inTester && val->m_inTester && !m_inTester->IsEqual(*val->m_inTester))
+ return false;
+ if ((!m_inTester && val->m_inTester) || (m_inTester && !val->m_inTester))
+ return false;
+ return true;
+ }
+private:
+ Operation m_oper;
+ ExpressionEvaluatorPtr<> m_leftExpr;
+ ExpressionEvaluatorPtr<> m_rightExpr;
+ IsExpression::TesterPtr m_inTester;
+};
+
+
+class CallExpression : public Expression
+{
+public:
+ virtual ~CallExpression() {}
+
+ CallExpression(ExpressionEvaluatorPtr<> valueRef, CallParamsInfo params)
+ : m_valueRef(std::move(valueRef))
+ , m_params(std::move(params))
+ {
+ }
+
+ InternalValue Evaluate(RenderContext &values) override;
+ void Render(OutStream &stream, RenderContext &values) override;
+
+ auto& GetValueRef() const {return m_valueRef;}
+ auto& GetParams() const {return m_params;}
+
+ bool IsEqual(const IComparable& other) const override
+ {
+ auto* val = dynamic_cast<const CallExpression*>(&other);
+ if (!val)
+ return false;
+ if (m_valueRef != val->m_valueRef)
+ return false;
+ return m_params == val->m_params;
+ }
+private:
+ InternalValue CallArbitraryFn(RenderContext &values);
+ InternalValue CallGlobalRange(RenderContext &values);
+ InternalValue CallLoopCycle(RenderContext &values);
+
+private:
+ ExpressionEvaluatorPtr<> m_valueRef;
+ CallParamsInfo m_params;
+};
+
+class ExpressionFilter : public IComparable
+{
+public:
+ virtual ~ExpressionFilter() {}
+
+ struct IExpressionFilter : IComparable
+ {
+ virtual ~IExpressionFilter() {}
+ virtual InternalValue Filter(const InternalValue& baseVal, RenderContext& context) = 0;
+ };
+ using ExpressionFilterPtr = std::shared_ptr<IExpressionFilter>;
+ using FilterFactoryFn = std::function<ExpressionFilterPtr(CallParamsInfo params)>;
+
+ ExpressionFilter(const std::string& filterName, CallParamsInfo params);
+
+ InternalValue Evaluate(const InternalValue& baseVal, RenderContext& context);
+ void SetParentFilter(std::shared_ptr<ExpressionFilter> parentFilter)
+ {
+ m_parentFilter = std::move(parentFilter);
+ }
+ bool IsEqual(const IComparable& other) const override
+ {
+ auto* valuePtr = dynamic_cast<const ExpressionFilter*>(&other);
+ if (!valuePtr)
+ return false;
+ if (m_filter && valuePtr->m_filter && !m_filter->IsEqual(*valuePtr->m_filter))
+ return false;
+ if ((m_filter && !valuePtr->m_filter) || (!m_filter && !valuePtr->m_filter))
+ return false;
+ if (m_parentFilter != valuePtr->m_parentFilter)
+ return false;
+ return true;
+ }
+
+
+private:
+ ExpressionFilterPtr m_filter;
+ std::shared_ptr<ExpressionFilter> m_parentFilter;
+};
+
+
+class IfExpression : public IComparable
+{
+public:
+ virtual ~IfExpression() {}
+
+ IfExpression(ExpressionEvaluatorPtr<> testExpr, ExpressionEvaluatorPtr<> altValue)
+ : m_testExpr(testExpr)
+ , m_altValue(altValue)
+ {
+ }
+
+ bool Evaluate(RenderContext& context);
+ InternalValue EvaluateAltValue(RenderContext& context);
+
+ void SetAltValue(ExpressionEvaluatorPtr<> altValue)
+ {
+ m_altValue = std::move(altValue);
+ }
+
+ bool IsEqual(const IComparable& other) const override
+ {
+ auto* valPtr = dynamic_cast<const IfExpression*>(&other);
+ if (!valPtr)
+ return false;
+ if (m_testExpr != valPtr->m_testExpr)
+ return false;
+ if (m_altValue != valPtr->m_altValue)
+ return false;
+ return true;
+ }
+
+private:
+ ExpressionEvaluatorPtr<> m_testExpr;
+ ExpressionEvaluatorPtr<> m_altValue;
+};
+
+namespace helpers
+{
+ParsedArguments ParseCallParams(const std::initializer_list<ArgumentInfo>& argsInfo, const CallParams& params, bool& isSucceeded);
+ParsedArguments ParseCallParams(const std::vector<ArgumentInfo>& args, const CallParams& params, bool& isSucceeded);
+ParsedArgumentsInfo ParseCallParamsInfo(const std::initializer_list<ArgumentInfo>& argsInfo, const CallParamsInfo& params, bool& isSucceeded);
+ParsedArgumentsInfo ParseCallParamsInfo(const std::vector<ArgumentInfo>& args, const CallParamsInfo& params, bool& isSucceeded);
+CallParams EvaluateCallParams(const CallParamsInfo& info, RenderContext& context);
+} // namespace helpers
+} // namespace jinja2
+
+#endif // JINJA2CPP_SRC_EXPRESSION_EVALUATOR_H
diff --git a/contrib/libs/jinja2cpp/src/expression_parser.cpp b/contrib/libs/jinja2cpp/src/expression_parser.cpp
new file mode 100644
index 0000000000..edc599cc19
--- /dev/null
+++ b/contrib/libs/jinja2cpp/src/expression_parser.cpp
@@ -0,0 +1,606 @@
+#include "expression_parser.h"
+
+#include <sstream>
+#include <unordered_set>
+#include <jinja2cpp/template_env.h>
+
+namespace jinja2
+{
+
+template<typename T>
+auto ReplaceErrorIfPossible(T& result, const Token& pivotTok, ErrorCode newError)
+{
+ auto& error = result.error();
+ if (error.errorToken.range.startOffset == pivotTok.range.startOffset)
+ return MakeParseError(newError, pivotTok);
+
+ return result.get_unexpected();
+}
+
+ExpressionParser::ExpressionParser(const Settings& /* settings */, TemplateEnv* /* env */)
+{
+
+}
+
+ExpressionParser::ParseResult<RendererPtr> ExpressionParser::Parse(LexScanner& lexer)
+{
+ auto evaluator = ParseFullExpression(lexer);
+ if (!evaluator)
+ return evaluator.get_unexpected();
+
+ auto tok = lexer.NextToken();
+ if (tok != Token::Eof)
+ {
+ auto tok1 = tok;
+ tok1.type = Token::Eof;
+
+ return MakeParseError(ErrorCode::ExpectedToken, tok, {tok1});
+ }
+
+ RendererPtr result = std::make_shared<ExpressionRenderer>(*evaluator);
+
+ return result;
+}
+
+ExpressionParser::ParseResult<ExpressionEvaluatorPtr<FullExpressionEvaluator>> ExpressionParser::ParseFullExpression(LexScanner &lexer, bool includeIfPart)
+{
+ ExpressionEvaluatorPtr<FullExpressionEvaluator> result;
+ LexScanner::StateSaver saver(lexer);
+
+ ExpressionEvaluatorPtr<FullExpressionEvaluator> evaluator = std::make_shared<FullExpressionEvaluator>();
+ auto value = ParseLogicalOr(lexer);
+ if (!value)
+ return value.get_unexpected();
+
+ evaluator->SetExpression(*value);
+
+ if (includeIfPart && lexer.EatIfEqual(Keyword::If))
+ {
+ auto ifExpr = ParseIfExpression(lexer);
+ if (!ifExpr)
+ return ifExpr.get_unexpected();
+ evaluator->SetTester(*ifExpr);
+ }
+
+ saver.Commit();
+
+ return evaluator;
+}
+
+ExpressionParser::ParseResult<ExpressionEvaluatorPtr<Expression>> ExpressionParser::ParseLogicalOr(LexScanner& lexer)
+{
+ auto left = ParseLogicalAnd(lexer);
+
+ if (left && lexer.EatIfEqual(Keyword::LogicalOr))
+ {
+ auto right = ParseLogicalOr(lexer);
+ if (!right)
+ return right.get_unexpected();
+
+ return std::make_shared<BinaryExpression>(BinaryExpression::LogicalOr, *left, *right);
+ }
+
+ return left;
+}
+
+ExpressionParser::ParseResult<ExpressionEvaluatorPtr<Expression>> ExpressionParser::ParseLogicalAnd(LexScanner& lexer)
+{
+ auto left = ParseLogicalCompare(lexer);
+
+ if (left && lexer.EatIfEqual(Keyword::LogicalAnd))
+ {
+ auto right = ParseLogicalAnd(lexer);
+ if (!right)
+ return right;
+
+ return std::make_shared<BinaryExpression>(BinaryExpression::LogicalAnd, *left, *right);
+ }
+
+ return left;
+}
+
+ExpressionParser::ParseResult<ExpressionEvaluatorPtr<Expression>> ExpressionParser::ParseLogicalCompare(LexScanner& lexer)
+{
+ auto left = ParseStringConcat(lexer);
+ if (!left)
+ return left;
+
+ auto tok = lexer.NextToken();
+ BinaryExpression::Operation operation;
+ switch (tok.type)
+ {
+ case Token::Equal:
+ operation = BinaryExpression::LogicalEq;
+ break;
+ case Token::NotEqual:
+ operation = BinaryExpression::LogicalNe;
+ break;
+ case '<':
+ operation = BinaryExpression::LogicalLt;
+ break;
+ case '>':
+ operation = BinaryExpression::LogicalGt;
+ break;
+ case Token::GreaterEqual:
+ operation = BinaryExpression::LogicalGe;
+ break;
+ case Token::LessEqual:
+ operation = BinaryExpression::LogicalLe;
+ break;
+ default:
+ switch (lexer.GetAsKeyword(tok))
+ {
+ case Keyword::In:
+ operation = BinaryExpression::In;
+ break;
+ case Keyword::Is:
+ {
+ Token nextTok = lexer.NextToken();
+ if (nextTok != Token::Identifier)
+ return MakeParseError(ErrorCode::ExpectedIdentifier, nextTok);
+
+ std::string name = AsString(nextTok.value);
+ ParseResult<CallParamsInfo> params;
+
+ if (lexer.EatIfEqual('('))
+ params = ParseCallParams(lexer);
+
+ if (!params)
+ return params.get_unexpected();
+
+ return std::make_shared<IsExpression>(*left, std::move(name), std::move(*params));
+ }
+ default:
+ lexer.ReturnToken();
+ return left;
+ }
+ }
+
+ auto right = ParseStringConcat(lexer);
+ if (!right)
+ return right;
+
+ return std::make_shared<BinaryExpression>(operation, *left, *right);
+}
+
+ExpressionParser::ParseResult<ExpressionEvaluatorPtr<Expression>> ExpressionParser::ParseStringConcat(LexScanner& lexer)
+{
+ auto left = ParseMathPow(lexer);
+
+ if (left && lexer.EatIfEqual('~'))
+ {
+ auto right = ParseLogicalAnd(lexer);
+ if (!right)
+ return right;
+
+ return std::make_shared<BinaryExpression>(BinaryExpression::StringConcat, *left, *right);
+ }
+ return left;
+}
+
+ExpressionParser::ParseResult<ExpressionEvaluatorPtr<Expression>> ExpressionParser::ParseMathPow(LexScanner& lexer)
+{
+ auto left = ParseMathPlusMinus(lexer);
+
+ if (left && lexer.EatIfEqual(Token::MulMul))
+ {
+ auto right = ParseMathPow(lexer);
+ if (!right)
+ return right;
+
+ return std::make_shared<BinaryExpression>(BinaryExpression::Pow, *left, *right);
+ }
+
+ return left;
+}
+
+ExpressionParser::ParseResult<ExpressionEvaluatorPtr<Expression>> ExpressionParser::ParseMathPlusMinus(LexScanner& lexer)
+{
+ auto left = ParseMathMulDiv(lexer);
+ if (!left)
+ return left;
+
+ auto tok = lexer.NextToken();
+ BinaryExpression::Operation operation;
+ switch (tok.type)
+ {
+ case '+':
+ operation = BinaryExpression::Plus;
+ break;
+ case '-':
+ operation = BinaryExpression::Minus;
+ break;
+ default:
+ lexer.ReturnToken();
+ return left;
+ }
+
+ auto right = ParseMathPlusMinus(lexer);
+ if (!right)
+ return right;
+
+ return std::make_shared<BinaryExpression>(operation, *left, *right);
+}
+
+ExpressionParser::ParseResult<ExpressionEvaluatorPtr<Expression>> ExpressionParser::ParseMathMulDiv(LexScanner& lexer)
+{
+ auto left = ParseUnaryPlusMinus(lexer);
+ if (!left)
+ return left;
+
+ auto tok = lexer.NextToken();
+ BinaryExpression::Operation operation;
+ switch (tok.type)
+ {
+ case '*':
+ operation = BinaryExpression::Mul;
+ break;
+ case '/':
+ operation = BinaryExpression::Div;
+ break;
+ case Token::DivDiv:
+ operation = BinaryExpression::DivInteger;
+ break;
+ case '%':
+ operation = BinaryExpression::DivReminder;
+ break;
+ default:
+ lexer.ReturnToken();
+ return left;
+ }
+
+ auto right = ParseMathMulDiv(lexer);
+ if (!right)
+ return right;
+
+ return std::make_shared<BinaryExpression>(operation, *left, *right);
+}
+
+ExpressionParser::ParseResult<ExpressionEvaluatorPtr<Expression>> ExpressionParser::ParseUnaryPlusMinus(LexScanner& lexer)
+{
+ const auto tok = lexer.NextToken();
+ const auto isUnary = tok == '+' || tok == '-' || lexer.GetAsKeyword(tok) == Keyword::LogicalNot;
+ if (!isUnary)
+ lexer.ReturnToken();
+
+ auto subExpr = ParseValueExpression(lexer);
+ if (!subExpr)
+ return subExpr;
+
+ ExpressionEvaluatorPtr<Expression> result;
+ if (isUnary)
+ result = std::make_shared<UnaryExpression>(tok == '+' ? UnaryExpression::UnaryPlus : (tok == '-' ? UnaryExpression::UnaryMinus : UnaryExpression::LogicalNot), *subExpr);
+ else
+ result = subExpr.value();
+
+ if (lexer.EatIfEqual('|'))
+ {
+ auto filter = ParseFilterExpression(lexer);
+ if (!filter)
+ return filter.get_unexpected();
+ result = std::make_shared<FilteredExpression>(std::move(result), *filter);
+ }
+
+ return result;
+}
+
+ExpressionParser::ParseResult<ExpressionEvaluatorPtr<Expression>> ExpressionParser::ParseValueExpression(LexScanner& lexer)
+{
+ Token tok = lexer.NextToken();
+ static const std::unordered_set<Keyword> forbiddenKw = {Keyword::Is, Keyword::In, Keyword::If, Keyword::Else};
+
+ ParseResult<ExpressionEvaluatorPtr<Expression>> valueRef;
+
+ switch (tok.type)
+ {
+ case Token::Identifier:
+ {
+ auto kwType = lexer.GetAsKeyword(tok);
+ if (forbiddenKw.count(kwType) != 0)
+ return MakeParseError(ErrorCode::UnexpectedToken, tok);
+
+ valueRef = std::make_shared<ValueRefExpression>(AsString(tok.value));
+ break;
+ }
+ case Token::IntegerNum:
+ case Token::FloatNum:
+ case Token::String:
+ return std::make_shared<ConstantExpression>(tok.value);
+ case Token::True:
+ return std::make_shared<ConstantExpression>(InternalValue(true));
+ case Token::False:
+ return std::make_shared<ConstantExpression>(InternalValue(false));
+ case '(':
+ valueRef = ParseBracedExpressionOrTuple(lexer);
+ break;
+ case '[':
+ valueRef = ParseTuple(lexer);
+ break;
+ case '{':
+ valueRef = ParseDictionary(lexer);
+ break;
+ default:
+ return MakeParseError(ErrorCode::UnexpectedToken, tok);
+ }
+
+ if (valueRef)
+ {
+ tok = lexer.PeekNextToken();
+ if (tok == '[' || tok == '.')
+ valueRef = ParseSubscript(lexer, *valueRef);
+
+ if (lexer.EatIfEqual('('))
+ valueRef = ParseCall(lexer, *valueRef);
+ }
+ return valueRef;
+}
+
+ExpressionParser::ParseResult<ExpressionEvaluatorPtr<Expression>> ExpressionParser::ParseBracedExpressionOrTuple(LexScanner& lexer)
+{
+ ExpressionEvaluatorPtr<Expression> result;
+
+ bool isTuple = false;
+ std::vector<ExpressionEvaluatorPtr<Expression>> exprs;
+ for (;;)
+ {
+ Token pivotTok = lexer.PeekNextToken();
+ auto expr = ParseFullExpression(lexer);
+
+ if (!expr)
+ return ReplaceErrorIfPossible(expr, pivotTok, ErrorCode::ExpectedRoundBracket);
+
+ exprs.push_back(*expr);
+ Token tok = lexer.NextToken();
+ if (tok == ')')
+ break;
+ else if (tok == ',')
+ isTuple = true;
+ }
+
+ if (isTuple)
+ result = std::make_shared<TupleCreator>(std::move(exprs));
+ else
+ result = exprs[0];
+
+ return result;
+}
+
+ExpressionParser::ParseResult<ExpressionEvaluatorPtr<Expression>> ExpressionParser::ParseDictionary(LexScanner& lexer)
+{
+ ExpressionEvaluatorPtr<Expression> result;
+
+ std::unordered_map<std::string, ExpressionEvaluatorPtr<Expression>> items;
+ if (lexer.EatIfEqual(']'))
+ return std::make_shared<DictCreator>(std::move(items));
+
+ do
+ {
+ Token key = lexer.NextToken();
+ if (key != Token::String)
+ return MakeParseError(ErrorCode::ExpectedStringLiteral, key);
+
+ if (!lexer.EatIfEqual('='))
+ {
+ auto tok = lexer.PeekNextToken();
+ auto tok1 = tok;
+ tok1.type = Token::Assign;
+ return MakeParseError(ErrorCode::ExpectedToken, tok, {tok1});
+ }
+
+ auto pivotTok = lexer.PeekNextToken();
+ auto expr = ParseFullExpression(lexer);
+ if (!expr)
+ return ReplaceErrorIfPossible(expr, pivotTok, ErrorCode::ExpectedExpression);
+
+ items[AsString(key.value)] = *expr;
+
+ } while (lexer.EatIfEqual(','));
+
+ auto tok = lexer.NextToken();
+ if (tok != '}')
+ return MakeParseError(ErrorCode::ExpectedCurlyBracket, tok);
+
+ result = std::make_shared<DictCreator>(std::move(items));
+
+ return result;
+}
+
+ExpressionParser::ParseResult<ExpressionEvaluatorPtr<Expression>> ExpressionParser::ParseTuple(LexScanner& lexer)
+{
+ ExpressionEvaluatorPtr<Expression> result;
+
+ std::vector<ExpressionEvaluatorPtr<Expression>> exprs;
+ if (lexer.EatIfEqual(']'))
+ return std::make_shared<TupleCreator>(exprs);
+
+ do
+ {
+ auto expr = ParseFullExpression(lexer);
+ if (!expr)
+ return expr.get_unexpected();
+
+ exprs.push_back(*expr);
+ } while (lexer.EatIfEqual(','));
+
+ auto tok = lexer.NextToken();
+ if (tok != ']')
+ return MakeParseError(ErrorCode::ExpectedSquareBracket, tok);
+
+ result = std::make_shared<TupleCreator>(std::move(exprs));
+
+ return result;
+}
+
+ExpressionParser::ParseResult<ExpressionEvaluatorPtr<Expression>> ExpressionParser::ParseCall(LexScanner& lexer, ExpressionEvaluatorPtr<Expression> valueRef)
+{
+ ExpressionEvaluatorPtr<Expression> result;
+
+ ParseResult<CallParamsInfo> params = ParseCallParams(lexer);
+ if (!params)
+ return params.get_unexpected();
+
+ result = std::make_shared<CallExpression>(valueRef, std::move(*params));
+
+ return result;
+}
+
+ExpressionParser::ParseResult<CallParamsInfo> ExpressionParser::ParseCallParams(LexScanner& lexer)
+{
+ CallParamsInfo result;
+
+ if (lexer.EatIfEqual(')'))
+ return result;
+
+ do
+ {
+ Token tok = lexer.NextToken();
+ std::string paramName;
+ if (tok == Token::Identifier && lexer.PeekNextToken() == '=')
+ {
+ paramName = AsString(tok.value);
+ lexer.EatToken();
+ }
+ else
+ {
+ lexer.ReturnToken();
+ }
+
+ auto valueExpr = ParseFullExpression(lexer);
+ if (!valueExpr)
+ {
+ return valueExpr.get_unexpected();
+ }
+ if (paramName.empty())
+ result.posParams.push_back(*valueExpr);
+ else
+ result.kwParams[paramName] = *valueExpr;
+
+ } while (lexer.EatIfEqual(','));
+
+ auto tok = lexer.NextToken();
+ if (tok != ')')
+ return MakeParseError(ErrorCode::ExpectedRoundBracket, tok);
+
+ return result;
+}
+
+ExpressionParser::ParseResult<ExpressionEvaluatorPtr<Expression>> ExpressionParser::ParseSubscript(LexScanner& lexer, ExpressionEvaluatorPtr<Expression> valueRef)
+{
+ ExpressionEvaluatorPtr<SubscriptExpression> result = std::make_shared<SubscriptExpression>(valueRef);
+ for (Token tok = lexer.NextToken(); tok.type == '.' || tok.type == '['; tok = lexer.NextToken())
+ {
+ ParseResult<ExpressionEvaluatorPtr<Expression>> indexExpr;
+ if (tok == '.')
+ {
+ tok = lexer.NextToken();
+ if (tok.type != Token::Identifier)
+ return MakeParseError(ErrorCode::ExpectedIdentifier, tok);
+
+ auto valueName = AsString(tok.value);
+ indexExpr = std::make_shared<ConstantExpression>(InternalValue(valueName));
+ }
+ else
+ {
+ auto expr = ParseFullExpression(lexer);
+
+ if (!expr)
+ return expr.get_unexpected();
+ else
+ indexExpr = *expr;
+
+ if (!lexer.EatIfEqual(']', &tok))
+ return MakeParseError(ErrorCode::ExpectedSquareBracket, lexer.PeekNextToken());
+ }
+
+ result->AddIndex(*indexExpr);
+ }
+
+ lexer.ReturnToken();
+
+ return result;
+}
+
+ExpressionParser::ParseResult<ExpressionEvaluatorPtr<ExpressionFilter>> ExpressionParser::ParseFilterExpression(LexScanner& lexer)
+{
+ ExpressionEvaluatorPtr<ExpressionFilter> result;
+
+ auto startTok = lexer.PeekNextToken();
+ try
+ {
+ do
+ {
+ Token tok = lexer.NextToken();
+ if (tok != Token::Identifier)
+ return MakeParseError(ErrorCode::ExpectedIdentifier, tok);
+
+ std::string name = AsString(tok.value);
+ ParseResult<CallParamsInfo> params;
+
+ if (lexer.NextToken() == '(')
+ params = ParseCallParams(lexer);
+ else
+ lexer.ReturnToken();
+
+ if (!params)
+ return params.get_unexpected();
+
+ auto filter = std::make_shared<ExpressionFilter>(name, std::move(*params));
+ if (result)
+ {
+ filter->SetParentFilter(result);
+ result = filter;
+ }
+ else
+ result = filter;
+
+ } while (lexer.NextToken() == '|');
+
+ lexer.ReturnToken();
+ }
+ catch (const ParseError& error)
+ {
+ return nonstd::make_unexpected(error);
+ }
+ catch (const std::runtime_error&)
+ {
+ return MakeParseError(ErrorCode::UnexpectedException, startTok);
+ }
+ return result;
+}
+
+ExpressionParser::ParseResult<ExpressionEvaluatorPtr<IfExpression>> ExpressionParser::ParseIfExpression(LexScanner& lexer)
+{
+ ExpressionEvaluatorPtr<IfExpression> result;
+
+ auto startTok = lexer.PeekNextToken();
+ try
+ {
+ auto testExpr = ParseLogicalOr(lexer);
+ if (!testExpr)
+ return testExpr.get_unexpected();
+
+ ParseResult<ExpressionEvaluatorPtr<>> altValue;
+ if (lexer.GetAsKeyword(lexer.PeekNextToken()) == Keyword::Else)
+ {
+ lexer.EatToken();
+ auto value = ParseFullExpression(lexer);
+ if (!value)
+ return value.get_unexpected();
+ altValue = *value;
+ }
+
+ result = std::make_shared<IfExpression>(*testExpr, *altValue);
+ }
+ catch (const ParseError& error)
+ {
+ return nonstd::make_unexpected(error);
+ }
+ catch (const std::runtime_error& ex)
+ {
+ std::cout << "Filter parsing problem: " << ex.what() << std::endl;
+ }
+
+ return result;
+}
+
+} // namespace jinja2
diff --git a/contrib/libs/jinja2cpp/src/expression_parser.h b/contrib/libs/jinja2cpp/src/expression_parser.h
new file mode 100644
index 0000000000..dd0b78458f
--- /dev/null
+++ b/contrib/libs/jinja2cpp/src/expression_parser.h
@@ -0,0 +1,49 @@
+#ifndef JINJA2CPP_SRC_EXPRESSION_PARSER_H
+#define JINJA2CPP_SRC_EXPRESSION_PARSER_H
+
+#include "lexer.h"
+#include "error_handling.h"
+#include "expression_evaluator.h"
+#include "renderer.h"
+
+#include <contrib/restricted/expected-lite/include/nonstd/expected.hpp>
+#include <jinja2cpp/template_env.h>
+
+namespace jinja2
+{
+class ExpressionParser
+{
+public:
+ template<typename T>
+ using ParseResult = nonstd::expected<T, ParseError>;
+
+ explicit ExpressionParser(const Settings& settings, TemplateEnv* env = nullptr);
+ ParseResult<RendererPtr> Parse(LexScanner& lexer);
+ ParseResult<ExpressionEvaluatorPtr<FullExpressionEvaluator>> ParseFullExpression(LexScanner& lexer, bool includeIfPart = true);
+ ParseResult<CallParamsInfo> ParseCallParams(LexScanner& lexer);
+ ParseResult<ExpressionEvaluatorPtr<ExpressionFilter>> ParseFilterExpression(LexScanner& lexer);
+private:
+ ParseResult<ExpressionEvaluatorPtr<Expression>> ParseLogicalNot(LexScanner& lexer);
+ ParseResult<ExpressionEvaluatorPtr<Expression>> ParseLogicalOr(LexScanner& lexer);
+ ParseResult<ExpressionEvaluatorPtr<Expression>> ParseLogicalAnd(LexScanner& lexer);
+ ParseResult<ExpressionEvaluatorPtr<Expression>> ParseLogicalCompare(LexScanner& lexer);
+ ParseResult<ExpressionEvaluatorPtr<Expression>> ParseStringConcat(LexScanner& lexer);
+ ParseResult<ExpressionEvaluatorPtr<Expression>> ParseMathPow(LexScanner& lexer);
+ ParseResult<ExpressionEvaluatorPtr<Expression>> ParseMathMulDiv(LexScanner& lexer);
+ ParseResult<ExpressionEvaluatorPtr<Expression>> ParseMathPlusMinus(LexScanner& lexer);
+ ParseResult<ExpressionEvaluatorPtr<Expression>> ParseUnaryPlusMinus(LexScanner& lexer);
+ ParseResult<ExpressionEvaluatorPtr<Expression>> ParseValueExpression(LexScanner& lexer);
+ ParseResult<ExpressionEvaluatorPtr<Expression>> ParseBracedExpressionOrTuple(LexScanner& lexer);
+ ParseResult<ExpressionEvaluatorPtr<Expression>> ParseDictionary(LexScanner& lexer);
+ ParseResult<ExpressionEvaluatorPtr<Expression>> ParseTuple(LexScanner& lexer);
+ ParseResult<ExpressionEvaluatorPtr<Expression>> ParseCall(LexScanner& lexer, ExpressionEvaluatorPtr<Expression> valueRef);
+ ParseResult<ExpressionEvaluatorPtr<Expression>> ParseSubscript(LexScanner& lexer, ExpressionEvaluatorPtr<Expression> valueRef);
+ ParseResult<ExpressionEvaluatorPtr<IfExpression>> ParseIfExpression(LexScanner& lexer);
+
+private:
+ ComposedRenderer* m_topLevelRenderer = nullptr;
+};
+
+} // namespace jinja2
+
+#endif // JINJA2CPP_SRC_EXPRESSION_PARSER_H
diff --git a/contrib/libs/jinja2cpp/src/filesystem_handler.cpp b/contrib/libs/jinja2cpp/src/filesystem_handler.cpp
new file mode 100644
index 0000000000..8325487aff
--- /dev/null
+++ b/contrib/libs/jinja2cpp/src/filesystem_handler.cpp
@@ -0,0 +1,163 @@
+#include <jinja2cpp/filesystem_handler.h>
+#include <jinja2cpp/string_helpers.h>
+
+#include <boost/filesystem/path.hpp>
+#include <boost/filesystem/operations.hpp>
+
+#include <sstream>
+#include <fstream>
+
+namespace jinja2
+{
+
+using TargetFileStream = std::variant<CharFileStreamPtr*, WCharFileStreamPtr*>;
+
+struct FileContentConverter
+{
+ void operator() (const std::string& content, CharFileStreamPtr* sPtr) const
+ {
+ sPtr->reset(new std::istringstream(content));
+ }
+
+ void operator() (const std::wstring& content, WCharFileStreamPtr* sPtr) const
+ {
+ sPtr->reset(new std::wistringstream(content));
+ }
+ void operator() (const std::wstring&, CharFileStreamPtr*) const
+ {
+// CharFileStreamPtr stream(new std::istringstream(content), [](std::istream* s) {delete static_cast<std::istringstream>(s);});
+// std::swap(*sPtr, stream);
+ }
+
+ void operator() (const std::string&, WCharFileStreamPtr*) const
+ {
+// WCharFileStreamPtr stream(new std::wistringstream(content), [](std::wistream* s) {delete static_cast<std::wistringstream>(s);});
+// std::swap(*sPtr, stream);
+ }
+};
+
+void MemoryFileSystem::AddFile(std::string fileName, std::string fileContent)
+{
+ m_filesMap[std::move(fileName)] = FileContent{std::move(fileContent), {}};
+}
+
+void MemoryFileSystem::AddFile(std::string fileName, std::wstring fileContent)
+{
+ m_filesMap[std::move(fileName)] = FileContent{ {}, std::move(fileContent) };
+}
+
+CharFileStreamPtr MemoryFileSystem::OpenStream(const std::string& name) const
+{
+ CharFileStreamPtr result(nullptr, [](std::istream* s) {delete static_cast<std::istringstream*>(s);});
+ auto p = m_filesMap.find(name);
+ if (p == m_filesMap.end())
+ return result;
+
+ auto& content = p->second;
+
+ if (!content.narrowContent && !content.wideContent)
+ return result;
+
+ if (!content.narrowContent)
+ content.narrowContent = ConvertString<std::string>(content.wideContent.value());
+
+ result.reset(new std::istringstream(content.narrowContent.value()));
+
+ return result;
+}
+
+WCharFileStreamPtr MemoryFileSystem::OpenWStream(const std::string& name) const
+{
+ WCharFileStreamPtr result(nullptr, [](std::wistream* s) {delete static_cast<std::wistringstream*>(s);});
+ auto p = m_filesMap.find(name);
+ if (p == m_filesMap.end())
+ return result;
+
+ auto& content = p->second;
+
+ if (!content.narrowContent && !content.wideContent)
+ return result;
+
+ if (!content.wideContent)
+ content.wideContent = ConvertString<std::wstring>(content.narrowContent.value());
+
+ result.reset(new std::wistringstream(content.wideContent.value()));
+
+ return result;
+}
+std::optional<std::chrono::system_clock::time_point> MemoryFileSystem::GetLastModificationDate(const std::string&) const
+{
+ return std::optional<std::chrono::system_clock::time_point>();
+}
+
+bool MemoryFileSystem::IsEqual(const IComparable& other) const
+{
+ auto* ptr = dynamic_cast<const MemoryFileSystem*>(&other);
+ if (!ptr)
+ return false;
+ return m_filesMap == ptr->m_filesMap;
+}
+
+RealFileSystem::RealFileSystem(std::string rootFolder)
+ : m_rootFolder(std::move(rootFolder))
+{
+
+}
+
+std::string RealFileSystem::GetFullFilePath(const std::string& name) const
+{
+ boost::filesystem::path root(m_rootFolder);
+ root /= name;
+ return root.string();
+}
+
+CharFileStreamPtr RealFileSystem::OpenStream(const std::string& name) const
+{
+ auto filePath = GetFullFilePath(name);
+
+ CharFileStreamPtr result(new std::ifstream(filePath), [](std::istream* s) {delete static_cast<std::ifstream*>(s);});
+ if (result->good())
+ return result;
+
+ return CharFileStreamPtr(nullptr, [](std::istream*){});
+}
+
+WCharFileStreamPtr RealFileSystem::OpenWStream(const std::string& name) const
+{
+ auto filePath = GetFullFilePath(name);
+
+ WCharFileStreamPtr result(new std::wifstream(filePath), [](std::wistream* s) {delete static_cast<std::wifstream*>(s);});
+ if (result->good())
+ return result;
+
+ return WCharFileStreamPtr(nullptr, [](std::wistream*){;});
+}
+std::optional<std::chrono::system_clock::time_point> RealFileSystem::GetLastModificationDate(const std::string& name) const
+{
+ boost::filesystem::path root(m_rootFolder);
+ root /= name;
+
+ auto modify_time = boost::filesystem::last_write_time(root);
+
+ return std::chrono::system_clock::from_time_t(modify_time);
+}
+CharFileStreamPtr RealFileSystem::OpenByteStream(const std::string& name) const
+{
+ auto filePath = GetFullFilePath(name);
+
+ CharFileStreamPtr result(new std::ifstream(filePath, std::ios_base::binary), [](std::istream* s) {delete static_cast<std::ifstream*>(s);});
+ if (result->good())
+ return result;
+
+ return CharFileStreamPtr(nullptr, [](std::istream*){});
+}
+
+bool RealFileSystem::IsEqual(const IComparable& other) const
+{
+ auto* ptr = dynamic_cast<const RealFileSystem*>(&other);
+ if (!ptr)
+ return false;
+ return m_rootFolder == ptr->m_rootFolder;
+}
+
+} // namespace jinja2
diff --git a/contrib/libs/jinja2cpp/src/filters.cpp b/contrib/libs/jinja2cpp/src/filters.cpp
new file mode 100644
index 0000000000..5e0725be96
--- /dev/null
+++ b/contrib/libs/jinja2cpp/src/filters.cpp
@@ -0,0 +1,1086 @@
+#include "filters.h"
+
+#include "binding/rapid_json_serializer.h"
+#include "generic_adapters.h"
+#include "out_stream.h"
+#include "testers.h"
+#include "value_helpers.h"
+#include "value_visitors.h"
+
+#include <algorithm>
+#include <numeric>
+#include <random>
+#include <sstream>
+#include <string>
+
+using namespace std::string_literals;
+
+namespace jinja2
+{
+
+template<typename F>
+struct FilterFactory
+{
+ static FilterPtr Create(FilterParams params) { return std::make_shared<F>(std::move(params)); }
+
+ template<typename... Args>
+ static ExpressionFilter::FilterFactoryFn MakeCreator(Args&&... args)
+ {
+ return [args...](FilterParams params) { return std::make_shared<F>(std::move(params), args...); };
+ }
+};
+
+std::unordered_map<std::string, ExpressionFilter::FilterFactoryFn> s_filters = {
+ { "abs", FilterFactory<filters::ValueConverter>::MakeCreator(filters::ValueConverter::AbsMode) },
+ { "applymacro", &FilterFactory<filters::ApplyMacro>::Create },
+ { "attr", &FilterFactory<filters::Attribute>::Create },
+ { "batch", FilterFactory<filters::Slice>::MakeCreator(filters::Slice::BatchMode) },
+ { "camelize", FilterFactory<filters::StringConverter>::MakeCreator(filters::StringConverter::CamelMode) },
+ { "capitalize", FilterFactory<filters::StringConverter>::MakeCreator(filters::StringConverter::CapitalMode) },
+ { "center", FilterFactory<filters::StringConverter>::MakeCreator(filters::StringConverter::CenterMode) },
+ { "default", &FilterFactory<filters::Default>::Create },
+ { "d", &FilterFactory<filters::Default>::Create },
+ { "dictsort", &FilterFactory<filters::DictSort>::Create },
+ { "escape", FilterFactory<filters::StringConverter>::MakeCreator(filters::StringConverter::EscapeHtmlMode) },
+ { "escapecpp", FilterFactory<filters::StringConverter>::MakeCreator(filters::StringConverter::EscapeCppMode) },
+ { "first", FilterFactory<filters::SequenceAccessor>::MakeCreator(filters::SequenceAccessor::FirstItemMode) },
+ { "float", FilterFactory<filters::ValueConverter>::MakeCreator(filters::ValueConverter::ToFloatMode) },
+ { "format", FilterFactory<filters::StringFormat>::Create },
+ { "groupby", &FilterFactory<filters::GroupBy>::Create },
+ { "int", FilterFactory<filters::ValueConverter>::MakeCreator(filters::ValueConverter::ToIntMode) },
+ { "join", &FilterFactory<filters::Join>::Create },
+ { "last", FilterFactory<filters::SequenceAccessor>::MakeCreator(filters::SequenceAccessor::LastItemMode) },
+ { "length", FilterFactory<filters::SequenceAccessor>::MakeCreator(filters::SequenceAccessor::LengthMode) },
+ { "list", FilterFactory<filters::ValueConverter>::MakeCreator(filters::ValueConverter::ToListMode) },
+ { "lower", FilterFactory<filters::StringConverter>::MakeCreator(filters::StringConverter::LowerMode) },
+ { "map", &FilterFactory<filters::Map>::Create },
+ { "max", FilterFactory<filters::SequenceAccessor>::MakeCreator(filters::SequenceAccessor::MaxItemMode) },
+ { "min", FilterFactory<filters::SequenceAccessor>::MakeCreator(filters::SequenceAccessor::MinItemMode) },
+ { "pprint", &FilterFactory<filters::PrettyPrint>::Create },
+ { "random", FilterFactory<filters::SequenceAccessor>::MakeCreator(filters::SequenceAccessor::RandomMode) },
+ { "reject", FilterFactory<filters::Tester>::MakeCreator(filters::Tester::RejectMode) },
+ { "rejectattr", FilterFactory<filters::Tester>::MakeCreator(filters::Tester::RejectAttrMode) },
+ { "replace", FilterFactory<filters::StringConverter>::MakeCreator(filters::StringConverter::ReplaceMode) },
+ { "round", FilterFactory<filters::ValueConverter>::MakeCreator(filters::ValueConverter::RoundMode) },
+ { "reverse", FilterFactory<filters::SequenceAccessor>::MakeCreator(filters::SequenceAccessor::ReverseMode) },
+ { "select", FilterFactory<filters::Tester>::MakeCreator(filters::Tester::SelectMode) },
+ { "selectattr", FilterFactory<filters::Tester>::MakeCreator(filters::Tester::SelectAttrMode) },
+ { "slice", FilterFactory<filters::Slice>::MakeCreator(filters::Slice::SliceMode) },
+ { "sort", &FilterFactory<filters::Sort>::Create },
+ { "striptags", FilterFactory<filters::StringConverter>::MakeCreator(filters::StringConverter::StriptagsMode) },
+ { "sum", FilterFactory<filters::SequenceAccessor>::MakeCreator(filters::SequenceAccessor::SumItemsMode) },
+ { "title", FilterFactory<filters::StringConverter>::MakeCreator(filters::StringConverter::TitleMode) },
+ { "tojson", FilterFactory<filters::Serialize>::MakeCreator(filters::Serialize::JsonMode) },
+ { "toxml", FilterFactory<filters::Serialize>::MakeCreator(filters::Serialize::XmlMode) },
+ { "toyaml", FilterFactory<filters::Serialize>::MakeCreator(filters::Serialize::YamlMode) },
+ { "trim", FilterFactory<filters::StringConverter>::MakeCreator(filters::StringConverter::TrimMode) },
+ { "truncate", FilterFactory<filters::StringConverter>::MakeCreator(filters::StringConverter::TruncateMode) },
+ { "unique", FilterFactory<filters::SequenceAccessor>::MakeCreator(filters::SequenceAccessor::UniqueItemsMode) },
+ { "upper", FilterFactory<filters::StringConverter>::MakeCreator(filters::StringConverter::UpperMode) },
+ { "urlencode", FilterFactory<filters::StringConverter>::MakeCreator(filters::StringConverter::UrlEncodeMode) },
+ { "wordcount", FilterFactory<filters::StringConverter>::MakeCreator(filters::StringConverter::WordCountMode) },
+ { "wordwrap", FilterFactory<filters::StringConverter>::MakeCreator(filters::StringConverter::WordWrapMode) },
+ { "underscorize", FilterFactory<filters::StringConverter>::MakeCreator(filters::StringConverter::UnderscoreMode) },
+ { "xmlattr", &FilterFactory<filters::XmlAttrFilter>::Create }
+};
+
+extern FilterPtr CreateFilter(std::string filterName, CallParamsInfo params)
+{
+ auto p = s_filters.find(filterName);
+ if (p == s_filters.end())
+ return std::make_shared<filters::UserDefinedFilter>(std::move(filterName), std::move(params));
+
+ return p->second(std::move(params));
+}
+
+namespace filters
+{
+
+Join::Join(FilterParams params)
+{
+ ParseParams({ { "d", false, std::string() }, { "attribute" } }, params);
+}
+
+InternalValue Join::Filter(const InternalValue& baseVal, RenderContext& context)
+{
+ InternalValue attrName = GetArgumentValue("attribute", context);
+
+ bool isConverted = false;
+ ListAdapter values = ConvertToList(baseVal, attrName, isConverted);
+
+ if (!isConverted)
+ return InternalValue();
+
+ bool isFirst = true;
+ InternalValue result;
+ InternalValue delimiter = m_args["d"]->Evaluate(context);
+ for (const InternalValue& val : values)
+ {
+ if (isFirst)
+ isFirst = false;
+ else
+ result = Apply2<visitors::StringJoiner>(result, delimiter);
+
+ result = Apply2<visitors::StringJoiner>(result, val);
+ }
+
+ return result;
+}
+
+Sort::Sort(FilterParams params)
+{
+ ParseParams({ { "reverse", false, InternalValue(false) }, { "case_sensitive", false, InternalValue(false) }, { "attribute", false } }, params);
+}
+
+InternalValue Sort::Filter(const InternalValue& baseVal, RenderContext& context)
+{
+ InternalValue attrName = GetArgumentValue("attribute", context);
+ InternalValue isReverseVal = GetArgumentValue("reverse", context, InternalValue(false));
+ InternalValue isCsVal = GetArgumentValue("case_sensitive", context, InternalValue(false));
+
+ bool isConverted = false;
+ ListAdapter origValues = ConvertToList(baseVal, isConverted);
+ if (!isConverted)
+ return InternalValue();
+ InternalValueList values = origValues.ToValueList();
+
+ BinaryExpression::Operation oper = ConvertToBool(isReverseVal) ? BinaryExpression::LogicalGt : BinaryExpression::LogicalLt;
+ BinaryExpression::CompareType compType = ConvertToBool(isCsVal) ? BinaryExpression::CaseSensitive : BinaryExpression::CaseInsensitive;
+
+ std::sort(values.begin(), values.end(), [&attrName, oper, compType, &context](auto& val1, auto& val2) {
+ InternalValue cmpRes;
+ if (IsEmpty(attrName))
+ cmpRes = Apply2<visitors::BinaryMathOperation>(val1, val2, oper, compType);
+ else
+ cmpRes = Apply2<visitors::BinaryMathOperation>(Subscript(val1, attrName, &context), Subscript(val2, attrName, &context), oper, compType);
+
+ return ConvertToBool(cmpRes);
+ });
+
+ return ListAdapter::CreateAdapter(std::move(values));
+}
+
+Attribute::Attribute(FilterParams params)
+{
+ ParseParams({ { "name", true }, { "default", false } }, params);
+}
+
+InternalValue Attribute::Filter(const InternalValue& baseVal, RenderContext& context)
+{
+ const auto attrNameVal = GetArgumentValue("name", context);
+ const auto result = Subscript(baseVal, attrNameVal, &context);
+ if (result.IsEmpty())
+ return GetArgumentValue("default", context);
+ return result;
+}
+
+Default::Default(FilterParams params)
+{
+ ParseParams({ { "default_value", false, InternalValue(""s) }, { "boolean", false, InternalValue(false) } }, params);
+}
+
+InternalValue Default::Filter(const InternalValue& baseVal, RenderContext& context)
+{
+ InternalValue defaultVal = GetArgumentValue("default_value", context);
+ InternalValue conditionResult = GetArgumentValue("boolean", context);
+
+ if (IsEmpty(baseVal))
+ return defaultVal;
+
+ if (ConvertToBool(conditionResult) && !ConvertToBool(baseVal))
+ return defaultVal;
+
+ return baseVal;
+}
+
+DictSort::DictSort(FilterParams params)
+{
+ ParseParams({ { "case_sensitive", false }, { "by", false, "key"s }, { "reverse", false } }, params);
+}
+
+InternalValue DictSort::Filter(const InternalValue& baseVal, RenderContext& context)
+{
+ const MapAdapter* map = GetIf<MapAdapter>(&baseVal);
+ if (map == nullptr)
+ return InternalValue();
+
+ InternalValue isReverseVal = GetArgumentValue("reverse", context);
+ InternalValue isCsVal = GetArgumentValue("case_sensitive", context);
+ InternalValue byVal = GetArgumentValue("by", context);
+
+ bool (*comparator)(const KeyValuePair& left, const KeyValuePair& right);
+
+ if (AsString(byVal) == "key") // Sort by key
+ {
+ if (ConvertToBool(isCsVal))
+ {
+ comparator = [](const KeyValuePair& left, const KeyValuePair& right) { return left.key < right.key; };
+ }
+ else
+ {
+ comparator = [](const KeyValuePair& left, const KeyValuePair& right) {
+ return boost::lexicographical_compare(left.key, right.key, boost::algorithm::is_iless());
+ };
+ }
+ }
+ else if (AsString(byVal) == "value")
+ {
+ if (ConvertToBool(isCsVal))
+ {
+ comparator = [](const KeyValuePair& left, const KeyValuePair& right) {
+ return ConvertToBool(
+ Apply2<visitors::BinaryMathOperation>(left.value, right.value, BinaryExpression::LogicalLt, BinaryExpression::CaseSensitive));
+ };
+ }
+ else
+ {
+ comparator = [](const KeyValuePair& left, const KeyValuePair& right) {
+ return ConvertToBool(
+ Apply2<visitors::BinaryMathOperation>(left.value, right.value, BinaryExpression::LogicalLt, BinaryExpression::CaseInsensitive));
+ };
+ }
+ }
+ else
+ return InternalValue();
+
+ std::vector<KeyValuePair> tempVector;
+ tempVector.reserve(map->GetSize());
+ for (auto& key : map->GetKeys())
+ {
+ auto val = map->GetValueByName(key);
+ tempVector.push_back(KeyValuePair{ key, val });
+ }
+
+ if (ConvertToBool(isReverseVal))
+ std::sort(tempVector.begin(), tempVector.end(), [comparator](auto& l, auto& r) { return comparator(r, l); });
+ else
+ std::sort(tempVector.begin(), tempVector.end(), [comparator](auto& l, auto& r) { return comparator(l, r); });
+
+ InternalValueList resultList;
+ for (auto& tmpVal : tempVector)
+ {
+ auto resultVal = InternalValue(std::move(tmpVal));
+ if (baseVal.ShouldExtendLifetime())
+ resultVal.SetParentData(baseVal);
+ resultList.push_back(std::move(resultVal));
+ }
+
+ return InternalValue(ListAdapter::CreateAdapter(std::move(resultList)));
+}
+
+GroupBy::GroupBy(FilterParams params)
+{
+ ParseParams({ { "attribute", true } }, params);
+}
+
+InternalValue GroupBy::Filter(const InternalValue& baseVal, RenderContext& context)
+{
+ bool isConverted = false;
+ ListAdapter list = ConvertToList(baseVal, isConverted);
+
+ if (!isConverted)
+ return InternalValue();
+
+ InternalValue attrName = GetArgumentValue("attribute", context);
+
+ auto equalComparator = [](auto& val1, auto& val2) {
+ InternalValue cmpRes = Apply2<visitors::BinaryMathOperation>(val1, val2, BinaryExpression::LogicalEq, BinaryExpression::CaseSensitive);
+
+ return ConvertToBool(cmpRes);
+ };
+
+ struct GroupInfo
+ {
+ InternalValue grouper;
+ InternalValueList items;
+ };
+
+ std::vector<GroupInfo> groups;
+
+ for (auto& item : list)
+ {
+ auto attr = Subscript(item, attrName, &context);
+ auto p = std::find_if(groups.begin(), groups.end(), [&equalComparator, &attr](auto& i) { return equalComparator(i.grouper, attr); });
+ if (p == groups.end())
+ groups.push_back(GroupInfo{ attr, { item } });
+ else
+ p->items.push_back(item);
+ }
+
+ InternalValueList result;
+ for (auto& g : groups)
+ {
+ InternalValueMap groupItem{ { "grouper", std::move(g.grouper) }, { "list", ListAdapter::CreateAdapter(std::move(g.items)) } };
+ result.push_back(CreateMapAdapter(std::move(groupItem)));
+ }
+
+ return ListAdapter::CreateAdapter(std::move(result));
+}
+
+ApplyMacro::ApplyMacro(FilterParams params)
+{
+ ParseParams({ { "macro", true } }, params);
+ m_mappingParams.kwParams = m_args.extraKwArgs;
+ m_mappingParams.posParams = m_args.extraPosArgs;
+}
+
+InternalValue ApplyMacro::Filter(const InternalValue& baseVal, RenderContext& context)
+{
+ InternalValue macroName = GetArgumentValue("macro", context);
+ if (IsEmpty(macroName))
+ return InternalValue();
+
+ bool macroFound = false;
+ auto macroValPtr = context.FindValue(AsString(macroName), macroFound);
+ if (!macroFound)
+ return InternalValue();
+
+ const Callable* callable = GetIf<Callable>(&macroValPtr->second);
+ if (callable == nullptr || callable->GetKind() != Callable::Macro)
+ return InternalValue();
+
+ CallParams tmpCallParams = helpers::EvaluateCallParams(m_mappingParams, context);
+ CallParams callParams;
+ callParams.kwParams = std::move(tmpCallParams.kwParams);
+ callParams.posParams.reserve(tmpCallParams.posParams.size() + 1);
+ callParams.posParams.push_back(baseVal);
+ for (auto& p : tmpCallParams.posParams)
+ callParams.posParams.push_back(std::move(p));
+
+ InternalValue result;
+ if (callable->GetType() == Callable::Type::Expression)
+ {
+ result = callable->GetExpressionCallable()(callParams, context);
+ }
+ else
+ {
+ TargetString resultStr;
+ auto stream = context.GetRendererCallback()->GetStreamOnString(resultStr);
+ callable->GetStatementCallable()(callParams, stream, context);
+ result = std::move(resultStr);
+ }
+
+ return result;
+}
+
+Map::Map(FilterParams params)
+{
+ ParseParams({ { "filter", true } }, MakeParams(std::move(params)));
+ m_mappingParams.kwParams = m_args.extraKwArgs;
+ m_mappingParams.posParams = m_args.extraPosArgs;
+}
+
+FilterParams Map::MakeParams(FilterParams params)
+{
+ if (!params.posParams.empty() || params.kwParams.empty() || params.kwParams.size() > 2)
+ {
+ return params;
+ }
+
+ const auto attributeIt = params.kwParams.find("attribute");
+ if (attributeIt == params.kwParams.cend())
+ {
+ return params;
+ }
+
+ FilterParams result;
+ result.kwParams["name"] = attributeIt->second;
+ result.kwParams["filter"] = std::make_shared<ConstantExpression>("attr"s);
+
+ const auto defaultIt = params.kwParams.find("default");
+ if (defaultIt != params.kwParams.cend())
+ result.kwParams["default"] = defaultIt->second;
+
+ return result;
+}
+
+InternalValue Map::Filter(const InternalValue& baseVal, RenderContext& context)
+{
+ InternalValue filterName = GetArgumentValue("filter", context);
+ if (IsEmpty(filterName))
+ return InternalValue();
+
+ auto filter = CreateFilter(AsString(filterName), m_mappingParams);
+ if (!filter)
+ return InternalValue();
+
+ bool isConverted = false;
+ auto list = ConvertToList(baseVal, isConverted);
+ if (!isConverted)
+ return InternalValue();
+
+ InternalValueList resultList;
+ resultList.reserve(list.GetSize().value_or(0));
+ std::transform(list.begin(), list.end(), std::back_inserter(resultList), [filter, &context](auto& val) { return filter->Filter(val, context); });
+
+ return ListAdapter::CreateAdapter(std::move(resultList));
+}
+Random::Random(FilterParams params) {}
+
+InternalValue Random::Filter(const InternalValue&, RenderContext&)
+{
+ return InternalValue();
+}
+
+SequenceAccessor::SequenceAccessor(FilterParams params, SequenceAccessor::Mode mode)
+ : m_mode(mode)
+{
+ switch (mode)
+ {
+ case FirstItemMode:
+ break;
+ case LastItemMode:
+ break;
+ case LengthMode:
+ break;
+ case MaxItemMode:
+ case MinItemMode:
+ ParseParams({ { "case_sensitive", false, InternalValue(false) }, { "attribute", false } }, params);
+ break;
+ case RandomMode:
+ case ReverseMode:
+ break;
+ case SumItemsMode:
+ ParseParams({ { "attribute", false }, { "start", false } }, params);
+ break;
+ case UniqueItemsMode:
+ ParseParams({ { "attribute", false } }, params);
+ break;
+ }
+}
+
+InternalValue SequenceAccessor::Filter(const InternalValue& baseVal, RenderContext& context)
+{
+ InternalValue result;
+
+ bool isConverted = false;
+ ListAdapter list = ConvertToList(baseVal, isConverted);
+
+ if (!isConverted)
+ return result;
+
+ InternalValue attrName = GetArgumentValue("attribute", context);
+ InternalValue isCsVal = GetArgumentValue("case_sensitive", context, InternalValue(false));
+
+ BinaryExpression::CompareType compType = ConvertToBool(isCsVal) ? BinaryExpression::CaseSensitive : BinaryExpression::CaseInsensitive;
+
+ auto lessComparator = [&attrName, &compType, &context](auto& val1, auto& val2) {
+ InternalValue cmpRes;
+
+ if (IsEmpty(attrName))
+ cmpRes = Apply2<visitors::BinaryMathOperation>(val1, val2, BinaryExpression::LogicalLt, compType);
+ else
+ cmpRes = Apply2<visitors::BinaryMathOperation>(
+ Subscript(val1, attrName, &context), Subscript(val2, attrName, &context), BinaryExpression::LogicalLt, compType);
+
+ return ConvertToBool(cmpRes);
+ };
+
+ const auto& listSize = list.GetSize();
+
+ switch (m_mode)
+ {
+ case FirstItemMode:
+ if (listSize)
+ result = list.GetValueByIndex(0);
+ else
+ {
+ auto it = list.begin();
+ if (it != list.end())
+ result = *it;
+ }
+ break;
+ case LastItemMode:
+ if (listSize)
+ result = list.GetValueByIndex(listSize.value() - 1);
+ else
+ {
+ auto it = list.begin();
+ auto end = list.end();
+ for (; it != end; ++it)
+ result = *it;
+ }
+ break;
+ case LengthMode:
+ if (listSize)
+ result = static_cast<int64_t>(listSize.value());
+ else
+ result = static_cast<int64_t>(std::distance(list.begin(), list.end()));
+ break;
+ case RandomMode:
+ {
+ std::random_device rd;
+ std::mt19937 gen(rd());
+ if (listSize)
+ {
+ std::uniform_int_distribution<> dis(0, static_cast<int>(listSize.value()) - 1);
+ result = list.GetValueByIndex(dis(gen));
+ }
+ else
+ {
+ auto it = list.begin();
+ auto end = list.end();
+ size_t count = 0;
+ for (; it != end; ++it, ++count)
+ {
+ bool doCopy = count == 0 || std::uniform_int_distribution<size_t>(0, count)(gen) == 0;
+ if (doCopy)
+ result = *it;
+ }
+ }
+ break;
+ }
+ case MaxItemMode:
+ {
+ auto b = list.begin();
+ auto e = list.end();
+ auto p = std::max_element(list.begin(), list.end(), lessComparator);
+ result = p != e ? *p : InternalValue();
+ break;
+ }
+ case MinItemMode:
+ {
+ auto b = list.begin();
+ auto e = list.end();
+ auto p = std::min_element(b, e, lessComparator);
+ result = p != e ? *p : InternalValue();
+ break;
+ }
+ case ReverseMode:
+ {
+ if (listSize)
+ {
+ auto size = listSize.value();
+ InternalValueList resultList(size);
+ for (std::size_t n = 0; n < size; ++n)
+ resultList[size - n - 1] = list.GetValueByIndex(n);
+ result = ListAdapter::CreateAdapter(std::move(resultList));
+ }
+ else
+ {
+ InternalValueList resultList;
+ auto it = list.begin();
+ auto end = list.end();
+ for (; it != end; ++it)
+ resultList.push_back(*it);
+
+ std::reverse(resultList.begin(), resultList.end());
+ result = ListAdapter::CreateAdapter(std::move(resultList));
+ }
+
+ break;
+ }
+ case SumItemsMode:
+ {
+ ListAdapter l1;
+ ListAdapter* actualList;
+ if (IsEmpty(attrName))
+ {
+ actualList = &list;
+ }
+ else
+ {
+ l1 = list.ToSubscriptedList(attrName, true);
+ actualList = &l1;
+ }
+ InternalValue start = GetArgumentValue("start", context);
+ InternalValue resultVal = std::accumulate(actualList->begin(), actualList->end(), start, [](const InternalValue& cur, const InternalValue& val) {
+ if (IsEmpty(cur))
+ return val;
+
+ return Apply2<visitors::BinaryMathOperation>(cur, val, BinaryExpression::Plus);
+ });
+
+ result = std::move(resultVal);
+ break;
+ }
+ case UniqueItemsMode:
+ {
+ InternalValueList resultList;
+
+ struct Item
+ {
+ InternalValue val;
+ int64_t idx;
+ };
+ std::vector<Item> items;
+
+ int idx = 0;
+ for (auto& v : list)
+ items.push_back(Item{ IsEmpty(attrName) ? v : Subscript(v, attrName, &context), idx++ });
+
+ std::stable_sort(items.begin(), items.end(), [&compType](auto& i1, auto& i2) {
+ auto cmpRes = Apply2<visitors::BinaryMathOperation>(i1.val, i2.val, BinaryExpression::LogicalLt, compType);
+
+ return ConvertToBool(cmpRes);
+ });
+
+ auto end = std::unique(items.begin(), items.end(), [&compType](auto& i1, auto& i2) {
+ auto cmpRes = Apply2<visitors::BinaryMathOperation>(i1.val, i2.val, BinaryExpression::LogicalEq, compType);
+
+ return ConvertToBool(cmpRes);
+ });
+ items.erase(end, items.end());
+
+ std::stable_sort(items.begin(), items.end(), [](auto& i1, auto& i2) { return i1.idx < i2.idx; });
+
+ for (auto& i : items)
+ resultList.push_back(list.GetValueByIndex(i.idx));
+
+ result = ListAdapter::CreateAdapter(std::move(resultList));
+ break;
+ }
+ }
+
+ return result;
+}
+Slice::Slice(FilterParams params, Slice::Mode mode)
+ : m_mode{ mode }
+{
+ if (m_mode == BatchMode)
+ ParseParams({ { "linecount"s, true }, { "fill_with"s, false } }, params);
+ else
+ ParseParams({ { "slices"s, true }, { "fill_with"s, false } }, params);
+}
+
+InternalValue Slice::Filter(const InternalValue& baseVal, RenderContext& context)
+{
+ if (m_mode == BatchMode)
+ return Batch(baseVal, context);
+
+ InternalValue result;
+
+ bool isConverted = false;
+ ListAdapter list = ConvertToList(baseVal, isConverted);
+
+ if (!isConverted)
+ return result;
+
+ InternalValue sliceLengthValue = GetArgumentValue("slices", context);
+ int64_t sliceLength = ConvertToInt(sliceLengthValue);
+ InternalValue fillWith = GetArgumentValue("fill_with", context);
+
+ InternalValueList resultList;
+ InternalValueList sublist;
+ int sublistItemIndex = 0;
+ for (auto& item : list)
+ {
+ if (sublistItemIndex == 0)
+ sublist.clear();
+ if (sublistItemIndex == sliceLength)
+ {
+ resultList.push_back(ListAdapter::CreateAdapter(std::move(sublist)));
+ sublist.clear();
+ sublistItemIndex %= sliceLength;
+ }
+ sublist.push_back(item);
+ ++sublistItemIndex;
+ }
+ if (!IsEmpty(fillWith))
+ {
+ while (sublistItemIndex++ < sliceLength)
+ sublist.push_back(fillWith);
+ }
+ if (sublistItemIndex > 0)
+ resultList.push_back(ListAdapter::CreateAdapter(std::move(sublist)));
+
+ return InternalValue(ListAdapter::CreateAdapter(std::move(resultList)));
+}
+
+InternalValue Slice::Batch(const InternalValue& baseVal, RenderContext& context)
+{
+ auto linecount_value = ConvertToInt(GetArgumentValue("linecount", context));
+ InternalValue fillWith = GetArgumentValue("fill_with", context);
+
+ if (linecount_value <= 0)
+ return InternalValue();
+ auto linecount = static_cast<std::size_t>(linecount_value);
+
+ bool isConverted = false;
+ auto list = ConvertToList(baseVal, isConverted);
+ if (!isConverted)
+ return InternalValue();
+
+ auto elementsCount = list.GetSize().value_or(0);
+ if (!elementsCount)
+ return InternalValue();
+
+ InternalValueList resultList;
+ resultList.reserve(linecount);
+
+ const auto remainder = elementsCount % linecount;
+ const auto columns = elementsCount / linecount + (remainder > 0 ? 1 : 0);
+ for (std::size_t line = 0, idx = 0; line < linecount; ++line)
+ {
+ const auto elems = columns - (remainder && line >= remainder ? 1 : 0);
+ InternalValueList row;
+ row.reserve(columns);
+ std::fill_n(std::back_inserter(row), columns, fillWith);
+
+ for (std::size_t column = 0; column < elems; ++column)
+ row[column] = list.GetValueByIndex(idx++);
+
+ resultList.push_back(ListAdapter::CreateAdapter(std::move(row)));
+ }
+ return ListAdapter::CreateAdapter(std::move(resultList));
+}
+
+StringFormat::StringFormat(FilterParams params)
+{
+ ParseParams({}, params);
+ m_params.kwParams = std::move(m_args.extraKwArgs);
+ m_params.posParams = std::move(m_args.extraPosArgs);
+}
+
+Tester::Tester(FilterParams params, Tester::Mode mode)
+ : m_mode(mode)
+{
+ FilterParams newParams;
+
+ if ((mode == RejectMode || mode == SelectMode) && params.kwParams.empty() && params.posParams.empty())
+ {
+ m_noParams = true;
+ return;
+ }
+
+ if (mode == RejectMode || mode == SelectMode)
+ ParseParams({ { "tester", false } }, params);
+ else
+ ParseParams({ { "attribute", true }, { "tester", false } }, params);
+
+ m_testingParams.kwParams = std::move(m_args.extraKwArgs);
+ m_testingParams.posParams = std::move(m_args.extraPosArgs);
+}
+
+InternalValue Tester::Filter(const InternalValue& baseVal, RenderContext& context)
+{
+ InternalValue testerName = GetArgumentValue("tester", context);
+ InternalValue attrName = GetArgumentValue("attribute", context);
+
+ TesterPtr tester;
+
+ if (!IsEmpty(testerName))
+ {
+ tester = CreateTester(AsString(testerName), m_testingParams);
+
+ if (!tester)
+ return InternalValue();
+ }
+
+ bool isConverted = false;
+ auto list = ConvertToList(baseVal, isConverted);
+ if (!isConverted)
+ return InternalValue();
+
+ InternalValueList resultList;
+ resultList.reserve(list.GetSize().value_or(0));
+ std::copy_if(list.begin(), list.end(), std::back_inserter(resultList), [this, tester, attrName, &context](auto& val) {
+ InternalValue attrVal;
+ bool isAttr = !IsEmpty(attrName);
+ if (isAttr)
+ attrVal = Subscript(val, attrName, &context);
+
+ bool result = false;
+ if (tester)
+ result = tester->Test(isAttr ? attrVal : val, context);
+ else
+ result = ConvertToBool(isAttr ? attrVal : val);
+
+ return (m_mode == SelectMode || m_mode == SelectAttrMode) ? result : !result;
+ });
+
+ return ListAdapter::CreateAdapter(std::move(resultList));
+}
+
+ValueConverter::ValueConverter(FilterParams params, ValueConverter::Mode mode)
+ : m_mode(mode)
+{
+ switch (mode)
+ {
+ case ToFloatMode:
+ ParseParams({ { "default"s, false } }, params);
+ break;
+ case ToIntMode:
+ ParseParams({ { "default"s, false }, { "base"s, false, static_cast<int64_t>(10) } }, params);
+ break;
+ case ToListMode:
+ case AbsMode:
+ break;
+ case RoundMode:
+ ParseParams({ { "precision"s, false }, { "method"s, false, "common"s } }, params);
+ break;
+ }
+}
+
+struct ConverterParams
+{
+ ValueConverter::Mode mode;
+ InternalValue defValule;
+ InternalValue base;
+ InternalValue prec;
+ InternalValue roundMethod;
+};
+
+struct ValueConverterImpl : visitors::BaseVisitor<>
+{
+ using BaseVisitor::operator();
+
+ ValueConverterImpl(ConverterParams params)
+ : m_params(std::move(params))
+ {
+ }
+
+ InternalValue operator()(int64_t val) const
+ {
+ InternalValue result;
+ switch (m_params.mode)
+ {
+ case ValueConverter::ToFloatMode:
+ result = InternalValue(static_cast<double>(val));
+ break;
+ case ValueConverter::AbsMode:
+ result = InternalValue(static_cast<int64_t>(std::abs(val)));
+ break;
+ case ValueConverter::ToIntMode:
+ case ValueConverter::RoundMode:
+ result = InternalValue(static_cast<int64_t>(val));
+ break;
+ default:
+ break;
+ }
+
+ return result;
+ }
+
+ InternalValue operator()(double val) const
+ {
+ InternalValue result;
+ switch (m_params.mode)
+ {
+ case ValueConverter::ToFloatMode:
+ result = static_cast<double>(val);
+ break;
+ case ValueConverter::ToIntMode:
+ result = static_cast<int64_t>(val);
+ break;
+ case ValueConverter::AbsMode:
+ result = InternalValue(fabs(val));
+ break;
+ case ValueConverter::RoundMode:
+ {
+ auto method = AsString(m_params.roundMethod);
+ auto prec = GetAs<int64_t>(m_params.prec);
+ double pow10 = std::pow(10, static_cast<int>(prec));
+ val *= pow10;
+ if (method == "ceil")
+ val = val < 0 ? std::floor(val) : std::ceil(val);
+ else if (method == "floor")
+ val = val > 0 ? std::floor(val) : std::ceil(val);
+ else if (method == "common")
+ val = std::round(val);
+ result = InternalValue(val / pow10);
+ break;
+ }
+ default:
+ break;
+ }
+
+ return result;
+ }
+
+ static double ConvertToDouble(const char* buff, bool& isConverted)
+ {
+ char* endBuff = nullptr;
+ double dblVal = strtod(buff, &endBuff);
+ isConverted = *endBuff == 0;
+ return dblVal;
+ }
+
+ static double ConvertToDouble(const wchar_t* buff, bool& isConverted)
+ {
+ wchar_t* endBuff = nullptr;
+ double dblVal = wcstod(buff, &endBuff);
+ isConverted = *endBuff == 0;
+ return dblVal;
+ }
+
+ static long long ConvertToInt(const char* buff, int base, bool& isConverted)
+ {
+ char* endBuff = nullptr;
+ long long intVal = strtoll(buff, &endBuff, base);
+ isConverted = *endBuff == 0;
+ return intVal;
+ }
+
+ static long long ConvertToInt(const wchar_t* buff, int base, bool& isConverted)
+ {
+ wchar_t* endBuff = nullptr;
+ long long intVal = wcstoll(buff, &endBuff, base);
+ isConverted = *endBuff == 0;
+ return intVal;
+ }
+
+ template<typename CharT>
+ InternalValue operator()(const std::basic_string<CharT>& val) const
+ {
+ InternalValue result;
+ switch (m_params.mode)
+ {
+ case ValueConverter::ToFloatMode:
+ {
+ bool converted = false;
+ double dblVal = ConvertToDouble(val.c_str(), converted);
+
+ if (!converted)
+ result = m_params.defValule;
+ else
+ result = dblVal;
+ break;
+ }
+ case ValueConverter::ToIntMode:
+ {
+ int base = static_cast<int>(GetAs<int64_t>(m_params.base));
+ bool converted = false;
+ long long intVal = ConvertToInt(val.c_str(), base, converted);
+
+ if (!converted)
+ result = m_params.defValule;
+ else
+ result = static_cast<int64_t>(intVal);
+ break;
+ }
+ case ValueConverter::ToListMode:
+ result = ListAdapter::CreateAdapter(val.size(), [str = val](size_t idx) { return InternalValue(TargetString(str.substr(idx, 1))); });
+ default:
+ break;
+ }
+
+ return result;
+ }
+
+ template<typename CharT>
+ InternalValue operator()(const std::basic_string_view<CharT>& val) const
+ {
+ InternalValue result;
+ switch (m_params.mode)
+ {
+ case ValueConverter::ToFloatMode:
+ {
+ bool converted = false;
+ std::basic_string<CharT> str(val.begin(), val.end());
+ double dblVal = ConvertToDouble(str.c_str(), converted);
+
+ if (!converted)
+ result = m_params.defValule;
+ else
+ result = static_cast<double>(dblVal);
+ break;
+ }
+ case ValueConverter::ToIntMode:
+ {
+ int base = static_cast<int>(GetAs<int64_t>(m_params.base));
+ bool converted = false;
+ std::basic_string<CharT> str(val.begin(), val.end());
+ long long intVal = ConvertToInt(str.c_str(), base, converted);
+
+ if (!converted)
+ result = m_params.defValule;
+ else
+ result = static_cast<int64_t>(intVal);
+ break;
+ }
+ case ValueConverter::ToListMode:
+ result = ListAdapter::CreateAdapter(val.size(), [str = val](size_t idx) { return InternalValue(str.substr(idx, 1)); });
+ default:
+ break;
+ }
+
+ return result;
+ }
+
+ InternalValue operator()(const ListAdapter& val) const
+ {
+ if (m_params.mode == ValueConverter::ToListMode)
+ return InternalValue(val);
+
+ return InternalValue();
+ }
+
+ InternalValue operator()(const MapAdapter& val) const
+ {
+ if (m_params.mode != ValueConverter::ToListMode)
+ return InternalValue();
+
+ auto keys = val.GetKeys();
+ auto num_keys = keys.size();
+ return ListAdapter::CreateAdapter(num_keys, [values = std::move(keys)](size_t idx) { return InternalValue(values[idx]); });
+ }
+
+ template<typename T>
+ static T GetAs(const InternalValue& val, T defValue = 0)
+ {
+ ConverterParams params;
+ params.mode = ValueConverter::ToIntMode;
+ params.base = static_cast<int64_t>(10);
+ InternalValue intVal = Apply<ValueConverterImpl>(val, params);
+ const T* result = GetIf<int64_t>(&intVal);
+ if (result == nullptr)
+ return defValue;
+
+ return *result;
+ }
+
+ ConverterParams m_params;
+};
+
+InternalValue ValueConverter::Filter(const InternalValue& baseVal, RenderContext& context)
+{
+ ConverterParams params;
+ params.mode = m_mode;
+ params.defValule = GetArgumentValue("default", context);
+ params.base = GetArgumentValue("base", context);
+ params.prec = GetArgumentValue("precision", context);
+ params.roundMethod = GetArgumentValue("method", context);
+ auto result = Apply<ValueConverterImpl>(baseVal, params);
+ if (baseVal.ShouldExtendLifetime())
+ result.SetParentData(baseVal);
+
+ return result;
+}
+
+UserDefinedFilter::UserDefinedFilter(std::string filterName, FilterParams params)
+ : m_filterName(std::move(filterName))
+{
+ ParseParams({ { "*args" }, { "**kwargs" } }, params);
+ m_callParams.kwParams = m_args.extraKwArgs;
+ m_callParams.posParams = m_args.extraPosArgs;
+}
+
+InternalValue UserDefinedFilter::Filter(const InternalValue& baseVal, RenderContext& context)
+{
+ bool filterFound = false;
+ auto filterValPtr = context.FindValue(m_filterName, filterFound);
+ if (!filterFound)
+ throw std::runtime_error("Can't find filter '" + m_filterName + "'");
+
+ const Callable* callable = GetIf<Callable>(&filterValPtr->second);
+ if (callable == nullptr || callable->GetKind() != Callable::UserCallable)
+ return InternalValue();
+
+ CallParams tmpCallParams = helpers::EvaluateCallParams(m_callParams, context);
+ CallParams callParams;
+ callParams.kwParams = std::move(tmpCallParams.kwParams);
+ callParams.posParams.reserve(tmpCallParams.posParams.size() + 1);
+ callParams.posParams.push_back(baseVal);
+ for (auto& p : tmpCallParams.posParams)
+ callParams.posParams.push_back(std::move(p));
+
+ InternalValue result;
+ if (callable->GetType() != Callable::Type::Expression)
+ return InternalValue();
+
+ return callable->GetExpressionCallable()(callParams, context);
+}
+
+} // namespace filters
+} // namespace jinja2
diff --git a/contrib/libs/jinja2cpp/src/filters.h b/contrib/libs/jinja2cpp/src/filters.h
new file mode 100644
index 0000000000..1fdfc465c3
--- /dev/null
+++ b/contrib/libs/jinja2cpp/src/filters.h
@@ -0,0 +1,474 @@
+#ifndef JINJA2CPP_SRC_FILTERS_H
+#define JINJA2CPP_SRC_FILTERS_H
+
+#include "expression_evaluator.h"
+#include "function_base.h"
+#include "jinja2cpp/value.h"
+#include "render_context.h"
+
+#include <memory>
+#include <functional>
+
+namespace jinja2
+{
+using FilterPtr = std::shared_ptr<ExpressionFilter::IExpressionFilter>;
+using FilterParams = CallParamsInfo;
+
+extern FilterPtr CreateFilter(std::string filterName, CallParamsInfo params);
+
+namespace filters
+{
+class FilterBase : public FunctionBase, public ExpressionFilter::IExpressionFilter
+{
+};
+
+class ApplyMacro : public FilterBase
+{
+public:
+ ApplyMacro(FilterParams params);
+
+ InternalValue Filter(const InternalValue& baseVal, RenderContext& context) override;
+ bool IsEqual(const IComparable& other) const override
+ {
+ auto* value = dynamic_cast<const ApplyMacro*>(&other);
+ if (!value)
+ return false;
+ if (m_args != value->m_args)
+ return false;
+ if (m_mappingParams != value->m_mappingParams)
+ return false;
+ return true;
+ }
+private:
+ FilterParams m_mappingParams;
+};
+
+class Attribute : public FilterBase
+{
+public:
+ Attribute(FilterParams params);
+
+ InternalValue Filter(const InternalValue& baseVal, RenderContext& context) override;
+
+ bool IsEqual(const IComparable& other) const override
+ {
+ auto* value = dynamic_cast<const Attribute*>(&other);
+ if (!value)
+ return false;
+ if (m_args != value->m_args)
+ return false;
+ return true;
+ }
+};
+
+class Default : public FilterBase
+{
+public:
+ Default(FilterParams params);
+
+ InternalValue Filter(const InternalValue& baseVal, RenderContext& context) override;
+ bool IsEqual(const IComparable& other) const override
+ {
+ auto* value = dynamic_cast<const Default*>(&other);
+ if (!value)
+ return false;
+ if (m_args != value->m_args)
+ return false;
+ return true;
+ }
+};
+
+class DictSort : public FilterBase
+{
+public:
+ DictSort(FilterParams params);
+
+ InternalValue Filter(const InternalValue& baseVal, RenderContext& context) override;
+ bool IsEqual(const IComparable& other) const override
+ {
+ auto* value = dynamic_cast<const DictSort*>(&other);
+ if (!value)
+ return false;
+ if (m_args != value->m_args)
+ return false;
+ return true;
+ }
+};
+
+class GroupBy : public FilterBase
+{
+public:
+ GroupBy(FilterParams params);
+
+ InternalValue Filter(const InternalValue& baseVal, RenderContext& context) override;
+ bool IsEqual(const IComparable& other) const override
+ {
+ auto* value = dynamic_cast<const GroupBy*>(&other);
+ if (!value)
+ return false;
+ if (m_args != value->m_args)
+ return false;
+ return true;
+ }
+};
+
+class Join : public FilterBase
+{
+public:
+ Join(FilterParams params);
+
+ InternalValue Filter(const InternalValue& baseVal, RenderContext& context) override;
+ bool IsEqual(const IComparable& other) const override
+ {
+ auto* value = dynamic_cast<const Join*>(&other);
+ if (!value)
+ return false;
+ if (m_args != value->m_args)
+ return false;
+ return true;
+ }
+};
+
+class Map : public FilterBase
+{
+public:
+ Map(FilterParams params);
+
+ InternalValue Filter(const InternalValue& baseVal, RenderContext& context) override;
+ bool IsEqual(const IComparable& other) const override
+ {
+ auto* value = dynamic_cast<const Map*>(&other);
+ if (!value)
+ return false;
+ if (m_args != value->m_args)
+ return false;
+ if (m_mappingParams != value->m_mappingParams)
+ return false;
+ return true;
+ }
+private:
+ static FilterParams MakeParams(FilterParams);
+
+ FilterParams m_mappingParams;
+};
+
+class PrettyPrint : public FilterBase
+{
+public:
+ PrettyPrint(FilterParams params);
+
+ InternalValue Filter(const InternalValue& baseVal, RenderContext& context) override;
+ bool IsEqual(const IComparable& other) const override
+ {
+ auto* value = dynamic_cast<const PrettyPrint*>(&other);
+ if (!value)
+ return false;
+ if (m_args != value->m_args)
+ return false;
+ return true;
+ }
+};
+
+class Random : public FilterBase
+{
+public:
+ Random(FilterParams params);
+
+ InternalValue Filter(const InternalValue& baseVal, RenderContext& context) override;
+ bool IsEqual(const IComparable& other) const override
+ {
+ auto* value = dynamic_cast<const Random*>(&other);
+ if (!value)
+ return false;
+ if (m_args != value->m_args)
+ return false;
+ return true;
+ }
+};
+
+class SequenceAccessor : public FilterBase
+{
+public:
+ enum Mode
+ {
+ FirstItemMode,
+ LastItemMode,
+ LengthMode,
+ MaxItemMode,
+ MinItemMode,
+ RandomMode,
+ ReverseMode,
+ SumItemsMode,
+ UniqueItemsMode,
+
+ };
+
+ SequenceAccessor(FilterParams params, Mode mode);
+
+ InternalValue Filter(const InternalValue& baseVal, RenderContext& context) override;
+
+ bool IsEqual(const IComparable& other) const override
+ {
+ auto* value = dynamic_cast<const SequenceAccessor*>(&other);
+ if (!value)
+ return false;
+ if (m_args != value->m_args)
+ return false;
+ if (m_mode != value->m_mode)
+ return false;
+ return true;
+ }
+private:
+ Mode m_mode;
+};
+
+class Serialize : public FilterBase
+{
+public:
+ enum Mode
+ {
+ JsonMode,
+ XmlMode,
+ YamlMode
+ };
+
+ Serialize(FilterParams params, Mode mode);
+
+ InternalValue Filter(const InternalValue& baseVal, RenderContext& context) override;
+
+ bool IsEqual(const IComparable& other) const override
+ {
+ auto* value = dynamic_cast<const Serialize*>(&other);
+ if (!value)
+ return false;
+ if (m_args != value->m_args)
+ return false;
+ if (m_mode != value->m_mode)
+ return false;
+ return true;
+ }
+private:
+ Mode m_mode;
+};
+
+class Slice : public FilterBase
+{
+public:
+ enum Mode
+ {
+ BatchMode,
+ SliceMode,
+ };
+
+ Slice(FilterParams params, Mode mode);
+
+ InternalValue Filter(const InternalValue& baseVal, RenderContext& context) override;
+ bool IsEqual(const IComparable& other) const override
+ {
+ auto* value = dynamic_cast<const Slice*>(&other);
+ if (!value)
+ return false;
+ if (m_args != value->m_args)
+ return false;
+ if (m_mode != value->m_mode)
+ return false;
+ return true;
+ }
+private:
+ InternalValue Batch(const InternalValue& baseVal, RenderContext& context);
+
+ Mode m_mode;
+};
+
+class Sort : public FilterBase
+{
+public:
+ Sort(FilterParams params);
+
+ InternalValue Filter(const InternalValue& baseVal, RenderContext& context) override;
+ bool IsEqual(const IComparable& other) const override
+ {
+ auto* value = dynamic_cast<const Sort*>(&other);
+ if (!value)
+ return false;
+ if (m_args != value->m_args)
+ return false;
+ return true;
+ }
+};
+
+class StringConverter : public FilterBase
+{
+public:
+ enum Mode
+ {
+ CapitalMode,
+ CamelMode,
+ EscapeCppMode,
+ EscapeHtmlMode,
+ LowerMode,
+ ReplaceMode,
+ StriptagsMode,
+ TitleMode,
+ TrimMode,
+ TruncateMode,
+ UpperMode,
+ WordCountMode,
+ WordWrapMode,
+ UnderscoreMode,
+ UrlEncodeMode,
+ CenterMode
+ };
+
+ StringConverter(FilterParams params, Mode mode);
+
+ InternalValue Filter(const InternalValue& baseVal, RenderContext& context) override;
+
+ bool IsEqual(const IComparable& other) const override
+ {
+ auto* value = dynamic_cast<const StringConverter*>(&other);
+ if (!value)
+ return false;
+ if (m_args != value->m_args)
+ return false;
+ if (m_mode != value->m_mode)
+ return false;
+ return true;
+ }
+private:
+ Mode m_mode;
+};
+
+class StringFormat : public FilterBase
+{
+public:
+ StringFormat(FilterParams params);
+
+ InternalValue Filter(const InternalValue& baseVal, RenderContext& context) override;
+
+ bool IsEqual(const IComparable& other) const override
+ {
+ auto* value = dynamic_cast<const StringFormat*>(&other);
+ if (!value)
+ return false;
+ if (m_args != value->m_args)
+ return false;
+ if (m_params != value->m_params)
+ return false;
+ return true;
+ }
+
+private:
+ FilterParams m_params;
+};
+
+class Tester : public FilterBase
+{
+public:
+ enum Mode
+ {
+ RejectMode,
+ RejectAttrMode,
+ SelectMode,
+ SelectAttrMode,
+ };
+
+ Tester(FilterParams params, Mode mode);
+
+ InternalValue Filter(const InternalValue& baseVal, RenderContext& context) override;
+
+ bool IsEqual(const IComparable& other) const override
+ {
+ auto* value = dynamic_cast<const Tester*>(&other);
+ if (!value)
+ return false;
+ if (m_args != value->m_args)
+ return false;
+ if (m_mode != value->m_mode)
+ return false;
+ if (m_testingParams != value->m_testingParams)
+ return false;
+ return true;
+ }
+private:
+ Mode m_mode;
+ FilterParams m_testingParams;
+ bool m_noParams = false;
+};
+
+class ValueConverter : public FilterBase
+{
+public:
+ enum Mode
+ {
+ ToFloatMode,
+ ToIntMode,
+ ToListMode,
+ AbsMode,
+ RoundMode,
+ };
+
+ ValueConverter(FilterParams params, Mode mode);
+
+ InternalValue Filter(const InternalValue& baseVal, RenderContext& context) override;
+
+ bool IsEqual(const IComparable& other) const override
+ {
+ auto* value = dynamic_cast<const ValueConverter*>(&other);
+ if (!value)
+ return false;
+ if (m_args != value->m_args)
+ return false;
+ return m_mode == value->m_mode;
+ }
+private:
+ Mode m_mode;
+};
+
+class XmlAttrFilter : public FilterBase
+{
+public:
+ explicit XmlAttrFilter(FilterParams params);
+
+ InternalValue Filter(const InternalValue& baseVal, RenderContext& context) override;
+ bool IsEqual(const IComparable& other) const override
+ {
+ auto* value = dynamic_cast<const XmlAttrFilter*>(&other);
+ if (!value)
+ return false;
+ if (m_args != value->m_args)
+ return false;
+ return true;
+ }
+};
+
+class UserDefinedFilter : public FilterBase
+{
+public:
+ UserDefinedFilter(std::string filterName, FilterParams params);
+
+ InternalValue Filter(const InternalValue& baseVal, RenderContext& context) override;
+
+ bool IsEqual(const IComparable& other) const override
+ {
+ auto* value = dynamic_cast<const UserDefinedFilter*>(&other);
+ if (!value)
+ return false;
+ if (m_args != value->m_args)
+ return false;
+ if (m_filterName != value->m_filterName)
+ return false;
+ if (m_callParams != m_callParams)
+ return false;
+ return true;
+ }
+
+private:
+ std::string m_filterName;
+ FilterParams m_callParams;
+};
+
+} // namespace filters
+} // namespace jinja2
+
+#endif // JINJA2CPP_SRC_FILTERS_H
diff --git a/contrib/libs/jinja2cpp/src/function_base.h b/contrib/libs/jinja2cpp/src/function_base.h
new file mode 100644
index 0000000000..578545b031
--- /dev/null
+++ b/contrib/libs/jinja2cpp/src/function_base.h
@@ -0,0 +1,49 @@
+#ifndef JINJA2CPP_SRC_FUNCTION_BASE_H
+#define JINJA2CPP_SRC_FUNCTION_BASE_H
+
+#include "expression_evaluator.h"
+#include "internal_value.h"
+
+namespace jinja2
+{
+class FunctionBase
+{
+public:
+ bool operator==(const FunctionBase& other) const
+ {
+ return m_args == other.m_args;
+ }
+ bool operator!=(const FunctionBase& other) const
+ {
+ return !(*this == other);
+ }
+protected:
+ bool ParseParams(const std::initializer_list<ArgumentInfo>& argsInfo, const CallParamsInfo& params);
+ InternalValue GetArgumentValue(const std::string& argName, RenderContext& context, InternalValue defVal = InternalValue());
+
+protected:
+ ParsedArgumentsInfo m_args;
+};
+
+//bool operator==(const FunctionBase& lhs, const FunctionBase& rhs)
+//{
+// return
+//}
+
+inline bool FunctionBase::ParseParams(const std::initializer_list<ArgumentInfo>& argsInfo, const CallParamsInfo& params)
+{
+ bool result = true;
+ m_args = helpers::ParseCallParamsInfo(argsInfo, params, result);
+
+ return result;
+}
+
+inline InternalValue FunctionBase::GetArgumentValue(const std::string& argName, RenderContext& context, InternalValue defVal)
+{
+ auto argExpr = m_args[argName];
+ return argExpr ? argExpr->Evaluate(context) : std::move(defVal);
+}
+
+} // namespace jinja2
+
+#endif // JINJA2CPP_SRC_FUNCTION_BASE_H
diff --git a/contrib/libs/jinja2cpp/src/generic_adapters.h b/contrib/libs/jinja2cpp/src/generic_adapters.h
new file mode 100644
index 0000000000..e6d0c9bcb0
--- /dev/null
+++ b/contrib/libs/jinja2cpp/src/generic_adapters.h
@@ -0,0 +1,215 @@
+#ifndef JINJA2CPP_SRC_GENERIC_ADAPTERS_H
+#define JINJA2CPP_SRC_GENERIC_ADAPTERS_H
+
+#include <jinja2cpp/value.h>
+#include "internal_value.h"
+
+namespace jinja2
+{
+
+template<typename ImplType, typename List, typename ValType, typename Base>
+class IndexedEnumeratorImpl : public Base
+{
+public:
+ using ValueType = ValType;
+ using ThisType = IndexedEnumeratorImpl<ImplType, List, ValType, Base>;
+
+ IndexedEnumeratorImpl(const List* list)
+ : m_list(list)
+ , m_maxItems(list->GetSize().value())
+ { }
+
+ void Reset() override
+ {
+ m_curItem = m_invalidIndex;
+ }
+
+ bool MoveNext() override
+ {
+ if (m_curItem == m_invalidIndex)
+ m_curItem = 0;
+ else
+ ++ m_curItem;
+
+ return m_curItem < m_maxItems;
+ }
+
+ bool IsEqual(const IComparable& other) const override
+ {
+ auto* val = dynamic_cast<const ThisType*>(&other);
+ if (!val)
+ return false;
+ if (m_list && val->m_list && !m_list->IsEqual(*val->m_list))
+ return false;
+ if ((m_list && !val->m_list) || (!m_list && val->m_list))
+ return false;
+ if (m_curItem != val->m_curItem)
+ return false;
+ if (m_maxItems != val->m_maxItems)
+ return false;
+ return true;
+ }
+
+protected:
+ constexpr static auto m_invalidIndex = std::numeric_limits<size_t>::max();
+ const List* m_list{};
+ size_t m_curItem = m_invalidIndex;
+ size_t m_maxItems{};
+};
+
+
+template<typename T>
+class IndexedListItemAccessorImpl : public IListItemAccessor, public IIndexBasedAccessor
+{
+public:
+ using ThisType = IndexedListItemAccessorImpl<T>;
+ class Enumerator : public IndexedEnumeratorImpl<Enumerator, ThisType, Value, IListEnumerator>
+ {
+ public:
+ using BaseClass = IndexedEnumeratorImpl<Enumerator, ThisType, Value, IListEnumerator>;
+#if defined(_MSC_VER)
+ using IndexedEnumeratorImpl::IndexedEnumeratorImpl;
+#else
+ using BaseClass::BaseClass;
+#endif
+
+ typename BaseClass::ValueType GetCurrent() const override
+ {
+ auto indexer = this->m_list->GetIndexer();
+ if (!indexer)
+ return Value();
+
+ return indexer->GetItemByIndex(this->m_curItem);
+ }
+ ListEnumeratorPtr Clone() const override
+ {
+ auto result = MakeEnumerator<Enumerator>(this->m_list);
+ auto base = static_cast<Enumerator*>(&(*result));
+ base->m_curItem = this->m_curItem;
+ return result;
+ }
+
+ ListEnumeratorPtr Move() override
+ {
+ auto result = MakeEnumerator<Enumerator>(this->m_list);
+ auto base = static_cast<Enumerator*>(&(*result));
+ base->m_curItem = this->m_curItem;
+ this->m_list = nullptr;
+ this->m_curItem = this->m_invalidIndex;
+ this->m_maxItems = 0;
+ return result;
+ }
+ };
+
+ Value GetItemByIndex(int64_t idx) const override
+ {
+ return IntValue2Value(std::move(static_cast<const T*>(this)->GetItem(idx).value()));
+ }
+
+ std::optional<size_t> GetSize() const override
+ {
+ return static_cast<const T*>(this)->GetItemsCountImpl();
+ }
+
+ const IIndexBasedAccessor* GetIndexer() const override
+ {
+ return this;
+ }
+
+ ListEnumeratorPtr CreateEnumerator() const override;
+
+ bool IsEqual(const IComparable& other) const override
+ {
+ auto* val = dynamic_cast<const ThisType*>(&other);
+ if (!val)
+ return false;
+ auto enumerator = CreateEnumerator();
+ auto otherEnum = val->CreateEnumerator();
+ if (enumerator && otherEnum && !enumerator->IsEqual(*otherEnum))
+ return false;
+ return true;
+ }
+};
+
+template<typename T>
+class IndexedListAccessorImpl : public IListAccessor, public IndexedListItemAccessorImpl<T>
+{
+public:
+ using ThisType = IndexedListAccessorImpl<T>;
+ class Enumerator : public IndexedEnumeratorImpl<Enumerator, ThisType, InternalValue, IListAccessorEnumerator>
+ {
+ public:
+ using BaseClass = IndexedEnumeratorImpl<Enumerator, ThisType, InternalValue, IListAccessorEnumerator>;
+#if defined(_MSC_VER)
+ using IndexedEnumeratorImpl::IndexedEnumeratorImpl;
+#else
+ using BaseClass::BaseClass;
+#endif
+
+ typename BaseClass::ValueType GetCurrent() const override
+ {
+ const auto& result = this->m_list->GetItem(this->m_curItem);
+ if (!result)
+ return InternalValue();
+
+ return result.value();
+ }
+
+ IListAccessorEnumerator* Clone() const override
+ {
+ auto result = new Enumerator(this->m_list);
+ auto base = result;
+ base->m_curItem = this->m_curItem;
+ return result;
+ }
+
+ IListAccessorEnumerator* Transfer() override
+ {
+ auto result = new Enumerator(std::move(*this));
+ auto base = result;
+ base->m_curItem = this->m_curItem;
+ this->m_list = nullptr;
+ this->m_curItem = this->m_invalidIndex;
+ this->m_maxItems = 0;
+ return result;
+ }
+ };
+
+ std::optional<size_t> GetSize() const override
+ {
+ return static_cast<const T*>(this)->GetItemsCountImpl();
+ }
+ ListAccessorEnumeratorPtr CreateListAccessorEnumerator() const override;
+};
+
+template<typename T>
+class MapItemAccessorImpl : public IMapItemAccessor
+{
+public:
+ Value GetValueByName(const std::string& name) const
+ {
+ return IntValue2Value(static_cast<const T*>(this)->GetItem(name));
+ }
+};
+
+template<typename T>
+class MapAccessorImpl : public IMapAccessor, public MapItemAccessorImpl<T>
+{
+public:
+};
+
+template<typename T>
+inline ListAccessorEnumeratorPtr IndexedListAccessorImpl<T>::CreateListAccessorEnumerator() const
+{
+ return ListAccessorEnumeratorPtr(new Enumerator(this));
+}
+
+template<typename T>
+inline ListEnumeratorPtr IndexedListItemAccessorImpl<T>::CreateEnumerator() const
+{
+ return MakeEnumerator<Enumerator>(this);
+}
+
+} // namespace jinja2
+
+#endif // JINJA2CPP_SRC_GENERIC_ADAPTERS_H
diff --git a/contrib/libs/jinja2cpp/src/generic_list.cpp b/contrib/libs/jinja2cpp/src/generic_list.cpp
new file mode 100644
index 0000000000..883ef3615a
--- /dev/null
+++ b/contrib/libs/jinja2cpp/src/generic_list.cpp
@@ -0,0 +1,38 @@
+#include <jinja2cpp/generic_list.h>
+#include <jinja2cpp/generic_list_iterator.h>
+
+namespace jinja2 {
+
+detail::GenericListIterator GenericList::begin() const
+{
+ return m_accessor && m_accessor() ? detail::GenericListIterator(m_accessor()->CreateEnumerator()) : detail::GenericListIterator();
+}
+
+detail::GenericListIterator GenericList::end() const
+{
+ return detail::GenericListIterator();
+}
+
+auto GenericList::cbegin() const {return begin();}
+auto GenericList::cend() const {return end();}
+
+bool GenericList::IsEqual(const GenericList& rhs) const
+{
+ if (IsValid() && rhs.IsValid() && !GetAccessor()->IsEqual(*rhs.GetAccessor()))
+ return false;
+ if ((IsValid() && !rhs.IsValid()) || (!IsValid() && rhs.IsValid()))
+ return false;
+ return true;
+}
+
+bool operator==(const GenericList& lhs, const GenericList& rhs)
+{
+ return lhs.IsEqual(rhs);
+}
+
+bool operator!=(const GenericList& lhs, const GenericList& rhs)
+{
+ return !(lhs == rhs);
+}
+
+} // namespace jinja2
diff --git a/contrib/libs/jinja2cpp/src/helpers.h b/contrib/libs/jinja2cpp/src/helpers.h
new file mode 100644
index 0000000000..74e87400df
--- /dev/null
+++ b/contrib/libs/jinja2cpp/src/helpers.h
@@ -0,0 +1,119 @@
+#ifndef JINJA2CPP_SRC_HELPERS_H
+#define JINJA2CPP_SRC_HELPERS_H
+
+#include <string_view>
+#include <jinja2cpp/string_helpers.h>
+
+#include <string>
+#include <type_traits>
+#include <cwchar>
+
+namespace jinja2
+{
+struct MultiStringLiteral
+{
+ const char* charValue;
+ const wchar_t* wcharValue;
+
+ constexpr MultiStringLiteral(const char* val, const wchar_t* wval)
+ : charValue(val)
+ , wcharValue(wval)
+ {
+ }
+
+ template<typename CharT>
+ constexpr auto GetValue() const
+ {
+#if __cplusplus < 202002L
+ return GetValueStr<CharT>();
+#else
+ constexpr auto memPtr = SelectMemberPtr<CharT, &MultiStringLiteral::charValue, &MultiStringLiteral::wcharValue>::GetPtr();
+ return std::basic_string_view<CharT>(this->*memPtr);
+#endif
+ }
+
+ template<typename CharT>
+ constexpr auto GetValueStr() const
+ {
+ constexpr auto memPtr = SelectMemberPtr<CharT, &MultiStringLiteral::charValue, &MultiStringLiteral::wcharValue>::GetPtr();
+ return std::basic_string<CharT>(this->*memPtr);
+ }
+
+ template<typename CharT, const char* MultiStringLiteral::*, const wchar_t* MultiStringLiteral::*>
+ struct SelectMemberPtr;
+
+ template<const char* (MultiStringLiteral::*charMemPtr), const wchar_t* (MultiStringLiteral::*wcharMemPtr)>
+ struct SelectMemberPtr<char, charMemPtr, wcharMemPtr>
+ {
+ static constexpr auto GetPtr() {return charMemPtr;}
+ };
+
+ template<const char* (MultiStringLiteral::*charMemPtr), const wchar_t* (MultiStringLiteral::*wcharMemPtr)>
+ struct SelectMemberPtr<wchar_t, charMemPtr, wcharMemPtr>
+ {
+ static constexpr auto GetPtr() {return wcharMemPtr;}
+ };
+
+ template<typename CharT>
+ friend std::basic_ostream<CharT>& operator << (std::basic_ostream<CharT>& os, const MultiStringLiteral& lit)
+ {
+ os << lit.GetValue<CharT>();
+ return os;
+ }
+};
+
+#define UNIVERSAL_STR(Str) \
+ ::jinja2::MultiStringLiteral { Str, L##Str }
+
+//! CompileEscapes replaces escape characters by their meanings.
+/**
+ * @param[in] s Characters sequence with zero or more escape characters.
+ * @return Characters sequence copy where replaced all escape characters by
+ * their meanings.
+ */
+template<typename Sequence>
+Sequence CompileEscapes(Sequence s)
+{
+ auto itr1 = s.begin();
+ auto itr2 = s.begin();
+ const auto end = s.cend();
+
+ auto removalCount = 0;
+
+ while (end != itr1)
+ {
+ if ('\\' == *itr1)
+ {
+ ++removalCount;
+
+ if (end == ++itr1)
+ break;
+ if ('\\' != *itr1)
+ {
+ switch (*itr1)
+ {
+ case 'n': *itr1 = '\n'; break;
+ case 'r': *itr1 = '\r'; break;
+ case 't': *itr1 = '\t'; break;
+ default: break;
+ }
+
+ continue;
+ }
+ }
+
+ if (itr1 != itr2)
+ *itr2 = *itr1;
+
+ ++itr1;
+ ++itr2;
+ }
+
+ s.resize(s.size() - removalCount);
+
+ return s;
+}
+
+} // namespace jinja2
+
+#endif // JINJA2CPP_SRC_HELPERS_H
diff --git a/contrib/libs/jinja2cpp/src/internal_value.cpp b/contrib/libs/jinja2cpp/src/internal_value.cpp
new file mode 100644
index 0000000000..7683bc2c97
--- /dev/null
+++ b/contrib/libs/jinja2cpp/src/internal_value.cpp
@@ -0,0 +1,1053 @@
+#include "internal_value.h"
+
+#include "expression_evaluator.h"
+#include "generic_adapters.h"
+#include "helpers.h"
+#include "value_visitors.h"
+
+namespace jinja2
+{
+
+std::atomic_uint64_t UserCallable::m_gen{};
+
+bool Value::IsEqual(const Value& rhs) const
+{
+ return this->m_data == rhs.m_data;
+}
+
+bool operator==(const Value& lhs, const Value& rhs)
+{
+ return lhs.IsEqual(rhs);
+}
+
+bool operator!=(const Value& lhs, const Value& rhs)
+{
+ return !(lhs == rhs);
+}
+
+bool operator==(const GenericMap& lhs, const GenericMap& rhs)
+{
+ auto* lhsAccessor = lhs.GetAccessor();
+ auto* rhsAccessor = rhs.GetAccessor();
+ return lhsAccessor && rhsAccessor && lhsAccessor->IsEqual(*rhsAccessor);
+}
+
+bool operator!=(const GenericMap& lhs, const GenericMap& rhs)
+{
+ return !(lhs == rhs);
+}
+
+bool operator==(const UserCallable& lhs, const UserCallable& rhs)
+{
+ // TODO: rework
+ return lhs.IsEqual(rhs);
+}
+
+bool operator!=(const UserCallable& lhs, const UserCallable& rhs)
+{
+ return !(lhs == rhs);
+}
+
+bool operator==(const types::ValuePtr<UserCallable>& lhs, const types::ValuePtr<UserCallable>& rhs)
+{
+ if (lhs && rhs)
+ return *lhs == *rhs;
+ if ((lhs && !rhs) || (!lhs && rhs))
+ return false;
+ return true;
+}
+
+bool operator!=(const types::ValuePtr<UserCallable>& lhs, const types::ValuePtr<UserCallable>& rhs)
+{
+ return !(lhs == rhs);
+}
+
+bool operator==(const types::ValuePtr<ValuesMap>& lhs, const types::ValuePtr<ValuesMap>& rhs)
+{
+ if (lhs && rhs)
+ return *lhs == *rhs;
+ if ((lhs && !rhs) || (!lhs && rhs))
+ return false;
+ return true;
+}
+
+bool operator!=(const types::ValuePtr<ValuesMap>& lhs, const types::ValuePtr<ValuesMap>& rhs)
+{
+ return !(lhs == rhs);
+}
+
+bool operator==(const types::ValuePtr<Value>& lhs, const types::ValuePtr<Value>& rhs)
+{
+ if (lhs && rhs)
+ return *lhs == *rhs;
+ if ((lhs && !rhs) || (!lhs && rhs))
+ return false;
+ return true;
+}
+
+bool operator!=(const types::ValuePtr<Value>& lhs, const types::ValuePtr<Value>& rhs)
+{
+ return !(lhs == rhs);
+}
+
+bool operator==(const types::ValuePtr<std::vector<Value>>& lhs, const types::ValuePtr<std::vector<Value>>& rhs)
+{
+ if (lhs && rhs)
+ return *lhs == *rhs;
+ if ((lhs && !rhs) || (!lhs && rhs))
+ return false;
+ return true;
+}
+
+bool operator!=(const types::ValuePtr<std::vector<Value>>& lhs, const types::ValuePtr<std::vector<Value>>& rhs)
+{
+ return !(lhs == rhs);
+}
+
+bool InternalValue::IsEqual(const InternalValue &other) const
+{
+ if (m_data != other.m_data)
+ return false;
+ return m_parentData == other.m_parentData;
+}
+
+InternalValue Value2IntValue(const Value& val);
+InternalValue Value2IntValue(Value&& val);
+
+struct SubscriptionVisitor : public visitors::BaseVisitor<>
+{
+ using BaseVisitor<>::operator();
+
+ template<typename CharT>
+ InternalValue operator()(const MapAdapter& values, const std::basic_string<CharT>& fieldName) const
+ {
+ auto field = ConvertString<std::string>(fieldName);
+ if (!values.HasValue(field))
+ return InternalValue();
+
+ return values.GetValueByName(field);
+ }
+
+ template<typename CharT>
+ InternalValue operator()(const MapAdapter& values, const std::basic_string_view<CharT>& fieldName) const
+ {
+ auto field = ConvertString<std::string>(fieldName);
+ if (!values.HasValue(field))
+ return InternalValue();
+
+ return values.GetValueByName(field);
+ }
+
+ template<typename CharT>
+ InternalValue operator()(std::basic_string<CharT> value, const std::basic_string<CharT>& /*fieldName*/) const
+ {
+ return TargetString(std::move(value));
+ }
+
+ InternalValue operator()(const ListAdapter& values, int64_t index) const
+ {
+ if (index < 0 || static_cast<size_t>(index) >= values.GetSize())
+ return InternalValue();
+
+ return values.GetValueByIndex(index);
+ }
+
+ InternalValue operator()(const MapAdapter& /*values*/, int64_t /*index*/) const { return InternalValue(); }
+
+ template<typename CharT>
+ InternalValue operator()(const std::basic_string<CharT>& str, int64_t index) const
+ {
+ if (index < 0 || static_cast<size_t>(index) >= str.size())
+ return InternalValue();
+
+ std::basic_string<CharT> resultStr(1, str[static_cast<size_t>(index)]);
+ return TargetString(std::move(resultStr));
+ }
+
+ template<typename CharT>
+ InternalValue operator()(const std::basic_string_view<CharT>& str, int64_t index) const
+ {
+ // std::cout << "operator() (const std::basic_string<CharT>& str, int64_t index)" << ": index = " << index << std::endl;
+ if (index < 0 || static_cast<size_t>(index) >= str.size())
+ return InternalValue();
+
+ std::basic_string<CharT> result(1, str[static_cast<size_t>(index)]);
+ return TargetString(std::move(result));
+ }
+
+ template<typename CharT>
+ InternalValue operator()(const KeyValuePair& values, const std::basic_string<CharT>& fieldName) const
+ {
+ return SubscriptKvPair(values, ConvertString<std::string>(fieldName));
+ }
+
+ template<typename CharT>
+ InternalValue operator()(const KeyValuePair& values, const std::basic_string_view<CharT>& fieldName) const
+ {
+ return SubscriptKvPair(values, ConvertString<std::string>(fieldName));
+ }
+
+ InternalValue SubscriptKvPair(const KeyValuePair& values, const std::string& field) const
+ {
+ // std::cout << "operator() (const KeyValuePair& values, const std::string& field)" << ": field = " << field << std::endl;
+ if (field == "key")
+ return InternalValue(values.key);
+ else if (field == "value")
+ return values.value;
+
+ return InternalValue();
+ }
+};
+
+InternalValue Subscript(const InternalValue& val, const InternalValue& subscript, RenderContext* values)
+{
+ static const std::string callOperName = "value()";
+ auto result = Apply2<SubscriptionVisitor>(val, subscript);
+
+ if (!values)
+ return result;
+
+ auto map = GetIf<MapAdapter>(&result);
+ if (!map || !map->HasValue(callOperName))
+ return result;
+
+ auto callableVal = map->GetValueByName(callOperName);
+ auto callable = GetIf<Callable>(&callableVal);
+ if (!callable || callable->GetKind() == Callable::Macro || callable->GetType() == Callable::Type::Statement)
+ return result;
+
+ CallParams callParams;
+ return callable->GetExpressionCallable()(callParams, *values);
+}
+
+InternalValue Subscript(const InternalValue& val, const std::string& subscript, RenderContext* values)
+{
+ return Subscript(val, InternalValue(subscript), values);
+}
+
+struct StringGetter : public visitors::BaseVisitor<std::string>
+{
+ using BaseVisitor::operator();
+
+ std::string operator()(const std::string& str) const { return str; }
+ std::string operator()(const std::string_view& str) const { return std::string(str.begin(), str.end()); }
+ std::string operator()(const std::wstring& str) const { return ConvertString<std::string>(str); }
+ std::string operator()(const std::wstring_view& str) const { return ConvertString<std::string>(str); }
+};
+
+std::string AsString(const InternalValue& val)
+{
+ return Apply<StringGetter>(val);
+}
+
+struct ListConverter : public visitors::BaseVisitor<boost::optional<ListAdapter>>
+{
+ using BaseVisitor::operator();
+
+ using result_t = boost::optional<ListAdapter>;
+
+ bool strictConvertion;
+
+ ListConverter(bool strict)
+ : strictConvertion(strict)
+ {
+ }
+
+ result_t operator()(const ListAdapter& list) const { return list; }
+ result_t operator()(const MapAdapter& map) const
+ {
+ if (strictConvertion)
+ return result_t();
+
+ InternalValueList list;
+ for (auto& k : map.GetKeys())
+ list.push_back(TargetString(k));
+
+ return ListAdapter::CreateAdapter(std::move(list));
+ }
+
+ template<typename CharT>
+ result_t operator() (const std::basic_string<CharT>& str) const
+ {
+ return strictConvertion ? result_t() : result_t(ListAdapter::CreateAdapter(str.size(), [str](size_t idx) {
+ return TargetString(str.substr(idx, 1));}));
+ }
+
+ template<typename CharT>
+ result_t operator()(const std::basic_string_view<CharT>& str) const
+ {
+ return strictConvertion ? result_t() : result_t(ListAdapter::CreateAdapter(str.size(), [str](size_t idx) {
+ return TargetString(std::basic_string<CharT>(str[idx], 1)); }));
+ }
+};
+
+ListAdapter ConvertToList(const InternalValue& val, bool& isConverted, bool strictConversion)
+{
+ auto result = Apply<ListConverter>(val, strictConversion);
+ if (!result)
+ {
+ isConverted = false;
+ return ListAdapter();
+ }
+ isConverted = true;
+ return result.get();
+}
+
+ListAdapter ConvertToList(const InternalValue& val, InternalValue subscipt, bool& isConverted, bool strictConversion)
+{
+ auto result = Apply<ListConverter>(val, strictConversion);
+ if (!result)
+ {
+ isConverted = false;
+ return ListAdapter();
+ }
+ isConverted = true;
+
+ if (IsEmpty(subscipt))
+ return std::move(result.get());
+
+ return result.get().ToSubscriptedList(subscipt, false);
+}
+
+template<typename T>
+class ByRef
+{
+public:
+ explicit ByRef(const T& val)
+ : m_val(&val)
+ {
+ }
+
+ const T& Get() const { return *m_val; }
+ T& Get() { return *const_cast<T*>(m_val); }
+ bool ShouldExtendLifetime() const { return false; }
+ bool operator==(const ByRef<T>& other) const
+ {
+ if (m_val && other.m_val && m_val != other.m_val)
+ return false;
+ if ((m_val && !other.m_val) || (!m_val && other.m_val))
+ return false;
+ return true;
+ }
+ bool operator!=(const ByRef<T>& other) const
+ {
+ return !(*this == other);
+ }
+private:
+ const T* m_val{};
+};
+
+template<typename T>
+class ByVal
+{
+public:
+ explicit ByVal(T&& val)
+ : m_val(std::move(val))
+ {
+ }
+ ~ByVal() = default;
+
+ const T& Get() const { return m_val; }
+ T& Get() { return m_val; }
+ bool ShouldExtendLifetime() const { return false; }
+ bool operator==(const ByVal<T>& other) const
+ {
+ return m_val == other.m_val;
+ }
+ bool operator!=(const ByVal<T>& other) const
+ {
+ return !(*this == other);
+ }
+private:
+ T m_val;
+};
+
+template<typename T>
+class BySharedVal
+{
+public:
+ explicit BySharedVal(T&& val)
+ : m_val(std::make_shared<T>(std::move(val)))
+ {
+ }
+ ~BySharedVal() = default;
+
+ const T& Get() const { return *m_val; }
+ T& Get() { return *m_val; }
+ bool ShouldExtendLifetime() const { return true; }
+
+ bool operator==(const BySharedVal<T>& other) const
+ {
+ return m_val == other.m_val;
+ }
+ bool operator!=(const BySharedVal<T>& other) const
+ {
+ return !(*this == other);
+ }
+private:
+ std::shared_ptr<T> m_val;
+};
+
+template<template<typename> class Holder>
+class GenericListAdapter : public IListAccessor
+{
+public:
+ struct Enumerator : public IListAccessorEnumerator
+ {
+ ListEnumeratorPtr m_enum;
+
+ explicit Enumerator(ListEnumeratorPtr e)
+ : m_enum(std::move(e))
+ {
+ }
+
+ // Inherited via IListAccessorEnumerator
+ void Reset() override
+ {
+ if (m_enum)
+ m_enum->Reset();
+ }
+ bool MoveNext() override { return !m_enum ? false : m_enum->MoveNext(); }
+ InternalValue GetCurrent() const override { return !m_enum ? InternalValue() : Value2IntValue(m_enum->GetCurrent()); }
+ IListAccessorEnumerator* Clone() const override { return !m_enum ? new Enumerator(MakeEmptyListEnumeratorPtr()) : new Enumerator(m_enum->Clone()); }
+ IListAccessorEnumerator* Transfer() override { return new Enumerator(std::move(m_enum)); }
+ bool IsEqual(const IComparable& other) const override
+ {
+ auto* val = dynamic_cast<const Enumerator*>(&other);
+ if (!val)
+ return false;
+ if (m_enum && val->m_enum && !m_enum->IsEqual(*val->m_enum))
+ return false;
+ if ((m_enum && !val->m_enum) || (!m_enum && val->m_enum))
+ return false;
+ return true;
+ }
+ };
+
+ template<typename U>
+ GenericListAdapter(U&& values)
+ : m_values(std::forward<U>(values))
+ {
+ }
+
+ std::optional<size_t> GetSize() const override { return m_values.Get().GetSize(); }
+ std::optional<InternalValue> GetItem(int64_t idx) const override
+ {
+ const IListItemAccessor* accessor = m_values.Get().GetAccessor();
+ auto indexer = accessor->GetIndexer();
+ if (!indexer)
+ return std::optional<InternalValue>();
+
+ auto val = indexer->GetItemByIndex(idx);
+ return visit(visitors::InputValueConvertor(true, false), std::move(val.data())).get();
+ }
+ bool ShouldExtendLifetime() const override { return m_values.ShouldExtendLifetime(); }
+ ListAccessorEnumeratorPtr CreateListAccessorEnumerator() const override
+ {
+ const IListItemAccessor* accessor = m_values.Get().GetAccessor();
+ if (!accessor)
+ return ListAccessorEnumeratorPtr(new Enumerator(MakeEmptyListEnumeratorPtr()));
+ return ListAccessorEnumeratorPtr(new Enumerator(m_values.Get().GetAccessor()->CreateEnumerator()));
+ }
+ GenericList CreateGenericList() const override
+ {
+ // return m_values.Get();
+ return GenericList([list = m_values]() -> const IListItemAccessor* { return list.Get().GetAccessor(); });
+ }
+
+private:
+ Holder<GenericList> m_values;
+};
+
+template<template<typename> class Holder>
+class ValuesListAdapter : public IndexedListAccessorImpl<ValuesListAdapter<Holder>>
+{
+public:
+ template<typename U>
+ ValuesListAdapter(U&& values)
+ : m_values(std::forward<U>(values))
+ {
+ }
+
+ size_t GetItemsCountImpl() const { return m_values.Get().size(); }
+ std::optional<InternalValue> GetItem(int64_t idx) const override
+ {
+ const auto& val = m_values.Get()[static_cast<size_t>(idx)];
+ return visit(visitors::InputValueConvertor(false, true), val.data()).get();
+ }
+ bool ShouldExtendLifetime() const override { return m_values.ShouldExtendLifetime(); }
+ GenericList CreateGenericList() const override
+ {
+ // return m_values.Get();
+ return GenericList([list = *this]() -> const IListItemAccessor* { return &list; });
+ }
+
+private:
+ Holder<ValuesList> m_values;
+};
+
+ListAdapter ListAdapter::CreateAdapter(InternalValueList&& values)
+{
+ class Adapter : public IndexedListAccessorImpl<Adapter>
+ {
+ public:
+ explicit Adapter(InternalValueList&& values)
+ : m_values(std::move(values))
+ {
+ }
+
+ size_t GetItemsCountImpl() const { return m_values.size(); }
+ std::optional<InternalValue> GetItem(int64_t idx) const override { return m_values[static_cast<size_t>(idx)]; }
+ bool ShouldExtendLifetime() const override { return false; }
+ GenericList CreateGenericList() const override
+ {
+ return GenericList([adapter = *this]() -> const IListItemAccessor* { return &adapter; });
+ }
+
+ private:
+ InternalValueList m_values;
+ };
+
+ return ListAdapter([accessor = Adapter(std::move(values))]() { return &accessor; });
+}
+
+ListAdapter ListAdapter::CreateAdapter(const GenericList& values)
+{
+ return ListAdapter([accessor = GenericListAdapter<ByRef>(values)]() { return &accessor; });
+}
+
+ListAdapter ListAdapter::CreateAdapter(const ValuesList& values)
+{
+ return ListAdapter([accessor = ValuesListAdapter<ByRef>(values)]() { return &accessor; });
+}
+
+ListAdapter ListAdapter::CreateAdapter(GenericList&& values)
+{
+ return ListAdapter([accessor = GenericListAdapter<BySharedVal>(std::move(values))]() { return &accessor; });
+}
+
+ListAdapter ListAdapter::CreateAdapter(ValuesList&& values)
+{
+ return ListAdapter([accessor = ValuesListAdapter<BySharedVal>(std::move(values))]() { return &accessor; });
+}
+
+ListAdapter ListAdapter::CreateAdapter(std::function<std::optional<InternalValue>()> fn)
+{
+ using GenFn = std::function<std::optional<InternalValue>()>;
+
+ class Adapter : public IListAccessor
+ {
+ public:
+ class Enumerator : public IListAccessorEnumerator
+ {
+ public:
+ explicit Enumerator(const GenFn* fn)
+ : m_fn(fn)
+ {
+ if (!fn)
+ throw std::runtime_error("List enumerator couldn't be created without element accessor function!");
+ }
+
+ void Reset() override {}
+
+ bool MoveNext() override
+ {
+ if (m_isFinished)
+ return false;
+
+ auto res = (*m_fn)();
+ if (!res)
+ return false;
+
+ m_current = *res;
+
+ return true;
+ }
+
+ InternalValue GetCurrent() const override { return m_current; }
+
+ IListAccessorEnumerator* Clone() const override
+ {
+ auto result = new Enumerator(*this);
+ return result;
+ }
+
+ IListAccessorEnumerator* Transfer() override
+ {
+ auto result = new Enumerator(std::move(*this));
+ return result;
+ }
+
+ bool IsEqual(const IComparable& other) const override
+ {
+ auto* val = dynamic_cast<const Enumerator*>(&other);
+ if (!val)
+ return false;
+ if (m_isFinished != val->m_isFinished)
+ return false;
+ if (m_current != val->m_current)
+ return false;
+ // TODO: compare fn?
+ if (m_fn != val->m_fn)
+ return false;
+ return true;
+ }
+
+ protected:
+ const GenFn* m_fn{};
+ InternalValue m_current;
+ bool m_isFinished = false;
+ };
+
+ explicit Adapter(std::function<std::optional<InternalValue>()>&& fn)
+ : m_fn(std::move(fn))
+ {
+ }
+
+ std::optional<size_t> GetSize() const override { return std::optional<size_t>(); }
+ std::optional<InternalValue> GetItem(int64_t /*idx*/) const override { return std::optional<InternalValue>(); }
+ bool ShouldExtendLifetime() const override { return false; }
+ ListAccessorEnumeratorPtr CreateListAccessorEnumerator() const override { return ListAccessorEnumeratorPtr(new Enumerator(&m_fn)); }
+
+ GenericList CreateGenericList() const override
+ {
+ return GenericList(); // return GenericList([adapter = *this]() -> const ListItemAccessor* {return &adapter; });
+ }
+
+ private:
+ std::function<std::optional<InternalValue>()> m_fn;
+ };
+
+ return ListAdapter([accessor = Adapter(std::move(fn))]() { return &accessor; });
+}
+
+ListAdapter ListAdapter::CreateAdapter(size_t listSize, std::function<InternalValue(size_t idx)> fn)
+{
+ using GenFn = std::function<InternalValue(size_t idx)>;
+
+ class Adapter : public IndexedListAccessorImpl<Adapter>
+ {
+ public:
+ explicit Adapter(size_t listSize, GenFn&& fn)
+ : m_listSize(listSize)
+ , m_fn(std::move(fn))
+ {
+ }
+
+ size_t GetItemsCountImpl() const { return m_listSize; }
+ std::optional<InternalValue> GetItem(int64_t idx) const override { return m_fn(static_cast<size_t>(idx)); }
+ bool ShouldExtendLifetime() const override { return false; }
+ GenericList CreateGenericList() const override
+ {
+ return GenericList([adapter = *this]() -> const IListItemAccessor* { return &adapter; });
+ }
+
+ private:
+ size_t m_listSize;
+ GenFn m_fn;
+ };
+
+ return ListAdapter([accessor = Adapter(listSize, std::move(fn))]() { return &accessor; });
+}
+
+template<typename Holder>
+auto CreateIndexedSubscribedList(Holder&& holder, const InternalValue& subscript, size_t size)
+{
+ return ListAdapter::CreateAdapter(
+ size, [h = std::forward<Holder>(holder), subscript](size_t idx) -> InternalValue { return Subscript(h.Get().GetValueByIndex(idx), subscript, nullptr); });
+}
+
+template<typename Holder>
+auto CreateGenericSubscribedList(Holder&& holder, const InternalValue& subscript)
+{
+ return ListAdapter::CreateAdapter([h = std::forward<Holder>(holder), e = ListAccessorEnumeratorPtr(), isFirst = true, isLast = false, subscript]() mutable {
+ using ResultType = std::optional<InternalValue>;
+ if (isFirst)
+ {
+ e = h.Get().GetEnumerator();
+ isLast = !e->MoveNext();
+ isFirst = false;
+ }
+ if (isLast)
+ return ResultType();
+
+ return ResultType(Subscript(e->GetCurrent(), subscript, nullptr));
+ });
+}
+
+ListAdapter ListAdapter::ToSubscriptedList(const InternalValue& subscript, bool asRef) const
+{
+ auto listSize = GetSize();
+ if (asRef)
+ {
+ ByRef<ListAdapter> holder(*this);
+ return listSize ? CreateIndexedSubscribedList(holder, subscript, *listSize) : CreateGenericSubscribedList(holder, subscript);
+ }
+ else
+ {
+ ListAdapter tmp(*this);
+ BySharedVal<ListAdapter> holder(std::move(tmp));
+ return listSize ? CreateIndexedSubscribedList(std::move(holder), subscript, *listSize) : CreateGenericSubscribedList(std::move(holder), subscript);
+ }
+}
+
+InternalValueList ListAdapter::ToValueList() const
+{
+ InternalValueList result;
+ std::copy(begin(), end(), std::back_inserter(result));
+ return result;
+}
+
+template<template<typename> class Holder, bool CanModify>
+class InternalValueMapAdapter : public MapAccessorImpl<InternalValueMapAdapter<Holder, CanModify>>
+{
+public:
+ template<typename U>
+ InternalValueMapAdapter(U&& values)
+ : m_values(std::forward<U>(values))
+ {
+ }
+
+ size_t GetSize() const override { return m_values.Get().size(); }
+ bool HasValue(const std::string& name) const override { return m_values.Get().count(name) != 0; }
+ InternalValue GetItem(const std::string& name) const override
+ {
+ auto& vals = m_values.Get();
+ auto p = vals.find(name);
+ if (p == vals.end())
+ return InternalValue();
+
+ return p->second;
+ }
+ std::vector<std::string> GetKeys() const override
+ {
+ std::vector<std::string> result;
+
+ for (auto& i : m_values.Get())
+ result.push_back(i.first);
+
+ return result;
+ }
+
+ bool SetValue(std::string name, const InternalValue& val) override
+ {
+ if (CanModify)
+ {
+ m_values.Get()[name] = val;
+ return true;
+ }
+ return false;
+ }
+ bool ShouldExtendLifetime() const override { return m_values.ShouldExtendLifetime(); }
+ GenericMap CreateGenericMap() const override
+ {
+ return GenericMap([accessor = *this]() -> const IMapItemAccessor* { return &accessor; });
+ }
+ bool IsEqual(const IComparable& other) const override
+ {
+ auto* val = dynamic_cast<const InternalValueMapAdapter*>(&other);
+ if (!val)
+ return false;
+ return m_values == val->m_values;
+ }
+private:
+ Holder<InternalValueMap> m_values;
+};
+
+InternalValue Value2IntValue(const Value& val)
+{
+ auto result = std::visit(visitors::InputValueConvertor(false, true), val.data());
+ if (result)
+ return result.get();
+
+ return InternalValue(ValueRef(val));
+}
+
+InternalValue Value2IntValue(Value&& val)
+{
+ auto result = std::visit(visitors::InputValueConvertor(true, false), val.data());
+ if (result)
+ return result.get();
+
+ return InternalValue(ValueRef(val));
+}
+
+template<template<typename> class Holder>
+class GenericMapAdapter : public MapAccessorImpl<GenericMapAdapter<Holder>>
+{
+public:
+ template<typename U>
+ GenericMapAdapter(U&& values)
+ : m_values(std::forward<U>(values))
+ {
+ }
+
+ size_t GetSize() const override { return m_values.Get().GetSize(); }
+ bool HasValue(const std::string& name) const override { return m_values.Get().HasValue(name); }
+ InternalValue GetItem(const std::string& name) const override
+ {
+ auto val = m_values.Get().GetValueByName(name);
+ if (val.isEmpty())
+ return InternalValue();
+
+ return Value2IntValue(std::move(val));
+ }
+ std::vector<std::string> GetKeys() const override { return m_values.Get().GetKeys(); }
+ bool ShouldExtendLifetime() const override { return m_values.ShouldExtendLifetime(); }
+ GenericMap CreateGenericMap() const override
+ {
+ return GenericMap([accessor = *this]() -> const IMapItemAccessor* { return accessor.m_values.Get().GetAccessor(); });
+ }
+ bool IsEqual(const IComparable& other) const override
+ {
+ auto* val = dynamic_cast<const GenericMapAdapter*>(&other);
+ if (!val)
+ return false;
+ return m_values == val->m_values;
+ }
+private:
+ Holder<GenericMap> m_values;
+};
+
+template<template<typename> class Holder>
+class ValuesMapAdapter : public MapAccessorImpl<ValuesMapAdapter<Holder>>
+{
+public:
+ template<typename U>
+ ValuesMapAdapter(U&& values)
+ : m_values(std::forward<U>(values))
+ {
+ }
+
+ size_t GetSize() const override { return m_values.Get().size(); }
+ bool HasValue(const std::string& name) const override { return m_values.Get().count(name) != 0; }
+ InternalValue GetItem(const std::string& name) const override
+ {
+ auto& vals = m_values.Get();
+ auto p = vals.find(name);
+ if (p == vals.end())
+ return InternalValue();
+
+ return Value2IntValue(p->second);
+ }
+ std::vector<std::string> GetKeys() const override
+ {
+ std::vector<std::string> result;
+
+ for (auto& i : m_values.Get())
+ result.push_back(i.first);
+
+ return result;
+ }
+ bool ShouldExtendLifetime() const override { return m_values.ShouldExtendLifetime(); }
+ GenericMap CreateGenericMap() const override
+ {
+ return GenericMap([accessor = *this]() -> const IMapItemAccessor* { return &accessor; });
+ }
+ bool IsEqual(const IComparable& other) const override
+ {
+ auto* val = dynamic_cast<const ValuesMapAdapter*>(&other);
+ if (!val)
+ return false;
+ return m_values == val->m_values;
+ }
+private:
+ Holder<ValuesMap> m_values;
+};
+
+MapAdapter CreateMapAdapter(InternalValueMap&& values)
+{
+ return MapAdapter([accessor = InternalValueMapAdapter<ByVal, true>(std::move(values))]() mutable { return &accessor; });
+}
+
+MapAdapter CreateMapAdapter(const InternalValueMap* values)
+{
+ return MapAdapter([accessor = InternalValueMapAdapter<ByRef, false>(*values)]() mutable { return &accessor; });
+}
+
+MapAdapter CreateMapAdapter(const GenericMap& values)
+{
+ return MapAdapter([accessor = GenericMapAdapter<ByRef>(values)]() mutable { return &accessor; });
+}
+
+MapAdapter CreateMapAdapter(GenericMap&& values)
+{
+ return MapAdapter([accessor = GenericMapAdapter<BySharedVal>(std::move(values))]() mutable { return &accessor; });
+}
+
+MapAdapter CreateMapAdapter(const ValuesMap& values)
+{
+ return MapAdapter([accessor = ValuesMapAdapter<ByRef>(values)]() mutable { return &accessor; });
+}
+
+MapAdapter CreateMapAdapter(ValuesMap&& values)
+{
+ return MapAdapter([accessor = ValuesMapAdapter<BySharedVal>(std::move(values))]() mutable { return &accessor; });
+}
+
+struct OutputValueConvertor
+{
+ using result_t = Value;
+
+ result_t operator()(const EmptyValue&) const { return result_t(); }
+ result_t operator()(const MapAdapter& adapter) const { return result_t(adapter.CreateGenericMap()); }
+ result_t operator()(const ListAdapter& adapter) const { return result_t(adapter.CreateGenericList()); }
+ result_t operator()(const ValueRef& ref) const { return ref.get(); }
+ result_t operator()(const TargetString& str) const
+ {
+ switch (str.index())
+ {
+ case 0:
+ return std::get<std::string>(str);
+ default:
+ return std::get<std::wstring>(str);
+ }
+ }
+ result_t operator()(const TargetStringView& str) const
+ {
+ switch (str.index())
+ {
+ case 0:
+ return std::get<std::string_view>(str);
+ default:
+ return std::get<std::wstring_view>(str);
+ }
+ }
+ result_t operator()(const KeyValuePair& pair) const { return ValuesMap{ { "key", Value(pair.key) }, { "value", IntValue2Value(pair.value) } }; }
+ result_t operator()(const Callable&) const { return result_t(); }
+ result_t operator()(const UserCallable&) const { return result_t(); }
+ result_t operator()(const std::shared_ptr<IRendererBase>&) const { return result_t(); }
+
+ template<typename T>
+ result_t operator()(const RecWrapper<T>& val) const
+ {
+ return this->operator()(const_cast<const T&>(*val));
+ }
+
+ template<typename T>
+ result_t operator()(RecWrapper<T>& val) const
+ {
+ return this->operator()(*val);
+ }
+
+ template<typename T>
+ result_t operator()(T&& val) const
+ {
+ return result_t(std::forward<T>(val));
+ }
+
+ bool m_byValue;
+};
+
+Value OptIntValue2Value(std::optional<InternalValue> val)
+{
+ if (val)
+ return Apply<OutputValueConvertor>(val.value());
+
+ return Value();
+}
+
+Value IntValue2Value(const InternalValue& val)
+{
+ return Apply<OutputValueConvertor>(val);
+}
+
+class ContextMapper : public IMapItemAccessor
+{
+public:
+ explicit ContextMapper(RenderContext* context)
+ : m_context(context)
+ {
+ }
+
+ size_t GetSize() const override { return std::numeric_limits<size_t>::max(); }
+ bool HasValue(const std::string& name) const override
+ {
+ bool found = false;
+ m_context->FindValue(name, found);
+ return found;
+ }
+ Value GetValueByName(const std::string& name) const override
+ {
+ bool found = false;
+ auto p = m_context->FindValue(name, found);
+ return found ? IntValue2Value(p->second) : Value();
+ }
+ std::vector<std::string> GetKeys() const override { return std::vector<std::string>(); }
+
+ bool IsEqual(const IComparable& other) const override
+ {
+ auto* val = dynamic_cast<const ContextMapper*>(&other);
+ if (!val)
+ return false;
+ if (m_context && val->m_context && !m_context->IsEqual(*val->m_context))
+ {
+ return false;
+ }
+ if ((m_context && !val->m_context) || (!m_context && val->m_context))
+ return false;
+ return true;
+ }
+
+private:
+ RenderContext* m_context;
+};
+
+UserCallableParams PrepareUserCallableParams(const CallParams& params, RenderContext& context, const std::vector<ArgumentInfo>& argsInfo)
+{
+ UserCallableParams result;
+
+ ParsedArguments args = helpers::ParseCallParams(argsInfo, params, result.paramsParsed);
+ if (!result.paramsParsed)
+ return result;
+
+ for (auto& argInfo : argsInfo)
+ {
+ if (argInfo.name.size() > 1 && argInfo.name[0] == '*')
+ continue;
+
+ auto p = args.args.find(argInfo.name);
+ if (p == args.args.end())
+ {
+ result.args[argInfo.name] = IntValue2Value(argInfo.defaultVal);
+ continue;
+ }
+
+ const auto& v = p->second;
+ result.args[argInfo.name] = IntValue2Value(v);
+ }
+
+ ValuesMap extraKwArgs;
+ for (auto& p : args.extraKwArgs)
+ extraKwArgs[p.first] = IntValue2Value(p.second);
+ result.extraKwArgs = Value(std::move(extraKwArgs));
+
+ ValuesList extraPosArgs;
+ for (auto& p : args.extraPosArgs)
+ extraPosArgs.push_back(IntValue2Value(p));
+ result.extraPosArgs = Value(std::move(extraPosArgs));
+ result.context = GenericMap([accessor = ContextMapper(&context)]() -> const IMapItemAccessor* { return &accessor; });
+
+ return result;
+}
+
+namespace visitors
+{
+
+InputValueConvertor::result_t InputValueConvertor::ConvertUserCallable(const UserCallable& val)
+{
+ std::vector<ArgumentInfo> args;
+ for (auto& pi : val.argsInfo)
+ {
+ args.emplace_back(pi.paramName, pi.isMandatory, Value2IntValue(pi.defValue));
+ }
+
+ return InternalValue(Callable(Callable::UserCallable, [val, argsInfo = std::move(args)](const CallParams& params, RenderContext& context) -> InternalValue {
+ auto ucParams = PrepareUserCallableParams(params, context, argsInfo);
+ return Value2IntValue(val.callable(ucParams));
+ }));
+}
+
+} // namespace visitors
+
+} // namespace jinja2
diff --git a/contrib/libs/jinja2cpp/src/internal_value.h b/contrib/libs/jinja2cpp/src/internal_value.h
new file mode 100644
index 0000000000..22a933f257
--- /dev/null
+++ b/contrib/libs/jinja2cpp/src/internal_value.h
@@ -0,0 +1,673 @@
+#ifndef JINJA2CPP_SRC_INTERNAL_VALUE_H
+#define JINJA2CPP_SRC_INTERNAL_VALUE_H
+
+#include <jinja2cpp/value.h>
+//#include <jinja2cpp/value_ptr.h>
+
+#include <boost/iterator/iterator_facade.hpp>
+#include <boost/variant/recursive_wrapper.hpp>
+#include <boost/unordered_map.hpp>
+
+#include <fmt/core.h>
+
+#if defined(_MSC_VER) && _MSC_VER <= 1900 // robin_hood hash map doesn't compatible with MSVC 14.0
+#include <unordered_map>
+#else
+#include "robin_hood.h"
+#endif
+
+
+#include <string_view>
+#include <variant>
+
+#include <functional>
+
+namespace jinja2
+{
+
+template <class T>
+class ReferenceWrapper
+{
+public:
+ using type = T;
+
+ ReferenceWrapper(T& ref) noexcept
+ : m_ptr(std::addressof(ref))
+ {
+ }
+
+ ReferenceWrapper(T&&) = delete;
+ ReferenceWrapper(const ReferenceWrapper&) noexcept = default;
+
+ // assignment
+ ReferenceWrapper& operator=(const ReferenceWrapper& x) noexcept = default;
+
+ // access
+ T& get() const noexcept
+ {
+ return *m_ptr;
+ }
+
+private:
+ T* m_ptr;
+};
+
+template<typename T, size_t SizeHint = 48>
+class RecursiveWrapper
+{
+public:
+ RecursiveWrapper() = default;
+
+ RecursiveWrapper(const T& value)
+ : m_data(value)
+ {}
+
+ RecursiveWrapper(T&& value)
+ : m_data(std::move(value))
+ {}
+
+ const T& GetValue() const {return m_data.get();}
+ T& GetValue() {return m_data.get();}
+
+private:
+ boost::recursive_wrapper<T> m_data;
+
+#if 0
+ enum class State
+ {
+ Undefined,
+ Inplace,
+ Ptr
+ };
+
+ State m_state;
+
+ union
+ {
+ uint64_t dummy;
+ nonstd::value_ptr<T> ptr;
+ } m_data;
+#endif
+};
+
+template<typename T>
+auto MakeWrapped(T&& val)
+{
+ return RecursiveWrapper<std::decay_t<T>>(std::forward<T>(val));
+}
+
+using ValueRef = ReferenceWrapper<const Value>;
+using TargetString = std::variant<std::string, std::wstring>;
+using TargetStringView = std::variant<std::string_view, std::wstring_view>;
+
+class ListAdapter;
+class MapAdapter;
+class RenderContext;
+class OutStream;
+class Callable;
+struct CallParams;
+struct KeyValuePair;
+class IRendererBase;
+
+class InternalValue;
+using InternalValueData = std::variant<
+ EmptyValue,
+ bool,
+ std::string,
+ TargetString,
+ TargetStringView,
+ int64_t,
+ double,
+ ValueRef,
+ ListAdapter,
+ MapAdapter,
+ RecursiveWrapper<KeyValuePair>,
+ RecursiveWrapper<Callable>,
+ std::shared_ptr<IRendererBase>>;
+
+
+using InternalValueRef = ReferenceWrapper<InternalValue>;
+using InternalValueList = std::vector<InternalValue>;
+
+template<typename T, bool isRecursive = false>
+struct ValueGetter
+{
+ template<typename V>
+ static auto& Get(V&& val)
+ {
+ return std::get<T>(std::forward<V>(val).GetData());
+ }
+
+ static auto GetPtr(const InternalValue* val);
+
+ static auto GetPtr(InternalValue* val);
+
+ template<typename V>
+ static auto GetPtr(V* val, std::enable_if_t<!std::is_same<V, InternalValue>::value>* = nullptr)
+ {
+ return std::get_if<T>(val);
+ }
+};
+
+template<typename T>
+struct ValueGetter<T, true>
+{
+ template<typename V>
+ static auto& Get(V&& val)
+ {
+ auto& ref = std::get<RecursiveWrapper<T>>(std::forward<V>(val));
+ return ref.GetValue();
+ }
+
+ static auto GetPtr(const InternalValue* val);
+
+ static auto GetPtr(InternalValue* val);
+
+ template<typename V>
+ static auto GetPtr(V* val, std::enable_if_t<!std::is_same<V, InternalValue>::value>* = nullptr)
+ {
+ auto ref = std::get_if<RecursiveWrapper<T>>(val);
+ return !ref ? nullptr : &ref->GetValue();
+ }
+};
+
+template<typename T>
+struct IsRecursive : std::false_type {};
+
+template<>
+struct IsRecursive<KeyValuePair> : std::true_type {};
+
+template<>
+struct IsRecursive<Callable> : std::true_type {};
+
+struct IListAccessorEnumerator : virtual IComparable
+{
+ virtual ~IListAccessorEnumerator() {}
+
+ virtual void Reset() = 0;
+
+ virtual bool MoveNext() = 0;
+ virtual InternalValue GetCurrent() const = 0;
+
+ virtual IListAccessorEnumerator* Clone() const = 0;
+ virtual IListAccessorEnumerator* Transfer() = 0;
+/*
+ struct Cloner
+ {
+ Cloner() = default;
+
+ IListAccessorEnumerator* operator()(const IListAccessorEnumerator &x) const
+ {
+ return x.Clone();
+ }
+
+ IListAccessorEnumerator* operator()(IListAccessorEnumerator &&x) const
+ {
+ return x.Transfer();
+ }
+ };
+ */
+};
+
+using ListAccessorEnumeratorPtr = types::ValuePtr<IListAccessorEnumerator>;
+
+struct IListAccessor
+{
+ virtual ~IListAccessor() {}
+
+ virtual std::optional<size_t> GetSize() const = 0;
+ virtual std::optional<InternalValue> GetItem(int64_t idx) const = 0;
+ virtual ListAccessorEnumeratorPtr CreateListAccessorEnumerator() const = 0;
+ virtual GenericList CreateGenericList() const = 0;
+ virtual bool ShouldExtendLifetime() const = 0;
+};
+
+
+using ListAccessorProvider = std::function<const IListAccessor*()>;
+
+struct IMapAccessor
+{
+ virtual ~IMapAccessor() = default;
+ virtual size_t GetSize() const = 0;
+ virtual bool HasValue(const std::string& name) const = 0;
+ virtual InternalValue GetItem(const std::string& name) const = 0;
+ virtual std::vector<std::string> GetKeys() const = 0;
+ virtual bool SetValue(std::string, const InternalValue&) {return false;}
+ virtual GenericMap CreateGenericMap() const = 0;
+ virtual bool ShouldExtendLifetime() const = 0;
+};
+
+using MapAccessorProvider = std::function<IMapAccessor*()>;
+
+class ListAdapter
+{
+public:
+ ListAdapter() {}
+ explicit ListAdapter(ListAccessorProvider prov) : m_accessorProvider(std::move(prov)) {}
+ ListAdapter(const ListAdapter&) = default;
+ ListAdapter(ListAdapter&&) = default;
+
+ static ListAdapter CreateAdapter(InternalValueList&& values);
+ static ListAdapter CreateAdapter(const GenericList& values);
+ static ListAdapter CreateAdapter(const ValuesList& values);
+ static ListAdapter CreateAdapter(GenericList&& values);
+ static ListAdapter CreateAdapter(ValuesList&& values);
+ static ListAdapter CreateAdapter(std::function<std::optional<InternalValue> ()> fn);
+ static ListAdapter CreateAdapter(size_t listSize, std::function<InternalValue (size_t idx)> fn);
+
+ ListAdapter& operator = (const ListAdapter&) = default;
+ ListAdapter& operator = (ListAdapter&&) = default;
+
+ std::optional<size_t> GetSize() const
+ {
+ if (m_accessorProvider && m_accessorProvider())
+ {
+ return m_accessorProvider()->GetSize();
+ }
+
+ return 0;
+ }
+ InternalValue GetValueByIndex(int64_t idx) const;
+ bool ShouldExtendLifetime() const
+ {
+ if (m_accessorProvider && m_accessorProvider())
+ {
+ return m_accessorProvider()->ShouldExtendLifetime();
+ }
+
+ return false;
+ }
+
+ ListAdapter ToSubscriptedList(const InternalValue& subscript, bool asRef = false) const;
+ InternalValueList ToValueList() const;
+ GenericList CreateGenericList() const
+ {
+ if (m_accessorProvider && m_accessorProvider())
+ return m_accessorProvider()->CreateGenericList();
+
+ return GenericList();
+ }
+ ListAccessorEnumeratorPtr GetEnumerator() const;
+
+ class Iterator;
+
+ Iterator begin() const;
+ Iterator end() const;
+
+private:
+ ListAccessorProvider m_accessorProvider;
+};
+
+class MapAdapter
+{
+public:
+ MapAdapter() = default;
+ explicit MapAdapter(MapAccessorProvider prov) : m_accessorProvider(std::move(prov)) {}
+
+ size_t GetSize() const
+ {
+ if (m_accessorProvider && m_accessorProvider())
+ {
+ return m_accessorProvider()->GetSize();
+ }
+
+ return 0;
+ }
+ // InternalValue GetValueByIndex(int64_t idx) const;
+ bool HasValue(const std::string& name) const
+ {
+ if (m_accessorProvider && m_accessorProvider())
+ {
+ return m_accessorProvider()->HasValue(name);
+ }
+
+ return false;
+ }
+ InternalValue GetValueByName(const std::string& name) const;
+ std::vector<std::string> GetKeys() const
+ {
+ if (m_accessorProvider && m_accessorProvider())
+ {
+ return m_accessorProvider()->GetKeys();
+ }
+
+ return std::vector<std::string>();
+ }
+ bool SetValue(std::string name, const InternalValue& val)
+ {
+ if (m_accessorProvider && m_accessorProvider())
+ {
+ return m_accessorProvider()->SetValue(std::move(name), val);
+ }
+
+ return false;
+ }
+ bool ShouldExtendLifetime() const
+ {
+ if (m_accessorProvider && m_accessorProvider())
+ {
+ return m_accessorProvider()->ShouldExtendLifetime();
+ }
+
+ return false;
+ }
+
+ GenericMap CreateGenericMap() const
+ {
+ if (m_accessorProvider && m_accessorProvider())
+ return m_accessorProvider()->CreateGenericMap();
+
+ return GenericMap();
+ }
+
+private:
+ MapAccessorProvider m_accessorProvider;
+};
+
+
+class InternalValue
+{
+public:
+ InternalValue() = default;
+
+ template<typename T>
+ InternalValue(T&& val, typename std::enable_if<!std::is_same<std::decay_t<T>, InternalValue>::value>::type* = nullptr)
+ : m_data(InternalValueData(std::forward<T>(val)))
+ {
+ }
+
+ auto& GetData() const {return m_data;}
+ auto& GetData() {return m_data;}
+
+ auto& GetParentData() {return m_parentData;}
+ auto& GetParentData() const {return m_parentData;}
+
+ void SetParentData(const InternalValue& val)
+ {
+ m_parentData = val.GetData();
+ }
+
+ void SetParentData(InternalValue&& val)
+ {
+ m_parentData = std::move(val.GetData());
+ }
+
+ bool ShouldExtendLifetime() const
+ {
+ if (m_parentData.index() != 0)
+ return true;
+
+ const MapAdapter* ma = std::get_if<MapAdapter>(&m_data);
+ if (ma != nullptr)
+ return ma->ShouldExtendLifetime();
+
+ const ListAdapter* la = std::get_if<ListAdapter>(&m_data);
+ if (la != nullptr)
+ return la->ShouldExtendLifetime();
+
+ return false;
+ }
+
+ bool IsEmpty() const {return m_data.index() == 0;}
+
+ bool IsEqual(const InternalValue& other) const;
+
+private:
+ InternalValueData m_data;
+ InternalValueData m_parentData;
+};
+
+inline bool operator==(const InternalValue& lhs, const InternalValue& rhs)
+{
+ return lhs.IsEqual(rhs);
+}
+inline bool operator!=(const InternalValue& lhs, const InternalValue& rhs)
+{
+ return !(lhs == rhs);
+}
+
+class ListAdapter::Iterator
+ : public boost::iterator_facade<
+ Iterator,
+ const InternalValue,
+ boost::forward_traversal_tag>
+{
+public:
+ Iterator() = default;
+
+ explicit Iterator(ListAccessorEnumeratorPtr&& iter)
+ : m_iterator(std::move(iter))
+ , m_isFinished(!m_iterator->MoveNext())
+ , m_currentVal(m_isFinished ? InternalValue() : m_iterator->GetCurrent())
+ {}
+
+private:
+ friend class boost::iterator_core_access;
+
+ void increment()
+ {
+ m_isFinished = !m_iterator->MoveNext();
+ ++ m_currentIndex;
+ m_currentVal = m_isFinished ? InternalValue() : m_iterator->GetCurrent();
+ }
+
+ bool equal(const Iterator& other) const
+ {
+ if (!this->m_iterator)
+ return !other.m_iterator ? true : other.equal(*this);
+
+ if (!other.m_iterator)
+ return this->m_isFinished;
+// return true;
+ //const InternalValue& lhs = *(this->m_iterator);
+ //const InternalValue& rhs = *(other.m_iterator);
+ //return lhs == rhs;
+ return this->m_iterator->GetCurrent() == other.m_iterator->GetCurrent() && this->m_currentIndex == other.m_currentIndex;
+ ///return *(this->m_iterator) == *(other.m_iterator) && this->m_currentIndex == other.m_currentIndex;
+ }
+
+ const InternalValue& dereference() const
+ {
+ return m_currentVal;
+ }
+
+ ListAccessorEnumeratorPtr m_iterator;
+ bool m_isFinished = true;
+ mutable uint64_t m_currentIndex = 0;
+ mutable InternalValue m_currentVal;
+};
+
+#if defined(_MSC_VER) && _MSC_VER <= 1900 // robin_hood hash map doesn't compatible with MSVC 14.0
+typedef std::unordered_map<std::string, InternalValue> InternalValueMap;
+#else
+typedef robin_hood::unordered_map<std::string, InternalValue> InternalValueMap;
+#endif
+
+
+MapAdapter CreateMapAdapter(InternalValueMap&& values);
+MapAdapter CreateMapAdapter(const InternalValueMap* values);
+MapAdapter CreateMapAdapter(const GenericMap& values);
+MapAdapter CreateMapAdapter(GenericMap&& values);
+MapAdapter CreateMapAdapter(const ValuesMap& values);
+MapAdapter CreateMapAdapter(ValuesMap&& values);
+
+template<typename T, bool V>
+inline auto ValueGetter<T, V>::GetPtr(const InternalValue* val)
+{
+ return std::get_if<T>(&val->GetData());
+}
+
+template<typename T, bool V>
+inline auto ValueGetter<T, V>::GetPtr(InternalValue* val)
+{
+ return std::get_if<T>(&val->GetData());
+}
+
+template<typename T>
+inline auto ValueGetter<T, true>::GetPtr(const InternalValue* val)
+{
+ auto ref = std::get_if<RecursiveWrapper<T>>(&val->GetData());
+ return !ref ? nullptr : &ref->GetValue();
+}
+
+template<typename T>
+inline auto ValueGetter<T, true>::GetPtr(InternalValue* val)
+{
+ auto ref = std::get_if<RecursiveWrapper<T>>(&val->GetData());
+ return !ref ? nullptr : &ref->GetValue();
+}
+
+template<typename T, typename V>
+auto& Get(V&& val)
+{
+ return ValueGetter<T, IsRecursive<T>::value>::Get(std::forward<V>(val).GetData());
+}
+
+template<typename T, typename V>
+auto GetIf(V* val)
+{
+ return ValueGetter<T, IsRecursive<T>::value>::GetPtr(val);
+}
+
+
+inline InternalValue ListAdapter::GetValueByIndex(int64_t idx) const
+{
+ if (m_accessorProvider && m_accessorProvider())
+ {
+ const auto& val = m_accessorProvider()->GetItem(idx);
+ if (val)
+ return std::move(val.value());
+
+ return InternalValue();
+ }
+
+ return InternalValue();
+}
+
+//inline InternalValue MapAdapter::GetValueByIndex(int64_t idx) const
+//{
+// if (m_accessorProvider && m_accessorProvider())
+// {
+// return static_cast<const IListAccessor*>(m_accessorProvider())->GetItem(idx);
+// }
+
+// return InternalValue();
+//}
+
+inline InternalValue MapAdapter::GetValueByName(const std::string& name) const
+{
+ if (m_accessorProvider && m_accessorProvider())
+ {
+ return m_accessorProvider()->GetItem(name);
+ }
+
+ return InternalValue();
+}
+
+inline ListAccessorEnumeratorPtr ListAdapter::GetEnumerator() const {return m_accessorProvider()->CreateListAccessorEnumerator();}
+inline ListAdapter::Iterator ListAdapter::begin() const {return Iterator(m_accessorProvider()->CreateListAccessorEnumerator());}
+inline ListAdapter::Iterator ListAdapter::end() const {return Iterator();}
+
+
+struct KeyValuePair
+{
+ std::string key;
+ InternalValue value;
+};
+
+
+class Callable
+{
+public:
+ enum Kind
+ {
+ GlobalFunc,
+ SpecialFunc,
+ Macro,
+ UserCallable
+ };
+ using ExpressionCallable = std::function<InternalValue (const CallParams&, RenderContext&)>;
+ using StatementCallable = std::function<void (const CallParams&, OutStream&, RenderContext&)>;
+
+ using CallableHolder = std::variant<ExpressionCallable, StatementCallable>;
+
+ enum class Type
+ {
+ Expression,
+ Statement
+ };
+
+ Callable(Kind kind, ExpressionCallable&& callable)
+ : m_kind(kind)
+ , m_callable(std::move(callable))
+ {
+ }
+
+ Callable(Kind kind, StatementCallable&& callable)
+ : m_kind(kind)
+ , m_callable(std::move(callable))
+ {
+ }
+
+ auto GetType() const
+ {
+ return m_callable.index() == 0 ? Type::Expression : Type::Statement;
+ }
+
+ auto GetKind() const
+ {
+ return m_kind;
+ }
+
+ auto& GetCallable() const
+ {
+ return m_callable;
+ }
+
+ auto& GetExpressionCallable() const
+ {
+ return std::get<ExpressionCallable>(m_callable);
+ }
+
+ auto& GetStatementCallable() const
+ {
+ return std::get<StatementCallable>(m_callable);
+ }
+
+private:
+ Kind m_kind;
+ CallableHolder m_callable;
+};
+
+inline bool IsEmpty(const InternalValue& val)
+{
+ return val.IsEmpty() || std::get_if<EmptyValue>(&val.GetData()) != nullptr;
+}
+
+class RenderContext;
+
+template<typename Fn>
+auto MakeDynamicProperty(Fn&& fn)
+{
+ return CreateMapAdapter(InternalValueMap{
+ {"value()", Callable(Callable::GlobalFunc, std::forward<Fn>(fn))}
+ });
+}
+
+template<typename CharT>
+auto sv_to_string(const std::basic_string_view<CharT>& sv)
+{
+ return std::basic_string<CharT>(sv.begin(), sv.end());
+}
+
+InternalValue Subscript(const InternalValue& val, const InternalValue& subscript, RenderContext* values);
+InternalValue Subscript(const InternalValue& val, const std::string& subscript, RenderContext* values);
+std::string AsString(const InternalValue& val);
+ListAdapter ConvertToList(const InternalValue& val, bool& isConverted, bool strictConversion = true);
+ListAdapter ConvertToList(const InternalValue& val, InternalValue subscipt, bool& isConverted, bool strictConversion = true);
+Value IntValue2Value(const InternalValue& val);
+Value OptIntValue2Value(std::optional<InternalValue> val);
+
+} // namespace jinja2
+
+#endif // JINJA2CPP_SRC_INTERNAL_VALUE_H
diff --git a/contrib/libs/jinja2cpp/src/lexer.cpp b/contrib/libs/jinja2cpp/src/lexer.cpp
new file mode 100644
index 0000000000..dfd33eb37e
--- /dev/null
+++ b/contrib/libs/jinja2cpp/src/lexer.cpp
@@ -0,0 +1,122 @@
+#include "lexer.h"
+
+#include <iostream>
+
+namespace jinja2
+{
+
+bool Lexer::Preprocess()
+{
+ bool result = true;
+ while (1)
+ {
+ lexertk::token token = m_tokenizer();
+ if (token.is_error())
+ {
+ result = false;
+ break;
+ }
+
+ Token newToken;
+ newToken.range.startOffset = token.position;
+ newToken.range.endOffset = newToken.range.startOffset + token.length;
+
+ if (token.type == lexertk::token::e_eof)
+ {
+ newToken.type = Token::Eof;
+ m_tokens.push_back(std::move(newToken));
+ break;
+ }
+
+ switch (token.type)
+ {
+ case lexertk::token::e_number:
+ result = ProcessNumber(token, newToken);
+ break;
+ case lexertk::token::e_symbol:
+ result = ProcessSymbolOrKeyword(token, newToken);
+ break;
+ case lexertk::token::e_string:
+ result = ProcessString(token, newToken);
+ break;
+ case lexertk::token::e_lte:
+ newToken.type = Token::LessEqual;
+ break;
+ case lexertk::token::e_ne:
+ newToken.type = Token::NotEqual;
+ break;
+ case lexertk::token::e_gte:
+ newToken.type = Token::GreaterEqual;
+ break;
+ case lexertk::token::e_eq:
+ newToken.type = Token::Equal;
+ break;
+ case lexertk::token::e_mulmul:
+ newToken.type = Token::MulMul;
+ break;
+ case lexertk::token::e_divdiv:
+ newToken.type = Token::DivDiv;
+ break;
+ default:
+ newToken.type = static_cast<Token::Type>(token.type);
+ break;
+ }
+
+ if (result)
+ m_tokens.push_back(std::move(newToken));
+ else
+ break;
+ }
+
+ return result;
+}
+
+bool Lexer::ProcessNumber(const lexertk::token&, Token& newToken)
+{
+ newToken.type = Token::FloatNum;
+ newToken.value = m_helper->GetAsValue(newToken.range, newToken.type);
+ return true;
+}
+
+bool Lexer::ProcessSymbolOrKeyword(const lexertk::token&, Token& newToken)
+{
+ Keyword kwType = m_helper->GetKeyword(newToken.range);
+ Token::Type tokType = Token::Unknown;
+
+ switch (kwType)
+ {
+ case Keyword::None:
+ tokType = Token::None;
+ break;
+ case Keyword::True:
+ tokType = Token::True;
+ break;
+ case Keyword::False:
+ tokType = Token::False;
+ break;
+ default:
+ tokType = Token::Unknown;
+ break;
+ }
+
+ if (tokType == Token::Unknown)
+ {
+ newToken.type = Token::Identifier;
+ auto id = m_helper->GetAsString(newToken.range);
+ newToken.value = InternalValue(id);
+ }
+ else
+ {
+ newToken.type = tokType;
+ }
+ return true;
+}
+
+bool Lexer::ProcessString(const lexertk::token&, Token& newToken)
+{
+ newToken.type = Token::String;
+ newToken.value = m_helper->GetAsValue(newToken.range, newToken.type);
+ return true;
+}
+
+} // namespace jinja2
diff --git a/contrib/libs/jinja2cpp/src/lexer.h b/contrib/libs/jinja2cpp/src/lexer.h
new file mode 100644
index 0000000000..e644de2f7b
--- /dev/null
+++ b/contrib/libs/jinja2cpp/src/lexer.h
@@ -0,0 +1,375 @@
+#ifndef JINJA2CPP_SRC_LEXER_H
+#define JINJA2CPP_SRC_LEXER_H
+
+#include "lexertk.h"
+#include "internal_value.h"
+
+#include <functional>
+
+namespace jinja2
+{
+struct CharRange
+{
+ size_t startOffset;
+ size_t endOffset;
+ auto size() const {return endOffset - startOffset;}
+};
+
+struct Token
+{
+ enum Type
+ {
+ Unknown,
+
+ // One-symbol operators
+ Lt = '<',
+ Gt = '>',
+ Plus = '+',
+ Minus = '-',
+ Percent = '%',
+ Mul = '*',
+ Div = '/',
+ LBracket = '(',
+ RBracket = ')',
+ LSqBracket = '[',
+ RSqBracket = ']',
+ LCrlBracket = '{',
+ RCrlBracket = '}',
+ Assign = '=',
+ Comma = ',',
+ Eof = 256,
+
+ // General
+ Identifier,
+ IntegerNum,
+ FloatNum,
+ String,
+
+ // Operators
+ Equal,
+ NotEqual,
+ LessEqual,
+ GreaterEqual,
+ StarStar,
+ DashDash,
+ MulMul,
+ DivDiv,
+ True,
+ False,
+ None,
+
+ // Keywords
+ LogicalOr,
+ LogicalAnd,
+ LogicalNot,
+ In,
+ Is,
+ For,
+ Endfor,
+ If,
+ Else,
+ ElIf,
+ EndIf,
+ Block,
+ EndBlock,
+ Extends,
+ Macro,
+ EndMacro,
+ Call,
+ EndCall,
+ Filter,
+ EndFilter,
+ Set,
+ EndSet,
+ Include,
+ Import,
+ Recursive,
+ Scoped,
+ With,
+ EndWith,
+ Without,
+ Ignore,
+ Missing,
+ Context,
+ From,
+ As,
+ Do,
+
+ // Template control
+ CommentBegin,
+ CommentEnd,
+ RawBegin,
+ RawEnd,
+ MetaBegin,
+ MetaEnd,
+ StmtBegin,
+ StmtEnd,
+ ExprBegin,
+ ExprEnd,
+ };
+
+ Type type = Unknown;
+ CharRange range = {0, 0};
+ InternalValue value;
+
+ bool IsEof() const
+ {
+ return type == Eof;
+ }
+
+ bool operator == (char ch) const
+ {
+ return type == ch;
+ }
+
+ bool operator == (Type t) const
+ {
+ return type == t;
+ }
+
+ template<typename T>
+ bool operator != (T v) const
+ {
+ return !(*this == v);
+ }
+};
+
+enum class Keyword
+{
+ Unknown,
+
+ // Keywords
+ LogicalOr,
+ LogicalAnd,
+ LogicalNot,
+ True,
+ False,
+ None,
+ In,
+ Is,
+ For,
+ Endfor,
+ If,
+ Else,
+ ElIf,
+ EndIf,
+ Block,
+ EndBlock,
+ Extends,
+ Macro,
+ EndMacro,
+ Call,
+ EndCall,
+ Filter,
+ EndFilter,
+ Set,
+ EndSet,
+ Include,
+ Import,
+ Recursive,
+ Scoped,
+ With,
+ EndWith,
+ Without,
+ Ignore,
+ Missing,
+ Context,
+ From,
+ As,
+ Do,
+};
+
+struct LexerHelper
+{
+ virtual std::string GetAsString(const CharRange& range) = 0;
+ virtual InternalValue GetAsValue(const CharRange& range, Token::Type type) = 0;
+ virtual Keyword GetKeyword(const CharRange& range) = 0;
+ virtual char GetCharAt(size_t pos) = 0;
+};
+
+class Lexer
+{
+public:
+ using TokensList = std::vector<Token>;
+ Lexer(std::function<lexertk::token ()> tokenizer, LexerHelper* helper)
+ : m_tokenizer(std::move(tokenizer))
+ , m_helper(helper)
+ {
+ }
+
+ bool Preprocess();
+ const TokensList& GetTokens() const
+ {
+ return m_tokens;
+ }
+
+ auto GetHelper() const {return m_helper;}
+
+private:
+ bool ProcessNumber(const lexertk::token& token, Token& newToken);
+ bool ProcessSymbolOrKeyword(const lexertk::token& token, Token& newToken);
+ bool ProcessString(const lexertk::token& token, Token& newToken);
+private:
+ std::function<lexertk::token ()> m_tokenizer;
+ TokensList m_tokens;
+ LexerHelper* m_helper;
+};
+
+class LexScanner
+{
+public:
+ struct State
+ {
+ Lexer::TokensList::const_iterator m_begin;
+ Lexer::TokensList::const_iterator m_end;
+ Lexer::TokensList::const_iterator m_cur;
+ };
+
+ struct StateSaver
+ {
+ StateSaver(LexScanner& scanner)
+ : m_state(scanner.m_state)
+ , m_scanner(scanner)
+ {
+ }
+
+ ~StateSaver()
+ {
+ if (!m_commited)
+ m_scanner.m_state = m_state;
+ }
+
+ void Commit()
+ {
+ m_commited = true;
+ }
+
+ State m_state;
+ LexScanner& m_scanner;
+ bool m_commited = false;
+ };
+
+ LexScanner(const Lexer& lexer)
+ : m_helper(lexer.GetHelper())
+ {
+ m_state.m_begin = lexer.GetTokens().begin();
+ m_state.m_end = lexer.GetTokens().end();
+ Reset();
+ }
+
+ void Reset()
+ {
+ m_state.m_cur = m_state.m_begin;
+ }
+
+ auto GetState() const
+ {
+ return m_state;
+ }
+
+ void RestoreState(const State& state)
+ {
+ m_state = state;
+ }
+
+ const Token& NextToken()
+ {
+ if (m_state.m_cur == m_state.m_end)
+ return EofToken();
+
+ return *m_state.m_cur ++;
+ }
+
+ void EatToken()
+ {
+ if (m_state.m_cur != m_state.m_end)
+ ++ m_state.m_cur;
+ }
+
+ void ReturnToken()
+ {
+ if (m_state.m_cur != m_state.m_begin)
+ -- m_state.m_cur;
+ }
+
+ const Token& PeekNextToken() const
+ {
+ if (m_state.m_cur == m_state.m_end)
+ return EofToken();
+
+ return *m_state.m_cur;
+ }
+
+ bool EatIfEqual(char type, Token* tok = nullptr)
+ {
+ return EatIfEqual(static_cast<Token::Type>(type), tok);
+ }
+
+ bool EatIfEqual(Token::Type type, Token* tok = nullptr)
+ {
+ if (m_state.m_cur == m_state.m_end)
+ {
+ if(type == Token::Type::Eof && tok)
+ *tok = EofToken();
+
+ return type == Token::Type::Eof;
+ }
+
+ return EatIfEqualImpl(tok, [type](const Token& t) {return t.type == type;});
+ }
+
+ auto GetAsKeyword(const Token& tok) const
+ {
+ return m_helper->GetKeyword(tok.range);
+ }
+
+ bool EatIfEqual(Keyword kwType, Token* tok = nullptr)
+ {
+ if (m_state.m_cur == m_state.m_end)
+ return false;
+
+ return EatIfEqualImpl(tok, [this, kwType](const Token& t) {return GetAsKeyword(t) == kwType;});
+ }
+
+private:
+ template<typename Fn>
+ bool EatIfEqualImpl(Token* tok, Fn&& predicate)
+ {
+ if (predicate(*m_state.m_cur))
+ {
+ if (tok)
+ *tok = *m_state.m_cur;
+ ++ m_state.m_cur;
+ return true;
+ }
+
+ return false;
+ }
+
+private:
+ State m_state;
+ LexerHelper* m_helper;
+
+ static const Token& EofToken()
+ {
+ static Token eof;
+ eof.type = Token::Eof;
+ return eof;
+ }
+};
+
+} // namespace jinja2
+
+namespace std
+{
+template<>
+struct hash<jinja2::Keyword>
+{
+ size_t operator()(jinja2::Keyword kw) const
+ {
+ return std::hash<int>{}(static_cast<int>(kw));
+ }
+};
+} // namespace std
+
+#endif // JINJA2CPP_SRC_LEXER_H
diff --git a/contrib/libs/jinja2cpp/src/lexertk.h b/contrib/libs/jinja2cpp/src/lexertk.h
new file mode 100644
index 0000000000..c318cc7f3d
--- /dev/null
+++ b/contrib/libs/jinja2cpp/src/lexertk.h
@@ -0,0 +1,1842 @@
+/*
+ *****************************************************************
+ * Simple C++ Lexer Toolkit Library *
+ * *
+ * Author: Arash Partow (2001) *
+ * Modified: Flex Ferrum (2018)
+ * URL: http://www.partow.net/programming/lexertk/index.html *
+ * *
+ * Copyright notice: *
+ * Free use of the Simple C++ Lexer Toolkit Library is permitted *
+ * under the guidelines and in accordance with the MIT License. *
+ * http://www.opensource.org/licenses/MIT *
+ * *
+ * *
+ * The lexer will tokenize input against the following BNF: *
+ * *
+ * expression ::= term { +|- term } *
+ * term ::= (symbol | factor) {operator symbol | factor} *
+ * factor ::= symbol | ( '(' {-} expression ')' ) *
+ * symbol ::= number | gensymb | string *
+ * gensymb ::= alphabet {alphabet | digit} *
+ * string ::= '"' {alphabet | digit | operator } '"' *
+ * operator ::= * | / | % | ^ | < | > | <= | >= | << | >> != *
+ * alphabet ::= a | b | .. | z | A | B | .. | Z *
+ * digit ::= 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 *
+ * sign ::= + | - *
+ * edef ::= e | E *
+ * decimal ::= {digit} (digit [.] | [.] digit) {digit} *
+ * exponent ::= edef [sign] digit {digit} *
+ * real ::= [sign] decimal [exponent] *
+ * integer ::= [sign] {digit} *
+ * number ::= real | integer *
+ * *
+ * *
+ * Note: This lexer has been taken from the ExprTk Library. *
+ * *
+ *****************************************************************
+*/
+
+
+#ifndef JINJA2CPP_SRC_LEXERTK_H
+#define JINJA2CPP_SRC_LEXERTK_H
+
+#include <algorithm>
+#include <cctype>
+#include <clocale>
+#include <cstddef>
+#include <cstdio>
+#include <cstdlib>
+#include <deque>
+#include <exception>
+#include <limits>
+#include <locale>
+#include <map>
+#include <set>
+#include <stack>
+#include <stdexcept>
+#include <string>
+#include <vector>
+
+
+namespace lexertk
+{
+ template<typename CharT>
+ struct CharRange
+ {
+ CharT* start;
+ CharT* end;
+
+ auto length() const {return end - start;}
+ auto offset(CharT* from) const {return start - from;}
+ auto operator[] (size_t idx) const {return start[idx];}
+ };
+ namespace details
+ {
+#if 0
+ inline bool is_whitespace(const char c)
+ {
+ return (' ' == c) || ('\n' == c) ||
+ ('\r' == c) || ('\t' == c) ||
+ ('\b' == c) || ('\v' == c) ||
+ ('\f' == c) ;
+ }
+
+
+ inline bool is_letter(const char c)
+ {
+ return (('a' <= c) && (c <= 'z')) || (('A' <= c) && (c <= 'Z'));
+ }
+
+ inline bool is_digit(const char c)
+ {
+ return ('0' <= c) && (c <= '9');
+ }
+
+ inline bool is_letter_or_digit(const char c)
+ {
+ return is_letter(c) || is_digit(c);
+ }
+#endif
+ template<typename CharT>
+ struct lexer_traits
+ {
+ static auto& get_locale()
+ {
+ static auto locale = std::locale();
+ return locale;
+ }
+
+ static bool is_whitespace(const CharT c)
+ {
+ return std::isspace(c, get_locale());
+ }
+ static bool is_letter(const CharT c)
+ {
+ return std::isalpha(c, get_locale());
+ }
+ static bool is_digit(const CharT c)
+ {
+ return std::isdigit(c, get_locale());
+ }
+ static bool is_letter_or_digit(CharT c)
+ {
+ return std::isalnum(c, get_locale());
+ }
+ static bool is_operator_char(const CharT c);
+ static bool is_left_bracket(const CharT c);
+ static bool is_right_bracket(const CharT c);
+ static bool is_sign(const CharT c);
+ static bool is_invalid(const CharT c);
+ static bool is_bracket(const CharT c)
+ {
+ return is_left_bracket(c) || is_right_bracket(c);
+ }
+ static CharT tolower(const CharT c)
+ {
+ return std::tolower(c, get_locale());
+ }
+ static CharT toupper(const CharT c)
+ {
+ return std::toupper(c, get_locale());
+ }
+ static inline bool imatch(const CharT c1, const CharT c2)
+ {
+ return tolower(c1) == tolower(c2);
+ }
+
+ static inline bool imatch(const CharRange<CharT>& s1, const CharRange<CharT>& s2)
+ {
+ if (s1.length() == s2.length())
+ {
+ for (std::size_t i = 0; i < s1.length(); ++i)
+ {
+ if (tolower(s1[i]) != tolower(s2[i]))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+ };
+
+ template<>
+ inline bool lexer_traits<char>::is_operator_char(const char c)
+ {
+ return ('+' == c) || ('-' == c) ||
+ ('*' == c) || ('/' == c) ||
+ ('^' == c) || ('<' == c) ||
+ ('>' == c) || ('=' == c) ||
+ (',' == c) || ('!' == c) ||
+ ('(' == c) || (')' == c) ||
+ ('[' == c) || (']' == c) ||
+ ('{' == c) || ('}' == c) ||
+ ('%' == c) || (':' == c) ||
+ ('?' == c) || ('&' == c) ||
+ ('|' == c) || (';' == c) ||
+ ('~' == c);
+ }
+
+ template<>
+ inline bool lexer_traits<wchar_t>::is_operator_char(const wchar_t c)
+ {
+ return (L'+' == c) || (L'-' == c) ||
+ (L'*' == c) || (L'/' == c) ||
+ (L'^' == c) || (L'<' == c) ||
+ (L'>' == c) || (L'=' == c) ||
+ (L',' == c) || (L'!' == c) ||
+ (L'(' == c) || (L')' == c) ||
+ (L'[' == c) || (L']' == c) ||
+ (L'{' == c) || (L'}' == c) ||
+ (L'%' == c) || (L':' == c) ||
+ (L'?' == c) || (L'&' == c) ||
+ (L'|' == c) || (L';' == c) ||
+ (L'~' == c);
+ }
+
+ template<>
+ inline bool lexer_traits<char>::is_left_bracket(const char c)
+ {
+ return ('(' == c) || ('[' == c) || ('{' == c);
+ }
+ template<>
+ inline bool lexer_traits<wchar_t>::is_left_bracket(const wchar_t c)
+ {
+ return (L'(' == c) || (L'[' == c) || (L'{' == c);
+ }
+
+ template<>
+ inline bool lexer_traits<char>::is_right_bracket(const char c)
+ {
+ return (')' == c) || (']' == c) || ('}' == c);
+ }
+
+ template<>
+ inline bool lexer_traits<wchar_t>::is_right_bracket(const wchar_t c)
+ {
+ return (L')' == c) || (L']' == c) || (L'}' == c);
+ }
+
+ template<>
+ inline bool lexer_traits<char>::is_sign(const char c)
+ {
+ return ('+' == c) || ('-' == c);
+ }
+
+ template<>
+ inline bool lexer_traits<wchar_t>::is_sign(const wchar_t c)
+ {
+ return (L'+' == c) || (L'-' == c);
+ }
+
+ template<>
+ inline bool lexer_traits<char>::is_invalid(const char c)
+ {
+ return !is_whitespace(c) &&
+ !is_operator_char(c) &&
+ !is_letter(c) &&
+ !is_digit(c) &&
+ ('.' != c) &&
+ ('_' != c) &&
+ ('$' != c) &&
+ ('~' != c) &&
+ ('\'' != c);
+ }
+
+ template<>
+ inline bool lexer_traits<wchar_t>::is_invalid(const wchar_t c)
+ {
+ return !is_whitespace(c) &&
+ !is_operator_char(c) &&
+ !is_letter(c) &&
+ !is_digit(c) &&
+ (L'.' != c) &&
+ (L'_' != c) &&
+ (L'$' != c) &&
+ (L'~' != c) &&
+ (L'\'' != c);
+ }
+
+ template<typename CharT>
+ struct ilesscompare
+ {
+ inline bool operator()(const CharRange<CharT>& s1, const CharRange<CharT>& s2) const
+ {
+ using traits = lexer_traits<CharT>;
+ const std::size_t length = std::min(s1.length(),s2.length());
+
+ for (std::size_t i = 0; i < length; ++i)
+ {
+ if (traits::tolower(s1[i]) > traits::tolower(s2[i]))
+ return false;
+ else if (traits::tolower(s1[i]) < traits::tolower(s2[i]))
+ return true;
+ }
+
+ return s1.length() < s2.length();
+ }
+ };
+
+ } // namespace details
+
+ struct token
+ {
+
+ enum token_type
+ {
+ e_none = 0, e_error = 1, e_err_symbol = 2,
+ e_err_number = 3, e_err_string = 4, e_err_sfunc = 5,
+ e_eof = 6, e_number = 7, e_symbol = 8,
+ e_string = 9, e_eq = 10, e_shr = 11,
+ e_shl = 12, e_lte = 13, e_ne = 14,
+ e_gte = 15, e_lt = '<', e_gt = '>',
+ e_rbracket = ')', e_lbracket = '(', e_tilda = '~',
+ e_rsqrbracket = ']', e_lsqrbracket = '[', e_rcrlbracket = '}',
+ e_lcrlbracket = '{', e_comma = ',', e_add = '+',
+ e_sub = '-', e_div = '/', e_mul = '*',
+ e_mod = '%', e_pow = '^', e_colon = ':',
+ e_dot = '.', e_divdiv = 16 , e_mulmul = 17 ,
+ e_assign = '=', e_pipe = '|',
+ };
+
+ token()
+ : type(e_none),
+ position(std::numeric_limits<std::size_t>::max()),
+ length(0)
+ {}
+
+ void clear()
+ {
+ type = e_none;
+ position = std::numeric_limits<std::size_t>::max();
+ }
+
+ template <typename Iterator>
+ inline token& set_operator(const token_type tt, const Iterator begin, const Iterator end, const Iterator base_begin)
+ {
+ type = tt;
+ position = std::distance(base_begin,begin);
+ length = end - begin;
+ return *this;
+ }
+
+ template <typename Iterator>
+ inline token& set_symbol(const Iterator begin, const Iterator end, const Iterator base_begin)
+ {
+ type = e_symbol;
+ position = std::distance(base_begin,begin);
+ length = end - begin;
+ return *this;
+ }
+
+ template <typename Iterator>
+ inline token& set_numeric(const Iterator begin, const Iterator end, const Iterator base_begin)
+ {
+ type = e_number;
+ position = std::distance(base_begin,begin);
+ length = end - begin;
+ return *this;
+ }
+
+ template <typename Iterator>
+ inline token& set_string(const Iterator begin, const Iterator end, const Iterator base_begin)
+ {
+ type = e_string;
+ position = std::distance(base_begin,begin);
+ length = end - begin;
+ return *this;
+ }
+
+ template <typename Iterator>
+ inline token& set_error(const token_type et, const Iterator begin, const Iterator end, const Iterator base_begin)
+ {
+ if (
+ (e_error == et) ||
+ (e_err_symbol == et) ||
+ (e_err_number == et) ||
+ (e_err_string == et)
+ )
+ {
+ type = e_error;
+ }
+ else
+ type = e_error;
+
+ position = std::distance(base_begin,begin);
+ length = end - begin;
+
+ return *this;
+ }
+
+ static inline const char* to_str(token_type t)
+ {
+ switch (t)
+ {
+ case e_none : return "NONE";
+ case e_error : return "ERROR";
+ case e_err_symbol : return "ERROR_SYMBOL";
+ case e_err_number : return "ERROR_NUMBER";
+ case e_err_string : return "ERROR_STRING";
+ case e_eof : return "EOF";
+ case e_number : return "NUMBER";
+ case e_symbol : return "SYMBOL";
+ case e_string : return "STRING";
+ case e_assign : return "=";
+ case e_shr : return ">>";
+ case e_shl : return "<<";
+ case e_lte : return "<=";
+ case e_ne : return "!=";
+ case e_gte : return ">=";
+ case e_lt : return "<";
+ case e_gt : return ">";
+ case e_eq : return "==";
+ case e_rbracket : return ")";
+ case e_lbracket : return "(";
+ case e_rsqrbracket : return "]";
+ case e_lsqrbracket : return "[";
+ case e_rcrlbracket : return "}";
+ case e_lcrlbracket : return "{";
+ case e_comma : return ",";
+ case e_dot : return ".";
+ case e_add : return "+";
+ case e_sub : return "-";
+ case e_div : return "/";
+ case e_mul : return "*";
+ case e_mod : return "%";
+ case e_pow : return "^";
+ case e_colon : return ":";
+ case e_divdiv : return "//";
+ case e_mulmul : return "**";
+ default : return "UNKNOWN";
+ }
+ }
+
+ inline bool is_error() const
+ {
+ return (
+ (e_error == type) ||
+ (e_err_symbol == type) ||
+ (e_err_number == type) ||
+ (e_err_string == type)
+ );
+ }
+
+ token_type type;
+ size_t position;
+ size_t length;
+ };
+
+ template<typename CharT>
+ class generator
+ {
+ public:
+
+ typedef token token_t;
+ typedef std::vector<token_t> token_list_t;
+ typedef std::vector<token_t>::iterator token_list_itr_t;
+ typedef details::lexer_traits<CharT> traits;
+
+ generator()
+ : base_itr_(0),
+ s_itr_(0),
+ s_end_(0)
+ {
+ clear();
+ }
+
+ inline void clear()
+ {
+ base_itr_ = 0;
+ s_itr_ = 0;
+ s_end_ = 0;
+ token_list_.clear();
+ token_itr_ = token_list_.end();
+ store_token_itr_ = token_itr_;
+ }
+
+ inline bool process(const std::basic_string<CharT>& str)
+ {
+ return process(str.data(), str.data() + str.size());
+ }
+
+ inline bool process(const CharT* begin, const CharT* end)
+ {
+ base_itr_ = begin;
+ s_itr_ = begin;
+ s_end_ = end;
+
+ eof_token_.set_operator(token_t::e_eof,s_end_,s_end_,base_itr_);
+ token_list_.clear();
+
+ while (!is_end(s_itr_))
+ {
+ scan_token();
+
+ if (token_list_.empty())
+ return true;
+ else if (token_list_.back().is_error())
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ inline bool empty() const
+ {
+ return token_list_.empty();
+ }
+
+ inline size_t size() const
+ {
+ return token_list_.size();
+ }
+
+ inline void begin()
+ {
+ token_itr_ = token_list_.begin();
+ store_token_itr_ = token_itr_;
+ }
+
+ inline void store()
+ {
+ store_token_itr_ = token_itr_;
+ }
+
+ inline void restore()
+ {
+ token_itr_ = store_token_itr_;
+ }
+
+ inline token_t& next_token()
+ {
+ if (token_list_.end() != token_itr_)
+ {
+ return *token_itr_++;
+ }
+ else
+ return eof_token_;
+ }
+
+ inline token_t& peek_next_token()
+ {
+ if (token_list_.end() != token_itr_)
+ {
+ return *token_itr_;
+ }
+ else
+ return eof_token_;
+ }
+
+ inline token_t& operator[](const std::size_t& index)
+ {
+ if (index < token_list_.size())
+ return token_list_[index];
+ else
+ return eof_token_;
+ }
+
+ inline token_t operator[](const std::size_t& index) const
+ {
+ if (index < token_list_.size())
+ return token_list_[index];
+ else
+ return eof_token_;
+ }
+
+ inline bool finished() const
+ {
+ return (token_list_.end() == token_itr_);
+ }
+
+ inline std::basic_string<CharT> remaining() const
+ {
+ using string = std::basic_string<CharT>;
+ if (finished())
+ return string();
+ else if (token_list_.begin() != token_itr_)
+ return string(base_itr_ + (token_itr_ - 1)->position,s_end_);
+ else
+ return string(base_itr_ + token_itr_->position,s_end_);
+ }
+
+ private:
+
+ inline bool is_end(const CharT* itr)
+ {
+ return (s_end_ == itr);
+ }
+
+ inline void skip_whitespace()
+ {
+ while (!is_end(s_itr_) && traits::is_whitespace(*s_itr_))
+ {
+ ++s_itr_;
+ }
+ }
+ inline void scan_token()
+ {
+ skip_whitespace();
+
+ if (is_end(s_itr_))
+ {
+ return;
+ }
+ else if (traits::is_operator_char(*s_itr_))
+ {
+ scan_operator();
+ return;
+ }
+ else if (traits::is_letter(*s_itr_) || ('_' == (*s_itr_)))
+ {
+ scan_symbol();
+ return;
+ }
+ else if (traits::is_digit((*s_itr_)) || ('.' == (*s_itr_)))
+ {
+ scan_number();
+ return;
+ }
+ else if ('\'' == (*s_itr_) || '\"' == (*s_itr_))
+ {
+ scan_string();
+ return;
+ }
+ else
+ {
+ token_t t;
+ t.set_error(token::e_error,s_itr_,s_itr_ + 2,base_itr_);
+ token_list_.push_back(t);
+ ++s_itr_;
+ }
+ }
+
+ inline void scan_operator()
+ {
+ token_t t;
+
+ if (!is_end(s_itr_ + 1))
+ {
+ token_t::token_type ttype = token_t::e_none;
+
+ CharT c0 = s_itr_[0];
+ CharT c1 = s_itr_[1];
+
+ if ((c0 == '<') && (c1 == '=')) ttype = token_t::e_lte;
+ else if ((c0 == '>') && (c1 == '=')) ttype = token_t::e_gte;
+ else if ((c0 == '<') && (c1 == '>')) ttype = token_t::e_ne;
+ else if ((c0 == '!') && (c1 == '=')) ttype = token_t::e_ne;
+ else if ((c0 == '=') && (c1 == '=')) ttype = token_t::e_eq;
+ else if ((c0 == ':') && (c1 == '=')) ttype = token_t::e_assign;
+ else if ((c0 == '<') && (c1 == '<')) ttype = token_t::e_shl;
+ else if ((c0 == '>') && (c1 == '>')) ttype = token_t::e_shr;
+ else if ((c0 == '*') && (c1 == '*')) ttype = token_t::e_mulmul;
+ else if ((c0 == '/') && (c1 == '/')) ttype = token_t::e_divdiv;
+
+ if (token_t::e_none != ttype)
+ {
+ t.set_operator(ttype,s_itr_,s_itr_ + 2,base_itr_);
+ token_list_.push_back(t);
+ s_itr_ += 2;
+ return;
+ }
+ }
+
+ if ('<' == *s_itr_)
+ t.set_operator(token_t::e_lt ,s_itr_,s_itr_ + 1,base_itr_);
+ else if ('>' == *s_itr_)
+ t.set_operator(token_t::e_gt ,s_itr_,s_itr_ + 1,base_itr_);
+ else if (';' == *s_itr_)
+ t.set_operator(token_t::e_eof,s_itr_,s_itr_ + 1,base_itr_);
+ else if ('&' == *s_itr_)
+ t.set_symbol(s_itr_,s_itr_ + 1,base_itr_);
+ else if ('|' == *s_itr_)
+ t.set_operator(token::e_pipe,s_itr_,s_itr_ + 1,base_itr_);
+ else
+ t.set_operator(token_t::token_type(*s_itr_),s_itr_,s_itr_ + 1,base_itr_);
+
+ token_list_.push_back(t);
+
+ ++s_itr_;
+ }
+
+ inline void scan_symbol()
+ {
+ const CharT* begin = s_itr_;
+ while (
+ (!is_end(s_itr_)) &&
+ (traits::is_letter_or_digit(*s_itr_) || ((*s_itr_) == '_'))
+ )
+ {
+ ++s_itr_;
+ }
+ token_t t;
+ t.set_symbol(begin,s_itr_,base_itr_);
+ token_list_.push_back(t);
+ }
+
+ inline void scan_number()
+ {
+ /*
+ Attempt to match a valid numeric value in one of the following formats:
+ 01. 123456
+ 02. 123.456
+ 03. 123.456e3
+ 04. 123.456E3
+ 05. 123.456e+3
+ 06. 123.456E+3
+ 07. 123.456e-3
+ 08. 123.456E-3
+ 09. .1234
+ 10. .1234e3
+ 11. .1234E+3
+ 12. .1234e+3
+ 13. .1234E-3
+ 14. .1234e-3
+ */
+ const CharT* begin = s_itr_;
+ bool dot_found = false;
+ bool e_found = false;
+ bool post_e_sign_found = false;
+ bool post_e_digit_found = false;
+ token_t t;
+
+ if ('.' == *begin && !is_end(begin + 1) && !traits::is_digit(begin[1]))
+ {
+ scan_operator();
+ return;
+ }
+
+ while (!is_end(s_itr_))
+ {
+ if ('.' == (*s_itr_))
+ {
+ if (dot_found)
+ {
+ t.set_error(token::e_err_number,begin,s_itr_,base_itr_);
+ token_list_.push_back(t);
+
+ return;
+ }
+
+ dot_found = true;
+ ++s_itr_;
+
+ continue;
+ }
+ else if (traits::imatch('e',(*s_itr_)))
+ {
+ const CharT& c = *(s_itr_ + 1);
+
+ if (is_end(s_itr_ + 1))
+ {
+ t.set_error(token::e_err_number,begin,s_itr_,base_itr_);
+ token_list_.push_back(t);
+
+ return;
+ }
+ else if (
+ ('+' != c) &&
+ ('-' != c) &&
+ !traits::is_digit(c)
+ )
+ {
+ t.set_error(token::e_err_number,begin,s_itr_,base_itr_);
+ token_list_.push_back(t);
+
+ return;
+ }
+
+ e_found = true;
+ ++s_itr_;
+
+ continue;
+ }
+ else if (e_found && traits::is_sign(*s_itr_) && !post_e_digit_found)
+ {
+ if (post_e_sign_found)
+ {
+ t.set_error(token::e_err_number,begin,s_itr_,base_itr_);
+ token_list_.push_back(t);
+
+ return;
+ }
+
+ post_e_sign_found = true;
+ ++s_itr_;
+
+ continue;
+ }
+ else if (e_found && traits::is_digit(*s_itr_))
+ {
+ post_e_digit_found = true;
+ ++s_itr_;
+
+ continue;
+ }
+ else if (('.' != (*s_itr_)) && !traits::is_digit(*s_itr_))
+ break;
+ else
+ ++s_itr_;
+ }
+
+ t.set_numeric(begin,s_itr_,base_itr_);
+
+ token_list_.push_back(t);
+
+ return;
+ }
+
+ inline void scan_string()
+ {
+ CharT endChar = *s_itr_;
+ const CharT* begin = s_itr_ + 1;
+
+ token_t t;
+
+ if (std::distance(s_itr_,s_end_) < 2)
+ {
+ t.set_error(token::e_err_string,s_itr_,s_end_,base_itr_);
+ token_list_.push_back(t);
+
+ return;
+ }
+
+ ++s_itr_;
+
+ bool escaped = false;
+
+ while (!is_end(s_itr_))
+ {
+ if (!escaped && ('\\' == *s_itr_))
+ {
+ escaped = true;
+ ++s_itr_;
+
+ continue;
+ }
+ else if (!escaped)
+ {
+ if (endChar == *s_itr_)
+ break;
+ }
+ else
+ escaped = false;
+
+ ++s_itr_;
+ }
+
+ if (is_end(s_itr_))
+ {
+ t.set_error(token::e_err_string,begin,s_itr_,base_itr_);
+ token_list_.push_back(t);
+
+ return;
+ }
+
+ t.set_string(begin,s_itr_,base_itr_);
+ token_list_.push_back(t);
+ ++s_itr_;
+
+ return;
+ }
+
+ private:
+
+ token_list_t token_list_;
+ token_list_itr_t token_itr_;
+ token_list_itr_t store_token_itr_;
+ token_t eof_token_;
+ const CharT* base_itr_;
+ const CharT* s_itr_;
+ const CharT* s_end_;
+
+ friend class token_scanner;
+ friend class token_modifier;
+ friend class token_inserter;
+ friend class token_joiner;
+ };
+#if 0
+ class helper_interface
+ {
+ public:
+
+ virtual void init() { }
+ virtual void reset() { }
+ virtual bool result() { return true; }
+ virtual std::size_t process(generator&) { return 0; }
+ virtual ~helper_interface() { }
+ };
+
+ class token_scanner : public helper_interface
+ {
+ public:
+
+ virtual ~token_scanner()
+ {}
+
+ explicit token_scanner(const std::size_t& stride)
+ : stride_(stride)
+ {
+ if (stride > 4)
+ {
+ throw std::invalid_argument("token_scanner() - Invalid stride value");
+ }
+ }
+
+ inline std::size_t process(generator& g)
+ {
+ if (!g.token_list_.empty())
+ {
+ for (std::size_t i = 0; i < (g.token_list_.size() - stride_ + 1); ++i)
+ {
+ token t;
+ switch (stride_)
+ {
+ case 1 :
+ {
+ const token& t0 = g.token_list_[i];
+
+ if (!operator()(t0)) return i;
+ }
+ break;
+
+ case 2 :
+ {
+ const token& t0 = g.token_list_[i ];
+ const token& t1 = g.token_list_[i + 1];
+
+ if (!operator()(t0,t1)) return i;
+ }
+ break;
+
+ case 3 :
+ {
+ const token& t0 = g.token_list_[i ];
+ const token& t1 = g.token_list_[i + 1];
+ const token& t2 = g.token_list_[i + 2];
+
+ if (!operator()(t0,t1,t2)) return i;
+ }
+ break;
+
+ case 4 :
+ {
+ const token& t0 = g.token_list_[i ];
+ const token& t1 = g.token_list_[i + 1];
+ const token& t2 = g.token_list_[i + 2];
+ const token& t3 = g.token_list_[i + 3];
+
+ if (!operator()(t0,t1,t2,t3)) return i;
+ }
+ break;
+ }
+ }
+ }
+
+ return (g.token_list_.size() - stride_ + 1);
+ }
+
+ virtual bool operator()(const token&)
+ {
+ return false;
+ }
+
+ virtual bool operator()(const token&, const token&)
+ {
+ return false;
+ }
+
+ virtual bool operator()(const token&, const token&, const token&)
+ {
+ return false;
+ }
+
+ virtual bool operator()(const token&, const token&, const token&, const token&)
+ {
+ return false;
+ }
+
+ private:
+
+ std::size_t stride_;
+ };
+
+ class token_modifier : public helper_interface
+ {
+ public:
+
+ inline std::size_t process(generator& g)
+ {
+ std::size_t changes = 0;
+
+ for (std::size_t i = 0; i < g.token_list_.size(); ++i)
+ {
+ if (modify(g.token_list_[i])) changes++;
+ }
+
+ return changes;
+ }
+
+ virtual bool modify(token& t) = 0;
+ };
+
+ class token_inserter : public helper_interface
+ {
+ public:
+
+ explicit token_inserter(const std::size_t& stride)
+ : stride_(stride)
+ {
+ if (stride > 5)
+ {
+ throw std::invalid_argument("token_inserter() - Invalid stride value");
+ }
+ }
+
+ inline std::size_t process(generator& g)
+ {
+ if (g.token_list_.empty())
+ return 0;
+
+ std::size_t changes = 0;
+
+ for (std::size_t i = 0; i < (g.token_list_.size() - stride_ + 1); ++i)
+ {
+ token t;
+ int insert_index = -1;
+
+ switch (stride_)
+ {
+ case 1 : insert_index = insert(g.token_list_[i],t);
+ break;
+
+ case 2 : insert_index = insert(g.token_list_[i],g.token_list_[i + 1],t);
+ break;
+
+ case 3 : insert_index = insert(g.token_list_[i],g.token_list_[i + 1],g.token_list_[i + 2],t);
+ break;
+
+ case 4 : insert_index = insert(g.token_list_[i],g.token_list_[i + 1],g.token_list_[i + 2],g.token_list_[i + 3],t);
+ break;
+
+ case 5 : insert_index = insert(g.token_list_[i],g.token_list_[i + 1],g.token_list_[i + 2],g.token_list_[i + 3],g.token_list_[i + 4],t);
+ break;
+ }
+
+ if ((insert_index >= 0) && (insert_index <= (static_cast<int>(stride_) + 1)))
+ {
+ g.token_list_.insert(g.token_list_.begin() + (i + insert_index),t);
+ changes++;
+ }
+ }
+
+ return changes;
+ }
+
+ virtual inline int insert(const token&, token& )
+ {
+ return -1;
+ }
+
+ virtual inline int insert(const token&, const token&, token&)
+ {
+ return -1;
+ }
+
+ virtual inline int insert(const token&, const token&, const token&, token&)
+ {
+ return -1;
+ }
+
+ virtual inline int insert(const token&, const token&, const token&, const token&, token&)
+ {
+ return -1;
+ }
+
+ virtual inline int insert(const token&, const token&, const token&, const token&, const token&, token&)
+ {
+ return -1;
+ }
+
+ private:
+
+ std::size_t stride_;
+ };
+
+ class token_joiner : public helper_interface
+ {
+ public:
+
+ inline std::size_t process(generator& g)
+ {
+ if (g.token_list_.empty())
+ return 0;
+
+ std::size_t changes = 0;
+
+ for (std::size_t i = 0; i < g.token_list_.size() - 1; ++i)
+ {
+ token t;
+
+ if (join(g.token_list_[i],g.token_list_[i + 1],t))
+ {
+ g.token_list_[i] = t;
+ g.token_list_.erase(g.token_list_.begin() + (i + 1));
+
+ ++changes;
+ }
+ }
+
+ return changes;
+ }
+
+ virtual bool join(const token&, const token&, token&) = 0;
+ };
+
+ namespace helper
+ {
+
+ inline void dump(lexertk::generator& generator)
+ {
+ for (std::size_t i = 0; i < generator.size(); ++i)
+ {
+ lexertk::token t = generator[i];
+ printf("Token[%02d] @ %03d %6s --> '%s'\n",
+ static_cast<unsigned int>(i),
+ static_cast<unsigned int>(t.position),
+ t.to_str(t.type).c_str(),
+ t.value.c_str());
+ }
+ }
+
+ class commutative_inserter : public token_inserter
+ {
+ public:
+
+ commutative_inserter()
+ : lexertk::token_inserter(2)
+ {}
+
+ inline void ignore_symbol(const std::string& symbol)
+ {
+ ignore_set_.insert(symbol);
+ }
+
+ inline int insert(const lexertk::token& t0, const lexertk::token& t1, lexertk::token& new_token)
+ {
+ new_token.type = lexertk::token::e_mul;
+ new_token.value = "*";
+ new_token.position = t1.position;
+ bool match = false;
+
+ if (t0.type == lexertk::token::e_symbol)
+ {
+ if (ignore_set_.end() != ignore_set_.find(t0.value))
+ {
+ return -1;
+ }
+ else if (!t0.value.empty() && ('$' == t0.value[0]))
+ {
+ return -1;
+ }
+ }
+
+ if (t1.type == lexertk::token::e_symbol)
+ {
+ if (ignore_set_.end() != ignore_set_.find(t1.value))
+ {
+ return -1;
+ }
+ }
+
+ if ((t0.type == lexertk::token::e_number ) && (t1.type == lexertk::token::e_symbol )) match = true;
+ else if ((t0.type == lexertk::token::e_number ) && (t1.type == lexertk::token::e_lbracket )) match = true;
+ else if ((t0.type == lexertk::token::e_number ) && (t1.type == lexertk::token::e_lcrlbracket)) match = true;
+ else if ((t0.type == lexertk::token::e_number ) && (t1.type == lexertk::token::e_lsqrbracket)) match = true;
+ else if ((t0.type == lexertk::token::e_symbol ) && (t1.type == lexertk::token::e_number )) match = true;
+ else if ((t0.type == lexertk::token::e_rbracket ) && (t1.type == lexertk::token::e_number )) match = true;
+ else if ((t0.type == lexertk::token::e_rcrlbracket) && (t1.type == lexertk::token::e_number )) match = true;
+ else if ((t0.type == lexertk::token::e_rsqrbracket) && (t1.type == lexertk::token::e_number )) match = true;
+ else if ((t0.type == lexertk::token::e_rbracket ) && (t1.type == lexertk::token::e_symbol )) match = true;
+ else if ((t0.type == lexertk::token::e_rcrlbracket) && (t1.type == lexertk::token::e_symbol )) match = true;
+ else if ((t0.type == lexertk::token::e_rsqrbracket) && (t1.type == lexertk::token::e_symbol )) match = true;
+
+ return (match) ? 1 : -1;
+ }
+
+ private:
+
+ std::set<std::string,details::ilesscompare> ignore_set_;
+ };
+
+ class operator_joiner : public token_joiner
+ {
+ public:
+
+ inline bool join(const lexertk::token& t0, const lexertk::token& t1, lexertk::token& t)
+ {
+ //': =' --> ':='
+ if ((t0.type == lexertk::token::e_colon) && (t1.type == lexertk::token::e_eq))
+ {
+ t.type = lexertk::token::e_assign;
+ t.value = ":=";
+ t.position = t0.position;
+
+ return true;
+ }
+ //'> =' --> '>='
+ else if ((t0.type == lexertk::token::e_gt) && (t1.type == lexertk::token::e_eq))
+ {
+ t.type = lexertk::token::e_gte;
+ t.value = ">=";
+ t.position = t0.position;
+
+ return true;
+ }
+ //'< =' --> '<='
+ else if ((t0.type == lexertk::token::e_lt) && (t1.type == lexertk::token::e_eq))
+ {
+ t.type = lexertk::token::e_lte;
+ t.value = "<=";
+ t.position = t0.position;
+
+ return true;
+ }
+ //'= =' --> '=='
+ else if ((t0.type == lexertk::token::e_eq) && (t1.type == lexertk::token::e_eq))
+ {
+ t.type = lexertk::token::e_eq;
+ t.value = "==";
+ t.position = t0.position;
+
+ return true;
+ }
+ //'! =' --> '!='
+ else if ((static_cast<char>(t0.type) == '!') && (t1.type == lexertk::token::e_eq))
+ {
+ t.type = lexertk::token::e_ne;
+ t.value = "!=";
+ t.position = t0.position;
+
+ return true;
+ }
+ //'< >' --> '<>'
+ else if ((t0.type == lexertk::token::e_lt) && (t1.type == lexertk::token::e_gt))
+ {
+ t.type = lexertk::token::e_ne;
+ t.value = "<>";
+ t.position = t0.position;
+
+ return true;
+ }
+ else
+ return false;
+ }
+ };
+
+ class bracket_checker : public token_scanner
+ {
+ public:
+
+ bracket_checker()
+ : token_scanner(1),
+ state_(true)
+ {}
+
+ bool result()
+ {
+ return state_ && stack_.empty();
+ }
+
+ lexertk::token error_token()
+ {
+ return error_token_;
+ }
+
+ void reset()
+ {
+ //why? because msvc doesn't support swap properly.
+ stack_ = std::stack<char>();
+ state_ = true;
+ error_token_.clear();
+ }
+
+ bool operator()(const lexertk::token& t)
+ {
+ if (
+ !t.value.empty() &&
+ (lexertk::token::e_string != t.type) &&
+ (lexertk::token::e_symbol != t.type) &&
+ details::is_bracket(t.value[0])
+ )
+ {
+ char c = t.value[0];
+
+ if (t.type == lexertk::token::e_lbracket) stack_.push(')');
+ else if (t.type == lexertk::token::e_lcrlbracket) stack_.push('}');
+ else if (t.type == lexertk::token::e_lsqrbracket) stack_.push(']');
+ else if (details::is_right_bracket(c))
+ {
+ if (stack_.empty())
+ {
+ state_ = false;
+ error_token_ = t;
+
+ return false;
+ }
+ else if (c != stack_.top())
+ {
+ state_ = false;
+ error_token_ = t;
+
+ return false;
+ }
+ else
+ stack_.pop();
+ }
+ }
+
+ return true;
+ }
+
+ private:
+
+ bool state_;
+ std::stack<char> stack_;
+ lexertk::token error_token_;
+ };
+
+ class symbol_replacer : public token_modifier
+ {
+ private:
+
+ typedef std::map<std::string,std::pair<std::string,token::token_type>,details::ilesscompare> replace_map_t;
+
+ public:
+
+ bool remove(const std::string& target_symbol)
+ {
+ replace_map_t::iterator itr = replace_map_.find(target_symbol);
+
+ if (replace_map_.end() == itr)
+ return false;
+
+ replace_map_.erase(itr);
+
+ return true;
+ }
+
+ bool add_replace(const std::string& target_symbol,
+ const std::string& replace_symbol,
+ const lexertk::token::token_type token_type = lexertk::token::e_symbol)
+ {
+ replace_map_t::iterator itr = replace_map_.find(target_symbol);
+
+ if (replace_map_.end() != itr)
+ {
+ return false;
+ }
+
+ replace_map_[target_symbol] = std::make_pair(replace_symbol,token_type);
+
+ return true;
+ }
+
+ void clear()
+ {
+ replace_map_.clear();
+ }
+
+ private:
+
+ bool modify(lexertk::token& t)
+ {
+ if (lexertk::token::e_symbol == t.type)
+ {
+ if (replace_map_.empty())
+ return false;
+
+ replace_map_t::iterator itr = replace_map_.find(t.value);
+
+ if (replace_map_.end() != itr)
+ {
+ t.value = itr->second.first;
+ t.type = itr->second.second;
+
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ replace_map_t replace_map_;
+ };
+
+ class sequence_validator : public token_scanner
+ {
+ private:
+
+ typedef std::pair<lexertk::token::token_type,lexertk::token::token_type> token_pair_t;
+ typedef std::set<token_pair_t> set_t;
+
+ public:
+
+ sequence_validator()
+ : lexertk::token_scanner(2)
+ {
+ add_invalid(lexertk::token::e_number,lexertk::token::e_number);
+ add_invalid(lexertk::token::e_string,lexertk::token::e_string);
+ add_invalid(lexertk::token::e_number,lexertk::token::e_string);
+ add_invalid(lexertk::token::e_string,lexertk::token::e_number);
+ add_invalid(lexertk::token::e_string,lexertk::token::e_colon);
+ add_invalid(lexertk::token::e_colon,lexertk::token::e_string);
+ add_invalid_set1(lexertk::token::e_assign);
+ add_invalid_set1(lexertk::token::e_shr );
+ add_invalid_set1(lexertk::token::e_shl );
+ add_invalid_set1(lexertk::token::e_lte );
+ add_invalid_set1(lexertk::token::e_ne );
+ add_invalid_set1(lexertk::token::e_gte );
+ add_invalid_set1(lexertk::token::e_lt );
+ add_invalid_set1(lexertk::token::e_gt );
+ add_invalid_set1(lexertk::token::e_eq );
+ add_invalid_set1(lexertk::token::e_comma );
+ add_invalid_set1(lexertk::token::e_add );
+ add_invalid_set1(lexertk::token::e_sub );
+ add_invalid_set1(lexertk::token::e_div );
+ add_invalid_set1(lexertk::token::e_mul );
+ add_invalid_set1(lexertk::token::e_mod );
+ add_invalid_set1(lexertk::token::e_pow );
+ add_invalid_set1(lexertk::token::e_colon );
+ }
+
+ bool result()
+ {
+ return error_list_.empty();
+ }
+
+ bool operator()(const lexertk::token& t0, const lexertk::token& t1)
+ {
+ set_t::value_type p = std::make_pair(t0.type,t1.type);
+
+ if (invalid_bracket_check(t0.type,t1.type))
+ {
+ error_list_.push_back(std::make_pair(t0,t1));
+ }
+ else if (invalid_comb_.find(p) != invalid_comb_.end())
+ error_list_.push_back(std::make_pair(t0,t1));
+
+ return true;
+ }
+
+ std::size_t error_count()
+ {
+ return error_list_.size();
+ }
+
+ std::pair<lexertk::token,lexertk::token> error(const std::size_t index)
+ {
+ if (index < error_list_.size())
+ {
+ return error_list_[index];
+ }
+ else
+ {
+ static const lexertk::token error_token;
+ return std::make_pair(error_token,error_token);
+ }
+ }
+
+ void clear_errors()
+ {
+ error_list_.clear();
+ }
+
+ private:
+
+ void add_invalid(lexertk::token::token_type base, lexertk::token::token_type t)
+ {
+ invalid_comb_.insert(std::make_pair(base,t));
+ }
+
+ void add_invalid_set1(lexertk::token::token_type t)
+ {
+ add_invalid(t,lexertk::token::e_assign);
+ add_invalid(t,lexertk::token::e_shr );
+ add_invalid(t,lexertk::token::e_shl );
+ add_invalid(t,lexertk::token::e_lte );
+ add_invalid(t,lexertk::token::e_ne );
+ add_invalid(t,lexertk::token::e_gte );
+ add_invalid(t,lexertk::token::e_lt );
+ add_invalid(t,lexertk::token::e_gt );
+ add_invalid(t,lexertk::token::e_eq );
+ add_invalid(t,lexertk::token::e_comma );
+ add_invalid(t,lexertk::token::e_div );
+ add_invalid(t,lexertk::token::e_mul );
+ add_invalid(t,lexertk::token::e_mod );
+ add_invalid(t,lexertk::token::e_pow );
+ add_invalid(t,lexertk::token::e_colon );
+ }
+
+ bool invalid_bracket_check(lexertk::token::token_type base, lexertk::token::token_type t)
+ {
+ if (details::is_right_bracket(static_cast<char>(base)))
+ {
+ switch (t)
+ {
+ case lexertk::token::e_string : return true;
+ case lexertk::token::e_assign : return true;
+ default : return false;
+ }
+ }
+ else if (details::is_left_bracket(static_cast<char>(base)))
+ {
+ if (details::is_right_bracket(static_cast<char>(t)))
+ return false;
+ else if (details::is_left_bracket(static_cast<char>(t)))
+ return false;
+ else
+ {
+ switch (t)
+ {
+ case lexertk::token::e_number : return false;
+ case lexertk::token::e_symbol : return false;
+ case lexertk::token::e_string : return false;
+ case lexertk::token::e_add : return false;
+ case lexertk::token::e_sub : return false;
+ case lexertk::token::e_colon : return false;
+ default : return true;
+ }
+ }
+ }
+ else if (details::is_right_bracket(static_cast<char>(t)))
+ {
+ switch (base)
+ {
+ case lexertk::token::e_number : return false;
+ case lexertk::token::e_symbol : return false;
+ case lexertk::token::e_string : return false;
+ case lexertk::token::e_eof : return false;
+ case lexertk::token::e_colon : return false;
+ default : return true;
+ }
+ }
+ else if (details::is_left_bracket(static_cast<char>(t)))
+ {
+ switch (base)
+ {
+ case lexertk::token::e_rbracket : return true;
+ case lexertk::token::e_rsqrbracket : return true;
+ case lexertk::token::e_rcrlbracket : return true;
+ default : return false;
+ }
+ }
+
+ return false;
+ }
+
+ set_t invalid_comb_;
+ std::deque<std::pair<lexertk::token,lexertk::token> > error_list_;
+
+ };
+
+ struct helper_assembly
+ {
+ inline bool register_scanner(lexertk::token_scanner* scanner)
+ {
+ if (token_scanner_list.end() != std::find(token_scanner_list.begin(),
+ token_scanner_list.end(),
+ scanner))
+ {
+ return false;
+ }
+
+ token_scanner_list.push_back(scanner);
+
+ return true;
+ }
+
+ inline bool register_modifier(lexertk::token_modifier* modifier)
+ {
+ if (token_modifier_list.end() != std::find(token_modifier_list.begin(),
+ token_modifier_list.end(),
+ modifier))
+ {
+ return false;
+ }
+
+ token_modifier_list.push_back(modifier);
+
+ return true;
+ }
+
+ inline bool register_joiner(lexertk::token_joiner* joiner)
+ {
+ if (token_joiner_list.end() != std::find(token_joiner_list.begin(),
+ token_joiner_list.end(),
+ joiner))
+ {
+ return false;
+ }
+
+ token_joiner_list.push_back(joiner);
+
+ return true;
+ }
+
+ inline bool register_inserter(lexertk::token_inserter* inserter)
+ {
+ if (token_inserter_list.end() != std::find(token_inserter_list.begin(),
+ token_inserter_list.end(),
+ inserter))
+ {
+ return false;
+ }
+
+ token_inserter_list.push_back(inserter);
+
+ return true;
+ }
+
+ inline bool run_modifiers(lexertk::generator& g)
+ {
+ error_token_modifier = reinterpret_cast<lexertk::token_modifier*>(0);
+
+ for (std::size_t i = 0; i < token_modifier_list.size(); ++i)
+ {
+ lexertk::token_modifier& modifier = (*token_modifier_list[i]);
+
+ modifier.reset();
+ modifier.process(g);
+
+ if (!modifier.result())
+ {
+ error_token_modifier = token_modifier_list[i];
+
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ inline bool run_joiners(lexertk::generator& g)
+ {
+ error_token_joiner = reinterpret_cast<lexertk::token_joiner*>(0);
+
+ for (std::size_t i = 0; i < token_joiner_list.size(); ++i)
+ {
+ lexertk::token_joiner& joiner = (*token_joiner_list[i]);
+
+ joiner.reset();
+ joiner.process(g);
+
+ if (!joiner.result())
+ {
+ error_token_joiner = token_joiner_list[i];
+
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ inline bool run_inserters(lexertk::generator& g)
+ {
+ error_token_inserter = reinterpret_cast<lexertk::token_inserter*>(0);
+
+ for (std::size_t i = 0; i < token_inserter_list.size(); ++i)
+ {
+ lexertk::token_inserter& inserter = (*token_inserter_list[i]);
+
+ inserter.reset();
+ inserter.process(g);
+
+ if (!inserter.result())
+ {
+ error_token_inserter = token_inserter_list[i];
+
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ inline bool run_scanners(lexertk::generator& g)
+ {
+ error_token_scanner = reinterpret_cast<lexertk::token_scanner*>(0);
+
+ for (std::size_t i = 0; i < token_scanner_list.size(); ++i)
+ {
+ lexertk::token_scanner& scanner = (*token_scanner_list[i]);
+
+ scanner.reset();
+ scanner.process(g);
+
+ if (!scanner.result())
+ {
+ error_token_scanner = token_scanner_list[i];
+
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ std::deque<lexertk::token_scanner*> token_scanner_list;
+ std::deque<lexertk::token_modifier*> token_modifier_list;
+ std::deque<lexertk::token_joiner*> token_joiner_list;
+ std::deque<lexertk::token_inserter*> token_inserter_list;
+
+ lexertk::token_scanner* error_token_scanner;
+ lexertk::token_modifier* error_token_modifier;
+ lexertk::token_joiner* error_token_joiner;
+ lexertk::token_inserter* error_token_inserter;
+ };
+ }
+
+ class parser_helper
+ {
+ public:
+
+ typedef token token_t;
+ typedef generator generator_t;
+
+ inline bool init(const std::string& str)
+ {
+ if (!lexer_.process(str))
+ {
+ return false;
+ }
+
+ lexer_.begin();
+
+ next_token();
+
+ return true;
+ }
+
+ inline generator_t& lexer()
+ {
+ return lexer_;
+ }
+
+ inline const generator_t& lexer() const
+ {
+ return lexer_;
+ }
+
+ inline void next_token()
+ {
+ current_token_ = lexer_.next_token();
+ }
+
+ inline const token_t& current_token() const
+ {
+ return current_token_;
+ }
+
+ enum token_advance_mode
+ {
+ e_hold = 0,
+ e_advance = 1
+ };
+
+ inline void advance_token(const token_advance_mode mode)
+ {
+ if (e_advance == mode)
+ {
+ next_token();
+ }
+ }
+
+ inline bool token_is(const token_t::token_type& ttype, const token_advance_mode mode = e_advance)
+ {
+ if (current_token().type != ttype)
+ {
+ return false;
+ }
+
+ advance_token(mode);
+
+ return true;
+ }
+
+ inline bool token_is(const token_t::token_type& ttype,
+ const std::string& value,
+ const token_advance_mode mode = e_advance)
+ {
+ if (
+ (current_token().type != ttype) ||
+ !details::imatch(value,current_token().value)
+ )
+ {
+ return false;
+ }
+
+ advance_token(mode);
+
+ return true;
+ }
+
+ inline bool token_is_then_assign(const token_t::token_type& ttype,
+ std::string& token,
+ const token_advance_mode mode = e_advance)
+ {
+ if (current_token_.type != ttype)
+ {
+ return false;
+ }
+
+ token = current_token_.value;
+
+ advance_token(mode);
+
+ return true;
+ }
+
+ template <typename Allocator,
+ template <typename,typename> class Container>
+ inline bool token_is_then_assign(const token_t::token_type& ttype,
+ Container<std::string,Allocator>& token_list,
+ const token_advance_mode mode = e_advance)
+ {
+ if (current_token_.type != ttype)
+ {
+ return false;
+ }
+
+ token_list.push_back(current_token_.value);
+
+ advance_token(mode);
+
+ return true;
+ }
+
+ inline bool peek_token_is(const token_t::token_type& ttype)
+ {
+ return (lexer_.peek_next_token().type == ttype);
+ }
+
+ inline bool peek_token_is(const std::string& s)
+ {
+ return (details::imatch(lexer_.peek_next_token().value,s));
+ }
+
+ private:
+
+ generator_t lexer_;
+ token_t current_token_;
+ };
+#endif
+} // namespace lexertk
+
+#endif
diff --git a/contrib/libs/jinja2cpp/src/out_stream.h b/contrib/libs/jinja2cpp/src/out_stream.h
new file mode 100644
index 0000000000..8e3f001ba9
--- /dev/null
+++ b/contrib/libs/jinja2cpp/src/out_stream.h
@@ -0,0 +1,43 @@
+#ifndef JINJA2CPP_SRC_OUT_STREAM_H
+#define JINJA2CPP_SRC_OUT_STREAM_H
+
+#include "internal_value.h"
+
+#include <functional>
+#include <iostream>
+#include <sstream>
+
+namespace jinja2
+{
+class OutStream
+{
+public:
+ struct StreamWriter
+ {
+ virtual ~StreamWriter() {}
+
+ virtual void WriteBuffer(const void* ptr, size_t length) = 0;
+ virtual void WriteValue(const InternalValue &val) = 0;
+ };
+
+ OutStream(std::function<StreamWriter*()> writerGetter)
+ : m_writerGetter(std::move(writerGetter))
+ {}
+
+ void WriteBuffer(const void* ptr, size_t length)
+ {
+ m_writerGetter()->WriteBuffer(ptr, length);
+ }
+
+ void WriteValue(const InternalValue& val)
+ {
+ m_writerGetter()->WriteValue(val);
+ }
+
+private:
+ std::function<StreamWriter*()> m_writerGetter;
+};
+
+} // namespace jinja2
+
+#endif // JINJA2CPP_SRC_OUT_STREAM_H
diff --git a/contrib/libs/jinja2cpp/src/render_context.h b/contrib/libs/jinja2cpp/src/render_context.h
new file mode 100644
index 0000000000..f6edcf444e
--- /dev/null
+++ b/contrib/libs/jinja2cpp/src/render_context.h
@@ -0,0 +1,182 @@
+#ifndef JINJA2CPP_SRC_RENDER_CONTEXT_H
+#define JINJA2CPP_SRC_RENDER_CONTEXT_H
+
+#include "internal_value.h"
+#include <jinja2cpp/error_info.h>
+#include <jinja2cpp/utils/i_comparable.h>
+
+#include <contrib/restricted/expected-lite/include/nonstd/expected.hpp>
+
+#include <list>
+#include <deque>
+
+namespace jinja2
+{
+template<typename CharT>
+class TemplateImpl;
+
+struct IRendererCallback : IComparable
+{
+ virtual ~IRendererCallback() {}
+ virtual TargetString GetAsTargetString(const InternalValue& val) = 0;
+ virtual OutStream GetStreamOnString(TargetString& str) = 0;
+ virtual std::variant<EmptyValue,
+ nonstd::expected<std::shared_ptr<TemplateImpl<char>>, ErrorInfo>,
+ nonstd::expected<std::shared_ptr<TemplateImpl<wchar_t>>, ErrorInfoW>> LoadTemplate(const std::string& fileName) const = 0;
+ virtual std::variant<EmptyValue,
+ nonstd::expected<std::shared_ptr<TemplateImpl<char>>, ErrorInfo>,
+ nonstd::expected<std::shared_ptr<TemplateImpl<wchar_t>>, ErrorInfoW>> LoadTemplate(const InternalValue& fileName) const = 0;
+ virtual void ThrowRuntimeError(ErrorCode code, ValuesList extraParams) = 0;
+};
+
+class RenderContext
+{
+public:
+ RenderContext(const InternalValueMap& extValues, const InternalValueMap& globalValues, IRendererCallback* rendererCallback)
+ : m_rendererCallback(rendererCallback)
+ {
+ m_externalScope = &extValues;
+ m_globalScope = &globalValues;
+ EnterScope();
+ (*m_currentScope)["self"] = CreateMapAdapter(InternalValueMap());
+ }
+
+ RenderContext(const RenderContext& other)
+ : m_rendererCallback(other.m_rendererCallback)
+ , m_externalScope(other.m_externalScope)
+ , m_globalScope(other.m_globalScope)
+ , m_boundScope(other.m_boundScope)
+ , m_scopes(other.m_scopes)
+ {
+ m_currentScope = &m_scopes.back();
+ }
+
+ InternalValueMap& EnterScope()
+ {
+ m_scopes.push_back(InternalValueMap());
+ m_currentScope = &m_scopes.back();
+ return *m_currentScope;
+ }
+
+ void ExitScope()
+ {
+ m_scopes.pop_back();
+ if (!m_scopes.empty())
+ m_currentScope = &m_scopes.back();
+ else
+ m_currentScope = nullptr;
+ }
+
+ auto FindValue(const std::string& val, bool& found) const
+ {
+ auto finder = [&val, &found](auto& map) mutable
+ {
+ auto p = map.find(val);
+ if (p != map.end())
+ found = true;
+
+ return p;
+ };
+
+ if (m_boundScope)
+ {
+ auto valP = finder(*m_boundScope);
+ if (found)
+ return valP;
+ }
+
+ for (auto p = m_scopes.rbegin(); p != m_scopes.rend(); ++ p)
+ {
+ auto valP = finder(*p);
+ if (found)
+ return valP;
+ }
+
+ auto valP = finder(*m_externalScope);
+ if (found)
+ return valP;
+
+ return finder(*m_globalScope);
+ }
+
+ auto& GetCurrentScope() const
+ {
+ return *m_currentScope;
+ }
+
+ auto& GetCurrentScope()
+ {
+ return *m_currentScope;
+ }
+ auto& GetGlobalScope()
+ {
+ return m_scopes.front();
+ }
+ auto GetRendererCallback()
+ {
+ return m_rendererCallback;
+ }
+ RenderContext Clone(bool includeCurrentContext) const
+ {
+ if (!includeCurrentContext)
+ return RenderContext(m_emptyScope, *m_globalScope, m_rendererCallback);
+
+ return RenderContext(*this);
+ }
+
+ void BindScope(InternalValueMap* scope)
+ {
+ m_boundScope = scope;
+ }
+
+ bool IsEqual(const RenderContext& other) const
+ {
+ if (!IsEqual(m_rendererCallback, other.m_rendererCallback))
+ return false;
+ if (!IsEqual(this->m_currentScope, other.m_currentScope))
+ return false;
+ if (!IsEqual(m_externalScope, other.m_externalScope))
+ return false;
+ if (!IsEqual(m_globalScope, other.m_globalScope))
+ return false;
+ if (!IsEqual(m_boundScope, other.m_boundScope))
+ return false;
+ if (m_emptyScope != other.m_emptyScope)
+ return false;
+ if (m_scopes != other.m_scopes)
+ return false;
+ return true;
+ }
+
+private:
+
+ bool IsEqual(const IRendererCallback* lhs, const IRendererCallback* rhs) const
+ {
+ if (lhs && rhs)
+ return lhs->IsEqual(*rhs);
+ if ((!lhs && rhs) || (lhs && !rhs))
+ return false;
+ return true;
+ }
+
+ bool IsEqual(const InternalValueMap* lhs, const InternalValueMap* rhs) const
+ {
+ if (lhs && rhs)
+ return *lhs == *rhs;
+ if ((!lhs && rhs) || (lhs && !rhs))
+ return false;
+ return true;
+ }
+
+private:
+ IRendererCallback* m_rendererCallback{};
+ InternalValueMap* m_currentScope{};
+ const InternalValueMap* m_externalScope{};
+ const InternalValueMap* m_globalScope{};
+ const InternalValueMap* m_boundScope{};
+ InternalValueMap m_emptyScope;
+ std::deque<InternalValueMap> m_scopes;
+};
+} // namespace jinja2
+
+#endif // JINJA2CPP_SRC_RENDER_CONTEXT_H
diff --git a/contrib/libs/jinja2cpp/src/renderer.h b/contrib/libs/jinja2cpp/src/renderer.h
new file mode 100644
index 0000000000..9c08d2379b
--- /dev/null
+++ b/contrib/libs/jinja2cpp/src/renderer.h
@@ -0,0 +1,131 @@
+#ifndef JINJA2CPP_SRC_RENDERER_H
+#define JINJA2CPP_SRC_RENDERER_H
+
+#include "out_stream.h"
+#include "lexertk.h"
+#include "expression_evaluator.h"
+#include "render_context.h"
+#include "ast_visitor.h"
+
+#include <jinja2cpp/value.h>
+#include <jinja2cpp/utils/i_comparable.h>
+
+#include <iostream>
+#include <string>
+#include <vector>
+#include <memory>
+
+namespace jinja2
+{
+class IRendererBase : public virtual IComparable
+{
+public:
+ virtual ~IRendererBase() = default;
+ virtual void Render(OutStream& os, RenderContext& values) = 0;
+};
+
+class VisitableRendererBase : public IRendererBase, public VisitableStatement
+{
+};
+
+using RendererPtr = std::shared_ptr<IRendererBase>;
+
+inline bool operator==(const RendererPtr& lhs, const RendererPtr& rhs)
+{
+ if (lhs && rhs && !lhs->IsEqual(*rhs))
+ return false;
+ if ((lhs && !rhs) || (!lhs && rhs))
+ return false;
+ return true;
+}
+
+inline bool operator!=(const RendererPtr& lhs, const RendererPtr& rhs)
+{
+ return !(lhs == rhs);
+}
+
+class ComposedRenderer : public VisitableRendererBase
+{
+public:
+ VISITABLE_STATEMENT();
+
+ void AddRenderer(RendererPtr r)
+ {
+ m_renderers.push_back(std::move(r));
+ }
+ void Render(OutStream& os, RenderContext& values) override
+ {
+ for (auto& r : m_renderers)
+ r->Render(os, values);
+ }
+
+ bool IsEqual(const IComparable& other) const override
+ {
+ auto* val = dynamic_cast<const ComposedRenderer*>(&other);
+ if (!val)
+ return false;
+ return m_renderers == val->m_renderers;
+ }
+
+private:
+ std::vector<RendererPtr> m_renderers;
+};
+
+class RawTextRenderer : public VisitableRendererBase
+{
+public:
+ VISITABLE_STATEMENT();
+
+ RawTextRenderer(const void* ptr, size_t len)
+ : m_ptr(ptr)
+ , m_length(len)
+ {
+ }
+
+ void Render(OutStream& os, RenderContext&) override
+ {
+ os.WriteBuffer(m_ptr, m_length);
+ }
+
+ bool IsEqual(const IComparable& other) const override
+ {
+ auto* val = dynamic_cast<const RawTextRenderer*>(&other);
+ if (!val)
+ return false;
+ if (m_ptr != val->m_ptr)
+ return false;
+ return m_length == val->m_length;
+ }
+private:
+ const void* m_ptr{};
+ size_t m_length{};
+};
+
+class ExpressionRenderer : public VisitableRendererBase
+{
+public:
+ VISITABLE_STATEMENT();
+
+ explicit ExpressionRenderer(ExpressionEvaluatorPtr<> expr)
+ : m_expression(std::move(expr))
+ {
+ }
+
+ void Render(OutStream& os, RenderContext& values) override
+ {
+ m_expression->Render(os, values);
+ }
+
+ bool IsEqual(const IComparable& other) const override
+ {
+ auto* val = dynamic_cast<const ExpressionRenderer*>(&other);
+ if (!val)
+ return false;
+ return m_expression == val->m_expression;
+ }
+private:
+ ExpressionEvaluatorPtr<> m_expression;
+};
+} // namespace jinja2
+
+#endif // JINJA2CPP_SRC_RENDERER_H
diff --git a/contrib/libs/jinja2cpp/src/robin_hood.h b/contrib/libs/jinja2cpp/src/robin_hood.h
new file mode 100644
index 0000000000..b4e0fbc56a
--- /dev/null
+++ b/contrib/libs/jinja2cpp/src/robin_hood.h
@@ -0,0 +1,2544 @@
+// ______ _____ ______ _________
+// ______________ ___ /_ ___(_)_______ ___ /_ ______ ______ ______ /
+// __ ___/_ __ \__ __ \__ / __ __ \ __ __ \_ __ \_ __ \_ __ /
+// _ / / /_/ /_ /_/ /_ / _ / / / _ / / // /_/ // /_/ // /_/ /
+// /_/ \____/ /_.___/ /_/ /_/ /_/ ________/_/ /_/ \____/ \____/ \__,_/
+// _/_____/
+//
+// Fast & memory efficient hashtable based on robin hood hashing for C++11/14/17/20
+// https://github.com/martinus/robin-hood-hashing
+//
+// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
+// SPDX-License-Identifier: MIT
+// Copyright (c) 2018-2021 Martin Ankerl <http://martin.ankerl.com>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+#ifndef ROBIN_HOOD_H_INCLUDED
+#define ROBIN_HOOD_H_INCLUDED
+
+// see https://semver.org/
+#define ROBIN_HOOD_VERSION_MAJOR 3 // for incompatible API changes
+#define ROBIN_HOOD_VERSION_MINOR 11 // for adding functionality in a backwards-compatible manner
+#define ROBIN_HOOD_VERSION_PATCH 5 // for backwards-compatible bug fixes
+
+#include <algorithm>
+#include <cstdlib>
+#include <cstring>
+#include <functional>
+#include <limits>
+#include <memory> // only to support hash of smart pointers
+#include <stdexcept>
+#include <string>
+#include <type_traits>
+#include <utility>
+#if __cplusplus >= 201703L
+# include <string_view>
+#endif
+
+// #define ROBIN_HOOD_LOG_ENABLED
+#ifdef ROBIN_HOOD_LOG_ENABLED
+# include <iostream>
+# define ROBIN_HOOD_LOG(...) \
+ std::cout << __FUNCTION__ << "@" << __LINE__ << ": " << __VA_ARGS__ << std::endl;
+#else
+# define ROBIN_HOOD_LOG(x)
+#endif
+
+// #define ROBIN_HOOD_TRACE_ENABLED
+#ifdef ROBIN_HOOD_TRACE_ENABLED
+# include <iostream>
+# define ROBIN_HOOD_TRACE(...) \
+ std::cout << __FUNCTION__ << "@" << __LINE__ << ": " << __VA_ARGS__ << std::endl;
+#else
+# define ROBIN_HOOD_TRACE(x)
+#endif
+
+// #define ROBIN_HOOD_COUNT_ENABLED
+#ifdef ROBIN_HOOD_COUNT_ENABLED
+# include <iostream>
+# define ROBIN_HOOD_COUNT(x) ++counts().x;
+namespace robin_hood {
+struct Counts {
+ uint64_t shiftUp{};
+ uint64_t shiftDown{};
+};
+inline std::ostream& operator<<(std::ostream& os, Counts const& c) {
+ return os << c.shiftUp << " shiftUp" << std::endl << c.shiftDown << " shiftDown" << std::endl;
+}
+
+static Counts& counts() {
+ static Counts counts{};
+ return counts;
+}
+} // namespace robin_hood
+#else
+# define ROBIN_HOOD_COUNT(x)
+#endif
+
+// all non-argument macros should use this facility. See
+// https://www.fluentcpp.com/2019/05/28/better-macros-better-flags/
+#define ROBIN_HOOD(x) ROBIN_HOOD_PRIVATE_DEFINITION_##x()
+
+// mark unused members with this macro
+#define ROBIN_HOOD_UNUSED(identifier)
+
+// bitness
+#if SIZE_MAX == UINT32_MAX
+# define ROBIN_HOOD_PRIVATE_DEFINITION_BITNESS() 32
+#elif SIZE_MAX == UINT64_MAX
+# define ROBIN_HOOD_PRIVATE_DEFINITION_BITNESS() 64
+#else
+# error Unsupported bitness
+#endif
+
+// endianess
+#ifdef _MSC_VER
+# define ROBIN_HOOD_PRIVATE_DEFINITION_LITTLE_ENDIAN() 1
+# define ROBIN_HOOD_PRIVATE_DEFINITION_BIG_ENDIAN() 0
+#else
+# define ROBIN_HOOD_PRIVATE_DEFINITION_LITTLE_ENDIAN() \
+ (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
+# define ROBIN_HOOD_PRIVATE_DEFINITION_BIG_ENDIAN() (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
+#endif
+
+// inline
+#ifdef _MSC_VER
+# define ROBIN_HOOD_PRIVATE_DEFINITION_NOINLINE() __declspec(noinline)
+#else
+# define ROBIN_HOOD_PRIVATE_DEFINITION_NOINLINE() __attribute__((noinline))
+#endif
+
+// exceptions
+#if !defined(__cpp_exceptions) && !defined(__EXCEPTIONS) && !defined(_CPPUNWIND)
+# define ROBIN_HOOD_PRIVATE_DEFINITION_HAS_EXCEPTIONS() 0
+#else
+# define ROBIN_HOOD_PRIVATE_DEFINITION_HAS_EXCEPTIONS() 1
+#endif
+
+// count leading/trailing bits
+#if !defined(ROBIN_HOOD_DISABLE_INTRINSICS)
+# ifdef _MSC_VER
+# if ROBIN_HOOD(BITNESS) == 32
+# define ROBIN_HOOD_PRIVATE_DEFINITION_BITSCANFORWARD() _BitScanForward
+# else
+# define ROBIN_HOOD_PRIVATE_DEFINITION_BITSCANFORWARD() _BitScanForward64
+# endif
+# include <intrin.h>
+# pragma intrinsic(ROBIN_HOOD(BITSCANFORWARD))
+# define ROBIN_HOOD_COUNT_TRAILING_ZEROES(x) \
+ [](size_t mask) noexcept -> int { \
+ unsigned long index; \
+ return ROBIN_HOOD(BITSCANFORWARD)(&index, mask) ? static_cast<int>(index) \
+ : ROBIN_HOOD(BITNESS); \
+ }(x)
+# else
+# if ROBIN_HOOD(BITNESS) == 32
+# define ROBIN_HOOD_PRIVATE_DEFINITION_CTZ() __builtin_ctzl
+# define ROBIN_HOOD_PRIVATE_DEFINITION_CLZ() __builtin_clzl
+# else
+# define ROBIN_HOOD_PRIVATE_DEFINITION_CTZ() __builtin_ctzll
+# define ROBIN_HOOD_PRIVATE_DEFINITION_CLZ() __builtin_clzll
+# endif
+# define ROBIN_HOOD_COUNT_LEADING_ZEROES(x) ((x) ? ROBIN_HOOD(CLZ)(x) : ROBIN_HOOD(BITNESS))
+# define ROBIN_HOOD_COUNT_TRAILING_ZEROES(x) ((x) ? ROBIN_HOOD(CTZ)(x) : ROBIN_HOOD(BITNESS))
+# endif
+#endif
+
+// fallthrough
+#ifndef __has_cpp_attribute // For backwards compatibility
+# define __has_cpp_attribute(x) 0
+#endif
+#if __has_cpp_attribute(clang::fallthrough)
+# define ROBIN_HOOD_PRIVATE_DEFINITION_FALLTHROUGH() [[clang::fallthrough]]
+#elif __has_cpp_attribute(gnu::fallthrough)
+# define ROBIN_HOOD_PRIVATE_DEFINITION_FALLTHROUGH() [[gnu::fallthrough]]
+#else
+# define ROBIN_HOOD_PRIVATE_DEFINITION_FALLTHROUGH()
+#endif
+
+// likely/unlikely
+#ifdef _MSC_VER
+# define ROBIN_HOOD_LIKELY(condition) condition
+# define ROBIN_HOOD_UNLIKELY(condition) condition
+#else
+# define ROBIN_HOOD_LIKELY(condition) __builtin_expect(condition, 1)
+# define ROBIN_HOOD_UNLIKELY(condition) __builtin_expect(condition, 0)
+#endif
+
+// detect if native wchar_t type is availiable in MSVC
+#ifdef _MSC_VER
+# ifdef _NATIVE_WCHAR_T_DEFINED
+# define ROBIN_HOOD_PRIVATE_DEFINITION_HAS_NATIVE_WCHART() 1
+# else
+# define ROBIN_HOOD_PRIVATE_DEFINITION_HAS_NATIVE_WCHART() 0
+# endif
+#else
+# define ROBIN_HOOD_PRIVATE_DEFINITION_HAS_NATIVE_WCHART() 1
+#endif
+
+// detect if MSVC supports the pair(std::piecewise_construct_t,...) consructor being constexpr
+#ifdef _MSC_VER
+# if _MSC_VER <= 1900
+# define ROBIN_HOOD_PRIVATE_DEFINITION_BROKEN_CONSTEXPR() 1
+# else
+# define ROBIN_HOOD_PRIVATE_DEFINITION_BROKEN_CONSTEXPR() 0
+# endif
+#else
+# define ROBIN_HOOD_PRIVATE_DEFINITION_BROKEN_CONSTEXPR() 0
+#endif
+
+// workaround missing "is_trivially_copyable" in g++ < 5.0
+// See https://stackoverflow.com/a/31798726/48181
+#if defined(__GNUC__) && __GNUC__ < 5 && !defined(__clang__)
+# define ROBIN_HOOD_IS_TRIVIALLY_COPYABLE(...) __has_trivial_copy(__VA_ARGS__)
+#else
+# define ROBIN_HOOD_IS_TRIVIALLY_COPYABLE(...) std::is_trivially_copyable<__VA_ARGS__>::value
+#endif
+
+// helpers for C++ versions, see https://gcc.gnu.org/onlinedocs/cpp/Standard-Predefined-Macros.html
+#define ROBIN_HOOD_PRIVATE_DEFINITION_CXX() __cplusplus
+#define ROBIN_HOOD_PRIVATE_DEFINITION_CXX98() 199711L
+#define ROBIN_HOOD_PRIVATE_DEFINITION_CXX11() 201103L
+#define ROBIN_HOOD_PRIVATE_DEFINITION_CXX14() 201402L
+#define ROBIN_HOOD_PRIVATE_DEFINITION_CXX17() 201703L
+
+#if ROBIN_HOOD(CXX) >= ROBIN_HOOD(CXX17)
+# define ROBIN_HOOD_PRIVATE_DEFINITION_NODISCARD() [[nodiscard]]
+#else
+# define ROBIN_HOOD_PRIVATE_DEFINITION_NODISCARD()
+#endif
+
+namespace robin_hood {
+
+#if ROBIN_HOOD(CXX) >= ROBIN_HOOD(CXX14)
+# define ROBIN_HOOD_STD std
+#else
+
+// c++11 compatibility layer
+namespace ROBIN_HOOD_STD {
+template <class T>
+struct alignment_of
+ : std::integral_constant<std::size_t, alignof(typename std::remove_all_extents<T>::type)> {};
+
+template <class T, T... Ints>
+class integer_sequence {
+public:
+ using value_type = T;
+ static_assert(std::is_integral<value_type>::value, "not integral type");
+ static constexpr std::size_t size() noexcept {
+ return sizeof...(Ints);
+ }
+};
+template <std::size_t... Inds>
+using index_sequence = integer_sequence<std::size_t, Inds...>;
+
+namespace detail_ {
+template <class T, T Begin, T End, bool>
+struct IntSeqImpl {
+ using TValue = T;
+ static_assert(std::is_integral<TValue>::value, "not integral type");
+ static_assert(Begin >= 0 && Begin < End, "unexpected argument (Begin<0 || Begin<=End)");
+
+ template <class, class>
+ struct IntSeqCombiner;
+
+ template <TValue... Inds0, TValue... Inds1>
+ struct IntSeqCombiner<integer_sequence<TValue, Inds0...>, integer_sequence<TValue, Inds1...>> {
+ using TResult = integer_sequence<TValue, Inds0..., Inds1...>;
+ };
+
+ using TResult =
+ typename IntSeqCombiner<typename IntSeqImpl<TValue, Begin, Begin + (End - Begin) / 2,
+ (End - Begin) / 2 == 1>::TResult,
+ typename IntSeqImpl<TValue, Begin + (End - Begin) / 2, End,
+ (End - Begin + 1) / 2 == 1>::TResult>::TResult;
+};
+
+template <class T, T Begin>
+struct IntSeqImpl<T, Begin, Begin, false> {
+ using TValue = T;
+ static_assert(std::is_integral<TValue>::value, "not integral type");
+ static_assert(Begin >= 0, "unexpected argument (Begin<0)");
+ using TResult = integer_sequence<TValue>;
+};
+
+template <class T, T Begin, T End>
+struct IntSeqImpl<T, Begin, End, true> {
+ using TValue = T;
+ static_assert(std::is_integral<TValue>::value, "not integral type");
+ static_assert(Begin >= 0, "unexpected argument (Begin<0)");
+ using TResult = integer_sequence<TValue, Begin>;
+};
+} // namespace detail_
+
+template <class T, T N>
+using make_integer_sequence = typename detail_::IntSeqImpl<T, 0, N, (N - 0) == 1>::TResult;
+
+template <std::size_t N>
+using make_index_sequence = make_integer_sequence<std::size_t, N>;
+
+template <class... T>
+using index_sequence_for = make_index_sequence<sizeof...(T)>;
+
+} // namespace ROBIN_HOOD_STD
+
+#endif
+
+namespace detail {
+
+// make sure we static_cast to the correct type for hash_int
+#if ROBIN_HOOD(BITNESS) == 64
+using SizeT = uint64_t;
+#else
+using SizeT = uint32_t;
+#endif
+
+template <typename T>
+T rotr(T x, unsigned k) {
+ return (x >> k) | (x << (8U * sizeof(T) - k));
+}
+
+// This cast gets rid of warnings like "cast from 'uint8_t*' {aka 'unsigned char*'} to
+// 'uint64_t*' {aka 'long unsigned int*'} increases required alignment of target type". Use with
+// care!
+template <typename T>
+inline T reinterpret_cast_no_cast_align_warning(void* ptr) noexcept {
+ return reinterpret_cast<T>(ptr);
+}
+
+template <typename T>
+inline T reinterpret_cast_no_cast_align_warning(void const* ptr) noexcept {
+ return reinterpret_cast<T>(ptr);
+}
+
+// make sure this is not inlined as it is slow and dramatically enlarges code, thus making other
+// inlinings more difficult. Throws are also generally the slow path.
+template <typename E, typename... Args>
+[[noreturn]] ROBIN_HOOD(NOINLINE)
+#if ROBIN_HOOD(HAS_EXCEPTIONS)
+ void doThrow(Args&&... args) {
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
+ throw E(std::forward<Args>(args)...);
+}
+#else
+ void doThrow(Args&&... ROBIN_HOOD_UNUSED(args) /*unused*/) {
+ abort();
+}
+#endif
+
+template <typename E, typename T, typename... Args>
+T* assertNotNull(T* t, Args&&... args) {
+ if (ROBIN_HOOD_UNLIKELY(nullptr == t)) {
+ doThrow<E>(std::forward<Args>(args)...);
+ }
+ return t;
+}
+
+template <typename T>
+inline T unaligned_load(void const* ptr) noexcept {
+ // using memcpy so we don't get into unaligned load problems.
+ // compiler should optimize this very well anyways.
+ T t;
+ std::memcpy(&t, ptr, sizeof(T));
+ return t;
+}
+
+// Allocates bulks of memory for objects of type T. This deallocates the memory in the destructor,
+// and keeps a linked list of the allocated memory around. Overhead per allocation is the size of a
+// pointer.
+template <typename T, size_t MinNumAllocs = 4, size_t MaxNumAllocs = 256>
+class BulkPoolAllocator {
+public:
+ BulkPoolAllocator() noexcept = default;
+
+ // does not copy anything, just creates a new allocator.
+ BulkPoolAllocator(const BulkPoolAllocator& ROBIN_HOOD_UNUSED(o) /*unused*/) noexcept
+ : mHead(nullptr)
+ , mListForFree(nullptr) {}
+
+ BulkPoolAllocator(BulkPoolAllocator&& o) noexcept
+ : mHead(o.mHead)
+ , mListForFree(o.mListForFree) {
+ o.mListForFree = nullptr;
+ o.mHead = nullptr;
+ }
+
+ BulkPoolAllocator& operator=(BulkPoolAllocator&& o) noexcept {
+ reset();
+ mHead = o.mHead;
+ mListForFree = o.mListForFree;
+ o.mListForFree = nullptr;
+ o.mHead = nullptr;
+ return *this;
+ }
+
+ BulkPoolAllocator&
+ // NOLINTNEXTLINE(bugprone-unhandled-self-assignment,cert-oop54-cpp)
+ operator=(const BulkPoolAllocator& ROBIN_HOOD_UNUSED(o) /*unused*/) noexcept {
+ // does not do anything
+ return *this;
+ }
+
+ ~BulkPoolAllocator() noexcept {
+ reset();
+ }
+
+ // Deallocates all allocated memory.
+ void reset() noexcept {
+ while (mListForFree) {
+ T* tmp = *mListForFree;
+ ROBIN_HOOD_LOG("std::free")
+ std::free(mListForFree);
+ mListForFree = reinterpret_cast_no_cast_align_warning<T**>(tmp);
+ }
+ mHead = nullptr;
+ }
+
+ // allocates, but does NOT initialize. Use in-place new constructor, e.g.
+ // T* obj = pool.allocate();
+ // ::new (static_cast<void*>(obj)) T();
+ T* allocate() {
+ T* tmp = mHead;
+ if (!tmp) {
+ tmp = performAllocation();
+ }
+
+ mHead = *reinterpret_cast_no_cast_align_warning<T**>(tmp);
+ return tmp;
+ }
+
+ // does not actually deallocate but puts it in store.
+ // make sure you have already called the destructor! e.g. with
+ // obj->~T();
+ // pool.deallocate(obj);
+ void deallocate(T* obj) noexcept {
+ *reinterpret_cast_no_cast_align_warning<T**>(obj) = mHead;
+ mHead = obj;
+ }
+
+ // Adds an already allocated block of memory to the allocator. This allocator is from now on
+ // responsible for freeing the data (with free()). If the provided data is not large enough to
+ // make use of, it is immediately freed. Otherwise it is reused and freed in the destructor.
+ void addOrFree(void* ptr, const size_t numBytes) noexcept {
+ // calculate number of available elements in ptr
+ if (numBytes < ALIGNMENT + ALIGNED_SIZE) {
+ // not enough data for at least one element. Free and return.
+ ROBIN_HOOD_LOG("std::free")
+ std::free(ptr);
+ } else {
+ ROBIN_HOOD_LOG("add to buffer")
+ add(ptr, numBytes);
+ }
+ }
+
+ void swap(BulkPoolAllocator<T, MinNumAllocs, MaxNumAllocs>& other) noexcept {
+ using std::swap;
+ swap(mHead, other.mHead);
+ swap(mListForFree, other.mListForFree);
+ }
+
+private:
+ // iterates the list of allocated memory to calculate how many to alloc next.
+ // Recalculating this each time saves us a size_t member.
+ // This ignores the fact that memory blocks might have been added manually with addOrFree. In
+ // practice, this should not matter much.
+ ROBIN_HOOD(NODISCARD) size_t calcNumElementsToAlloc() const noexcept {
+ auto tmp = mListForFree;
+ size_t numAllocs = MinNumAllocs;
+
+ while (numAllocs * 2 <= MaxNumAllocs && tmp) {
+ auto x = reinterpret_cast<T***>(tmp);
+ tmp = *x;
+ numAllocs *= 2;
+ }
+
+ return numAllocs;
+ }
+
+ // WARNING: Underflow if numBytes < ALIGNMENT! This is guarded in addOrFree().
+ void add(void* ptr, const size_t numBytes) noexcept {
+ const size_t numElements = (numBytes - ALIGNMENT) / ALIGNED_SIZE;
+
+ auto data = reinterpret_cast<T**>(ptr);
+
+ // link free list
+ auto x = reinterpret_cast<T***>(data);
+ *x = mListForFree;
+ mListForFree = data;
+
+ // create linked list for newly allocated data
+ auto* const headT =
+ reinterpret_cast_no_cast_align_warning<T*>(reinterpret_cast<char*>(ptr) + ALIGNMENT);
+
+ auto* const head = reinterpret_cast<char*>(headT);
+
+ // Visual Studio compiler automatically unrolls this loop, which is pretty cool
+ for (size_t i = 0; i < numElements; ++i) {
+ *reinterpret_cast_no_cast_align_warning<char**>(head + i * ALIGNED_SIZE) =
+ head + (i + 1) * ALIGNED_SIZE;
+ }
+
+ // last one points to 0
+ *reinterpret_cast_no_cast_align_warning<T**>(head + (numElements - 1) * ALIGNED_SIZE) =
+ mHead;
+ mHead = headT;
+ }
+
+ // Called when no memory is available (mHead == 0).
+ // Don't inline this slow path.
+ ROBIN_HOOD(NOINLINE) T* performAllocation() {
+ size_t const numElementsToAlloc = calcNumElementsToAlloc();
+
+ // alloc new memory: [prev |T, T, ... T]
+ size_t const bytes = ALIGNMENT + ALIGNED_SIZE * numElementsToAlloc;
+ ROBIN_HOOD_LOG("std::malloc " << bytes << " = " << ALIGNMENT << " + " << ALIGNED_SIZE
+ << " * " << numElementsToAlloc)
+ add(assertNotNull<std::bad_alloc>(std::malloc(bytes)), bytes);
+ return mHead;
+ }
+
+ // enforce byte alignment of the T's
+#if ROBIN_HOOD(CXX) >= ROBIN_HOOD(CXX14)
+ static constexpr size_t ALIGNMENT =
+ (std::max)(std::alignment_of<T>::value, std::alignment_of<T*>::value);
+#else
+ static const size_t ALIGNMENT =
+ (ROBIN_HOOD_STD::alignment_of<T>::value > ROBIN_HOOD_STD::alignment_of<T*>::value)
+ ? ROBIN_HOOD_STD::alignment_of<T>::value
+ : +ROBIN_HOOD_STD::alignment_of<T*>::value; // the + is for walkarround
+#endif
+
+ static constexpr size_t ALIGNED_SIZE = ((sizeof(T) - 1) / ALIGNMENT + 1) * ALIGNMENT;
+
+ static_assert(MinNumAllocs >= 1, "MinNumAllocs");
+ static_assert(MaxNumAllocs >= MinNumAllocs, "MaxNumAllocs");
+ static_assert(ALIGNED_SIZE >= sizeof(T*), "ALIGNED_SIZE");
+ static_assert(0 == (ALIGNED_SIZE % sizeof(T*)), "ALIGNED_SIZE mod");
+ static_assert(ALIGNMENT >= sizeof(T*), "ALIGNMENT");
+
+ T* mHead{nullptr};
+ T** mListForFree{nullptr};
+};
+
+template <typename T, size_t MinSize, size_t MaxSize, bool IsFlat>
+struct NodeAllocator;
+
+// dummy allocator that does nothing
+template <typename T, size_t MinSize, size_t MaxSize>
+struct NodeAllocator<T, MinSize, MaxSize, true> {
+
+ // we are not using the data, so just free it.
+ void addOrFree(void* ptr, size_t ROBIN_HOOD_UNUSED(numBytes) /*unused*/) noexcept {
+ ROBIN_HOOD_LOG("std::free")
+ std::free(ptr);
+ }
+};
+
+template <typename T, size_t MinSize, size_t MaxSize>
+struct NodeAllocator<T, MinSize, MaxSize, false> : public BulkPoolAllocator<T, MinSize, MaxSize> {};
+
+// c++14 doesn't have is_nothrow_swappable, and clang++ 6.0.1 doesn't like it either, so I'm making
+// my own here.
+namespace swappable {
+#if ROBIN_HOOD(CXX) < ROBIN_HOOD(CXX17)
+using std::swap;
+template <typename T>
+struct nothrow {
+ static const bool value = noexcept(swap(std::declval<T&>(), std::declval<T&>()));
+};
+#else
+template <typename T>
+struct nothrow {
+ static const bool value = std::is_nothrow_swappable<T>::value;
+};
+#endif
+} // namespace swappable
+
+} // namespace detail
+
+struct is_transparent_tag {};
+
+// A custom pair implementation is used in the map because std::pair is not is_trivially_copyable,
+// which means it would not be allowed to be used in std::memcpy. This struct is copyable, which is
+// also tested.
+template <typename T1, typename T2>
+struct pair {
+ using first_type = T1;
+ using second_type = T2;
+
+ template <typename U1 = T1, typename U2 = T2,
+ typename = typename std::enable_if<std::is_default_constructible<U1>::value &&
+ std::is_default_constructible<U2>::value>::type>
+ constexpr pair() noexcept(noexcept(U1()) && noexcept(U2()))
+ : first()
+ , second() {}
+
+ // pair constructors are explicit so we don't accidentally call this ctor when we don't have to.
+ explicit constexpr pair(std::pair<T1, T2> const& o) noexcept(
+ noexcept(T1(std::declval<T1 const&>())) && noexcept(T2(std::declval<T2 const&>())))
+ : first(o.first)
+ , second(o.second) {}
+
+ // pair constructors are explicit so we don't accidentally call this ctor when we don't have to.
+ explicit constexpr pair(std::pair<T1, T2>&& o) noexcept(noexcept(
+ T1(std::move(std::declval<T1&&>()))) && noexcept(T2(std::move(std::declval<T2&&>()))))
+ : first(std::move(o.first))
+ , second(std::move(o.second)) {}
+
+ constexpr pair(T1&& a, T2&& b) noexcept(noexcept(
+ T1(std::move(std::declval<T1&&>()))) && noexcept(T2(std::move(std::declval<T2&&>()))))
+ : first(std::move(a))
+ , second(std::move(b)) {}
+
+ template <typename U1, typename U2>
+ constexpr pair(U1&& a, U2&& b) noexcept(noexcept(T1(std::forward<U1>(
+ std::declval<U1&&>()))) && noexcept(T2(std::forward<U2>(std::declval<U2&&>()))))
+ : first(std::forward<U1>(a))
+ , second(std::forward<U2>(b)) {}
+
+ template <typename... U1, typename... U2>
+ // MSVC 2015 produces error "C2476: ‘constexpr’ constructor does not initialize all members"
+ // if this constructor is constexpr
+#if !ROBIN_HOOD(BROKEN_CONSTEXPR)
+ constexpr
+#endif
+ pair(std::piecewise_construct_t /*unused*/, std::tuple<U1...> a,
+ std::tuple<U2...>
+ b) noexcept(noexcept(pair(std::declval<std::tuple<U1...>&>(),
+ std::declval<std::tuple<U2...>&>(),
+ ROBIN_HOOD_STD::index_sequence_for<U1...>(),
+ ROBIN_HOOD_STD::index_sequence_for<U2...>())))
+ : pair(a, b, ROBIN_HOOD_STD::index_sequence_for<U1...>(),
+ ROBIN_HOOD_STD::index_sequence_for<U2...>()) {
+ }
+
+ // constructor called from the std::piecewise_construct_t ctor
+ template <typename... U1, size_t... I1, typename... U2, size_t... I2>
+ pair(std::tuple<U1...>& a, std::tuple<U2...>& b, ROBIN_HOOD_STD::index_sequence<I1...> /*unused*/, ROBIN_HOOD_STD::index_sequence<I2...> /*unused*/) noexcept(
+ noexcept(T1(std::forward<U1>(std::get<I1>(
+ std::declval<std::tuple<
+ U1...>&>()))...)) && noexcept(T2(std::
+ forward<U2>(std::get<I2>(
+ std::declval<std::tuple<U2...>&>()))...)))
+ : first(std::forward<U1>(std::get<I1>(a))...)
+ , second(std::forward<U2>(std::get<I2>(b))...) {
+ // make visual studio compiler happy about warning about unused a & b.
+ // Visual studio's pair implementation disables warning 4100.
+ (void)a;
+ (void)b;
+ }
+
+ void swap(pair<T1, T2>& o) noexcept((detail::swappable::nothrow<T1>::value) &&
+ (detail::swappable::nothrow<T2>::value)) {
+ using std::swap;
+ swap(first, o.first);
+ swap(second, o.second);
+ }
+
+ T1 first; // NOLINT(misc-non-private-member-variables-in-classes)
+ T2 second; // NOLINT(misc-non-private-member-variables-in-classes)
+};
+
+template <typename A, typename B>
+inline void swap(pair<A, B>& a, pair<A, B>& b) noexcept(
+ noexcept(std::declval<pair<A, B>&>().swap(std::declval<pair<A, B>&>()))) {
+ a.swap(b);
+}
+
+template <typename A, typename B>
+inline constexpr bool operator==(pair<A, B> const& x, pair<A, B> const& y) {
+ return (x.first == y.first) && (x.second == y.second);
+}
+template <typename A, typename B>
+inline constexpr bool operator!=(pair<A, B> const& x, pair<A, B> const& y) {
+ return !(x == y);
+}
+template <typename A, typename B>
+inline constexpr bool operator<(pair<A, B> const& x, pair<A, B> const& y) noexcept(noexcept(
+ std::declval<A const&>() < std::declval<A const&>()) && noexcept(std::declval<B const&>() <
+ std::declval<B const&>())) {
+ return x.first < y.first || (!(y.first < x.first) && x.second < y.second);
+}
+template <typename A, typename B>
+inline constexpr bool operator>(pair<A, B> const& x, pair<A, B> const& y) {
+ return y < x;
+}
+template <typename A, typename B>
+inline constexpr bool operator<=(pair<A, B> const& x, pair<A, B> const& y) {
+ return !(x > y);
+}
+template <typename A, typename B>
+inline constexpr bool operator>=(pair<A, B> const& x, pair<A, B> const& y) {
+ return !(x < y);
+}
+
+inline size_t hash_bytes(void const* ptr, size_t len) noexcept {
+ static constexpr uint64_t m = UINT64_C(0xc6a4a7935bd1e995);
+ static constexpr uint64_t seed = UINT64_C(0xe17a1465);
+ static constexpr unsigned int r = 47;
+
+ auto const* const data64 = static_cast<uint64_t const*>(ptr);
+ uint64_t h = seed ^ (len * m);
+
+ size_t const n_blocks = len / 8;
+ for (size_t i = 0; i < n_blocks; ++i) {
+ auto k = detail::unaligned_load<uint64_t>(data64 + i);
+
+ k *= m;
+ k ^= k >> r;
+ k *= m;
+
+ h ^= k;
+ h *= m;
+ }
+
+ auto const* const data8 = reinterpret_cast<uint8_t const*>(data64 + n_blocks);
+ switch (len & 7U) {
+ case 7:
+ h ^= static_cast<uint64_t>(data8[6]) << 48U;
+ ROBIN_HOOD(FALLTHROUGH); // FALLTHROUGH
+ case 6:
+ h ^= static_cast<uint64_t>(data8[5]) << 40U;
+ ROBIN_HOOD(FALLTHROUGH); // FALLTHROUGH
+ case 5:
+ h ^= static_cast<uint64_t>(data8[4]) << 32U;
+ ROBIN_HOOD(FALLTHROUGH); // FALLTHROUGH
+ case 4:
+ h ^= static_cast<uint64_t>(data8[3]) << 24U;
+ ROBIN_HOOD(FALLTHROUGH); // FALLTHROUGH
+ case 3:
+ h ^= static_cast<uint64_t>(data8[2]) << 16U;
+ ROBIN_HOOD(FALLTHROUGH); // FALLTHROUGH
+ case 2:
+ h ^= static_cast<uint64_t>(data8[1]) << 8U;
+ ROBIN_HOOD(FALLTHROUGH); // FALLTHROUGH
+ case 1:
+ h ^= static_cast<uint64_t>(data8[0]);
+ h *= m;
+ ROBIN_HOOD(FALLTHROUGH); // FALLTHROUGH
+ default:
+ break;
+ }
+
+ h ^= h >> r;
+
+ // not doing the final step here, because this will be done by keyToIdx anyways
+ // h *= m;
+ // h ^= h >> r;
+ return static_cast<size_t>(h);
+}
+
+inline size_t hash_int(uint64_t x) noexcept {
+ // tried lots of different hashes, let's stick with murmurhash3. It's simple, fast, well tested,
+ // and doesn't need any special 128bit operations.
+ x ^= x >> 33U;
+ x *= UINT64_C(0xff51afd7ed558ccd);
+ x ^= x >> 33U;
+
+ // not doing the final step here, because this will be done by keyToIdx anyways
+ // x *= UINT64_C(0xc4ceb9fe1a85ec53);
+ // x ^= x >> 33U;
+ return static_cast<size_t>(x);
+}
+
+// A thin wrapper around std::hash, performing an additional simple mixing step of the result.
+template <typename T, typename Enable = void>
+struct hash : public std::hash<T> {
+ size_t operator()(T const& obj) const
+ noexcept(noexcept(std::declval<std::hash<T>>().operator()(std::declval<T const&>()))) {
+ // call base hash
+ auto result = std::hash<T>::operator()(obj);
+ // return mixed of that, to be save against identity has
+ return hash_int(static_cast<detail::SizeT>(result));
+ }
+};
+
+template <typename CharT>
+struct hash<std::basic_string<CharT>> {
+ size_t operator()(std::basic_string<CharT> const& str) const noexcept {
+ return hash_bytes(str.data(), sizeof(CharT) * str.size());
+ }
+};
+
+#if ROBIN_HOOD(CXX) >= ROBIN_HOOD(CXX17)
+template <typename CharT>
+struct hash<std::basic_string_view<CharT>> {
+ size_t operator()(std::basic_string_view<CharT> const& sv) const noexcept {
+ return hash_bytes(sv.data(), sizeof(CharT) * sv.size());
+ }
+};
+#endif
+
+template <class T>
+struct hash<T*> {
+ size_t operator()(T* ptr) const noexcept {
+ return hash_int(reinterpret_cast<detail::SizeT>(ptr));
+ }
+};
+
+template <class T>
+struct hash<std::unique_ptr<T>> {
+ size_t operator()(std::unique_ptr<T> const& ptr) const noexcept {
+ return hash_int(reinterpret_cast<detail::SizeT>(ptr.get()));
+ }
+};
+
+template <class T>
+struct hash<std::shared_ptr<T>> {
+ size_t operator()(std::shared_ptr<T> const& ptr) const noexcept {
+ return hash_int(reinterpret_cast<detail::SizeT>(ptr.get()));
+ }
+};
+
+template <typename Enum>
+struct hash<Enum, typename std::enable_if<std::is_enum<Enum>::value>::type> {
+ size_t operator()(Enum e) const noexcept {
+ using Underlying = typename std::underlying_type<Enum>::type;
+ return hash<Underlying>{}(static_cast<Underlying>(e));
+ }
+};
+
+#define ROBIN_HOOD_HASH_INT(T) \
+ template <> \
+ struct hash<T> { \
+ size_t operator()(T const& obj) const noexcept { \
+ return hash_int(static_cast<uint64_t>(obj)); \
+ } \
+ }
+
+#if defined(__GNUC__) && !defined(__clang__)
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wuseless-cast"
+#endif
+// see https://en.cppreference.com/w/cpp/utility/hash
+ROBIN_HOOD_HASH_INT(bool);
+ROBIN_HOOD_HASH_INT(char);
+ROBIN_HOOD_HASH_INT(signed char);
+ROBIN_HOOD_HASH_INT(unsigned char);
+ROBIN_HOOD_HASH_INT(char16_t);
+ROBIN_HOOD_HASH_INT(char32_t);
+#if ROBIN_HOOD(HAS_NATIVE_WCHART)
+ROBIN_HOOD_HASH_INT(wchar_t);
+#endif
+ROBIN_HOOD_HASH_INT(short);
+ROBIN_HOOD_HASH_INT(unsigned short);
+ROBIN_HOOD_HASH_INT(int);
+ROBIN_HOOD_HASH_INT(unsigned int);
+ROBIN_HOOD_HASH_INT(long);
+ROBIN_HOOD_HASH_INT(long long);
+ROBIN_HOOD_HASH_INT(unsigned long);
+ROBIN_HOOD_HASH_INT(unsigned long long);
+#if defined(__GNUC__) && !defined(__clang__)
+# pragma GCC diagnostic pop
+#endif
+namespace detail {
+
+template <typename T>
+struct void_type {
+ using type = void;
+};
+
+template <typename T, typename = void>
+struct has_is_transparent : public std::false_type {};
+
+template <typename T>
+struct has_is_transparent<T, typename void_type<typename T::is_transparent>::type>
+ : public std::true_type {};
+
+// using wrapper classes for hash and key_equal prevents the diamond problem when the same type
+// is used. see https://stackoverflow.com/a/28771920/48181
+template <typename T>
+struct WrapHash : public T {
+ WrapHash() = default;
+ explicit WrapHash(T const& o) noexcept(noexcept(T(std::declval<T const&>())))
+ : T(o) {}
+};
+
+template <typename T>
+struct WrapKeyEqual : public T {
+ WrapKeyEqual() = default;
+ explicit WrapKeyEqual(T const& o) noexcept(noexcept(T(std::declval<T const&>())))
+ : T(o) {}
+};
+
+// A highly optimized hashmap implementation, using the Robin Hood algorithm.
+//
+// In most cases, this map should be usable as a drop-in replacement for std::unordered_map, but
+// be about 2x faster in most cases and require much less allocations.
+//
+// This implementation uses the following memory layout:
+//
+// [Node, Node, ... Node | info, info, ... infoSentinel ]
+//
+// * Node: either a DataNode that directly has the std::pair<key, val> as member,
+// or a DataNode with a pointer to std::pair<key,val>. Which DataNode representation to use
+// depends on how fast the swap() operation is. Heuristically, this is automatically choosen
+// based on sizeof(). there are always 2^n Nodes.
+//
+// * info: Each Node in the map has a corresponding info byte, so there are 2^n info bytes.
+// Each byte is initialized to 0, meaning the corresponding Node is empty. Set to 1 means the
+// corresponding node contains data. Set to 2 means the corresponding Node is filled, but it
+// actually belongs to the previous position and was pushed out because that place is already
+// taken.
+//
+// * infoSentinel: Sentinel byte set to 1, so that iterator's ++ can stop at end() without the
+// need for a idx variable.
+//
+// According to STL, order of templates has effect on throughput. That's why I've moved the
+// boolean to the front.
+// https://www.reddit.com/r/cpp/comments/ahp6iu/compile_time_binary_size_reductions_and_cs_future/eeguck4/
+template <bool IsFlat, size_t MaxLoadFactor100, typename Key, typename T, typename Hash,
+ typename KeyEqual>
+class Table
+ : public WrapHash<Hash>,
+ public WrapKeyEqual<KeyEqual>,
+ detail::NodeAllocator<
+ typename std::conditional<
+ std::is_void<T>::value, Key,
+ robin_hood::pair<typename std::conditional<IsFlat, Key, Key const>::type, T>>::type,
+ 4, 16384, IsFlat> {
+public:
+ static constexpr bool is_flat = IsFlat;
+ static constexpr bool is_map = !std::is_void<T>::value;
+ static constexpr bool is_set = !is_map;
+ static constexpr bool is_transparent =
+ has_is_transparent<Hash>::value && has_is_transparent<KeyEqual>::value;
+
+ using key_type = Key;
+ using mapped_type = T;
+ using value_type = typename std::conditional<
+ is_set, Key,
+ robin_hood::pair<typename std::conditional<is_flat, Key, Key const>::type, T>>::type;
+ using size_type = size_t;
+ using hasher = Hash;
+ using key_equal = KeyEqual;
+ using Self = Table<IsFlat, MaxLoadFactor100, key_type, mapped_type, hasher, key_equal>;
+
+private:
+ static_assert(MaxLoadFactor100 > 10 && MaxLoadFactor100 < 100,
+ "MaxLoadFactor100 needs to be >10 && < 100");
+
+ using WHash = WrapHash<Hash>;
+ using WKeyEqual = WrapKeyEqual<KeyEqual>;
+
+ // configuration defaults
+
+ // make sure we have 8 elements, needed to quickly rehash mInfo
+ static constexpr size_t InitialNumElements = sizeof(uint64_t);
+ static constexpr uint32_t InitialInfoNumBits = 5;
+ static constexpr uint8_t InitialInfoInc = 1U << InitialInfoNumBits;
+ static constexpr size_t InfoMask = InitialInfoInc - 1U;
+ static constexpr uint8_t InitialInfoHashShift = 0;
+ using DataPool = detail::NodeAllocator<value_type, 4, 16384, IsFlat>;
+
+ // type needs to be wider than uint8_t.
+ using InfoType = uint32_t;
+
+ // DataNode ////////////////////////////////////////////////////////
+
+ // Primary template for the data node. We have special implementations for small and big
+ // objects. For large objects it is assumed that swap() is fairly slow, so we allocate these
+ // on the heap so swap merely swaps a pointer.
+ template <typename M, bool>
+ class DataNode {};
+
+ // Small: just allocate on the stack.
+ template <typename M>
+ class DataNode<M, true> final {
+ public:
+ template <typename... Args>
+ explicit DataNode(M& ROBIN_HOOD_UNUSED(map) /*unused*/, Args&&... args) noexcept(
+ noexcept(value_type(std::forward<Args>(args)...)))
+ : mData(std::forward<Args>(args)...) {}
+
+ DataNode(M& ROBIN_HOOD_UNUSED(map) /*unused*/, DataNode<M, true>&& n) noexcept(
+ std::is_nothrow_move_constructible<value_type>::value)
+ : mData(std::move(n.mData)) {}
+
+ // doesn't do anything
+ void destroy(M& ROBIN_HOOD_UNUSED(map) /*unused*/) noexcept {}
+ void destroyDoNotDeallocate() noexcept {}
+
+ value_type const* operator->() const noexcept {
+ return &mData;
+ }
+ value_type* operator->() noexcept {
+ return &mData;
+ }
+
+ const value_type& operator*() const noexcept {
+ return mData;
+ }
+
+ value_type& operator*() noexcept {
+ return mData;
+ }
+
+ template <typename VT = value_type>
+ ROBIN_HOOD(NODISCARD)
+ typename std::enable_if<is_map, typename VT::first_type&>::type getFirst() noexcept {
+ return mData.first;
+ }
+ template <typename VT = value_type>
+ ROBIN_HOOD(NODISCARD)
+ typename std::enable_if<is_set, VT&>::type getFirst() noexcept {
+ return mData;
+ }
+
+ template <typename VT = value_type>
+ ROBIN_HOOD(NODISCARD)
+ typename std::enable_if<is_map, typename VT::first_type const&>::type
+ getFirst() const noexcept {
+ return mData.first;
+ }
+ template <typename VT = value_type>
+ ROBIN_HOOD(NODISCARD)
+ typename std::enable_if<is_set, VT const&>::type getFirst() const noexcept {
+ return mData;
+ }
+
+ template <typename MT = mapped_type>
+ ROBIN_HOOD(NODISCARD)
+ typename std::enable_if<is_map, MT&>::type getSecond() noexcept {
+ return mData.second;
+ }
+
+ template <typename MT = mapped_type>
+ ROBIN_HOOD(NODISCARD)
+ typename std::enable_if<is_set, MT const&>::type getSecond() const noexcept {
+ return mData.second;
+ }
+
+ void swap(DataNode<M, true>& o) noexcept(
+ noexcept(std::declval<value_type>().swap(std::declval<value_type>()))) {
+ mData.swap(o.mData);
+ }
+
+ private:
+ value_type mData;
+ };
+
+ // big object: allocate on heap.
+ template <typename M>
+ class DataNode<M, false> {
+ public:
+ template <typename... Args>
+ explicit DataNode(M& map, Args&&... args)
+ : mData(map.allocate()) {
+ ::new (static_cast<void*>(mData)) value_type(std::forward<Args>(args)...);
+ }
+
+ DataNode(M& ROBIN_HOOD_UNUSED(map) /*unused*/, DataNode<M, false>&& n) noexcept
+ : mData(std::move(n.mData)) {}
+
+ void destroy(M& map) noexcept {
+ // don't deallocate, just put it into list of datapool.
+ mData->~value_type();
+ map.deallocate(mData);
+ }
+
+ void destroyDoNotDeallocate() noexcept {
+ mData->~value_type();
+ }
+
+ value_type const* operator->() const noexcept {
+ return mData;
+ }
+
+ value_type* operator->() noexcept {
+ return mData;
+ }
+
+ const value_type& operator*() const {
+ return *mData;
+ }
+
+ value_type& operator*() {
+ return *mData;
+ }
+
+ template <typename VT = value_type>
+ ROBIN_HOOD(NODISCARD)
+ typename std::enable_if<is_map, typename VT::first_type&>::type getFirst() noexcept {
+ return mData->first;
+ }
+ template <typename VT = value_type>
+ ROBIN_HOOD(NODISCARD)
+ typename std::enable_if<is_set, VT&>::type getFirst() noexcept {
+ return *mData;
+ }
+
+ template <typename VT = value_type>
+ ROBIN_HOOD(NODISCARD)
+ typename std::enable_if<is_map, typename VT::first_type const&>::type
+ getFirst() const noexcept {
+ return mData->first;
+ }
+ template <typename VT = value_type>
+ ROBIN_HOOD(NODISCARD)
+ typename std::enable_if<is_set, VT const&>::type getFirst() const noexcept {
+ return *mData;
+ }
+
+ template <typename MT = mapped_type>
+ ROBIN_HOOD(NODISCARD)
+ typename std::enable_if<is_map, MT&>::type getSecond() noexcept {
+ return mData->second;
+ }
+
+ template <typename MT = mapped_type>
+ ROBIN_HOOD(NODISCARD)
+ typename std::enable_if<is_map, MT const&>::type getSecond() const noexcept {
+ return mData->second;
+ }
+
+ void swap(DataNode<M, false>& o) noexcept {
+ using std::swap;
+ swap(mData, o.mData);
+ }
+
+ private:
+ value_type* mData;
+ };
+
+ using Node = DataNode<Self, IsFlat>;
+
+ // helpers for insertKeyPrepareEmptySpot: extract first entry (only const required)
+ ROBIN_HOOD(NODISCARD) key_type const& getFirstConst(Node const& n) const noexcept {
+ return n.getFirst();
+ }
+
+ // in case we have void mapped_type, we are not using a pair, thus we just route k through.
+ // No need to disable this because it's just not used if not applicable.
+ ROBIN_HOOD(NODISCARD) key_type const& getFirstConst(key_type const& k) const noexcept {
+ return k;
+ }
+
+ // in case we have non-void mapped_type, we have a standard robin_hood::pair
+ template <typename Q = mapped_type>
+ ROBIN_HOOD(NODISCARD)
+ typename std::enable_if<!std::is_void<Q>::value, key_type const&>::type
+ getFirstConst(value_type const& vt) const noexcept {
+ return vt.first;
+ }
+
+ // Cloner //////////////////////////////////////////////////////////
+
+ template <typename M, bool UseMemcpy>
+ struct Cloner;
+
+ // fast path: Just copy data, without allocating anything.
+ template <typename M>
+ struct Cloner<M, true> {
+ void operator()(M const& source, M& target) const {
+ auto const* const src = reinterpret_cast<char const*>(source.mKeyVals);
+ auto* tgt = reinterpret_cast<char*>(target.mKeyVals);
+ auto const numElementsWithBuffer = target.calcNumElementsWithBuffer(target.mMask + 1);
+ std::copy(src, src + target.calcNumBytesTotal(numElementsWithBuffer), tgt);
+ }
+ };
+
+ template <typename M>
+ struct Cloner<M, false> {
+ void operator()(M const& s, M& t) const {
+ auto const numElementsWithBuffer = t.calcNumElementsWithBuffer(t.mMask + 1);
+ std::copy(s.mInfo, s.mInfo + t.calcNumBytesInfo(numElementsWithBuffer), t.mInfo);
+
+ for (size_t i = 0; i < numElementsWithBuffer; ++i) {
+ if (t.mInfo[i]) {
+ ::new (static_cast<void*>(t.mKeyVals + i)) Node(t, *s.mKeyVals[i]);
+ }
+ }
+ }
+ };
+
+ // Destroyer ///////////////////////////////////////////////////////
+
+ template <typename M, bool IsFlatAndTrivial>
+ struct Destroyer {};
+
+ template <typename M>
+ struct Destroyer<M, true> {
+ void nodes(M& m) const noexcept {
+ m.mNumElements = 0;
+ }
+
+ void nodesDoNotDeallocate(M& m) const noexcept {
+ m.mNumElements = 0;
+ }
+ };
+
+ template <typename M>
+ struct Destroyer<M, false> {
+ void nodes(M& m) const noexcept {
+ m.mNumElements = 0;
+ // clear also resets mInfo to 0, that's sometimes not necessary.
+ auto const numElementsWithBuffer = m.calcNumElementsWithBuffer(m.mMask + 1);
+
+ for (size_t idx = 0; idx < numElementsWithBuffer; ++idx) {
+ if (0 != m.mInfo[idx]) {
+ Node& n = m.mKeyVals[idx];
+ n.destroy(m);
+ n.~Node();
+ }
+ }
+ }
+
+ void nodesDoNotDeallocate(M& m) const noexcept {
+ m.mNumElements = 0;
+ // clear also resets mInfo to 0, that's sometimes not necessary.
+ auto const numElementsWithBuffer = m.calcNumElementsWithBuffer(m.mMask + 1);
+ for (size_t idx = 0; idx < numElementsWithBuffer; ++idx) {
+ if (0 != m.mInfo[idx]) {
+ Node& n = m.mKeyVals[idx];
+ n.destroyDoNotDeallocate();
+ n.~Node();
+ }
+ }
+ }
+ };
+
+ // Iter ////////////////////////////////////////////////////////////
+
+ struct fast_forward_tag {};
+
+ // generic iterator for both const_iterator and iterator.
+ template <bool IsConst>
+ // NOLINTNEXTLINE(hicpp-special-member-functions,cppcoreguidelines-special-member-functions)
+ class Iter {
+ private:
+ using NodePtr = typename std::conditional<IsConst, Node const*, Node*>::type;
+
+ public:
+ using difference_type = std::ptrdiff_t;
+ using value_type = typename Self::value_type;
+ using reference = typename std::conditional<IsConst, value_type const&, value_type&>::type;
+ using pointer = typename std::conditional<IsConst, value_type const*, value_type*>::type;
+ using iterator_category = std::forward_iterator_tag;
+
+ // default constructed iterator can be compared to itself, but WON'T return true when
+ // compared to end().
+ Iter() = default;
+
+ // Rule of zero: nothing specified. The conversion constructor is only enabled for
+ // iterator to const_iterator, so it doesn't accidentally work as a copy ctor.
+
+ // Conversion constructor from iterator to const_iterator.
+ template <bool OtherIsConst,
+ typename = typename std::enable_if<IsConst && !OtherIsConst>::type>
+ // NOLINTNEXTLINE(hicpp-explicit-conversions)
+ Iter(Iter<OtherIsConst> const& other) noexcept
+ : mKeyVals(other.mKeyVals)
+ , mInfo(other.mInfo) {}
+
+ Iter(NodePtr valPtr, uint8_t const* infoPtr) noexcept
+ : mKeyVals(valPtr)
+ , mInfo(infoPtr) {}
+
+ Iter(NodePtr valPtr, uint8_t const* infoPtr,
+ fast_forward_tag ROBIN_HOOD_UNUSED(tag) /*unused*/) noexcept
+ : mKeyVals(valPtr)
+ , mInfo(infoPtr) {
+ fastForward();
+ }
+
+ template <bool OtherIsConst,
+ typename = typename std::enable_if<IsConst && !OtherIsConst>::type>
+ Iter& operator=(Iter<OtherIsConst> const& other) noexcept {
+ mKeyVals = other.mKeyVals;
+ mInfo = other.mInfo;
+ return *this;
+ }
+
+ // prefix increment. Undefined behavior if we are at end()!
+ Iter& operator++() noexcept {
+ mInfo++;
+ mKeyVals++;
+ fastForward();
+ return *this;
+ }
+
+ Iter operator++(int) noexcept {
+ Iter tmp = *this;
+ ++(*this);
+ return tmp;
+ }
+
+ reference operator*() const {
+ return **mKeyVals;
+ }
+
+ pointer operator->() const {
+ return &**mKeyVals;
+ }
+
+ template <bool O>
+ bool operator==(Iter<O> const& o) const noexcept {
+ return mKeyVals == o.mKeyVals;
+ }
+
+ template <bool O>
+ bool operator!=(Iter<O> const& o) const noexcept {
+ return mKeyVals != o.mKeyVals;
+ }
+
+ private:
+ // fast forward to the next non-free info byte
+ // I've tried a few variants that don't depend on intrinsics, but unfortunately they are
+ // quite a bit slower than this one. So I've reverted that change again. See map_benchmark.
+ void fastForward() noexcept {
+ size_t n = 0;
+ while (0U == (n = detail::unaligned_load<size_t>(mInfo))) {
+ mInfo += sizeof(size_t);
+ mKeyVals += sizeof(size_t);
+ }
+#if defined(ROBIN_HOOD_DISABLE_INTRINSICS)
+ // we know for certain that within the next 8 bytes we'll find a non-zero one.
+ if (ROBIN_HOOD_UNLIKELY(0U == detail::unaligned_load<uint32_t>(mInfo))) {
+ mInfo += 4;
+ mKeyVals += 4;
+ }
+ if (ROBIN_HOOD_UNLIKELY(0U == detail::unaligned_load<uint16_t>(mInfo))) {
+ mInfo += 2;
+ mKeyVals += 2;
+ }
+ if (ROBIN_HOOD_UNLIKELY(0U == *mInfo)) {
+ mInfo += 1;
+ mKeyVals += 1;
+ }
+#else
+# if ROBIN_HOOD(LITTLE_ENDIAN)
+ auto inc = ROBIN_HOOD_COUNT_TRAILING_ZEROES(n) / 8;
+# else
+ auto inc = ROBIN_HOOD_COUNT_LEADING_ZEROES(n) / 8;
+# endif
+ mInfo += inc;
+ mKeyVals += inc;
+#endif
+ }
+
+ friend class Table<IsFlat, MaxLoadFactor100, key_type, mapped_type, hasher, key_equal>;
+ NodePtr mKeyVals{nullptr};
+ uint8_t const* mInfo{nullptr};
+ };
+
+ ////////////////////////////////////////////////////////////////////
+
+ // highly performance relevant code.
+ // Lower bits are used for indexing into the array (2^n size)
+ // The upper 1-5 bits need to be a reasonable good hash, to save comparisons.
+ template <typename HashKey>
+ void keyToIdx(HashKey&& key, size_t* idx, InfoType* info) const {
+ // In addition to whatever hash is used, add another mul & shift so we get better hashing.
+ // This serves as a bad hash prevention, if the given data is
+ // badly mixed.
+ auto h = static_cast<uint64_t>(WHash::operator()(key));
+
+ h *= mHashMultiplier;
+ h ^= h >> 33U;
+
+ // the lower InitialInfoNumBits are reserved for info.
+ *info = mInfoInc + static_cast<InfoType>((h & InfoMask) >> mInfoHashShift);
+ *idx = (static_cast<size_t>(h) >> InitialInfoNumBits) & mMask;
+ }
+
+ // forwards the index by one, wrapping around at the end
+ void next(InfoType* info, size_t* idx) const noexcept {
+ *idx = *idx + 1;
+ *info += mInfoInc;
+ }
+
+ void nextWhileLess(InfoType* info, size_t* idx) const noexcept {
+ // unrolling this by hand did not bring any speedups.
+ while (*info < mInfo[*idx]) {
+ next(info, idx);
+ }
+ }
+
+ // Shift everything up by one element. Tries to move stuff around.
+ void
+ shiftUp(size_t startIdx,
+ size_t const insertion_idx) noexcept(std::is_nothrow_move_assignable<Node>::value) {
+ auto idx = startIdx;
+ ::new (static_cast<void*>(mKeyVals + idx)) Node(std::move(mKeyVals[idx - 1]));
+ while (--idx != insertion_idx) {
+ mKeyVals[idx] = std::move(mKeyVals[idx - 1]);
+ }
+
+ idx = startIdx;
+ while (idx != insertion_idx) {
+ ROBIN_HOOD_COUNT(shiftUp)
+ mInfo[idx] = static_cast<uint8_t>(mInfo[idx - 1] + mInfoInc);
+ if (ROBIN_HOOD_UNLIKELY(mInfo[idx] + mInfoInc > 0xFF)) {
+ mMaxNumElementsAllowed = 0;
+ }
+ --idx;
+ }
+ }
+
+ void shiftDown(size_t idx) noexcept(std::is_nothrow_move_assignable<Node>::value) {
+ // until we find one that is either empty or has zero offset.
+ // TODO(martinus) we don't need to move everything, just the last one for the same
+ // bucket.
+ mKeyVals[idx].destroy(*this);
+
+ // until we find one that is either empty or has zero offset.
+ while (mInfo[idx + 1] >= 2 * mInfoInc) {
+ ROBIN_HOOD_COUNT(shiftDown)
+ mInfo[idx] = static_cast<uint8_t>(mInfo[idx + 1] - mInfoInc);
+ mKeyVals[idx] = std::move(mKeyVals[idx + 1]);
+ ++idx;
+ }
+
+ mInfo[idx] = 0;
+ // don't destroy, we've moved it
+ // mKeyVals[idx].destroy(*this);
+ mKeyVals[idx].~Node();
+ }
+
+ // copy of find(), except that it returns iterator instead of const_iterator.
+ template <typename Other>
+ ROBIN_HOOD(NODISCARD)
+ size_t findIdx(Other const& key) const {
+ size_t idx{};
+ InfoType info{};
+ keyToIdx(key, &idx, &info);
+
+ do {
+ // unrolling this twice gives a bit of a speedup. More unrolling did not help.
+ if (info == mInfo[idx] &&
+ ROBIN_HOOD_LIKELY(WKeyEqual::operator()(key, mKeyVals[idx].getFirst()))) {
+ return idx;
+ }
+ next(&info, &idx);
+ if (info == mInfo[idx] &&
+ ROBIN_HOOD_LIKELY(WKeyEqual::operator()(key, mKeyVals[idx].getFirst()))) {
+ return idx;
+ }
+ next(&info, &idx);
+ } while (info <= mInfo[idx]);
+
+ // nothing found!
+ return mMask == 0 ? 0
+ : static_cast<size_t>(std::distance(
+ mKeyVals, reinterpret_cast_no_cast_align_warning<Node*>(mInfo)));
+ }
+
+ void cloneData(const Table& o) {
+ Cloner<Table, IsFlat && ROBIN_HOOD_IS_TRIVIALLY_COPYABLE(Node)>()(o, *this);
+ }
+
+ // inserts a keyval that is guaranteed to be new, e.g. when the hashmap is resized.
+ // @return True on success, false if something went wrong
+ void insert_move(Node&& keyval) {
+ // we don't retry, fail if overflowing
+ // don't need to check max num elements
+ if (0 == mMaxNumElementsAllowed && !try_increase_info()) {
+ throwOverflowError();
+ }
+
+ size_t idx{};
+ InfoType info{};
+ keyToIdx(keyval.getFirst(), &idx, &info);
+
+ // skip forward. Use <= because we are certain that the element is not there.
+ while (info <= mInfo[idx]) {
+ idx = idx + 1;
+ info += mInfoInc;
+ }
+
+ // key not found, so we are now exactly where we want to insert it.
+ auto const insertion_idx = idx;
+ auto const insertion_info = static_cast<uint8_t>(info);
+ if (ROBIN_HOOD_UNLIKELY(insertion_info + mInfoInc > 0xFF)) {
+ mMaxNumElementsAllowed = 0;
+ }
+
+ // find an empty spot
+ while (0 != mInfo[idx]) {
+ next(&info, &idx);
+ }
+
+ auto& l = mKeyVals[insertion_idx];
+ if (idx == insertion_idx) {
+ ::new (static_cast<void*>(&l)) Node(std::move(keyval));
+ } else {
+ shiftUp(idx, insertion_idx);
+ l = std::move(keyval);
+ }
+
+ // put at empty spot
+ mInfo[insertion_idx] = insertion_info;
+
+ ++mNumElements;
+ }
+
+public:
+ using iterator = Iter<false>;
+ using const_iterator = Iter<true>;
+
+ Table() noexcept(noexcept(Hash()) && noexcept(KeyEqual()))
+ : WHash()
+ , WKeyEqual() {
+ ROBIN_HOOD_TRACE(this)
+ }
+
+ // Creates an empty hash map. Nothing is allocated yet, this happens at the first insert.
+ // This tremendously speeds up ctor & dtor of a map that never receives an element. The
+ // penalty is payed at the first insert, and not before. Lookup of this empty map works
+ // because everybody points to DummyInfoByte::b. parameter bucket_count is dictated by the
+ // standard, but we can ignore it.
+ explicit Table(
+ size_t ROBIN_HOOD_UNUSED(bucket_count) /*unused*/, const Hash& h = Hash{},
+ const KeyEqual& equal = KeyEqual{}) noexcept(noexcept(Hash(h)) && noexcept(KeyEqual(equal)))
+ : WHash(h)
+ , WKeyEqual(equal) {
+ ROBIN_HOOD_TRACE(this)
+ }
+
+ template <typename Iter>
+ Table(Iter first, Iter last, size_t ROBIN_HOOD_UNUSED(bucket_count) /*unused*/ = 0,
+ const Hash& h = Hash{}, const KeyEqual& equal = KeyEqual{})
+ : WHash(h)
+ , WKeyEqual(equal) {
+ ROBIN_HOOD_TRACE(this)
+ insert(first, last);
+ }
+
+ Table(std::initializer_list<value_type> initlist,
+ size_t ROBIN_HOOD_UNUSED(bucket_count) /*unused*/ = 0, const Hash& h = Hash{},
+ const KeyEqual& equal = KeyEqual{})
+ : WHash(h)
+ , WKeyEqual(equal) {
+ ROBIN_HOOD_TRACE(this)
+ insert(initlist.begin(), initlist.end());
+ }
+
+ Table(Table&& o) noexcept
+ : WHash(std::move(static_cast<WHash&>(o)))
+ , WKeyEqual(std::move(static_cast<WKeyEqual&>(o)))
+ , DataPool(std::move(static_cast<DataPool&>(o))) {
+ ROBIN_HOOD_TRACE(this)
+ if (o.mMask) {
+ mHashMultiplier = std::move(o.mHashMultiplier);
+ mKeyVals = std::move(o.mKeyVals);
+ mInfo = std::move(o.mInfo);
+ mNumElements = std::move(o.mNumElements);
+ mMask = std::move(o.mMask);
+ mMaxNumElementsAllowed = std::move(o.mMaxNumElementsAllowed);
+ mInfoInc = std::move(o.mInfoInc);
+ mInfoHashShift = std::move(o.mInfoHashShift);
+ // set other's mask to 0 so its destructor won't do anything
+ o.init();
+ }
+ }
+
+ Table& operator=(Table&& o) noexcept {
+ ROBIN_HOOD_TRACE(this)
+ if (&o != this) {
+ if (o.mMask) {
+ // only move stuff if the other map actually has some data
+ destroy();
+ mHashMultiplier = std::move(o.mHashMultiplier);
+ mKeyVals = std::move(o.mKeyVals);
+ mInfo = std::move(o.mInfo);
+ mNumElements = std::move(o.mNumElements);
+ mMask = std::move(o.mMask);
+ mMaxNumElementsAllowed = std::move(o.mMaxNumElementsAllowed);
+ mInfoInc = std::move(o.mInfoInc);
+ mInfoHashShift = std::move(o.mInfoHashShift);
+ WHash::operator=(std::move(static_cast<WHash&>(o)));
+ WKeyEqual::operator=(std::move(static_cast<WKeyEqual&>(o)));
+ DataPool::operator=(std::move(static_cast<DataPool&>(o)));
+
+ o.init();
+
+ } else {
+ // nothing in the other map => just clear us.
+ clear();
+ }
+ }
+ return *this;
+ }
+
+ Table(const Table& o)
+ : WHash(static_cast<const WHash&>(o))
+ , WKeyEqual(static_cast<const WKeyEqual&>(o))
+ , DataPool(static_cast<const DataPool&>(o)) {
+ ROBIN_HOOD_TRACE(this)
+ if (!o.empty()) {
+ // not empty: create an exact copy. it is also possible to just iterate through all
+ // elements and insert them, but copying is probably faster.
+
+ auto const numElementsWithBuffer = calcNumElementsWithBuffer(o.mMask + 1);
+ auto const numBytesTotal = calcNumBytesTotal(numElementsWithBuffer);
+
+ ROBIN_HOOD_LOG("std::malloc " << numBytesTotal << " = calcNumBytesTotal("
+ << numElementsWithBuffer << ")")
+ mHashMultiplier = o.mHashMultiplier;
+ mKeyVals = static_cast<Node*>(
+ detail::assertNotNull<std::bad_alloc>(std::malloc(numBytesTotal)));
+ // no need for calloc because clonData does memcpy
+ mInfo = reinterpret_cast<uint8_t*>(mKeyVals + numElementsWithBuffer);
+ mNumElements = o.mNumElements;
+ mMask = o.mMask;
+ mMaxNumElementsAllowed = o.mMaxNumElementsAllowed;
+ mInfoInc = o.mInfoInc;
+ mInfoHashShift = o.mInfoHashShift;
+ cloneData(o);
+ }
+ }
+
+ // Creates a copy of the given map. Copy constructor of each entry is used.
+ // Not sure why clang-tidy thinks this doesn't handle self assignment, it does
+ // NOLINTNEXTLINE(bugprone-unhandled-self-assignment,cert-oop54-cpp)
+ Table& operator=(Table const& o) {
+ ROBIN_HOOD_TRACE(this)
+ if (&o == this) {
+ // prevent assigning of itself
+ return *this;
+ }
+
+ // we keep using the old allocator and not assign the new one, because we want to keep
+ // the memory available. when it is the same size.
+ if (o.empty()) {
+ if (0 == mMask) {
+ // nothing to do, we are empty too
+ return *this;
+ }
+
+ // not empty: destroy what we have there
+ // clear also resets mInfo to 0, that's sometimes not necessary.
+ destroy();
+ init();
+ WHash::operator=(static_cast<const WHash&>(o));
+ WKeyEqual::operator=(static_cast<const WKeyEqual&>(o));
+ DataPool::operator=(static_cast<DataPool const&>(o));
+
+ return *this;
+ }
+
+ // clean up old stuff
+ Destroyer<Self, IsFlat && std::is_trivially_destructible<Node>::value>{}.nodes(*this);
+
+ if (mMask != o.mMask) {
+ // no luck: we don't have the same array size allocated, so we need to realloc.
+ if (0 != mMask) {
+ // only deallocate if we actually have data!
+ ROBIN_HOOD_LOG("std::free")
+ std::free(mKeyVals);
+ }
+
+ auto const numElementsWithBuffer = calcNumElementsWithBuffer(o.mMask + 1);
+ auto const numBytesTotal = calcNumBytesTotal(numElementsWithBuffer);
+ ROBIN_HOOD_LOG("std::malloc " << numBytesTotal << " = calcNumBytesTotal("
+ << numElementsWithBuffer << ")")
+ mKeyVals = static_cast<Node*>(
+ detail::assertNotNull<std::bad_alloc>(std::malloc(numBytesTotal)));
+
+ // no need for calloc here because cloneData performs a memcpy.
+ mInfo = reinterpret_cast<uint8_t*>(mKeyVals + numElementsWithBuffer);
+ // sentinel is set in cloneData
+ }
+ WHash::operator=(static_cast<const WHash&>(o));
+ WKeyEqual::operator=(static_cast<const WKeyEqual&>(o));
+ DataPool::operator=(static_cast<DataPool const&>(o));
+ mHashMultiplier = o.mHashMultiplier;
+ mNumElements = o.mNumElements;
+ mMask = o.mMask;
+ mMaxNumElementsAllowed = o.mMaxNumElementsAllowed;
+ mInfoInc = o.mInfoInc;
+ mInfoHashShift = o.mInfoHashShift;
+ cloneData(o);
+
+ return *this;
+ }
+
+ // Swaps everything between the two maps.
+ void swap(Table& o) {
+ ROBIN_HOOD_TRACE(this)
+ using std::swap;
+ swap(o, *this);
+ }
+
+ // Clears all data, without resizing.
+ void clear() {
+ ROBIN_HOOD_TRACE(this)
+ if (empty()) {
+ // don't do anything! also important because we don't want to write to
+ // DummyInfoByte::b, even though we would just write 0 to it.
+ return;
+ }
+
+ Destroyer<Self, IsFlat && std::is_trivially_destructible<Node>::value>{}.nodes(*this);
+
+ auto const numElementsWithBuffer = calcNumElementsWithBuffer(mMask + 1);
+ // clear everything, then set the sentinel again
+ uint8_t const z = 0;
+ std::fill(mInfo, mInfo + calcNumBytesInfo(numElementsWithBuffer), z);
+ mInfo[numElementsWithBuffer] = 1;
+
+ mInfoInc = InitialInfoInc;
+ mInfoHashShift = InitialInfoHashShift;
+ }
+
+ // Destroys the map and all it's contents.
+ ~Table() {
+ ROBIN_HOOD_TRACE(this)
+ destroy();
+ }
+
+ // Checks if both tables contain the same entries. Order is irrelevant.
+ bool operator==(const Table& other) const {
+ ROBIN_HOOD_TRACE(this)
+ if (other.size() != size()) {
+ return false;
+ }
+ for (auto const& otherEntry : other) {
+ if (!has(otherEntry)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ bool operator!=(const Table& other) const {
+ ROBIN_HOOD_TRACE(this)
+ return !operator==(other);
+ }
+
+ template <typename Q = mapped_type>
+ typename std::enable_if<!std::is_void<Q>::value, Q&>::type operator[](const key_type& key) {
+ ROBIN_HOOD_TRACE(this)
+ auto idxAndState = insertKeyPrepareEmptySpot(key);
+ switch (idxAndState.second) {
+ case InsertionState::key_found:
+ break;
+
+ case InsertionState::new_node:
+ ::new (static_cast<void*>(&mKeyVals[idxAndState.first]))
+ Node(*this, std::piecewise_construct, std::forward_as_tuple(key),
+ std::forward_as_tuple());
+ break;
+
+ case InsertionState::overwrite_node:
+ mKeyVals[idxAndState.first] = Node(*this, std::piecewise_construct,
+ std::forward_as_tuple(key), std::forward_as_tuple());
+ break;
+
+ case InsertionState::overflow_error:
+ throwOverflowError();
+ }
+
+ return mKeyVals[idxAndState.first].getSecond();
+ }
+
+ template <typename Q = mapped_type>
+ typename std::enable_if<!std::is_void<Q>::value, Q&>::type operator[](key_type&& key) {
+ ROBIN_HOOD_TRACE(this)
+ auto idxAndState = insertKeyPrepareEmptySpot(key);
+ switch (idxAndState.second) {
+ case InsertionState::key_found:
+ break;
+
+ case InsertionState::new_node:
+ ::new (static_cast<void*>(&mKeyVals[idxAndState.first]))
+ Node(*this, std::piecewise_construct, std::forward_as_tuple(std::move(key)),
+ std::forward_as_tuple());
+ break;
+
+ case InsertionState::overwrite_node:
+ mKeyVals[idxAndState.first] =
+ Node(*this, std::piecewise_construct, std::forward_as_tuple(std::move(key)),
+ std::forward_as_tuple());
+ break;
+
+ case InsertionState::overflow_error:
+ throwOverflowError();
+ }
+
+ return mKeyVals[idxAndState.first].getSecond();
+ }
+
+ template <typename Iter>
+ void insert(Iter first, Iter last) {
+ for (; first != last; ++first) {
+ // value_type ctor needed because this might be called with std::pair's
+ insert(value_type(*first));
+ }
+ }
+
+ void insert(std::initializer_list<value_type> ilist) {
+ for (auto&& vt : ilist) {
+ insert(std::move(vt));
+ }
+ }
+
+ template <typename... Args>
+ std::pair<iterator, bool> emplace(Args&&... args) {
+ ROBIN_HOOD_TRACE(this)
+ Node n{*this, std::forward<Args>(args)...};
+ auto idxAndState = insertKeyPrepareEmptySpot(getFirstConst(n));
+ switch (idxAndState.second) {
+ case InsertionState::key_found:
+ n.destroy(*this);
+ break;
+
+ case InsertionState::new_node:
+ ::new (static_cast<void*>(&mKeyVals[idxAndState.first])) Node(*this, std::move(n));
+ break;
+
+ case InsertionState::overwrite_node:
+ mKeyVals[idxAndState.first] = std::move(n);
+ break;
+
+ case InsertionState::overflow_error:
+ n.destroy(*this);
+ throwOverflowError();
+ break;
+ }
+
+ return std::make_pair(iterator(mKeyVals + idxAndState.first, mInfo + idxAndState.first),
+ InsertionState::key_found != idxAndState.second);
+ }
+
+ template <typename... Args>
+ iterator emplace_hint(const_iterator position, Args&&... args) {
+ (void)position;
+ return emplace(std::forward<Args>(args)...).first;
+ }
+
+ template <typename... Args>
+ std::pair<iterator, bool> try_emplace(const key_type& key, Args&&... args) {
+ return try_emplace_impl(key, std::forward<Args>(args)...);
+ }
+
+ template <typename... Args>
+ std::pair<iterator, bool> try_emplace(key_type&& key, Args&&... args) {
+ return try_emplace_impl(std::move(key), std::forward<Args>(args)...);
+ }
+
+ template <typename... Args>
+ iterator try_emplace(const_iterator hint, const key_type& key, Args&&... args) {
+ (void)hint;
+ return try_emplace_impl(key, std::forward<Args>(args)...).first;
+ }
+
+ template <typename... Args>
+ iterator try_emplace(const_iterator hint, key_type&& key, Args&&... args) {
+ (void)hint;
+ return try_emplace_impl(std::move(key), std::forward<Args>(args)...).first;
+ }
+
+ template <typename Mapped>
+ std::pair<iterator, bool> insert_or_assign(const key_type& key, Mapped&& obj) {
+ return insertOrAssignImpl(key, std::forward<Mapped>(obj));
+ }
+
+ template <typename Mapped>
+ std::pair<iterator, bool> insert_or_assign(key_type&& key, Mapped&& obj) {
+ return insertOrAssignImpl(std::move(key), std::forward<Mapped>(obj));
+ }
+
+ template <typename Mapped>
+ iterator insert_or_assign(const_iterator hint, const key_type& key, Mapped&& obj) {
+ (void)hint;
+ return insertOrAssignImpl(key, std::forward<Mapped>(obj)).first;
+ }
+
+ template <typename Mapped>
+ iterator insert_or_assign(const_iterator hint, key_type&& key, Mapped&& obj) {
+ (void)hint;
+ return insertOrAssignImpl(std::move(key), std::forward<Mapped>(obj)).first;
+ }
+
+ std::pair<iterator, bool> insert(const value_type& keyval) {
+ ROBIN_HOOD_TRACE(this)
+ return emplace(keyval);
+ }
+
+ iterator insert(const_iterator hint, const value_type& keyval) {
+ (void)hint;
+ return emplace(keyval).first;
+ }
+
+ std::pair<iterator, bool> insert(value_type&& keyval) {
+ return emplace(std::move(keyval));
+ }
+
+ iterator insert(const_iterator hint, value_type&& keyval) {
+ (void)hint;
+ return emplace(std::move(keyval)).first;
+ }
+
+ // Returns 1 if key is found, 0 otherwise.
+ size_t count(const key_type& key) const { // NOLINT(modernize-use-nodiscard)
+ ROBIN_HOOD_TRACE(this)
+ auto kv = mKeyVals + findIdx(key);
+ if (kv != reinterpret_cast_no_cast_align_warning<Node*>(mInfo)) {
+ return 1;
+ }
+ return 0;
+ }
+
+ template <typename OtherKey, typename Self_ = Self>
+ // NOLINTNEXTLINE(modernize-use-nodiscard)
+ typename std::enable_if<Self_::is_transparent, size_t>::type count(const OtherKey& key) const {
+ ROBIN_HOOD_TRACE(this)
+ auto kv = mKeyVals + findIdx(key);
+ if (kv != reinterpret_cast_no_cast_align_warning<Node*>(mInfo)) {
+ return 1;
+ }
+ return 0;
+ }
+
+ bool contains(const key_type& key) const { // NOLINT(modernize-use-nodiscard)
+ return 1U == count(key);
+ }
+
+ template <typename OtherKey, typename Self_ = Self>
+ // NOLINTNEXTLINE(modernize-use-nodiscard)
+ typename std::enable_if<Self_::is_transparent, bool>::type contains(const OtherKey& key) const {
+ return 1U == count(key);
+ }
+
+ // Returns a reference to the value found for key.
+ // Throws std::out_of_range if element cannot be found
+ template <typename Q = mapped_type>
+ // NOLINTNEXTLINE(modernize-use-nodiscard)
+ typename std::enable_if<!std::is_void<Q>::value, Q&>::type at(key_type const& key) {
+ ROBIN_HOOD_TRACE(this)
+ auto kv = mKeyVals + findIdx(key);
+ if (kv == reinterpret_cast_no_cast_align_warning<Node*>(mInfo)) {
+ doThrow<std::out_of_range>("key not found");
+ }
+ return kv->getSecond();
+ }
+
+ // Returns a reference to the value found for key.
+ // Throws std::out_of_range if element cannot be found
+ template <typename Q = mapped_type>
+ // NOLINTNEXTLINE(modernize-use-nodiscard)
+ typename std::enable_if<!std::is_void<Q>::value, Q const&>::type at(key_type const& key) const {
+ ROBIN_HOOD_TRACE(this)
+ auto kv = mKeyVals + findIdx(key);
+ if (kv == reinterpret_cast_no_cast_align_warning<Node*>(mInfo)) {
+ doThrow<std::out_of_range>("key not found");
+ }
+ return kv->getSecond();
+ }
+
+ const_iterator find(const key_type& key) const { // NOLINT(modernize-use-nodiscard)
+ ROBIN_HOOD_TRACE(this)
+ const size_t idx = findIdx(key);
+ return const_iterator{mKeyVals + idx, mInfo + idx};
+ }
+
+ template <typename OtherKey>
+ const_iterator find(const OtherKey& key, is_transparent_tag /*unused*/) const {
+ ROBIN_HOOD_TRACE(this)
+ const size_t idx = findIdx(key);
+ return const_iterator{mKeyVals + idx, mInfo + idx};
+ }
+
+ template <typename OtherKey, typename Self_ = Self>
+ typename std::enable_if<Self_::is_transparent, // NOLINT(modernize-use-nodiscard)
+ const_iterator>::type // NOLINT(modernize-use-nodiscard)
+ find(const OtherKey& key) const { // NOLINT(modernize-use-nodiscard)
+ ROBIN_HOOD_TRACE(this)
+ const size_t idx = findIdx(key);
+ return const_iterator{mKeyVals + idx, mInfo + idx};
+ }
+
+ iterator find(const key_type& key) {
+ ROBIN_HOOD_TRACE(this)
+ const size_t idx = findIdx(key);
+ return iterator{mKeyVals + idx, mInfo + idx};
+ }
+
+ template <typename OtherKey>
+ iterator find(const OtherKey& key, is_transparent_tag /*unused*/) {
+ ROBIN_HOOD_TRACE(this)
+ const size_t idx = findIdx(key);
+ return iterator{mKeyVals + idx, mInfo + idx};
+ }
+
+ template <typename OtherKey, typename Self_ = Self>
+ typename std::enable_if<Self_::is_transparent, iterator>::type find(const OtherKey& key) {
+ ROBIN_HOOD_TRACE(this)
+ const size_t idx = findIdx(key);
+ return iterator{mKeyVals + idx, mInfo + idx};
+ }
+
+ iterator begin() {
+ ROBIN_HOOD_TRACE(this)
+ if (empty()) {
+ return end();
+ }
+ return iterator(mKeyVals, mInfo, fast_forward_tag{});
+ }
+ const_iterator begin() const { // NOLINT(modernize-use-nodiscard)
+ ROBIN_HOOD_TRACE(this)
+ return cbegin();
+ }
+ const_iterator cbegin() const { // NOLINT(modernize-use-nodiscard)
+ ROBIN_HOOD_TRACE(this)
+ if (empty()) {
+ return cend();
+ }
+ return const_iterator(mKeyVals, mInfo, fast_forward_tag{});
+ }
+
+ iterator end() {
+ ROBIN_HOOD_TRACE(this)
+ // no need to supply valid info pointer: end() must not be dereferenced, and only node
+ // pointer is compared.
+ return iterator{reinterpret_cast_no_cast_align_warning<Node*>(mInfo), nullptr};
+ }
+ const_iterator end() const { // NOLINT(modernize-use-nodiscard)
+ ROBIN_HOOD_TRACE(this)
+ return cend();
+ }
+ const_iterator cend() const { // NOLINT(modernize-use-nodiscard)
+ ROBIN_HOOD_TRACE(this)
+ return const_iterator{reinterpret_cast_no_cast_align_warning<Node*>(mInfo), nullptr};
+ }
+
+ iterator erase(const_iterator pos) {
+ ROBIN_HOOD_TRACE(this)
+ // its safe to perform const cast here
+ // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
+ return erase(iterator{const_cast<Node*>(pos.mKeyVals), const_cast<uint8_t*>(pos.mInfo)});
+ }
+
+ // Erases element at pos, returns iterator to the next element.
+ iterator erase(iterator pos) {
+ ROBIN_HOOD_TRACE(this)
+ // we assume that pos always points to a valid entry, and not end().
+ auto const idx = static_cast<size_t>(pos.mKeyVals - mKeyVals);
+
+ shiftDown(idx);
+ --mNumElements;
+
+ if (*pos.mInfo) {
+ // we've backward shifted, return this again
+ return pos;
+ }
+
+ // no backward shift, return next element
+ return ++pos;
+ }
+
+ size_t erase(const key_type& key) {
+ ROBIN_HOOD_TRACE(this)
+ size_t idx{};
+ InfoType info{};
+ keyToIdx(key, &idx, &info);
+
+ // check while info matches with the source idx
+ do {
+ if (info == mInfo[idx] && WKeyEqual::operator()(key, mKeyVals[idx].getFirst())) {
+ shiftDown(idx);
+ --mNumElements;
+ return 1;
+ }
+ next(&info, &idx);
+ } while (info <= mInfo[idx]);
+
+ // nothing found to delete
+ return 0;
+ }
+
+ // reserves space for the specified number of elements. Makes sure the old data fits.
+ // exactly the same as reserve(c).
+ void rehash(size_t c) {
+ // forces a reserve
+ reserve(c, true);
+ }
+
+ // reserves space for the specified number of elements. Makes sure the old data fits.
+ // Exactly the same as rehash(c). Use rehash(0) to shrink to fit.
+ void reserve(size_t c) {
+ // reserve, but don't force rehash
+ reserve(c, false);
+ }
+
+ // If possible reallocates the map to a smaller one. This frees the underlying table.
+ // Does not do anything if load_factor is too large for decreasing the table's size.
+ void compact() {
+ ROBIN_HOOD_TRACE(this)
+ auto newSize = InitialNumElements;
+ while (calcMaxNumElementsAllowed(newSize) < mNumElements && newSize != 0) {
+ newSize *= 2;
+ }
+ if (ROBIN_HOOD_UNLIKELY(newSize == 0)) {
+ throwOverflowError();
+ }
+
+ ROBIN_HOOD_LOG("newSize > mMask + 1: " << newSize << " > " << mMask << " + 1")
+
+ // only actually do anything when the new size is bigger than the old one. This prevents to
+ // continuously allocate for each reserve() call.
+ if (newSize < mMask + 1) {
+ rehashPowerOfTwo(newSize, true);
+ }
+ }
+
+ size_type size() const noexcept { // NOLINT(modernize-use-nodiscard)
+ ROBIN_HOOD_TRACE(this)
+ return mNumElements;
+ }
+
+ size_type max_size() const noexcept { // NOLINT(modernize-use-nodiscard)
+ ROBIN_HOOD_TRACE(this)
+ return static_cast<size_type>(-1);
+ }
+
+ ROBIN_HOOD(NODISCARD) bool empty() const noexcept {
+ ROBIN_HOOD_TRACE(this)
+ return 0 == mNumElements;
+ }
+
+ float max_load_factor() const noexcept { // NOLINT(modernize-use-nodiscard)
+ ROBIN_HOOD_TRACE(this)
+ return MaxLoadFactor100 / 100.0F;
+ }
+
+ // Average number of elements per bucket. Since we allow only 1 per bucket
+ float load_factor() const noexcept { // NOLINT(modernize-use-nodiscard)
+ ROBIN_HOOD_TRACE(this)
+ return static_cast<float>(size()) / static_cast<float>(mMask + 1);
+ }
+
+ ROBIN_HOOD(NODISCARD) size_t mask() const noexcept {
+ ROBIN_HOOD_TRACE(this)
+ return mMask;
+ }
+
+ ROBIN_HOOD(NODISCARD) size_t calcMaxNumElementsAllowed(size_t maxElements) const noexcept {
+ if (ROBIN_HOOD_LIKELY(maxElements <= (std::numeric_limits<size_t>::max)() / 100)) {
+ return maxElements * MaxLoadFactor100 / 100;
+ }
+
+ // we might be a bit inprecise, but since maxElements is quite large that doesn't matter
+ return (maxElements / 100) * MaxLoadFactor100;
+ }
+
+ ROBIN_HOOD(NODISCARD) size_t calcNumBytesInfo(size_t numElements) const noexcept {
+ // we add a uint64_t, which houses the sentinel (first byte) and padding so we can load
+ // 64bit types.
+ return numElements + sizeof(uint64_t);
+ }
+
+ ROBIN_HOOD(NODISCARD)
+ size_t calcNumElementsWithBuffer(size_t numElements) const noexcept {
+ auto maxNumElementsAllowed = calcMaxNumElementsAllowed(numElements);
+ return numElements + (std::min)(maxNumElementsAllowed, (static_cast<size_t>(0xFF)));
+ }
+
+ // calculation only allowed for 2^n values
+ ROBIN_HOOD(NODISCARD) size_t calcNumBytesTotal(size_t numElements) const {
+#if ROBIN_HOOD(BITNESS) == 64
+ return numElements * sizeof(Node) + calcNumBytesInfo(numElements);
+#else
+ // make sure we're doing 64bit operations, so we are at least safe against 32bit overflows.
+ auto const ne = static_cast<uint64_t>(numElements);
+ auto const s = static_cast<uint64_t>(sizeof(Node));
+ auto const infos = static_cast<uint64_t>(calcNumBytesInfo(numElements));
+
+ auto const total64 = ne * s + infos;
+ auto const total = static_cast<size_t>(total64);
+
+ if (ROBIN_HOOD_UNLIKELY(static_cast<uint64_t>(total) != total64)) {
+ throwOverflowError();
+ }
+ return total;
+#endif
+ }
+
+private:
+ template <typename Q = mapped_type>
+ ROBIN_HOOD(NODISCARD)
+ typename std::enable_if<!std::is_void<Q>::value, bool>::type has(const value_type& e) const {
+ ROBIN_HOOD_TRACE(this)
+ auto it = find(e.first);
+ return it != end() && it->second == e.second;
+ }
+
+ template <typename Q = mapped_type>
+ ROBIN_HOOD(NODISCARD)
+ typename std::enable_if<std::is_void<Q>::value, bool>::type has(const value_type& e) const {
+ ROBIN_HOOD_TRACE(this)
+ return find(e) != end();
+ }
+
+ void reserve(size_t c, bool forceRehash) {
+ ROBIN_HOOD_TRACE(this)
+ auto const minElementsAllowed = (std::max)(c, mNumElements);
+ auto newSize = InitialNumElements;
+ while (calcMaxNumElementsAllowed(newSize) < minElementsAllowed && newSize != 0) {
+ newSize *= 2;
+ }
+ if (ROBIN_HOOD_UNLIKELY(newSize == 0)) {
+ throwOverflowError();
+ }
+
+ ROBIN_HOOD_LOG("newSize > mMask + 1: " << newSize << " > " << mMask << " + 1")
+
+ // only actually do anything when the new size is bigger than the old one. This prevents to
+ // continuously allocate for each reserve() call.
+ if (forceRehash || newSize > mMask + 1) {
+ rehashPowerOfTwo(newSize, false);
+ }
+ }
+
+ // reserves space for at least the specified number of elements.
+ // only works if numBuckets if power of two
+ // True on success, false otherwise
+ void rehashPowerOfTwo(size_t numBuckets, bool forceFree) {
+ ROBIN_HOOD_TRACE(this)
+
+ Node* const oldKeyVals = mKeyVals;
+ uint8_t const* const oldInfo = mInfo;
+
+ const size_t oldMaxElementsWithBuffer = calcNumElementsWithBuffer(mMask + 1);
+
+ // resize operation: move stuff
+ initData(numBuckets);
+ if (oldMaxElementsWithBuffer > 1) {
+ for (size_t i = 0; i < oldMaxElementsWithBuffer; ++i) {
+ if (oldInfo[i] != 0) {
+ // might throw an exception, which is really bad since we are in the middle of
+ // moving stuff.
+ insert_move(std::move(oldKeyVals[i]));
+ // destroy the node but DON'T destroy the data.
+ oldKeyVals[i].~Node();
+ }
+ }
+
+ // this check is not necessary as it's guarded by the previous if, but it helps
+ // silence g++'s overeager "attempt to free a non-heap object 'map'
+ // [-Werror=free-nonheap-object]" warning.
+ if (oldKeyVals != reinterpret_cast_no_cast_align_warning<Node*>(&mMask)) {
+ // don't destroy old data: put it into the pool instead
+ if (forceFree) {
+ std::free(oldKeyVals);
+ } else {
+ DataPool::addOrFree(oldKeyVals, calcNumBytesTotal(oldMaxElementsWithBuffer));
+ }
+ }
+ }
+ }
+
+ ROBIN_HOOD(NOINLINE) void throwOverflowError() const {
+#if ROBIN_HOOD(HAS_EXCEPTIONS)
+ throw std::overflow_error("robin_hood::map overflow");
+#else
+ abort();
+#endif
+ }
+
+ template <typename OtherKey, typename... Args>
+ std::pair<iterator, bool> try_emplace_impl(OtherKey&& key, Args&&... args) {
+ ROBIN_HOOD_TRACE(this)
+ auto idxAndState = insertKeyPrepareEmptySpot(key);
+ switch (idxAndState.second) {
+ case InsertionState::key_found:
+ break;
+
+ case InsertionState::new_node:
+ ::new (static_cast<void*>(&mKeyVals[idxAndState.first])) Node(
+ *this, std::piecewise_construct, std::forward_as_tuple(std::forward<OtherKey>(key)),
+ std::forward_as_tuple(std::forward<Args>(args)...));
+ break;
+
+ case InsertionState::overwrite_node:
+ mKeyVals[idxAndState.first] = Node(*this, std::piecewise_construct,
+ std::forward_as_tuple(std::forward<OtherKey>(key)),
+ std::forward_as_tuple(std::forward<Args>(args)...));
+ break;
+
+ case InsertionState::overflow_error:
+ throwOverflowError();
+ break;
+ }
+
+ return std::make_pair(iterator(mKeyVals + idxAndState.first, mInfo + idxAndState.first),
+ InsertionState::key_found != idxAndState.second);
+ }
+
+ template <typename OtherKey, typename Mapped>
+ std::pair<iterator, bool> insertOrAssignImpl(OtherKey&& key, Mapped&& obj) {
+ ROBIN_HOOD_TRACE(this)
+ auto idxAndState = insertKeyPrepareEmptySpot(key);
+ switch (idxAndState.second) {
+ case InsertionState::key_found:
+ mKeyVals[idxAndState.first].getSecond() = std::forward<Mapped>(obj);
+ break;
+
+ case InsertionState::new_node:
+ ::new (static_cast<void*>(&mKeyVals[idxAndState.first])) Node(
+ *this, std::piecewise_construct, std::forward_as_tuple(std::forward<OtherKey>(key)),
+ std::forward_as_tuple(std::forward<Mapped>(obj)));
+ break;
+
+ case InsertionState::overwrite_node:
+ mKeyVals[idxAndState.first] = Node(*this, std::piecewise_construct,
+ std::forward_as_tuple(std::forward<OtherKey>(key)),
+ std::forward_as_tuple(std::forward<Mapped>(obj)));
+ break;
+
+ case InsertionState::overflow_error:
+ throwOverflowError();
+ break;
+ }
+
+ return std::make_pair(iterator(mKeyVals + idxAndState.first, mInfo + idxAndState.first),
+ InsertionState::key_found != idxAndState.second);
+ }
+
+ void initData(size_t max_elements) {
+ mNumElements = 0;
+ mMask = max_elements - 1;
+ mMaxNumElementsAllowed = calcMaxNumElementsAllowed(max_elements);
+
+ auto const numElementsWithBuffer = calcNumElementsWithBuffer(max_elements);
+
+ // malloc & zero mInfo. Faster than calloc everything.
+ auto const numBytesTotal = calcNumBytesTotal(numElementsWithBuffer);
+ ROBIN_HOOD_LOG("std::calloc " << numBytesTotal << " = calcNumBytesTotal("
+ << numElementsWithBuffer << ")")
+ mKeyVals = reinterpret_cast<Node*>(
+ detail::assertNotNull<std::bad_alloc>(std::malloc(numBytesTotal)));
+ mInfo = reinterpret_cast<uint8_t*>(mKeyVals + numElementsWithBuffer);
+ std::memset(mInfo, 0, numBytesTotal - numElementsWithBuffer * sizeof(Node));
+
+ // set sentinel
+ mInfo[numElementsWithBuffer] = 1;
+
+ mInfoInc = InitialInfoInc;
+ mInfoHashShift = InitialInfoHashShift;
+ }
+
+ enum class InsertionState { overflow_error, key_found, new_node, overwrite_node };
+
+ // Finds key, and if not already present prepares a spot where to pot the key & value.
+ // This potentially shifts nodes out of the way, updates mInfo and number of inserted
+ // elements, so the only operation left to do is create/assign a new node at that spot.
+ template <typename OtherKey>
+ std::pair<size_t, InsertionState> insertKeyPrepareEmptySpot(OtherKey&& key) {
+ for (int i = 0; i < 256; ++i) {
+ size_t idx{};
+ InfoType info{};
+ keyToIdx(key, &idx, &info);
+ nextWhileLess(&info, &idx);
+
+ // while we potentially have a match
+ while (info == mInfo[idx]) {
+ if (WKeyEqual::operator()(key, mKeyVals[idx].getFirst())) {
+ // key already exists, do NOT insert.
+ // see http://en.cppreference.com/w/cpp/container/unordered_map/insert
+ return std::make_pair(idx, InsertionState::key_found);
+ }
+ next(&info, &idx);
+ }
+
+ // unlikely that this evaluates to true
+ if (ROBIN_HOOD_UNLIKELY(mNumElements >= mMaxNumElementsAllowed)) {
+ if (!increase_size()) {
+ return std::make_pair(size_t(0), InsertionState::overflow_error);
+ }
+ continue;
+ }
+
+ // key not found, so we are now exactly where we want to insert it.
+ auto const insertion_idx = idx;
+ auto const insertion_info = info;
+ if (ROBIN_HOOD_UNLIKELY(insertion_info + mInfoInc > 0xFF)) {
+ mMaxNumElementsAllowed = 0;
+ }
+
+ // find an empty spot
+ while (0 != mInfo[idx]) {
+ next(&info, &idx);
+ }
+
+ if (idx != insertion_idx) {
+ shiftUp(idx, insertion_idx);
+ }
+ // put at empty spot
+ mInfo[insertion_idx] = static_cast<uint8_t>(insertion_info);
+ ++mNumElements;
+ return std::make_pair(insertion_idx, idx == insertion_idx
+ ? InsertionState::new_node
+ : InsertionState::overwrite_node);
+ }
+
+ // enough attempts failed, so finally give up.
+ return std::make_pair(size_t(0), InsertionState::overflow_error);
+ }
+
+ bool try_increase_info() {
+ ROBIN_HOOD_LOG("mInfoInc=" << mInfoInc << ", numElements=" << mNumElements
+ << ", maxNumElementsAllowed="
+ << calcMaxNumElementsAllowed(mMask + 1))
+ if (mInfoInc <= 2) {
+ // need to be > 2 so that shift works (otherwise undefined behavior!)
+ return false;
+ }
+ // we got space left, try to make info smaller
+ mInfoInc = static_cast<uint8_t>(mInfoInc >> 1U);
+
+ // remove one bit of the hash, leaving more space for the distance info.
+ // This is extremely fast because we can operate on 8 bytes at once.
+ ++mInfoHashShift;
+ auto const numElementsWithBuffer = calcNumElementsWithBuffer(mMask + 1);
+
+ for (size_t i = 0; i < numElementsWithBuffer; i += 8) {
+ auto val = unaligned_load<uint64_t>(mInfo + i);
+ val = (val >> 1U) & UINT64_C(0x7f7f7f7f7f7f7f7f);
+ std::memcpy(mInfo + i, &val, sizeof(val));
+ }
+ // update sentinel, which might have been cleared out!
+ mInfo[numElementsWithBuffer] = 1;
+
+ mMaxNumElementsAllowed = calcMaxNumElementsAllowed(mMask + 1);
+ return true;
+ }
+
+ // True if resize was possible, false otherwise
+ bool increase_size() {
+ // nothing allocated yet? just allocate InitialNumElements
+ if (0 == mMask) {
+ initData(InitialNumElements);
+ return true;
+ }
+
+ auto const maxNumElementsAllowed = calcMaxNumElementsAllowed(mMask + 1);
+ if (mNumElements < maxNumElementsAllowed && try_increase_info()) {
+ return true;
+ }
+
+ ROBIN_HOOD_LOG("mNumElements=" << mNumElements << ", maxNumElementsAllowed="
+ << maxNumElementsAllowed << ", load="
+ << (static_cast<double>(mNumElements) * 100.0 /
+ (static_cast<double>(mMask) + 1)))
+
+ if (mNumElements * 2 < calcMaxNumElementsAllowed(mMask + 1)) {
+ // we have to resize, even though there would still be plenty of space left!
+ // Try to rehash instead. Delete freed memory so we don't steadyily increase mem in case
+ // we have to rehash a few times
+ nextHashMultiplier();
+ rehashPowerOfTwo(mMask + 1, true);
+ } else {
+ // we've reached the capacity of the map, so the hash seems to work nice. Keep using it.
+ rehashPowerOfTwo((mMask + 1) * 2, false);
+ }
+ return true;
+ }
+
+ void nextHashMultiplier() {
+ // adding an *even* number, so that the multiplier will always stay odd. This is necessary
+ // so that the hash stays a mixing function (and thus doesn't have any information loss).
+ mHashMultiplier += UINT64_C(0xc4ceb9fe1a85ec54);
+ }
+
+ void destroy() {
+ if (0 == mMask) {
+ // don't deallocate!
+ return;
+ }
+
+ Destroyer<Self, IsFlat && std::is_trivially_destructible<Node>::value>{}
+ .nodesDoNotDeallocate(*this);
+
+ // This protection against not deleting mMask shouldn't be needed as it's sufficiently
+ // protected with the 0==mMask check, but I have this anyways because g++ 7 otherwise
+ // reports a compile error: attempt to free a non-heap object 'fm'
+ // [-Werror=free-nonheap-object]
+ if (mKeyVals != reinterpret_cast_no_cast_align_warning<Node*>(&mMask)) {
+ ROBIN_HOOD_LOG("std::free")
+ std::free(mKeyVals);
+ }
+ }
+
+ void init() noexcept {
+ mKeyVals = reinterpret_cast_no_cast_align_warning<Node*>(&mMask);
+ mInfo = reinterpret_cast<uint8_t*>(&mMask);
+ mNumElements = 0;
+ mMask = 0;
+ mMaxNumElementsAllowed = 0;
+ mInfoInc = InitialInfoInc;
+ mInfoHashShift = InitialInfoHashShift;
+ }
+
+ // members are sorted so no padding occurs
+ uint64_t mHashMultiplier = UINT64_C(0xc4ceb9fe1a85ec53); // 8 byte 8
+ Node* mKeyVals = reinterpret_cast_no_cast_align_warning<Node*>(&mMask); // 8 byte 16
+ uint8_t* mInfo = reinterpret_cast<uint8_t*>(&mMask); // 8 byte 24
+ size_t mNumElements = 0; // 8 byte 32
+ size_t mMask = 0; // 8 byte 40
+ size_t mMaxNumElementsAllowed = 0; // 8 byte 48
+ InfoType mInfoInc = InitialInfoInc; // 4 byte 52
+ InfoType mInfoHashShift = InitialInfoHashShift; // 4 byte 56
+ // 16 byte 56 if NodeAllocator
+};
+
+} // namespace detail
+
+// map
+
+template <typename Key, typename T, typename Hash = hash<Key>,
+ typename KeyEqual = std::equal_to<Key>, size_t MaxLoadFactor100 = 80>
+using unordered_flat_map = detail::Table<true, MaxLoadFactor100, Key, T, Hash, KeyEqual>;
+
+template <typename Key, typename T, typename Hash = hash<Key>,
+ typename KeyEqual = std::equal_to<Key>, size_t MaxLoadFactor100 = 80>
+using unordered_node_map = detail::Table<false, MaxLoadFactor100, Key, T, Hash, KeyEqual>;
+
+template <typename Key, typename T, typename Hash = hash<Key>,
+ typename KeyEqual = std::equal_to<Key>, size_t MaxLoadFactor100 = 80>
+using unordered_map =
+ detail::Table<sizeof(robin_hood::pair<Key, T>) <= sizeof(size_t) * 6 &&
+ std::is_nothrow_move_constructible<robin_hood::pair<Key, T>>::value &&
+ std::is_nothrow_move_assignable<robin_hood::pair<Key, T>>::value,
+ MaxLoadFactor100, Key, T, Hash, KeyEqual>;
+
+// set
+
+template <typename Key, typename Hash = hash<Key>, typename KeyEqual = std::equal_to<Key>,
+ size_t MaxLoadFactor100 = 80>
+using unordered_flat_set = detail::Table<true, MaxLoadFactor100, Key, void, Hash, KeyEqual>;
+
+template <typename Key, typename Hash = hash<Key>, typename KeyEqual = std::equal_to<Key>,
+ size_t MaxLoadFactor100 = 80>
+using unordered_node_set = detail::Table<false, MaxLoadFactor100, Key, void, Hash, KeyEqual>;
+
+template <typename Key, typename Hash = hash<Key>, typename KeyEqual = std::equal_to<Key>,
+ size_t MaxLoadFactor100 = 80>
+using unordered_set = detail::Table<sizeof(Key) <= sizeof(size_t) * 6 &&
+ std::is_nothrow_move_constructible<Key>::value &&
+ std::is_nothrow_move_assignable<Key>::value,
+ MaxLoadFactor100, Key, void, Hash, KeyEqual>;
+
+} // namespace robin_hood
+
+#endif
diff --git a/contrib/libs/jinja2cpp/src/serialize_filters.cpp b/contrib/libs/jinja2cpp/src/serialize_filters.cpp
new file mode 100644
index 0000000000..f373492967
--- /dev/null
+++ b/contrib/libs/jinja2cpp/src/serialize_filters.cpp
@@ -0,0 +1,442 @@
+#include "filters.h"
+#include "generic_adapters.h"
+#include "out_stream.h"
+#include "testers.h"
+#include "value_helpers.h"
+#include "value_visitors.h"
+
+#include <fmt/args.h>
+
+#include <algorithm>
+#include <numeric>
+#include <random>
+#include <sstream>
+#include <string>
+
+#ifdef JINJA2CPP_WITH_JSON_BINDINGS_BOOST
+#error #include "binding/boost_json_serializer.h"
+using DocumentWrapper = jinja2::boost_json_serializer::DocumentWrapper;
+#else
+#include "binding/rapid_json_serializer.h"
+using DocumentWrapper = jinja2::rapidjson_serializer::DocumentWrapper;
+#endif
+
+
+using namespace std::string_literals;
+
+namespace jinja2
+{
+namespace filters
+{
+struct PrettyPrinter : visitors::BaseVisitor<std::string>
+{
+ using BaseVisitor::operator();
+
+ PrettyPrinter(const RenderContext* context)
+ : m_context(context)
+ {
+ }
+
+ std::string operator()(const ListAdapter& list) const
+ {
+ std::string str;
+ auto os = std::back_inserter(str);
+
+ fmt::format_to(os, "[");
+ bool isFirst = true;
+
+ for (auto& v : list)
+ {
+ if (isFirst)
+ isFirst = false;
+ else
+ fmt::format_to(os, ", ");
+ fmt::format_to(os, "{}", Apply<PrettyPrinter>(v, m_context));
+ }
+ fmt::format_to(os, "]");
+
+ return str;
+ }
+
+ std::string operator()(const MapAdapter& map) const
+ {
+ std::string str;
+ auto os = std::back_inserter(str);
+
+ fmt::format_to(os, "{{");
+
+ const auto& keys = map.GetKeys();
+
+ bool isFirst = true;
+ for (auto& k : keys)
+ {
+ if (isFirst)
+ isFirst = false;
+ else
+ fmt::format_to(os, ", ");
+
+ fmt::format_to(os, "'{}': ", k);
+ fmt::format_to(os, "{}", Apply<PrettyPrinter>(map.GetValueByName(k), m_context));
+ }
+
+ fmt::format_to(os, "}}");
+
+ return str;
+ }
+
+ std::string operator()(const KeyValuePair& kwPair) const
+ {
+ std::string str;
+ auto os = std::back_inserter(str);
+
+ fmt::format_to(os, "'{}': ", kwPair.key);
+ fmt::format_to(os, "{}", Apply<PrettyPrinter>(kwPair.value, m_context));
+
+ return str;
+ }
+
+ std::string operator()(const std::string& str) const { return fmt::format("'{}'", str); }
+
+ std::string operator()(const std::string_view& str) const { return fmt::format("'{}'", fmt::basic_string_view<char>(str.data(), str.size())); }
+
+ std::string operator()(const std::wstring& str) const { return fmt::format("'{}'", ConvertString<std::string>(str)); }
+
+ std::string operator()(const std::wstring_view& str) const { return fmt::format("'{}'", ConvertString<std::string>(str)); }
+
+ std::string operator()(bool val) const { return val ? "true"s : "false"s; }
+
+ std::string operator()(EmptyValue) const { return "none"s; }
+
+ std::string operator()(const Callable&) const { return "<callable>"s; }
+
+ std::string operator()(double val) const
+ {
+ std::string str;
+ auto os = std::back_inserter(str);
+
+ fmt::format_to(os, "{:.8g}", val);
+
+ return str;
+ }
+
+ std::string operator()(int64_t val) const { return fmt::format("{}", val); }
+
+ const RenderContext* m_context;
+};
+
+PrettyPrint::PrettyPrint(FilterParams params) {}
+
+InternalValue PrettyPrint::Filter(const InternalValue& baseVal, RenderContext& context)
+{
+ return Apply<PrettyPrinter>(baseVal, &context);
+}
+
+Serialize::Serialize(const FilterParams params, const Serialize::Mode mode)
+ : m_mode(mode)
+{
+ switch (mode)
+ {
+ case JsonMode:
+ ParseParams({ { "indent", false, static_cast<int64_t>(0) } }, params);
+ break;
+ default:
+ break;
+ }
+}
+
+InternalValue Serialize::Filter(const InternalValue& value, RenderContext& context)
+{
+ if (m_mode == JsonMode)
+ {
+ const auto indent = ConvertToInt(this->GetArgumentValue("indent", context));
+ DocumentWrapper jsonDoc;
+ const auto jsonValue = jsonDoc.CreateValue(value);
+ const auto jsonString = jsonValue.AsString(static_cast<uint8_t>(indent));
+ std::string result = ""s;
+ for (char c : jsonString) {
+ if (c == '<') {
+ result.append("\\u003c");
+ } else if (c == '>') {
+ result.append("\\u003e");
+ } else if (c == '&') {
+ result.append("\\u0026");
+ } else if (c == '\'') {
+ result.append("\\u0027");
+ } else {
+ result.push_back(c);
+ }
+ }
+
+ return result;
+ }
+
+ return InternalValue();
+}
+
+namespace
+{
+
+using FormatContext = fmt::format_context;
+using FormatArgument = fmt::basic_format_arg<FormatContext>;
+using FormatDynamicArgsStore = fmt::dynamic_format_arg_store<FormatContext>;
+
+struct FormatArgumentConverter : visitors::BaseVisitor<FormatArgument>
+{
+ using result_t = FormatArgument;
+
+ using BaseVisitor::operator();
+
+ FormatArgumentConverter(const RenderContext* context, FormatDynamicArgsStore& store)
+ : m_context(context)
+ , m_store(store)
+ {
+ }
+
+ FormatArgumentConverter(const RenderContext* context, FormatDynamicArgsStore& store, const std::string& name)
+ : m_context(context)
+ , m_store(store)
+ , m_name(name)
+ , m_named(true)
+ {
+ }
+
+ result_t operator()(const ListAdapter& list) const { return make_result(Apply<PrettyPrinter>(list, m_context)); }
+
+ result_t operator()(const MapAdapter& map) const { return make_result(Apply<PrettyPrinter>(map, m_context)); }
+
+ result_t operator()(const std::string& str) const { return make_result(str); }
+
+ result_t operator()(const std::string_view& str) const { return make_result(std::string(str.data(), str.size())); }
+
+ result_t operator()(const std::wstring& str) const { return make_result(ConvertString<std::string>(str)); }
+
+ result_t operator()(const std::wstring_view& str) const { return make_result(ConvertString<std::string>(str)); }
+
+ result_t operator()(double val) const { return make_result(val); }
+
+ result_t operator()(int64_t val) const { return make_result(val); }
+
+ result_t operator()(bool val) const { return make_result(val ? "true"s : "false"s); }
+
+ result_t operator()(EmptyValue) const { return make_result("none"s); }
+
+ result_t operator()(const Callable&) const { return make_result("<callable>"s); }
+
+ template<typename T>
+ result_t make_result(const T& t) const
+ {
+ if (!m_named)
+ {
+ m_store.push_back(t);
+ }
+ else
+ {
+ m_store.push_back(fmt::arg(m_name.c_str(), t));
+ }
+ return fmt::detail::make_arg<FormatContext>(t);
+ }
+
+ const RenderContext* m_context;
+ FormatDynamicArgsStore& m_store;
+ const std::string m_name;
+ bool m_named = false;
+};
+
+} // namespace
+
+InternalValue StringFormat::Filter(const InternalValue& baseVal, RenderContext& context)
+{
+ // Format library internally likes using non-owning views to complex arguments.
+ // In order to ensure proper lifetime of values and named args,
+ // helper buffer is created and passed to visitors.
+ FormatDynamicArgsStore store;
+ for (auto& arg : m_params.posParams)
+ {
+ Apply<FormatArgumentConverter>(arg->Evaluate(context), &context, store);
+ }
+
+ for (auto& arg : m_params.kwParams)
+ {
+ Apply<FormatArgumentConverter>(arg.second->Evaluate(context), &context, store, arg.first);
+ }
+
+ return InternalValue(fmt::vformat(AsString(baseVal), store));
+}
+
+class XmlAttrPrinter : public visitors::BaseVisitor<std::string>
+{
+public:
+ using BaseVisitor::operator();
+
+ explicit XmlAttrPrinter(RenderContext* context, bool isFirstLevel = false)
+ : m_context(context)
+ , m_isFirstLevel(isFirstLevel)
+ {
+ }
+
+ std::string operator()(const ListAdapter& list) const
+ {
+ EnforceThatNested();
+
+ return EscapeHtml(Apply<PrettyPrinter>(list, m_context));
+ }
+
+ std::string operator()(const MapAdapter& map) const
+ {
+ if (!m_isFirstLevel)
+ {
+ return EscapeHtml(Apply<PrettyPrinter>(map, m_context));
+ }
+
+ std::string str;
+ auto os = std::back_inserter(str);
+
+ const auto& keys = map.GetKeys();
+
+ bool isFirst = true;
+ for (auto& k : keys)
+ {
+ const auto& v = map.GetValueByName(k);
+ const auto item = Apply<XmlAttrPrinter>(v, m_context, false);
+ if (item.length() > 0)
+ {
+ if (isFirst)
+ isFirst = false;
+ else
+ fmt::format_to(os, " ");
+
+ fmt::format_to(os, "{}=\"{}\"", k, item);
+ }
+ }
+
+ return str;
+ }
+
+ std::string operator()(const KeyValuePair& kwPair) const
+ {
+ EnforceThatNested();
+
+ return EscapeHtml(Apply<PrettyPrinter>(kwPair, m_context));
+ }
+
+ std::string operator()(const std::string& str) const
+ {
+ EnforceThatNested();
+
+ return EscapeHtml(str);
+ }
+
+ std::string operator()(const std::string_view& str) const
+ {
+ EnforceThatNested();
+
+ const auto result = fmt::format("{}", fmt::basic_string_view<char>(str.data(), str.size()));
+ return EscapeHtml(result);
+ }
+
+ std::string operator()(const std::wstring& str) const
+ {
+ EnforceThatNested();
+
+ return EscapeHtml(ConvertString<std::string>(str));
+ }
+
+ std::string operator()(const std::wstring_view& str) const
+ {
+ EnforceThatNested();
+
+ const auto result = fmt::format("{}", ConvertString<std::string>(str));
+ return EscapeHtml(result);
+ }
+
+ std::string operator()(bool val) const
+ {
+ EnforceThatNested();
+
+ return val ? "true"s : "false"s;
+ }
+
+ std::string operator()(EmptyValue) const
+ {
+ EnforceThatNested();
+
+ return ""s;
+ }
+
+ std::string operator()(const Callable&) const
+ {
+ EnforceThatNested();
+
+ return ""s;
+ }
+
+ std::string operator()(double val) const
+ {
+ EnforceThatNested();
+
+ std::string str;
+ auto os = std::back_inserter(str);
+
+ fmt::format_to(os, "{:.8g}", val);
+
+ return str;
+ }
+
+ std::string operator()(int64_t val) const
+ {
+ EnforceThatNested();
+
+ return fmt::format("{}", val);
+ }
+
+private:
+ void EnforceThatNested() const
+ {
+ if (m_isFirstLevel)
+ m_context->GetRendererCallback()->ThrowRuntimeError(ErrorCode::InvalidValueType, ValuesList{});
+ }
+
+ std::string EscapeHtml(const std::string &str) const
+ {
+ const auto result = std::accumulate(str.begin(), str.end(), ""s, [](const auto &str, const auto &c)
+ {
+ switch (c)
+ {
+ case '<':
+ return str + "&lt;";
+ break;
+ case '>':
+ return str +"&gt;";
+ break;
+ case '&':
+ return str +"&amp;";
+ break;
+ case '\'':
+ return str +"&#39;";
+ break;
+ case '\"':
+ return str +"&#34;";
+ break;
+ default:
+ return str + c;
+ break;
+ }
+ });
+
+ return result;
+ }
+
+private:
+ RenderContext* m_context;
+ bool m_isFirstLevel;
+};
+
+XmlAttrFilter::XmlAttrFilter(FilterParams) {}
+
+InternalValue XmlAttrFilter::Filter(const InternalValue& baseVal, RenderContext& context)
+{
+ return Apply<XmlAttrPrinter>(baseVal, &context, true);
+}
+
+} // namespace filters
+} // namespace jinja2
diff --git a/contrib/libs/jinja2cpp/src/statements.cpp b/contrib/libs/jinja2cpp/src/statements.cpp
new file mode 100644
index 0000000000..bb4718d2e4
--- /dev/null
+++ b/contrib/libs/jinja2cpp/src/statements.cpp
@@ -0,0 +1,839 @@
+#include "statements.h"
+
+#include "expression_evaluator.h"
+#include "template_impl.h"
+#include "value_visitors.h"
+
+#include <boost/core/null_deleter.hpp>
+
+#include <string>
+
+using namespace std::string_literals;
+
+namespace jinja2
+{
+
+void ForStatement::Render(OutStream& os, RenderContext& values)
+{
+ InternalValue loopVal = m_value->Evaluate(values);
+
+ RenderLoop(loopVal, os, values, 0);
+}
+
+void ForStatement::RenderLoop(const InternalValue& loopVal, OutStream& os, RenderContext& values, int level)
+{
+ auto& context = values.EnterScope();
+
+ InternalValueMap loopVar;
+ context["loop"s] = CreateMapAdapter(&loopVar);
+ if (m_isRecursive)
+ {
+ loopVar["operator()"s] = Callable(Callable::GlobalFunc, [this, level](const CallParams& params, OutStream& stream, RenderContext& context) {
+ bool isSucceeded = false;
+ auto parsedParams = helpers::ParseCallParams({ { "var", true } }, params, isSucceeded);
+ if (!isSucceeded)
+ return;
+
+ auto var = parsedParams["var"];
+ if (var.IsEmpty())
+ return;
+
+ RenderLoop(var, stream, context, level + 1);
+ });
+ loopVar["depth"s] = static_cast<int64_t>(level + 1);
+ loopVar["depth0"s] = static_cast<int64_t>(level);
+ }
+
+ bool isConverted = false;
+ auto loopItems = ConvertToList(loopVal, isConverted, false);
+ ListAdapter filteredList;
+ ListAdapter indexedList;
+ ListAccessorEnumeratorPtr enumerator;
+ size_t itemIdx = 0;
+ if (!isConverted)
+ {
+ if (m_elseBody)
+ m_elseBody->Render(os, values);
+ values.ExitScope();
+ return;
+ }
+
+ std::optional<size_t> listSize;
+ if (m_ifExpr)
+ {
+ filteredList = CreateFilteredAdapter(loopItems, values);
+ enumerator = filteredList.GetEnumerator();
+ }
+ else
+ {
+ enumerator = loopItems.GetEnumerator();
+ listSize = loopItems.GetSize();
+ }
+
+ bool isLast = false;
+ auto makeIndexedList = [&enumerator, &listSize, &indexedList, &itemIdx, &isLast] {
+ if (isLast)
+ listSize = itemIdx;
+
+ InternalValueList items;
+ do
+ {
+ items.push_back(enumerator->GetCurrent());
+ } while (enumerator->MoveNext());
+
+ listSize = itemIdx + items.size() + 1;
+ indexedList = ListAdapter::CreateAdapter(std::move(items));
+ enumerator = indexedList.GetEnumerator();
+ isLast = !enumerator->MoveNext();
+ };
+
+ if (listSize)
+ {
+ int64_t itemsNum = static_cast<int64_t>(listSize.value());
+ loopVar["length"s] = InternalValue(itemsNum);
+ }
+ else
+ {
+ loopVar["length"s] = MakeDynamicProperty([&listSize, &makeIndexedList](const CallParams& /*params*/, RenderContext & /*context*/) -> InternalValue {
+ if (!listSize)
+ makeIndexedList();
+ return static_cast<int64_t>(listSize.value());
+ });
+ }
+ bool loopRendered = false;
+ isLast = !enumerator->MoveNext();
+ InternalValue prevValue;
+ InternalValue curValue;
+ InternalValue nextValue;
+ loopVar["cycle"s] = static_cast<int64_t>(LoopCycleFn);
+ for (; !isLast; ++itemIdx)
+ {
+ prevValue = std::move(curValue);
+ if (itemIdx != 0)
+ {
+ std::swap(curValue, nextValue);
+ loopVar["previtem"s] = prevValue;
+ }
+ else
+ curValue = enumerator->GetCurrent();
+
+ isLast = !enumerator->MoveNext();
+ if (!isLast)
+ {
+ nextValue = enumerator->GetCurrent();
+ loopVar["nextitem"s] = nextValue;
+ }
+ else
+ loopVar.erase("nextitem"s);
+
+ loopRendered = true;
+ loopVar["index"s] = static_cast<int64_t>(itemIdx + 1);
+ loopVar["index0"s] = static_cast<int64_t>(itemIdx);
+ loopVar["first"s] = itemIdx == 0;
+ loopVar["last"s] = isLast;
+
+ if (m_vars.size() > 1)
+ {
+ const auto& valList = ConvertToList(curValue, isConverted);
+ if (!isConverted)
+ continue;
+
+ auto b = valList.begin();
+ auto e = valList.end();
+
+ for (auto& varName : m_vars)
+ {
+ if (b == e)
+ continue;
+ context[varName] = *b;
+ ++ b;
+ }
+ }
+ else
+ context[m_vars[0]] = curValue;
+
+ values.EnterScope();
+ m_mainBody->Render(os, values);
+ values.ExitScope();
+ }
+
+ if (!loopRendered && m_elseBody)
+ m_elseBody->Render(os, values);
+
+ values.ExitScope();
+}
+
+ListAdapter ForStatement::CreateFilteredAdapter(const ListAdapter& loopItems, RenderContext& values) const
+{
+ return ListAdapter::CreateAdapter([e = loopItems.GetEnumerator(), this, &values]() mutable {
+ using ResultType = std::optional<InternalValue>;
+
+ auto& tempContext = values.EnterScope();
+ for (bool finish = !e->MoveNext(); !finish; finish = !e->MoveNext())
+ {
+ auto curValue = e->GetCurrent();
+ if (m_vars.size() > 1)
+ {
+ for (auto& varName : m_vars)
+ tempContext[varName] = Subscript(curValue, varName, &values);
+ }
+ else
+ {
+ tempContext[m_vars[0]] = curValue;
+ }
+
+ if (ConvertToBool(m_ifExpr->Evaluate(values)))
+ {
+ values.ExitScope();
+ return ResultType(std::move(curValue));
+ }
+ }
+ values.ExitScope();
+
+ return ResultType();
+ });
+}
+
+void IfStatement::Render(OutStream& os, RenderContext& values)
+{
+ InternalValue val = m_expr->Evaluate(values);
+ bool isTrue = Apply<visitors::BooleanEvaluator>(val);
+
+ if (isTrue)
+ {
+ m_mainBody->Render(os, values);
+ return;
+ }
+
+ for (auto& b : m_elseBranches)
+ {
+ if (b->ShouldRender(values))
+ {
+ b->Render(os, values);
+ break;
+ }
+ }
+}
+
+bool ElseBranchStatement::ShouldRender(RenderContext& values) const
+{
+ if (!m_expr)
+ return true;
+
+ return Apply<visitors::BooleanEvaluator>(m_expr->Evaluate(values));
+}
+
+void ElseBranchStatement::Render(OutStream& os, RenderContext& values)
+{
+ m_mainBody->Render(os, values);
+}
+
+void SetStatement::AssignBody(InternalValue body, RenderContext& values)
+{
+ auto& scope = values.GetCurrentScope();
+ if (m_fields.size() == 1)
+ scope[m_fields.front()] = std::move(body);
+ else
+ {
+ for (const auto& name : m_fields)
+ scope[name] = Subscript(body, name, &values);
+ }
+}
+
+void SetLineStatement::Render(OutStream&, RenderContext& values)
+{
+ if (!m_expr)
+ return;
+ AssignBody(m_expr->Evaluate(values), values);
+}
+
+InternalValue SetBlockStatement::RenderBody(RenderContext& values)
+{
+ TargetString result;
+ auto stream = values.GetRendererCallback()->GetStreamOnString(result);
+ auto innerValues = values.Clone(true);
+ m_body->Render(stream, innerValues);
+ return result;
+}
+
+void SetRawBlockStatement::Render(OutStream&, RenderContext& values)
+{
+ AssignBody(RenderBody(values), values);
+}
+
+void SetFilteredBlockStatement::Render(OutStream&, RenderContext& values)
+{
+ if (!m_expr)
+ return;
+ AssignBody(m_expr->Evaluate(RenderBody(values), values), values);
+}
+
+class IBlocksRenderer : public IRendererBase
+{
+public:
+ virtual bool HasBlock(const std::string& blockName) = 0;
+ virtual void RenderBlock(const std::string& blockName, OutStream& os, RenderContext& values) = 0;
+};
+
+void ParentBlockStatement::Render(OutStream& os, RenderContext& values)
+{
+ RenderContext innerContext = values.Clone(m_isScoped);
+ bool found = false;
+ auto parentTplVal = values.FindValue("$$__parent_template", found);
+ if (!found)
+ {
+ m_mainBody->Render(os, values);
+ return;
+ }
+
+ bool isConverted = false;
+ auto parentTplsList = ConvertToList(parentTplVal->second, isConverted);
+ if (!isConverted)
+ return;
+
+ IBlocksRenderer* blockRenderer = nullptr; // static_cast<BlocksRenderer*>(*parentTplPtr);
+ for (auto& tplVal : parentTplsList)
+ {
+ auto ptr = GetIf<RendererPtr>(&tplVal);
+ if (!ptr)
+ continue;
+
+ auto parentTplPtr = static_cast<IBlocksRenderer*>(ptr->get());
+
+ if (parentTplPtr->HasBlock(m_name))
+ {
+ blockRenderer = parentTplPtr;
+ break;
+ }
+ }
+
+ if (!blockRenderer)
+ {
+ m_mainBody->Render(os, values);
+ return;
+ }
+
+ auto& scope = innerContext.EnterScope();
+ scope["$$__super_block"] = RendererPtr(this, boost::null_deleter());
+ scope["super"] =
+ Callable(Callable::SpecialFunc, [this](const CallParams&, OutStream& stream, RenderContext& context) { m_mainBody->Render(stream, context); });
+ if (!m_isScoped)
+ scope["$$__parent_template"] = parentTplsList;
+
+ blockRenderer->RenderBlock(m_name, os, innerContext);
+ innerContext.ExitScope();
+
+ auto& globalScope = values.GetGlobalScope();
+ auto selfMap = GetIf<MapAdapter>(&globalScope[std::string("self")]);
+ if (!selfMap->HasValue(m_name))
+ selfMap->SetValue(m_name, MakeWrapped(Callable(Callable::SpecialFunc, [this](const CallParams&, OutStream& stream, RenderContext& context) {
+ Render(stream, context);
+ })));
+}
+
+void BlockStatement::Render(OutStream& os, RenderContext& values)
+{
+ m_mainBody->Render(os, values);
+}
+
+template<typename CharT>
+class ParentTemplateRenderer : public IBlocksRenderer
+{
+public:
+ ParentTemplateRenderer(std::shared_ptr<TemplateImpl<CharT>> tpl, ExtendsStatement::BlocksCollection* blocks)
+ : m_template(tpl)
+ , m_blocks(blocks)
+ {
+ }
+
+ void Render(OutStream& os, RenderContext& values) override
+ {
+ auto& scope = values.GetCurrentScope();
+ InternalValueList parentTemplates;
+ parentTemplates.push_back(InternalValue(RendererPtr(this, boost::null_deleter())));
+ bool isFound = false;
+ auto p = values.FindValue("$$__parent_template", isFound);
+ if (isFound)
+ {
+ bool isConverted = false;
+ auto prevTplsList = ConvertToList(p->second, isConverted);
+ if (isConverted)
+ {
+ for (auto& tpl : prevTplsList)
+ parentTemplates.push_back(tpl);
+ }
+ }
+ scope["$$__parent_template"] = ListAdapter::CreateAdapter(std::move(parentTemplates));
+ m_template->GetRenderer()->Render(os, values);
+ }
+
+ void RenderBlock(const std::string& blockName, OutStream& os, RenderContext& values) override
+ {
+ auto p = m_blocks->find(blockName);
+ if (p == m_blocks->end())
+ return;
+
+ p->second->Render(os, values);
+ }
+
+ bool HasBlock(const std::string& blockName) override { return m_blocks->count(blockName) != 0; }
+
+ bool IsEqual(const IComparable& other) const override
+ {
+ auto* val = dynamic_cast<const ParentTemplateRenderer*>(&other);
+ if (!val)
+ return false;
+ if (m_template != val->m_template)
+ return false;
+ if (m_blocks && val->m_blocks && *m_blocks != *(val->m_blocks))
+ return false;
+ if ((m_blocks && !val->m_blocks) || (!m_blocks && val->m_blocks))
+ return false;
+ return true;
+ }
+
+private:
+ std::shared_ptr<TemplateImpl<CharT>> m_template;
+ ExtendsStatement::BlocksCollection* m_blocks;
+};
+
+template<typename Result, typename Fn>
+struct TemplateImplVisitor
+{
+ // ExtendsStatement::BlocksCollection* m_blocks;
+ const Fn& m_fn;
+ bool m_throwError{};
+
+ explicit TemplateImplVisitor(const Fn& fn, bool throwError)
+ : m_fn(fn)
+ , m_throwError(throwError)
+ {
+ }
+
+ template<typename CharT>
+ Result operator()(nonstd::expected<std::shared_ptr<TemplateImpl<CharT>>, ErrorInfoTpl<CharT>> tpl) const
+ {
+ if (!m_throwError && !tpl)
+ {
+ return Result{};
+ }
+ else if (!tpl)
+ {
+ throw tpl.error();
+ }
+ return m_fn(tpl.value());
+ }
+
+ Result operator()(EmptyValue) const { return Result(); }
+};
+
+template<typename Result, typename Fn, typename Arg>
+Result VisitTemplateImpl(Arg&& tpl, bool throwError, Fn&& fn)
+{
+ return visit(TemplateImplVisitor<Result, Fn>(fn, throwError), tpl);
+}
+
+template<template<typename T> class RendererTpl, typename CharT, typename... Args>
+auto CreateTemplateRenderer(std::shared_ptr<TemplateImpl<CharT>> tpl, Args&&... args)
+{
+ return std::make_shared<RendererTpl<CharT>>(tpl, std::forward<Args>(args)...);
+}
+
+void ExtendsStatement::Render(OutStream& os, RenderContext& values)
+{
+ if (!m_isPath)
+ {
+ // FIXME: Implement processing of templates
+ return;
+ }
+ auto tpl = values.GetRendererCallback()->LoadTemplate(m_templateName);
+ auto renderer =
+ VisitTemplateImpl<RendererPtr>(tpl, true, [this](auto tplPtr) { return CreateTemplateRenderer<ParentTemplateRenderer>(tplPtr, &m_blocks); });
+ if (renderer)
+ renderer->Render(os, values);
+}
+
+template<typename CharT>
+class IncludedTemplateRenderer : public IRendererBase
+{
+public:
+ IncludedTemplateRenderer(std::shared_ptr<TemplateImpl<CharT>> tpl, bool withContext)
+ : m_template(tpl)
+ , m_withContext(withContext)
+ {
+ }
+
+ void Render(OutStream& os, RenderContext& values) override
+ {
+ RenderContext innerContext = values.Clone(m_withContext);
+ if (m_withContext)
+ innerContext.EnterScope();
+
+ m_template->GetRenderer()->Render(os, innerContext);
+ if (m_withContext)
+ {
+ auto& innerScope = innerContext.GetCurrentScope();
+ auto& scope = values.GetCurrentScope();
+ for (auto& v : innerScope)
+ {
+ scope[v.first] = std::move(v.second);
+ }
+ }
+ }
+
+ bool IsEqual(const IComparable& other) const override
+ {
+ auto* val = dynamic_cast<const IncludedTemplateRenderer<CharT>*>(&other);
+ if (!val)
+ return false;
+ if (m_template != val->m_template)
+ return false;
+ if (m_withContext != val->m_withContext)
+ return false;
+ return true;
+ }
+
+private:
+ std::shared_ptr<TemplateImpl<CharT>> m_template;
+ bool m_withContext{};
+};
+
+void IncludeStatement::Render(OutStream& os, RenderContext& values)
+{
+ auto templateNames = m_expr->Evaluate(values);
+ bool isConverted = false;
+ ListAdapter list = ConvertToList(templateNames, isConverted);
+
+ auto doRender = [this, &values, &os](auto&& name) -> bool {
+ auto tpl = values.GetRendererCallback()->LoadTemplate(name);
+
+ try
+ {
+ auto renderer = VisitTemplateImpl<RendererPtr>(
+ tpl, true, [this](auto tplPtr) { return CreateTemplateRenderer<IncludedTemplateRenderer>(tplPtr, m_withContext); });
+
+ if (renderer)
+ {
+ renderer->Render(os, values);
+ return true;
+ }
+ }
+ catch (const ErrorInfoTpl<char>& err)
+ {
+ if (err.GetCode() != ErrorCode::FileNotFound)
+ throw;
+ }
+ catch (const ErrorInfoTpl<wchar_t>& err)
+ {
+ if (err.GetCode() != ErrorCode::FileNotFound)
+ throw;
+ }
+
+ return false;
+ };
+
+ bool rendered = false;
+ if (isConverted)
+ {
+ for (auto& name : list)
+ {
+ rendered = doRender(name);
+ if (rendered)
+ break;
+ }
+ }
+ else
+ {
+ rendered = doRender(templateNames);
+ }
+
+ if (!rendered && !m_ignoreMissing)
+ {
+ InternalValueList files;
+ ValuesList extraParams;
+ if (isConverted)
+ {
+ extraParams.push_back(IntValue2Value(templateNames));
+ }
+ else
+ {
+ files.push_back(templateNames);
+ extraParams.push_back(IntValue2Value(ListAdapter::CreateAdapter(std::move(files))));
+ }
+
+ values.GetRendererCallback()->ThrowRuntimeError(ErrorCode::TemplateNotFound, std::move(extraParams));
+ }
+}
+
+class ImportedMacroRenderer : public IRendererBase
+{
+public:
+ explicit ImportedMacroRenderer(InternalValueMap&& map, bool withContext)
+ : m_importedContext(std::move(map))
+ , m_withContext(withContext)
+ {
+ }
+
+ void Render(OutStream& /*os*/, RenderContext& /*values*/) override {}
+
+ void InvokeMacro(const Callable& callable, const CallParams& params, OutStream& stream, RenderContext& context)
+ {
+ auto ctx = context.Clone(m_withContext);
+ ctx.BindScope(&m_importedContext);
+ callable.GetStatementCallable()(params, stream, ctx);
+ }
+
+ static void InvokeMacro(const std::string& contextName, const Callable& callable, const CallParams& params, OutStream& stream, RenderContext& context)
+ {
+ bool contextValFound = false;
+ auto contextVal = context.FindValue(contextName, contextValFound);
+ if (!contextValFound)
+ return;
+
+ auto rendererPtr = GetIf<RendererPtr>(&contextVal->second);
+ if (!rendererPtr)
+ return;
+
+ auto renderer = static_cast<ImportedMacroRenderer*>(rendererPtr->get());
+ renderer->InvokeMacro(callable, params, stream, context);
+ }
+
+ bool IsEqual(const IComparable& other) const override
+ {
+ auto* val = dynamic_cast<const ImportedMacroRenderer*>(&other);
+ if (!val)
+ return false;
+ if (m_importedContext != val->m_importedContext)
+ return false;
+ if (m_withContext != val->m_withContext)
+ return false;
+ return true;
+ }
+
+private:
+ InternalValueMap m_importedContext;
+ bool m_withContext{};
+};
+
+void ImportStatement::Render(OutStream& /*os*/, RenderContext& values)
+{
+ auto name = m_nameExpr->Evaluate(values);
+
+ if (!m_renderer)
+ {
+ auto tpl = values.GetRendererCallback()->LoadTemplate(name);
+ m_renderer = VisitTemplateImpl<RendererPtr>(tpl, true, [](auto tplPtr) { return CreateTemplateRenderer<IncludedTemplateRenderer>(tplPtr, true); });
+ }
+
+ if (!m_renderer)
+ return;
+
+ std::string scopeName;
+ {
+ TargetString tsScopeName = values.GetRendererCallback()->GetAsTargetString(name);
+ scopeName = "$$_imported_" + GetAsSameString(scopeName, tsScopeName).value();
+ }
+
+ TargetString str;
+ auto tmpStream = values.GetRendererCallback()->GetStreamOnString(str);
+
+ RenderContext newContext = values.Clone(m_withContext);
+ InternalValueMap importedScope;
+ {
+ auto& intImportedScope = newContext.EnterScope();
+ m_renderer->Render(tmpStream, newContext);
+ importedScope = std::move(intImportedScope);
+ }
+
+ ImportNames(values, importedScope, scopeName);
+ values.GetCurrentScope()[scopeName] =
+ std::static_pointer_cast<IRendererBase>(std::make_shared<ImportedMacroRenderer>(std::move(importedScope), m_withContext));
+}
+
+void ImportStatement::ImportNames(RenderContext& values, InternalValueMap& importedScope, const std::string& scopeName) const
+{
+ InternalValueMap importedNs;
+
+ for (auto& var : importedScope)
+ {
+ if (var.first.empty())
+ continue;
+
+ if (var.first[0] == '_')
+ continue;
+
+ auto mappedP = m_namesToImport.find(var.first);
+ if (!m_namespace && mappedP == m_namesToImport.end())
+ continue;
+
+ InternalValue imported;
+ auto callable = GetIf<Callable>(&var.second);
+ if (!callable)
+ {
+ imported = std::move(var.second);
+ }
+ else if (callable->GetKind() == Callable::Macro)
+ {
+ imported = Callable(Callable::Macro, [fn = std::move(*callable), scopeName](const CallParams& params, OutStream& stream, RenderContext& context) {
+ ImportedMacroRenderer::InvokeMacro(scopeName, fn, params, stream, context);
+ });
+ }
+ else
+ {
+ continue;
+ }
+
+ if (m_namespace)
+ importedNs[var.first] = std::move(imported);
+ else
+ values.GetCurrentScope()[mappedP->second] = std::move(imported);
+ }
+
+ if (m_namespace)
+ values.GetCurrentScope()[m_namespace.value()] = CreateMapAdapter(std::move(importedNs));
+}
+
+std::vector<ArgumentInfo> MacroStatement::PrepareMacroParams(RenderContext& values)
+{
+ std::vector<ArgumentInfo> preparedParams;
+
+ for (auto& p : m_params)
+ {
+ ArgumentInfo info(p.paramName, !p.defaultValue);
+ if (p.defaultValue)
+ info.defaultVal = p.defaultValue->Evaluate(values);
+ preparedParams.push_back(std::move(info));
+ }
+
+ return preparedParams;
+}
+
+void MacroStatement::Render(OutStream&, RenderContext& values)
+{
+ auto p = PrepareMacroParams(values);
+
+ values.GetCurrentScope()[m_name] = Callable(Callable::Macro, [this, params = std::move(p)](const CallParams& callParams, OutStream& stream, RenderContext& context) {
+ InvokeMacroRenderer(params, callParams, stream, context);
+ });
+}
+
+void MacroStatement::InvokeMacroRenderer(const std::vector<ArgumentInfo>& params, const CallParams& callParams, OutStream& stream, RenderContext& context)
+{
+ InternalValueMap callArgs;
+ InternalValueMap kwArgs;
+ InternalValueList varArgs;
+
+ SetupCallArgs(params, callParams, context, callArgs, kwArgs, varArgs);
+ InternalValueList arguments;
+ InternalValueList defaults;
+ for (auto& a : params)
+ {
+ arguments.emplace_back(a.name);
+ defaults.emplace_back(a.defaultVal);
+ }
+
+ auto& scope = context.EnterScope();
+ for (auto& a : callArgs)
+ scope[a.first] = std::move(a.second);
+
+ scope["kwargs"s] = CreateMapAdapter(std::move(kwArgs));
+ scope["varargs"s] = ListAdapter::CreateAdapter(std::move(varArgs));
+
+ scope["name"s] = static_cast<std::string>(m_name);
+ scope["arguments"s] = ListAdapter::CreateAdapter(std::move(arguments));
+ scope["defaults"s] = ListAdapter::CreateAdapter(std::move(defaults));
+
+ m_mainBody->Render(stream, context);
+
+ context.ExitScope();
+}
+
+void MacroStatement::SetupCallArgs(const std::vector<ArgumentInfo>& argsInfo,
+ const CallParams& callParams,
+ RenderContext& /* context */,
+ InternalValueMap& callArgs,
+ InternalValueMap& kwArgs,
+ InternalValueList& varArgs)
+{
+ bool isSucceeded = true;
+ ParsedArguments args = helpers::ParseCallParams(argsInfo, callParams, isSucceeded);
+
+ for (auto& a : args.args)
+ callArgs[a.first] = std::move(a.second);
+
+ for (auto& a : args.extraKwArgs)
+ kwArgs[a.first] = std::move(a.second);
+
+ for (auto& a : args.extraPosArgs)
+ varArgs.push_back(std::move(a));
+}
+
+void MacroStatement::SetupMacroScope(InternalValueMap&)
+{
+ ;
+}
+
+void MacroCallStatement::Render(OutStream& os, RenderContext& values)
+{
+ bool isMacroFound = false;
+ auto macroPtr = values.FindValue(m_macroName, isMacroFound);
+ if (!isMacroFound)
+ return;
+
+ auto& fnVal = macroPtr->second;
+ const Callable* callable = GetIf<Callable>(&fnVal);
+ if (callable == nullptr || callable->GetType() == Callable::Type::Expression)
+ return;
+
+ auto& curScope = values.GetCurrentScope();
+ auto callerP = curScope.find("caller");
+ bool hasCallerVal = callerP != curScope.end();
+ InternalValue prevCaller;
+ if (hasCallerVal)
+ prevCaller = callerP->second;
+
+ auto p = PrepareMacroParams(values);
+
+ curScope["caller"] = Callable(Callable::Macro, [this, params = std::move(p)](const CallParams& callParams, OutStream& stream, RenderContext& context) {
+ InvokeMacroRenderer(params, callParams, stream, context);
+ });
+
+ auto callParams = helpers::EvaluateCallParams(m_callParams, values);
+ callable->GetStatementCallable()(callParams, os, values);
+
+ if (hasCallerVal)
+ curScope["caller"] = prevCaller;
+ else
+ values.GetCurrentScope().erase("caller");
+}
+
+void MacroCallStatement::SetupMacroScope(InternalValueMap&) {}
+
+void DoStatement::Render(OutStream& /*os*/, RenderContext& values)
+{
+ m_expr->Evaluate(values);
+}
+
+void WithStatement::Render(OutStream& os, RenderContext& values)
+{
+ auto innerValues = values.Clone(true);
+ auto& scope = innerValues.EnterScope();
+
+ for (auto& var : m_scopeVars)
+ scope[var.first] = var.second->Evaluate(values);
+
+ m_mainBody->Render(os, innerValues);
+
+ innerValues.ExitScope();
+}
+
+void FilterStatement::Render(OutStream& os, RenderContext& values)
+{
+ TargetString arg;
+ auto argStream = values.GetRendererCallback()->GetStreamOnString(arg);
+ auto innerValues = values.Clone(true);
+ m_body->Render(argStream, innerValues);
+ const auto result = m_expr->Evaluate(std::move(arg), values);
+ os.WriteValue(result);
+}
+} // namespace jinja2
diff --git a/contrib/libs/jinja2cpp/src/statements.h b/contrib/libs/jinja2cpp/src/statements.h
new file mode 100644
index 0000000000..2a7db94a87
--- /dev/null
+++ b/contrib/libs/jinja2cpp/src/statements.h
@@ -0,0 +1,661 @@
+#ifndef JINJA2CPP_SRC_STATEMENTS_H
+#define JINJA2CPP_SRC_STATEMENTS_H
+
+#include "renderer.h"
+#include "expression_evaluator.h"
+
+#include <string>
+#include <vector>
+
+namespace jinja2
+{
+class Statement : public VisitableRendererBase
+{
+public:
+ VISITABLE_STATEMENT();
+};
+
+template<typename T = Statement>
+using StatementPtr = std::shared_ptr<T>;
+
+template<typename CharT>
+class TemplateImpl;
+
+struct MacroParam
+{
+ std::string paramName;
+ ExpressionEvaluatorPtr<> defaultValue;
+};
+inline bool operator==(const MacroParam& lhs, const MacroParam& rhs)
+{
+ if (lhs.paramName != rhs.paramName)
+ return false;
+ if (lhs.defaultValue != rhs.defaultValue)
+ return false;
+ return true;
+}
+
+using MacroParams = std::vector<MacroParam>;
+
+class ForStatement : public Statement
+{
+public:
+ VISITABLE_STATEMENT();
+
+ ForStatement(std::vector<std::string> vars, ExpressionEvaluatorPtr<> expr, ExpressionEvaluatorPtr<> ifExpr, bool isRecursive)
+ : m_vars(std::move(vars))
+ , m_value(expr)
+ , m_ifExpr(ifExpr)
+ , m_isRecursive(isRecursive)
+ {
+ }
+
+ void SetMainBody(RendererPtr renderer)
+ {
+ m_mainBody = std::move(renderer);
+ }
+
+ void SetElseBody(RendererPtr renderer)
+ {
+ m_elseBody = std::move(renderer);
+ }
+
+ void Render(OutStream& os, RenderContext& values) override;
+
+ bool IsEqual(const IComparable& other) const override
+ {
+ auto* val = dynamic_cast<const ForStatement*>(&other);
+ if (!val)
+ return false;
+ if (m_vars != val->m_vars)
+ return false;
+ if (m_value != val->m_value)
+ return false;
+ if (m_ifExpr != val->m_ifExpr)
+ return false;
+ if (m_isRecursive != val->m_isRecursive)
+ return false;
+ if (m_mainBody != val->m_mainBody)
+ return false;
+ if (m_elseBody != val->m_elseBody)
+ return false;
+ return true;
+ }
+
+private:
+ void RenderLoop(const InternalValue &loopVal, OutStream &os,
+ RenderContext &values, int level);
+ ListAdapter CreateFilteredAdapter(const ListAdapter& loopItems, RenderContext& values) const;
+
+private:
+ std::vector<std::string> m_vars;
+ ExpressionEvaluatorPtr<> m_value;
+ ExpressionEvaluatorPtr<> m_ifExpr;
+ bool m_isRecursive{};
+ RendererPtr m_mainBody;
+ RendererPtr m_elseBody;
+};
+
+class ElseBranchStatement;
+
+class IfStatement : public Statement
+{
+public:
+ VISITABLE_STATEMENT();
+
+ IfStatement(ExpressionEvaluatorPtr<> expr)
+ : m_expr(expr)
+ {
+ }
+
+ void SetMainBody(RendererPtr renderer)
+ {
+ m_mainBody = std::move(renderer);
+ }
+
+ void AddElseBranch(StatementPtr<ElseBranchStatement> branch)
+ {
+ m_elseBranches.push_back(branch);
+ }
+
+ void Render(OutStream& os, RenderContext& values) override;
+
+ bool IsEqual(const IComparable& other) const override
+ {
+ auto* val = dynamic_cast<const IfStatement*>(&other);
+ if (!val)
+ return false;
+ if (m_expr != val->m_expr)
+ return false;
+ if (m_mainBody != val->m_mainBody)
+ return false;
+ if (m_elseBranches != val->m_elseBranches)
+ return false;
+ return true;
+ }
+private:
+ ExpressionEvaluatorPtr<> m_expr;
+ RendererPtr m_mainBody;
+ std::vector<StatementPtr<ElseBranchStatement>> m_elseBranches;
+};
+
+
+class ElseBranchStatement : public Statement
+{
+public:
+ VISITABLE_STATEMENT();
+
+ ElseBranchStatement(ExpressionEvaluatorPtr<> expr)
+ : m_expr(expr)
+ {
+ }
+
+ bool ShouldRender(RenderContext& values) const;
+ void SetMainBody(RendererPtr renderer)
+ {
+ m_mainBody = std::move(renderer);
+ }
+ void Render(OutStream& os, RenderContext& values) override;
+ bool IsEqual(const IComparable& other) const override
+ {
+ auto* val = dynamic_cast<const ElseBranchStatement*>(&other);
+ if (!val)
+ return false;
+ if (m_expr != val->m_expr)
+ return false;
+ if (m_mainBody != val->m_mainBody)
+ return false;
+ return true;
+ }
+
+private:
+ ExpressionEvaluatorPtr<> m_expr;
+ RendererPtr m_mainBody;
+};
+
+class SetStatement : public Statement
+{
+public:
+ SetStatement(std::vector<std::string> fields)
+ : m_fields(std::move(fields))
+ {
+ }
+
+ bool IsEqual(const IComparable& other) const override
+ {
+ auto* val = dynamic_cast<const SetStatement*>(&other);
+ if (!val)
+ return false;
+ if (m_fields != val->m_fields)
+ return false;
+ return true;
+ }
+protected:
+ void AssignBody(InternalValue, RenderContext&);
+
+private:
+ const std::vector<std::string> m_fields;
+};
+
+class SetLineStatement final : public SetStatement
+{
+public:
+ VISITABLE_STATEMENT();
+
+ SetLineStatement(std::vector<std::string> fields, ExpressionEvaluatorPtr<> expr)
+ : SetStatement(std::move(fields)), m_expr(std::move(expr))
+ {
+ }
+
+ void Render(OutStream& os, RenderContext& values) override;
+
+ bool IsEqual(const IComparable& other) const override
+ {
+ auto* val = dynamic_cast<const SetLineStatement*>(&other);
+ if (!val)
+ return false;
+ if (m_expr != val->m_expr)
+ return false;
+ return true;
+ }
+private:
+ const ExpressionEvaluatorPtr<> m_expr;
+};
+
+class SetBlockStatement : public SetStatement
+{
+public:
+ using SetStatement::SetStatement;
+
+ void SetBody(RendererPtr renderer)
+ {
+ m_body = std::move(renderer);
+ }
+
+ bool IsEqual(const IComparable& other) const override
+ {
+ auto* val = dynamic_cast<const SetBlockStatement*>(&other);
+ if (!val)
+ return false;
+ if (!SetStatement::IsEqual(*val))
+ return false;
+ if (m_body != val->m_body)
+ return false;
+ return true;
+ }
+protected:
+ InternalValue RenderBody(RenderContext&);
+
+private:
+ RendererPtr m_body;
+};
+
+class SetRawBlockStatement final : public SetBlockStatement
+{
+public:
+ VISITABLE_STATEMENT();
+
+ using SetBlockStatement::SetBlockStatement;
+
+ void Render(OutStream&, RenderContext&) override;
+
+ bool IsEqual(const IComparable& other) const override
+ {
+ auto* val = dynamic_cast<const SetRawBlockStatement*>(&other);
+ if (!val)
+ return false;
+ if (!SetBlockStatement::IsEqual(*val))
+ return false;
+ return true;
+ }
+};
+
+class SetFilteredBlockStatement final : public SetBlockStatement
+{
+public:
+ VISITABLE_STATEMENT();
+
+ explicit SetFilteredBlockStatement(std::vector<std::string> fields, ExpressionEvaluatorPtr<ExpressionFilter> expr)
+ : SetBlockStatement(std::move(fields)), m_expr(std::move(expr))
+ {
+ }
+
+ void Render(OutStream&, RenderContext&) override;
+
+ bool IsEqual(const IComparable& other) const override
+ {
+ auto* val = dynamic_cast<const SetFilteredBlockStatement*>(&other);
+ if (!val)
+ return false;
+ if (!SetBlockStatement::IsEqual(*val))
+ return false;
+ if (m_expr != val->m_expr)
+ return false;
+ return true;
+ }
+
+private:
+ const ExpressionEvaluatorPtr<ExpressionFilter> m_expr;
+};
+
+class ParentBlockStatement : public Statement
+{
+public:
+ VISITABLE_STATEMENT();
+
+ ParentBlockStatement(std::string name, bool isScoped)
+ : m_name(std::move(name))
+ , m_isScoped(isScoped)
+ {
+ }
+
+ void SetMainBody(RendererPtr renderer)
+ {
+ m_mainBody = std::move(renderer);
+ }
+ void Render(OutStream &os, RenderContext &values) override;
+
+ bool IsEqual(const IComparable& other) const override
+ {
+ auto* val = dynamic_cast<const ParentBlockStatement*>(&other);
+ if (!val)
+ return false;
+ if (m_name != val->m_name)
+ return false;
+ if (m_isScoped != val->m_isScoped)
+ return false;
+ if (m_mainBody != val->m_mainBody)
+ return false;
+ return true;
+ }
+
+private:
+ std::string m_name;
+ bool m_isScoped{};
+ RendererPtr m_mainBody;
+};
+
+class BlockStatement : public Statement
+{
+public:
+ VISITABLE_STATEMENT();
+
+ BlockStatement(std::string name)
+ : m_name(std::move(name))
+ {
+ }
+
+ auto& GetName() const {return m_name;}
+
+ void SetMainBody(RendererPtr renderer)
+ {
+ m_mainBody = std::move(renderer);
+ }
+ void Render(OutStream &os, RenderContext &values) override;
+
+ bool IsEqual(const IComparable& other) const override
+ {
+ auto* val = dynamic_cast<const BlockStatement*>(&other);
+ if (!val)
+ return false;
+ if (m_name != val->m_name)
+ return false;
+ if (m_mainBody != val->m_mainBody)
+ return false;
+ return true;
+ }
+private:
+ std::string m_name;
+ RendererPtr m_mainBody;
+};
+
+class ExtendsStatement : public Statement
+{
+public:
+ VISITABLE_STATEMENT();
+
+ using BlocksCollection = std::unordered_map<std::string, StatementPtr<BlockStatement>>;
+
+ ExtendsStatement(std::string name, bool isPath)
+ : m_templateName(std::move(name))
+ , m_isPath(isPath)
+ {
+ }
+
+ void Render(OutStream &os, RenderContext &values) override;
+ void AddBlock(StatementPtr<BlockStatement> block)
+ {
+ m_blocks[block->GetName()] = block;
+ }
+ bool IsEqual(const IComparable& other) const override
+ {
+ auto* val = dynamic_cast<const ExtendsStatement*>(&other);
+ if (!val)
+ return false;
+ if (m_templateName != val->m_templateName)
+ return false;
+ if (m_isPath != val->m_isPath)
+ return false;
+ if (m_blocks != val->m_blocks)
+ return false;
+ return true;
+ }
+private:
+ std::string m_templateName;
+ bool m_isPath{};
+ BlocksCollection m_blocks;
+ void DoRender(OutStream &os, RenderContext &values);
+};
+
+class IncludeStatement : public Statement
+{
+public:
+ VISITABLE_STATEMENT();
+
+ IncludeStatement(bool ignoreMissing, bool withContext)
+ : m_ignoreMissing(ignoreMissing)
+ , m_withContext(withContext)
+ {}
+
+ void SetIncludeNamesExpr(ExpressionEvaluatorPtr<> expr)
+ {
+ m_expr = std::move(expr);
+ }
+
+ void Render(OutStream& os, RenderContext& values) override;
+ bool IsEqual(const IComparable& other) const override
+ {
+ auto* val = dynamic_cast<const IncludeStatement*>(&other);
+ if (!val)
+ return false;
+ if (m_ignoreMissing != val->m_ignoreMissing)
+ return false;
+ if (m_withContext != val->m_withContext)
+ return false;
+ if (m_expr != val->m_expr)
+ return false;
+ return true;
+ }
+private:
+ bool m_ignoreMissing{};
+ bool m_withContext{};
+ ExpressionEvaluatorPtr<> m_expr;
+};
+
+class ImportStatement : public Statement
+{
+public:
+ VISITABLE_STATEMENT();
+
+ explicit ImportStatement(bool withContext)
+ : m_withContext(withContext)
+ {}
+
+ void SetImportNameExpr(ExpressionEvaluatorPtr<> expr)
+ {
+ m_nameExpr = std::move(expr);
+ }
+
+ void SetNamespace(std::string name)
+ {
+ m_namespace = std::move(name);
+ }
+
+ void AddNameToImport(std::string name, std::string alias)
+ {
+ m_namesToImport[std::move(name)] = std::move(alias);
+ }
+
+ void Render(OutStream& os, RenderContext& values) override;
+
+ bool IsEqual(const IComparable& other) const override
+ {
+ auto* val = dynamic_cast<const ImportStatement*>(&other);
+ if (!val)
+ return false;
+ if (m_namespace != val->m_namespace)
+ return false;
+ if (m_withContext != val->m_withContext)
+ return false;
+ if (m_namesToImport != val->m_namesToImport)
+ return false;
+ if (m_nameExpr != val->m_nameExpr)
+ return false;
+ if (m_renderer != val->m_renderer)
+ return false;
+ return true;
+ }
+private:
+ void ImportNames(RenderContext& values, InternalValueMap& importedScope, const std::string& scopeName) const;
+
+private:
+ bool m_withContext{};
+ RendererPtr m_renderer;
+ ExpressionEvaluatorPtr<> m_nameExpr;
+ std::optional<std::string> m_namespace;
+ std::unordered_map<std::string, std::string> m_namesToImport;
+};
+
+class MacroStatement : public Statement
+{
+public:
+ VISITABLE_STATEMENT();
+
+ MacroStatement(std::string name, MacroParams params)
+ : m_name(std::move(name))
+ , m_params(std::move(params))
+ {
+ }
+
+ void SetMainBody(RendererPtr renderer)
+ {
+ m_mainBody = std::move(renderer);
+ }
+
+ void Render(OutStream &os, RenderContext &values) override;
+
+ bool IsEqual(const IComparable& other) const override
+ {
+ auto* val = dynamic_cast<const MacroStatement*>(&other);
+ if (!val)
+ return false;
+ if (m_name != val->m_name)
+ return false;
+ if (m_params != val->m_params)
+ return false;
+ if (m_mainBody != val->m_mainBody)
+ return false;
+ return true;
+ }
+
+protected:
+ void InvokeMacroRenderer(const std::vector<ArgumentInfo>& params, const CallParams& callParams, OutStream& stream, RenderContext& context);
+ void SetupCallArgs(const std::vector<ArgumentInfo>& argsInfo, const CallParams& callParams, RenderContext& context, InternalValueMap& callArgs, InternalValueMap& kwArgs, InternalValueList& varArgs);
+ virtual void SetupMacroScope(InternalValueMap& scope);
+ std::vector<ArgumentInfo> PrepareMacroParams(RenderContext& values);
+
+protected:
+ std::string m_name;
+ MacroParams m_params;
+ RendererPtr m_mainBody;
+};
+
+class MacroCallStatement : public MacroStatement
+{
+public:
+ VISITABLE_STATEMENT();
+
+ MacroCallStatement(std::string macroName, CallParamsInfo callParams, MacroParams callbackParams)
+ : MacroStatement("$call$", std::move(callbackParams))
+ , m_macroName(std::move(macroName))
+ , m_callParams(std::move(callParams))
+ {
+ }
+
+ void Render(OutStream &os, RenderContext &values) override;
+
+ bool IsEqual(const IComparable& other) const override
+ {
+ auto* val = dynamic_cast<const MacroCallStatement*>(&other);
+ if (!val)
+ return false;
+ if (m_macroName != val->m_macroName)
+ return false;
+ if (m_callParams != val->m_callParams)
+ return false;
+ return true;
+ }
+protected:
+ void SetupMacroScope(InternalValueMap& scope) override;
+
+protected:
+ std::string m_macroName;
+ CallParamsInfo m_callParams;
+};
+
+class DoStatement : public Statement
+{
+public:
+ VISITABLE_STATEMENT();
+
+ DoStatement(ExpressionEvaluatorPtr<> expr) : m_expr(expr) {}
+
+ void Render(OutStream &os, RenderContext &values) override;
+ bool IsEqual(const IComparable& other) const override
+ {
+ auto* val = dynamic_cast<const DoStatement*>(&other);
+ if (!val)
+ return false;
+ if (m_expr != val->m_expr)
+ return false;
+ return true;
+ }
+private:
+ ExpressionEvaluatorPtr<> m_expr;
+};
+
+class WithStatement : public Statement
+{
+public:
+ VISITABLE_STATEMENT();
+
+ void SetScopeVars(std::vector<std::pair<std::string, ExpressionEvaluatorPtr<>>> vars)
+ {
+ m_scopeVars = std::move(vars);
+ }
+ void SetMainBody(RendererPtr renderer)
+ {
+ m_mainBody = std::move(renderer);
+ }
+
+ void Render(OutStream &os, RenderContext &values) override;
+ bool IsEqual(const IComparable& other) const override
+ {
+ auto* val = dynamic_cast<const WithStatement*>(&other);
+ if (!val)
+ return false;
+ if (m_scopeVars != val->m_scopeVars)
+ return false;
+ if (m_mainBody != val->m_mainBody)
+ return false;
+ return true;
+ }
+private:
+ std::vector<std::pair<std::string, ExpressionEvaluatorPtr<>>> m_scopeVars;
+ RendererPtr m_mainBody;
+};
+
+class FilterStatement : public Statement
+{
+public:
+ VISITABLE_STATEMENT();
+
+ explicit FilterStatement(ExpressionEvaluatorPtr<ExpressionFilter> expr)
+ : m_expr(std::move(expr)) {}
+
+ void SetBody(RendererPtr renderer)
+ {
+ m_body = std::move(renderer);
+ }
+
+ void Render(OutStream &, RenderContext &) override;
+
+ bool IsEqual(const IComparable& other) const override
+ {
+ auto* val = dynamic_cast<const FilterStatement*>(&other);
+ if (!val)
+ return false;
+ if (m_expr != val->m_expr)
+ return false;
+ if (m_body != val->m_body)
+ return false;
+ return true;
+ }
+private:
+ ExpressionEvaluatorPtr<ExpressionFilter> m_expr;
+ RendererPtr m_body;
+};
+
+} // namespace jinja2
+
+#endif // JINJA2CPP_SRC_STATEMENTS_H
diff --git a/contrib/libs/jinja2cpp/src/string_converter_filter.cpp b/contrib/libs/jinja2cpp/src/string_converter_filter.cpp
new file mode 100644
index 0000000000..574fbe0464
--- /dev/null
+++ b/contrib/libs/jinja2cpp/src/string_converter_filter.cpp
@@ -0,0 +1,395 @@
+#include "filters.h"
+#include "testers.h"
+#include "value_visitors.h"
+#include "value_helpers.h"
+
+#include <algorithm>
+#include <numeric>
+#include <regex>
+#include <sstream>
+
+#include <boost/algorithm/string/trim_all.hpp>
+#include <boost/algorithm/string/replace.hpp>
+
+namespace ba = boost::algorithm;
+
+namespace jinja2
+{
+
+namespace filters
+{
+
+template<typename D>
+struct StringEncoder : public visitors::BaseVisitor<TargetString>
+{
+ using BaseVisitor::operator();
+
+ template<typename CharT>
+ TargetString operator() (const std::basic_string<CharT>& str) const
+ {
+ std::basic_string<CharT> result;
+
+ for (auto& ch : str)
+ {
+ static_cast<const D*>(this)->EncodeChar(ch, [&result](auto ... chs) {AppendChar(result, chs...);});
+ }
+
+ return TargetString(std::move(result));
+ }
+
+ template<typename CharT>
+ TargetString operator() (const std::basic_string_view<CharT>& str) const
+ {
+ std::basic_string<CharT> result;
+
+ for (auto& ch : str)
+ {
+ static_cast<const D*>(this)->EncodeChar(ch, [&result](auto ... chs) {AppendChar(result, chs...);});
+ }
+
+ return TargetString(std::move(result));
+ }
+
+ template<typename Str, typename CharT>
+ static void AppendChar(Str& str, CharT ch)
+ {
+ str.push_back(static_cast<typename Str::value_type>(ch));
+ }
+ template<typename Str, typename CharT, typename ... Args>
+ static void AppendChar(Str& str, CharT ch, Args ... chs)
+ {
+ str.push_back(static_cast<typename Str::value_type>(ch));
+ AppendChar(str, chs...);
+ }
+};
+
+template<typename Fn>
+struct GenericStringEncoder : public StringEncoder<GenericStringEncoder<Fn>>
+{
+ GenericStringEncoder(Fn fn) : m_fn(std::move(fn)) {}
+
+ template<typename CharT, typename AppendFn>
+ void EncodeChar(CharT ch, AppendFn&& fn) const
+ {
+ m_fn(ch, std::forward<AppendFn>(fn));
+ }
+
+ mutable Fn m_fn;
+};
+
+struct UrlStringEncoder : public StringEncoder<UrlStringEncoder>
+{
+ template<typename CharT, typename Fn>
+ void EncodeChar(CharT ch, Fn&& fn) const
+ {
+ enum EncodeStyle
+ {
+ None,
+ Percent
+ };
+
+ EncodeStyle encStyle = None;
+ switch (ch)
+ {
+ case ' ':
+ fn('+');
+ return;
+ case '+': case '\"': case '%': case '-':
+ case '!': case '#': case '$': case '&':
+ case '\'': case '(': case ')': case '*':
+ case ',': case '/': case ':': case ';':
+ case '=': case '?': case '@': case '[':
+ case ']':
+ encStyle = Percent;
+ break;
+ default:
+ if (AsUnsigned(ch) > 0x7f)
+ encStyle = Percent;
+ break;
+ }
+
+ if (encStyle == None)
+ {
+ fn(ch);
+ return;
+ }
+ union
+ {
+ uint32_t intCh;
+ uint8_t chars[4];
+ };
+ intCh = AsUnsigned(ch);
+ if (intCh > 0xffffff)
+ DoPercentEncoding(chars[3], fn);
+ if (intCh > 0xffff)
+ DoPercentEncoding(chars[2], fn);
+ if (intCh > 0xff)
+ DoPercentEncoding(chars[1], fn);
+ DoPercentEncoding(chars[0], fn);
+ }
+
+ template<typename Fn>
+ void DoPercentEncoding(uint8_t ch, Fn&& fn) const
+ {
+ char chars[] = "0123456789ABCDEF";
+ int ch1 = static_cast<int>(chars[(ch & 0xf0) >> 4]);
+ int ch2 = static_cast<int>(chars[ch & 0x0f]);
+ fn('%', ch1, ch2);
+ }
+
+ template<typename Ch, size_t SZ>
+ struct ToUnsigned;
+
+ template<typename Ch>
+ struct ToUnsigned<Ch, 1>
+ {
+ static auto Cast(Ch ch) {return static_cast<uint8_t>(ch);}
+ };
+
+ template<typename Ch>
+ struct ToUnsigned<Ch, 2>
+ {
+ static auto Cast(Ch ch) {return static_cast<uint16_t>(ch);}
+ };
+
+ template<typename Ch>
+ struct ToUnsigned<Ch, 4>
+ {
+ static auto Cast(Ch ch) {return static_cast<uint32_t>(ch);}
+ };
+
+ template<typename Ch>
+ auto AsUnsigned(Ch ch) const
+ {
+ return static_cast<uint32_t>(ToUnsigned<Ch, sizeof(Ch)>::Cast(ch));
+ }
+};
+
+StringConverter::StringConverter(FilterParams params, StringConverter::Mode mode)
+ : m_mode(mode)
+{
+ switch (m_mode)
+ {
+ case ReplaceMode:
+ ParseParams({{"old", true}, {"new", true}, {"count", false, static_cast<int64_t>(0)}}, params);
+ break;
+ case TruncateMode:
+ ParseParams({{"length", false, static_cast<int64_t>(255)}, {"killwords", false, false}, {"end", false, std::string("...")}, {"leeway", false}}, params);
+ break;
+ case CenterMode:
+ ParseParams({{"width", false, static_cast<int64_t>(80)}}, params);
+ break;
+ default: break;
+ }
+}
+
+InternalValue StringConverter::Filter(const InternalValue& baseVal, RenderContext& context)
+{
+ TargetString result;
+
+ auto isAlpha = ba::is_alpha();
+ auto isAlNum = ba::is_alnum();
+
+ switch (m_mode)
+ {
+ case TrimMode:
+ result = ApplyStringConverter(baseVal, [](auto strView) -> TargetString {
+ auto str = sv_to_string(strView);
+ ba::trim_all(str);
+ return TargetString(str);
+ });
+ break;
+ case TitleMode:
+ result = ApplyStringConverter<GenericStringEncoder>(baseVal, [isDelim = true, &isAlpha, &isAlNum](auto ch, auto&& fn) mutable {
+ if (isDelim && isAlpha(ch))
+ {
+ isDelim = false;
+ fn(std::toupper(ch, std::locale()));
+ return;
+ }
+
+ isDelim = !isAlNum(ch);
+ fn(ch);
+ });
+ break;
+ case WordCountMode:
+ {
+ int64_t wc = 0;
+ ApplyStringConverter<GenericStringEncoder>(baseVal, [isDelim = true, &wc, &isAlNum](auto ch, auto&&) mutable {
+ if (isDelim && isAlNum(ch))
+ {
+ isDelim = false;
+ wc ++;
+ return;
+ }
+ isDelim = !isAlNum(ch);
+ });
+ return InternalValue(wc);
+ }
+ case UpperMode:
+ result = ApplyStringConverter<GenericStringEncoder>(baseVal, [&isAlpha](auto ch, auto&& fn) mutable {
+ if (isAlpha(ch))
+ fn(std::toupper(ch, std::locale()));
+ else
+ fn(ch);
+ });
+ break;
+ case LowerMode:
+ result = ApplyStringConverter<GenericStringEncoder>(baseVal, [&isAlpha](auto ch, auto&& fn) mutable {
+ if (isAlpha(ch))
+ fn(std::tolower(ch, std::locale()));
+ else
+ fn(ch);
+ });
+ break;
+ case ReplaceMode:
+ result = ApplyStringConverter(baseVal, [this, &context](auto srcStr) -> TargetString {
+ std::decay_t<decltype(srcStr)> emptyStrView;
+ using CharT = typename decltype(emptyStrView)::value_type;
+ std::basic_string<CharT> emptyStr;
+ auto oldStr = GetAsSameString(srcStr, this->GetArgumentValue("old", context)).value_or(emptyStr);
+ auto newStr = GetAsSameString(srcStr, this->GetArgumentValue("new", context)).value_or(emptyStr);
+ auto count = ConvertToInt(this->GetArgumentValue("count", context));
+ auto str = sv_to_string(srcStr);
+ if (count == 0)
+ ba::replace_all(str, oldStr, newStr);
+ else
+ {
+ for (int64_t n = 0; n < count; ++ n)
+ ba::replace_first(str, oldStr, newStr);
+ }
+ return str;
+ });
+ break;
+ case TruncateMode:
+ result = ApplyStringConverter(baseVal, [this, &context, &isAlNum](auto srcStr) -> TargetString {
+ std::decay_t<decltype(srcStr)> emptyStrView;
+ using CharT = typename decltype(emptyStrView)::value_type;
+ std::basic_string<CharT> emptyStr;
+ auto length = ConvertToInt(this->GetArgumentValue("length", context));
+ auto killWords = ConvertToBool(this->GetArgumentValue("killwords", context));
+ auto end = GetAsSameString(srcStr, this->GetArgumentValue("end", context));
+ auto leeway = ConvertToInt(this->GetArgumentValue("leeway", context), 5);
+ if (static_cast<long long int>(srcStr.size()) <= length)
+ return sv_to_string(srcStr);
+
+ auto str = sv_to_string(srcStr);
+
+ if (killWords)
+ {
+ if (static_cast<long long int>(str.size()) > (length + leeway))
+ {
+ str.erase(str.begin() + static_cast<std::ptrdiff_t>(length), str.end());
+ str += end.value_or(emptyStr);
+ }
+ return str;
+ }
+
+ auto p = str.begin() + static_cast<std::ptrdiff_t>(length);
+ if (leeway != 0)
+ {
+ for (; leeway != 0 && p != str.end() && isAlNum(*p); -- leeway, ++ p);
+ if (p == str.end())
+ return TargetString(str);
+ }
+
+ if (isAlNum(*p))
+ {
+ for (; p != str.begin() && isAlNum(*p); -- p);
+ }
+ str.erase(p, str.end());
+ ba::trim_right(str);
+ str += end.value_or(emptyStr);
+
+ return TargetString(std::move(str));
+ });
+ break;
+ case UrlEncodeMode:
+ result = Apply<UrlStringEncoder>(baseVal);
+ break;
+ case CapitalMode:
+ result = ApplyStringConverter<GenericStringEncoder>(baseVal, [isFirstChar = true, &isAlpha](auto ch, auto&& fn) mutable {
+ if (isAlpha(ch))
+ {
+ if (isFirstChar)
+ fn(std::toupper(ch, std::locale()));
+ else
+ fn(std::tolower(ch, std::locale()));
+ }
+ else
+ fn(ch);
+
+ isFirstChar = false;
+ });
+ break;
+ case EscapeHtmlMode:
+ result = ApplyStringConverter<GenericStringEncoder>(baseVal, [](auto ch, auto&& fn) mutable {
+ switch(ch)
+ {
+ case '<':
+ fn('&', 'l', 't', ';');
+ break;
+ case '>':
+ fn('&', 'g', 't', ';');
+ break;
+ case '&':
+ fn('&', 'a', 'm', 'p', ';');
+ break;
+ case '\'':
+ fn('&', '#', '3', '9', ';');
+ break;
+ case '\"':
+ fn('&', '#', '3', '4', ';');
+ break;
+ default:
+ fn(ch);
+ break;
+ }
+ });
+ break;
+ case StriptagsMode:
+ result = ApplyStringConverter(baseVal, [](auto srcStr) -> TargetString {
+ auto str = sv_to_string(srcStr);
+ using StringT = decltype(str);
+ using CharT = typename StringT::value_type;
+ static const std::basic_regex<CharT> STRIPTAGS_RE(UNIVERSAL_STR("(<!--.*?-->|<[^>]*>)").GetValueStr<CharT>());
+ str = std::regex_replace(str, STRIPTAGS_RE, UNIVERSAL_STR("").GetValueStr<CharT>());
+ ba::trim_all(str);
+ static const StringT html_entities [] {
+ UNIVERSAL_STR("&amp;").GetValueStr<CharT>(), UNIVERSAL_STR("&").GetValueStr<CharT>(),
+ UNIVERSAL_STR("&apos;").GetValueStr<CharT>(), UNIVERSAL_STR("\'").GetValueStr<CharT>(),
+ UNIVERSAL_STR("&gt;").GetValueStr<CharT>(), UNIVERSAL_STR(">").GetValueStr<CharT>(),
+ UNIVERSAL_STR("&lt;").GetValueStr<CharT>(), UNIVERSAL_STR("<").GetValueStr<CharT>(),
+ UNIVERSAL_STR("&quot;").GetValueStr<CharT>(), UNIVERSAL_STR("\"").GetValueStr<CharT>(),
+ UNIVERSAL_STR("&#39;").GetValueStr<CharT>(), UNIVERSAL_STR("\'").GetValueStr<CharT>(),
+ UNIVERSAL_STR("&#34;").GetValueStr<CharT>(), UNIVERSAL_STR("\"").GetValueStr<CharT>(),
+ };
+ for (auto it = std::begin(html_entities), end = std::end(html_entities); it < end; it += 2)
+ {
+ ba::replace_all(str, *it, *(it + 1));
+ }
+ return str;
+ });
+ break;
+ case CenterMode:
+ result = ApplyStringConverter(baseVal, [this, &context](auto srcStr) -> TargetString {
+ auto width = ConvertToInt(this->GetArgumentValue("width", context));
+ auto str = sv_to_string(srcStr);
+ auto string_length = static_cast<long long int>(str.size());
+ if (string_length >= width)
+ return str;
+ auto whitespaces = width - string_length;
+ str = decltype(str)(static_cast<std::string::size_type>(whitespaces + 1) / 2, ' ') + str;
+ str.append(static_cast<std::string::size_type>(whitespaces / 2), ' ');
+ return TargetString(std::move(str));
+ });
+ break;
+ default:
+ break;
+ }
+
+ return std::move(result);
+}
+
+} // namespace filters
+} // namespace jinja2
diff --git a/contrib/libs/jinja2cpp/src/template.cpp b/contrib/libs/jinja2cpp/src/template.cpp
new file mode 100644
index 0000000000..2734387508
--- /dev/null
+++ b/contrib/libs/jinja2cpp/src/template.cpp
@@ -0,0 +1,190 @@
+#include "jinja2cpp/template.h"
+#include "template_impl.h"
+
+#include <fmt/format.h>
+
+#include <fstream>
+#include <sstream>
+
+namespace jinja2
+{
+bool operator==(const Template& lhs, const Template& rhs)
+{
+ return lhs.IsEqual(rhs);
+}
+
+bool operator==(const TemplateW& lhs, const TemplateW& rhs)
+{
+ return lhs.IsEqual(rhs);
+}
+
+template<typename CharT>
+auto GetImpl(std::shared_ptr<ITemplateImpl> impl)
+{
+ return static_cast<TemplateImpl<CharT>*>(impl.get());
+}
+
+Template::Template(TemplateEnv* env)
+ : m_impl(new TemplateImpl<char>(env))
+{
+
+}
+
+Template::~Template() = default;
+
+Result<void> Template::Load(const char* tpl, std::string tplName)
+{
+ std::string t(tpl);
+ auto result = GetImpl<char>(m_impl)->Load(std::move(t), std::move(tplName));
+ return !result ? Result<void>() : nonstd::make_unexpected(std::move(result.get()));
+}
+
+Result<void> Template::Load(const std::string& str, std::string tplName)
+{
+ auto result = GetImpl<char>(m_impl)->Load(str, std::move(tplName));
+ return !result ? Result<void>() : nonstd::make_unexpected(std::move(result.get()));
+}
+
+Result<void> Template::Load(std::istream& stream, std::string tplName)
+{
+ std::string t;
+
+ while (stream.good() && !stream.eof())
+ {
+ char buff[0x10000];
+ stream.read(buff, sizeof(buff));
+ auto read = stream.gcount();
+ if (read)
+ t.append(buff, buff + read);
+ }
+
+ auto result = GetImpl<char>(m_impl)->Load(std::move(t), std::move(tplName));
+ return !result ? Result<void>() : nonstd::make_unexpected(std::move(result.get()));
+}
+
+Result<void> Template::LoadFromFile(const std::string& fileName)
+{
+ std::ifstream file(fileName);
+
+ if (!file.good())
+ return Result<void>();
+
+ return Load(file, fileName);
+}
+
+Result<void> Template::Render(std::ostream& os, const jinja2::ValuesMap& params)
+{
+ std::string buffer;
+ auto result = GetImpl<char>(m_impl)->Render(buffer, params);
+
+ if (!result)
+ os.write(buffer.data(), buffer.size());
+
+ return !result ? Result<void>() : nonstd::make_unexpected(std::move(result.get()));
+}
+
+Result<std::string> Template::RenderAsString(const jinja2::ValuesMap& params)
+{
+ std::string buffer;
+ auto result = GetImpl<char>(m_impl)->Render(buffer, params);
+ return !result ? Result<std::string>(std::move(buffer)) : Result<std::string>(nonstd::make_unexpected(std::move(result.get())));;
+}
+
+Result<GenericMap> Template::GetMetadata()
+{
+ return GetImpl<char>(m_impl)->GetMetadata();
+}
+
+Result<MetadataInfo<char>> Template::GetMetadataRaw()
+{
+ return GetImpl<char>(m_impl)->GetMetadataRaw();
+}
+
+bool Template::IsEqual(const Template& other) const
+{
+ return m_impl == other.m_impl;
+}
+
+TemplateW::TemplateW(TemplateEnv* env)
+ : m_impl(new TemplateImpl<wchar_t>(env))
+{
+
+}
+
+TemplateW::~TemplateW() = default;
+
+ResultW<void> TemplateW::Load(const wchar_t* tpl, std::string tplName)
+{
+ std::wstring t(tpl);
+ auto result = GetImpl<wchar_t>(m_impl)->Load(t, std::move(tplName));
+ return !result ? ResultW<void>() : nonstd::make_unexpected(std::move(result.get()));
+}
+
+ResultW<void> TemplateW::Load(const std::wstring& str, std::string tplName)
+{
+ auto result = GetImpl<wchar_t>(m_impl)->Load(str, std::move(tplName));
+ return !result ? ResultW<void>() : nonstd::make_unexpected(std::move(result.get()));
+}
+
+ResultW<void> TemplateW::Load(std::wistream& stream, std::string tplName)
+{
+ std::wstring t;
+
+ while (stream.good() && !stream.eof())
+ {
+ wchar_t buff[0x10000];
+ stream.read(buff, sizeof(buff));
+ auto read = stream.gcount();
+ if (read)
+ t.append(buff, buff + read);
+ }
+
+ auto result = GetImpl<wchar_t>(m_impl)->Load(t, std::move(tplName));
+ return !result ? ResultW<void>() : nonstd::make_unexpected(std::move(result.get()));
+}
+
+ResultW<void> TemplateW::LoadFromFile(const std::string& fileName)
+{
+ std::wifstream file(fileName);
+
+ if (!file.good())
+ return ResultW<void>();
+
+ return Load(file, fileName);
+}
+
+ResultW<void> TemplateW::Render(std::wostream& os, const jinja2::ValuesMap& params)
+{
+ std::wstring buffer;
+ auto result = GetImpl<wchar_t>(m_impl)->Render(buffer, params);
+ if (!result)
+ os.write(buffer.data(), buffer.size());
+ return !result ? ResultW<void>() : ResultW<void>(nonstd::make_unexpected(std::move(result.get())));
+}
+
+ResultW<std::wstring> TemplateW::RenderAsString(const jinja2::ValuesMap& params)
+{
+ std::wstring buffer;
+ auto result = GetImpl<wchar_t>(m_impl)->Render(buffer, params);
+
+ return !result ? buffer : ResultW<std::wstring>(nonstd::make_unexpected(std::move(result.get())));
+}
+
+ResultW<GenericMap> TemplateW::GetMetadata()
+{
+ return GenericMap();
+ // GetImpl<wchar_t>(m_impl)->GetMetadata();
+}
+
+ResultW<MetadataInfo<wchar_t>> TemplateW::GetMetadataRaw()
+{
+ return MetadataInfo<wchar_t>();
+ // GetImpl<wchar_t>(m_impl)->GetMetadataRaw();
+ ;
+}
+bool TemplateW::IsEqual(const TemplateW& other) const
+{
+ return m_impl == other.m_impl;
+}
+
+} // namespace jinja2
diff --git a/contrib/libs/jinja2cpp/src/template_env.cpp b/contrib/libs/jinja2cpp/src/template_env.cpp
new file mode 100644
index 0000000000..239a4f02e1
--- /dev/null
+++ b/contrib/libs/jinja2cpp/src/template_env.cpp
@@ -0,0 +1,95 @@
+#include <jinja2cpp/template.h>
+#include <jinja2cpp/template_env.h>
+
+namespace jinja2
+{
+template<typename CharT>
+struct TemplateFunctions;
+
+template<>
+struct TemplateFunctions<char>
+{
+ using ResultType = nonstd::expected<Template, ErrorInfo>;
+ static Template CreateTemplate(TemplateEnv* env) { return Template(env); }
+ static auto LoadFile(const std::string& fileName, const IFilesystemHandler* fs) { return fs->OpenStream(fileName); }
+};
+
+template<>
+struct TemplateFunctions<wchar_t>
+{
+ using ResultType = nonstd::expected<TemplateW, ErrorInfoW>;
+ static TemplateW CreateTemplate(TemplateEnv* env) { return TemplateW(env); }
+ static auto LoadFile(const std::string& fileName, const IFilesystemHandler* fs) { return fs->OpenWStream(fileName); }
+};
+
+template<typename CharT, typename T, typename Cache>
+auto TemplateEnv::LoadTemplateImpl(TemplateEnv* env, std::string fileName, const T& filesystemHandlers, Cache& cache)
+{
+ using Functions = TemplateFunctions<CharT>;
+ using ResultType = typename Functions::ResultType;
+ using ErrorType = typename ResultType::error_type;
+ auto tpl = Functions::CreateTemplate(env);
+
+ {
+ std::shared_lock<std::shared_timed_mutex> l(m_guard);
+ auto p = cache.find(fileName);
+ if (p != cache.end())
+ {
+ if (m_settings.autoReload)
+ {
+ auto lastModified = p->second.handler->GetLastModificationDate(fileName);
+ if (!lastModified || (p->second.lastModification && lastModified.value() <= p->second.lastModification.value()))
+ return ResultType(p->second.tpl);
+ }
+ else
+ return ResultType(p->second.tpl);
+ }
+ }
+
+ for (auto& fh : filesystemHandlers)
+ {
+ if (!fh.prefix.empty() && fileName.find(fh.prefix) != 0)
+ continue;
+
+ auto stream = Functions::LoadFile(fileName, fh.handler.get());
+ if (stream)
+ {
+ auto res = tpl.Load(*stream, fileName);
+ if (!res)
+ return ResultType(res.get_unexpected());
+
+ if (m_settings.cacheSize != 0)
+ {
+ auto lastModified = fh.handler->GetLastModificationDate(fileName);
+ std::unique_lock<std::shared_timed_mutex> l(m_guard);
+ auto& cacheEntry = cache[fileName];
+ cacheEntry.tpl = tpl;
+ cacheEntry.handler = fh.handler;
+ cacheEntry.lastModification = lastModified;
+ }
+
+ return ResultType(tpl);
+ }
+ }
+
+ typename ErrorType::Data errorData;
+ errorData.code = ErrorCode::FileNotFound;
+ errorData.srcLoc.col = 1;
+ errorData.srcLoc.line = 1;
+ errorData.srcLoc.fileName = "";
+ errorData.extraParams.push_back(Value(fileName));
+
+ return ResultType(nonstd::make_unexpected(ErrorType(errorData)));
+}
+
+nonstd::expected<Template, ErrorInfo> TemplateEnv::LoadTemplate(std::string fileName)
+{
+ return LoadTemplateImpl<char>(this, std::move(fileName), m_filesystemHandlers, m_templateCache);
+}
+
+nonstd::expected<TemplateW, ErrorInfoW> TemplateEnv::LoadTemplateW(std::string fileName)
+{
+ return LoadTemplateImpl<wchar_t>(this, std::move(fileName), m_filesystemHandlers, m_templateWCache);
+}
+
+} // namespace jinja2
diff --git a/contrib/libs/jinja2cpp/src/template_impl.h b/contrib/libs/jinja2cpp/src/template_impl.h
new file mode 100644
index 0000000000..cc9c9a2a42
--- /dev/null
+++ b/contrib/libs/jinja2cpp/src/template_impl.h
@@ -0,0 +1,487 @@
+#ifndef JINJA2CPP_SRC_TEMPLATE_IMPL_H
+#define JINJA2CPP_SRC_TEMPLATE_IMPL_H
+
+#include "internal_value.h"
+#include "jinja2cpp/binding/rapid_json.h"
+#include "jinja2cpp/template_env.h"
+#include "jinja2cpp/value.h"
+#include "renderer.h"
+#include "template_parser.h"
+#include "value_visitors.h"
+
+#include <boost/optional.hpp>
+#include <boost/predef/other/endian.h>
+#include <contrib/restricted/expected-lite/include/nonstd/expected.hpp>
+#include <rapidjson/error/en.h>
+
+#include <string>
+
+namespace jinja2
+{
+namespace detail
+{
+template<size_t Sz>
+struct RapidJsonEncodingType;
+
+template<>
+struct RapidJsonEncodingType<1>
+{
+ using type = rapidjson::UTF8<char>;
+};
+
+#ifdef BOOST_ENDIAN_BIG_BYTE
+template<>
+struct RapidJsonEncodingType<2>
+{
+ using type = rapidjson::UTF16BE<wchar_t>;
+};
+
+template<>
+struct RapidJsonEncodingType<4>
+{
+ using type = rapidjson::UTF32BE<wchar_t>;
+};
+#else
+template<>
+struct RapidJsonEncodingType<2>
+{
+ using type = rapidjson::UTF16LE<wchar_t>;
+};
+
+template<>
+struct RapidJsonEncodingType<4>
+{
+ using type = rapidjson::UTF32LE<wchar_t>;
+};
+#endif
+} // namespace detail
+
+extern void SetupGlobals(InternalValueMap& globalParams);
+
+class ITemplateImpl
+{
+public:
+ virtual ~ITemplateImpl() = default;
+};
+
+
+template<typename U>
+struct TemplateLoader;
+
+template<>
+struct TemplateLoader<char>
+{
+ static auto Load(const std::string& fileName, TemplateEnv* env)
+ {
+ return env->LoadTemplate(fileName);
+ }
+};
+
+template<>
+struct TemplateLoader<wchar_t>
+{
+ static auto Load(const std::string& fileName, TemplateEnv* env)
+ {
+ return env->LoadTemplateW(fileName);
+ }
+};
+
+template<typename CharT>
+class GenericStreamWriter : public OutStream::StreamWriter
+{
+public:
+ explicit GenericStreamWriter(std::basic_string<CharT>& os)
+ : m_os(os)
+ {}
+
+ // StreamWriter interface
+ void WriteBuffer(const void* ptr, size_t length) override
+ {
+ m_os.append(reinterpret_cast<const CharT*>(ptr), length);
+ }
+ void WriteValue(const InternalValue& val) override
+ {
+ Apply<visitors::ValueRenderer<CharT>>(val, m_os);
+ }
+
+private:
+ std::basic_string<CharT>& m_os;
+};
+
+template<typename CharT>
+class StringStreamWriter : public OutStream::StreamWriter
+{
+public:
+ explicit StringStreamWriter(std::basic_string<CharT>* targetStr)
+ : m_targetStr(targetStr)
+ {}
+
+ // StreamWriter interface
+ void WriteBuffer(const void* ptr, size_t length) override
+ {
+ m_targetStr->append(reinterpret_cast<const CharT*>(ptr), length);
+ // m_os.write(reinterpret_cast<const CharT*>(ptr), length);
+ }
+ void WriteValue(const InternalValue& val) override
+ {
+ Apply<visitors::ValueRenderer<CharT>>(val, *m_targetStr);
+ }
+
+private:
+ std::basic_string<CharT>* m_targetStr;
+};
+
+template<typename ErrorTpl1, typename ErrorTpl2>
+struct ErrorConverter;
+
+template<typename CharT1, typename CharT2>
+struct ErrorConverter<ErrorInfoTpl<CharT1>, ErrorInfoTpl<CharT2>>
+{
+ static ErrorInfoTpl<CharT1> Convert(const ErrorInfoTpl<CharT2>& srcError)
+ {
+ typename ErrorInfoTpl<CharT1>::Data errorData;
+ errorData.code = srcError.GetCode();
+ errorData.srcLoc = srcError.GetErrorLocation();
+ errorData.locationDescr = ConvertString<std::basic_string<CharT1>>(srcError.GetLocationDescr());
+ errorData.extraParams = srcError.GetExtraParams();
+
+ return ErrorInfoTpl<CharT1>(errorData);
+ }
+};
+
+template<typename CharT>
+struct ErrorConverter<ErrorInfoTpl<CharT>, ErrorInfoTpl<CharT>>
+{
+ static const ErrorInfoTpl<CharT>& Convert(const ErrorInfoTpl<CharT>& srcError)
+ {
+ return srcError;
+ }
+};
+
+template<typename CharT>
+inline bool operator==(const MetadataInfo<CharT>& lhs, const MetadataInfo<CharT>& rhs)
+{
+ if (lhs.metadata != rhs.metadata)
+ return false;
+ if (lhs.metadataType != rhs.metadataType)
+ return false;
+ if (lhs.location != rhs.location)
+ return false;
+ return true;
+}
+
+template<typename CharT>
+inline bool operator!=(const MetadataInfo<CharT>& lhs, const MetadataInfo<CharT>& rhs)
+{
+ return !(lhs == rhs);
+}
+
+inline bool operator==(const TemplateEnv& lhs, const TemplateEnv& rhs)
+{
+ return lhs.IsEqual(rhs);
+}
+inline bool operator!=(const TemplateEnv& lhs, const TemplateEnv& rhs)
+{
+ return !(lhs == rhs);
+}
+
+inline bool operator==(const SourceLocation& lhs, const SourceLocation& rhs)
+{
+ if (lhs.fileName != rhs.fileName)
+ return false;
+ if (lhs.line != rhs.line)
+ return false;
+ if (lhs.col != rhs.col)
+ return false;
+ return true;
+}
+inline bool operator!=(const SourceLocation& lhs, const SourceLocation& rhs)
+{
+ return !(lhs == rhs);
+}
+
+template<typename CharT>
+class TemplateImpl : public ITemplateImpl
+{
+public:
+ using ThisType = TemplateImpl<CharT>;
+
+ explicit TemplateImpl(TemplateEnv* env)
+ : m_env(env)
+ {
+ if (env)
+ m_settings = env->GetSettings();
+ }
+
+ auto GetRenderer() const {return m_renderer;}
+ auto GetTemplateName() const {};
+
+ boost::optional<ErrorInfoTpl<CharT>> Load(std::basic_string<CharT> tpl, std::string tplName)
+ {
+ m_template = std::move(tpl);
+ m_templateName = tplName.empty() ? std::string("noname.j2tpl") : std::move(tplName);
+ TemplateParser<CharT> parser(&m_template, m_settings, m_env, m_templateName);
+
+ auto parseResult = parser.Parse();
+ if (!parseResult)
+ return parseResult.error()[0];
+
+ m_renderer = *parseResult;
+ m_metadataInfo = parser.GetMetadataInfo();
+ return boost::optional<ErrorInfoTpl<CharT>>();
+ }
+
+ boost::optional<ErrorInfoTpl<CharT>> Render(std::basic_string<CharT>& os, const ValuesMap& params)
+ {
+ boost::optional<ErrorInfoTpl<CharT>> normalResult;
+
+ if (!m_renderer)
+ {
+ typename ErrorInfoTpl<CharT>::Data errorData;
+ errorData.code = ErrorCode::TemplateNotParsed;
+ errorData.srcLoc.col = 1;
+ errorData.srcLoc.line = 1;
+ errorData.srcLoc.fileName = "<unknown file>";
+
+ return ErrorInfoTpl<CharT>(errorData);
+ }
+
+ try
+ {
+ InternalValueMap extParams;
+ InternalValueMap intParams;
+
+ auto convertFn = [&intParams](const auto& params) {
+ for (auto& ip : params)
+ {
+ auto valRef = &ip.second.data();
+ auto newParam = visit(visitors::InputValueConvertor(false, true), *valRef);
+ if (!newParam)
+ intParams[ip.first] = ValueRef(static_cast<const Value&>(*valRef));
+ else
+ intParams[ip.first] = newParam.get();
+ }
+ };
+
+ if (m_env)
+ {
+ m_env->ApplyGlobals(convertFn);
+ std::swap(extParams, intParams);
+ }
+
+ convertFn(params);
+ SetupGlobals(extParams);
+
+ RendererCallback callback(this);
+ RenderContext context(intParams, extParams, &callback);
+ InitRenderContext(context);
+ OutStream outStream([writer = GenericStreamWriter<CharT>(os)]() mutable -> OutStream::StreamWriter* {return &writer;});
+ m_renderer->Render(outStream, context);
+ }
+ catch (const ErrorInfoTpl<char>& error)
+ {
+ return ErrorConverter<ErrorInfoTpl<CharT>, ErrorInfoTpl<char>>::Convert(error);
+ }
+ catch (const ErrorInfoTpl<wchar_t>& error)
+ {
+ return ErrorConverter<ErrorInfoTpl<CharT>, ErrorInfoTpl<wchar_t>>::Convert(error);
+ }
+ catch (const std::exception& ex)
+ {
+ typename ErrorInfoTpl<CharT>::Data errorData;
+ errorData.code = ErrorCode::UnexpectedException;
+ errorData.srcLoc.col = 1;
+ errorData.srcLoc.line = 1;
+ errorData.srcLoc.fileName = m_templateName;
+ errorData.extraParams.push_back(Value(std::string(ex.what())));
+
+ return ErrorInfoTpl<CharT>(errorData);
+ }
+
+ return normalResult;
+ }
+
+ InternalValueMap& InitRenderContext(RenderContext& context)
+ {
+ auto& curScope = context.GetCurrentScope();
+ return curScope;
+ }
+
+ using TplLoadResultType = std::variant<EmptyValue,
+ nonstd::expected<std::shared_ptr<TemplateImpl<char>>, ErrorInfo>,
+ nonstd::expected<std::shared_ptr<TemplateImpl<wchar_t>>, ErrorInfoW>>;
+
+ using TplOrError = nonstd::expected<std::shared_ptr<TemplateImpl<CharT>>, ErrorInfoTpl<CharT>>;
+
+ TplLoadResultType LoadTemplate(const std::string& fileName)
+ {
+ if (!m_env)
+ return TplLoadResultType(EmptyValue());
+
+ auto tplWrapper = TemplateLoader<CharT>::Load(fileName, m_env);
+ if (!tplWrapper)
+ return TplLoadResultType(TplOrError(tplWrapper.get_unexpected()));
+
+ return TplLoadResultType(TplOrError(std::static_pointer_cast<ThisType>(tplWrapper.value().m_impl)));
+ }
+
+ TplLoadResultType LoadTemplate(const InternalValue& fileName)
+ {
+ auto name = GetAsSameString(std::string(), fileName);
+ if (!name)
+ {
+ typename ErrorInfoTpl<CharT>::Data errorData;
+ errorData.code = ErrorCode::InvalidTemplateName;
+ errorData.srcLoc.col = 1;
+ errorData.srcLoc.line = 1;
+ errorData.srcLoc.fileName = m_templateName;
+ errorData.extraParams.push_back(IntValue2Value(fileName));
+ return TplOrError(nonstd::make_unexpected(ErrorInfoTpl<CharT>(errorData)));
+ }
+
+ return LoadTemplate(name.value());
+ }
+
+ nonstd::expected<GenericMap, ErrorInfoTpl<CharT>> GetMetadata() const
+ {
+ auto& metadataString = m_metadataInfo.metadata;
+ if (metadataString.empty())
+ return GenericMap();
+
+ if (m_metadataInfo.metadataType == "json")
+ {
+ m_metadataJson = JsonDocumentType();
+ rapidjson::ParseResult res = m_metadataJson.value().Parse(metadataString.data(), metadataString.size());
+ if (!res)
+ {
+ typename ErrorInfoTpl<CharT>::Data errorData;
+ errorData.code = ErrorCode::MetadataParseError;
+ errorData.srcLoc = m_metadataInfo.location;
+ std::string jsonError = rapidjson::GetParseError_En(res.Code());
+ errorData.extraParams.push_back(Value(std::move(jsonError)));
+ return nonstd::make_unexpected(ErrorInfoTpl<CharT>(errorData));
+ }
+ m_metadata = std::move(std::get<GenericMap>(Reflect(m_metadataJson.value()).data()));
+ return m_metadata.value();
+ }
+ return GenericMap();
+ }
+
+ nonstd::expected<MetadataInfo<CharT>, ErrorInfoTpl<CharT>> GetMetadataRaw() const { return m_metadataInfo; }
+
+ bool operator==(const TemplateImpl<CharT>& other) const
+ {
+ if (m_env && other.m_env)
+ {
+ if (*m_env != *other.m_env)
+ return false;
+ }
+ if (m_settings != other.m_settings)
+ return false;
+ if (m_template != other.m_template)
+ return false;
+ if (m_renderer && other.m_renderer && !m_renderer->IsEqual(*other.m_renderer))
+ return false;
+ if (m_metadata != other.m_metadata)
+ return false;
+ if (m_metadataJson != other.m_metadataJson)
+ return false;
+ if (m_metadataInfo != other.m_metadataInfo)
+ return false;
+ return true;
+ }
+private:
+ void ThrowRuntimeError(ErrorCode code, ValuesList extraParams)
+ {
+ typename ErrorInfoTpl<CharT>::Data errorData;
+ errorData.code = code;
+ errorData.srcLoc.col = 1;
+ errorData.srcLoc.line = 1;
+ errorData.srcLoc.fileName = m_templateName;
+ errorData.extraParams = std::move(extraParams);
+
+ throw ErrorInfoTpl<CharT>(std::move(errorData));
+ }
+
+ class RendererCallback : public IRendererCallback
+ {
+ public:
+ explicit RendererCallback(ThisType* host)
+ : m_host(host)
+ {}
+
+ TargetString GetAsTargetString(const InternalValue& val) override
+ {
+ std::basic_string<CharT> os;
+ Apply<visitors::ValueRenderer<CharT>>(val, os);
+ return TargetString(std::move(os));
+ }
+
+ OutStream GetStreamOnString(TargetString& str) override
+ {
+ using string_t = std::basic_string<CharT>;
+ str = string_t();
+ return OutStream([writer = StringStreamWriter<CharT>(&std::get<string_t>(str))]() mutable -> OutStream::StreamWriter* { return &writer; });
+ }
+
+ std::variant<EmptyValue,
+ nonstd::expected<std::shared_ptr<TemplateImpl<char>>, ErrorInfo>,
+ nonstd::expected<std::shared_ptr<TemplateImpl<wchar_t>>, ErrorInfoW>> LoadTemplate(const std::string& fileName) const override
+ {
+ return m_host->LoadTemplate(fileName);
+ }
+
+ std::variant<EmptyValue,
+ nonstd::expected<std::shared_ptr<TemplateImpl<char>>, ErrorInfo>,
+ nonstd::expected<std::shared_ptr<TemplateImpl<wchar_t>>, ErrorInfoW>> LoadTemplate(const InternalValue& fileName) const override
+ {
+ return m_host->LoadTemplate(fileName);
+ }
+
+ void ThrowRuntimeError(ErrorCode code, ValuesList extraParams) override
+ {
+ m_host->ThrowRuntimeError(code, std::move(extraParams));
+ }
+
+ bool IsEqual(const IComparable& other) const override
+ {
+ auto* callback = dynamic_cast<const RendererCallback*>(&other);
+ if (!callback)
+ return false;
+ if (m_host && callback->m_host)
+ return *m_host == *(callback->m_host);
+ if ((!m_host && (callback->m_host)) || (m_host && !(callback->m_host)))
+ return false;
+ return true;
+ }
+ bool operator==(const IComparable& other) const
+ {
+ auto* callback = dynamic_cast<const RendererCallback*>(&other);
+ if (!callback)
+ return false;
+ if (m_host && callback->m_host)
+ return *m_host == *(callback->m_host);
+ if ((!m_host && (callback->m_host)) || (m_host && !(callback->m_host)))
+ return false;
+ return true;
+ }
+
+ private:
+ ThisType* m_host;
+ };
+private:
+ using JsonDocumentType = rapidjson::GenericDocument<typename detail::RapidJsonEncodingType<sizeof(CharT)>::type>;
+
+ TemplateEnv* m_env{};
+ Settings m_settings;
+ std::basic_string<CharT> m_template;
+ std::string m_templateName;
+ RendererPtr m_renderer;
+ mutable std::optional<GenericMap> m_metadata;
+ mutable std::optional<JsonDocumentType> m_metadataJson;
+ MetadataInfo<CharT> m_metadataInfo;
+};
+
+} // namespace jinja2
+
+#endif // JINJA2CPP_SRC_TEMPLATE_IMPL_H
diff --git a/contrib/libs/jinja2cpp/src/template_parser.cpp b/contrib/libs/jinja2cpp/src/template_parser.cpp
new file mode 100644
index 0000000000..bd09039341
--- /dev/null
+++ b/contrib/libs/jinja2cpp/src/template_parser.cpp
@@ -0,0 +1,972 @@
+#include "template_parser.h"
+#include "renderer.h"
+#include <boost/cast.hpp>
+
+namespace jinja2
+{
+
+StatementsParser::ParseResult StatementsParser::Parse(LexScanner& lexer, StatementInfoList& statementsInfo)
+{
+ Token tok = lexer.NextToken();
+ ParseResult result;
+
+ switch (lexer.GetAsKeyword(tok))
+ {
+ case Keyword::For:
+ result = ParseFor(lexer, statementsInfo, tok);
+ break;
+ case Keyword::Endfor:
+ result = ParseEndFor(lexer, statementsInfo, tok);
+ break;
+ case Keyword::If:
+ result = ParseIf(lexer, statementsInfo, tok);
+ break;
+ case Keyword::Else:
+ result = ParseElse(lexer, statementsInfo, tok);
+ break;
+ case Keyword::ElIf:
+ result = ParseElIf(lexer, statementsInfo, tok);
+ break;
+ case Keyword::EndIf:
+ result = ParseEndIf(lexer, statementsInfo, tok);
+ break;
+ case Keyword::Set:
+ result = ParseSet(lexer, statementsInfo, tok);
+ break;
+ case Keyword::EndSet:
+ result = ParseEndSet(lexer, statementsInfo, tok);
+ break;
+ case Keyword::Block:
+ result = ParseBlock(lexer, statementsInfo, tok);
+ break;
+ case Keyword::EndBlock:
+ result = ParseEndBlock(lexer, statementsInfo, tok);
+ break;
+ case Keyword::Extends:
+ result = ParseExtends(lexer, statementsInfo, tok);
+ break;
+ case Keyword::Macro:
+ result = ParseMacro(lexer, statementsInfo, tok);
+ break;
+ case Keyword::EndMacro:
+ result = ParseEndMacro(lexer, statementsInfo, tok);
+ break;
+ case Keyword::Call:
+ result = ParseCall(lexer, statementsInfo, tok);
+ break;
+ case Keyword::EndCall:
+ result = ParseEndCall(lexer, statementsInfo, tok);
+ break;
+ case Keyword::Include:
+ result = ParseInclude(lexer, statementsInfo, tok);
+ break;
+ case Keyword::Import:
+ result = ParseImport(lexer, statementsInfo, tok);
+ break;
+ case Keyword::From:
+ result = ParseFrom(lexer, statementsInfo, tok);
+ break;
+ case Keyword::Do:
+ if (!m_settings.extensions.Do)
+ return MakeParseError(ErrorCode::ExtensionDisabled, tok);
+ result = ParseDo(lexer, statementsInfo, tok);
+ break;
+ case Keyword::With:
+ result = ParseWith(lexer, statementsInfo, tok);
+ break;
+ case Keyword::EndWith:
+ result = ParseEndWith(lexer, statementsInfo, tok);
+ break;
+ case Keyword::Filter:
+ result = ParseFilter(lexer, statementsInfo, tok);
+ break;
+ case Keyword::EndFilter:
+ result = ParseEndFilter(lexer, statementsInfo, tok);
+ break;
+ default:
+ return MakeParseError(ErrorCode::UnexpectedToken, tok);
+ }
+
+ if (result)
+ {
+ tok = lexer.PeekNextToken();
+ if (tok != Token::Eof)
+ return MakeParseError(ErrorCode::ExpectedEndOfStatement, tok);
+ }
+
+ return result;
+}
+
+struct ErrorTokenConverter
+{
+ const Token& baseTok;
+
+ explicit ErrorTokenConverter(const Token& t)
+ : baseTok(t)
+ {}
+
+ Token operator()(const Token& tok) const
+ {
+ return tok;
+ }
+
+ template<typename T>
+ Token operator()(T tokType) const
+ {
+ auto newTok = baseTok;
+ newTok.type = static_cast<Token::Type>(tokType);
+ if (newTok.type == Token::Identifier || newTok.type == Token::String)
+ newTok.range.endOffset = newTok.range.startOffset;
+ return newTok;
+ }
+};
+
+template<typename ... Args>
+auto MakeParseErrorTL(ErrorCode code, const Token& baseTok, Args ... expectedTokens)
+{
+ ErrorTokenConverter tokCvt(baseTok);
+
+ return MakeParseError(code, baseTok, {tokCvt(expectedTokens)...});
+}
+
+StatementsParser::ParseResult StatementsParser::ParseFor(LexScanner &lexer, StatementInfoList &statementsInfo,
+ const Token &stmtTok)
+{
+ std::vector<std::string> vars;
+
+ while (lexer.PeekNextToken() == Token::Identifier)
+ {
+ auto tok = lexer.NextToken();
+ vars.push_back(AsString(tok.value));
+ if (lexer.NextToken() != ',')
+ {
+ lexer.ReturnToken();
+ break;
+ }
+ }
+
+ if (vars.empty())
+ return MakeParseError(ErrorCode::ExpectedIdentifier, lexer.PeekNextToken());
+
+ if (!lexer.EatIfEqual(Keyword::In))
+ {
+ Token tok1 = lexer.PeekNextToken();
+ Token tok2 = tok1;
+ tok2.type = Token::Identifier;
+ tok2.range.endOffset = tok2.range.startOffset;
+ tok2.value = InternalValue();
+ return MakeParseErrorTL(ErrorCode::ExpectedToken, tok1, tok2, Token::In, ',');
+ }
+
+ auto pivotToken = lexer.PeekNextToken();
+ ExpressionParser exprPraser(m_settings);
+ auto valueExpr = exprPraser.ParseFullExpression(lexer, false);
+ if (!valueExpr)
+ return valueExpr.get_unexpected();
+ // return MakeParseError(ErrorCode::ExpectedExpression, pivotToken);
+
+ Token flagsTok;
+ bool isRecursive = false;
+ if (lexer.EatIfEqual(Keyword::Recursive, &flagsTok))
+ {
+ isRecursive = true;
+ }
+
+ ExpressionEvaluatorPtr<> ifExpr;
+ if (lexer.EatIfEqual(Keyword::If))
+ {
+ auto parsedExpr = exprPraser.ParseFullExpression(lexer, false);
+ if (!parsedExpr)
+ return parsedExpr.get_unexpected();
+ ifExpr = *parsedExpr;
+ }
+ else if (lexer.PeekNextToken() != Token::Eof)
+ {
+ auto tok1 = lexer.PeekNextToken();
+ return MakeParseErrorTL(ErrorCode::ExpectedToken, tok1, Token::If, Token::Recursive, Token::Eof);
+ }
+
+ auto renderer = std::make_shared<ForStatement>(vars, *valueExpr, ifExpr, isRecursive);
+ StatementInfo statementInfo = StatementInfo::Create(StatementInfo::ForStatement, stmtTok);
+ statementInfo.renderer = renderer;
+ statementsInfo.push_back(statementInfo);
+ return ParseResult();
+}
+
+StatementsParser::ParseResult StatementsParser::ParseEndFor(LexScanner&, StatementInfoList& statementsInfo, const Token& stmtTok)
+{
+ if (statementsInfo.size() <= 1)
+ return MakeParseError(ErrorCode::UnexpectedStatement, stmtTok);
+
+ StatementInfo info = statementsInfo.back();
+ RendererPtr elseRenderer;
+ if (info.type == StatementInfo::ElseIfStatement)
+ {
+ auto r = std::static_pointer_cast<ElseBranchStatement>(info.renderer);
+ r->SetMainBody(info.compositions[0]);
+ elseRenderer = std::static_pointer_cast<IRendererBase>(r);
+
+ statementsInfo.pop_back();
+ info = statementsInfo.back();
+ }
+
+ if (info.type != StatementInfo::ForStatement)
+ {
+ return MakeParseError(ErrorCode::UnexpectedStatement, stmtTok);
+ }
+
+ statementsInfo.pop_back();
+ auto renderer = static_cast<ForStatement*>(info.renderer.get());
+ renderer->SetMainBody(info.compositions[0]);
+ if (elseRenderer)
+ renderer->SetElseBody(elseRenderer);
+
+ statementsInfo.back().currentComposition->AddRenderer(info.renderer);
+
+ return ParseResult();
+}
+
+StatementsParser::ParseResult StatementsParser::ParseIf(LexScanner &lexer, StatementInfoList &statementsInfo,
+ const Token &stmtTok)
+{
+ auto pivotTok = lexer.PeekNextToken();
+ ExpressionParser exprParser(m_settings);
+ auto valueExpr = exprParser.ParseFullExpression(lexer);
+ if (!valueExpr)
+ return MakeParseError(ErrorCode::ExpectedExpression, pivotTok);
+
+ auto renderer = std::make_shared<IfStatement>(*valueExpr);
+ StatementInfo statementInfo = StatementInfo::Create(StatementInfo::IfStatement, stmtTok);
+ statementInfo.renderer = renderer;
+ statementsInfo.push_back(statementInfo);
+ return ParseResult();
+}
+
+StatementsParser::ParseResult StatementsParser::ParseElse(LexScanner& /*lexer*/, StatementInfoList& statementsInfo
+ , const Token& stmtTok)
+{
+ auto renderer = std::make_shared<ElseBranchStatement>(ExpressionEvaluatorPtr<>());
+ StatementInfo statementInfo = StatementInfo::Create(StatementInfo::ElseIfStatement, stmtTok);
+ statementInfo.renderer = std::static_pointer_cast<IRendererBase>(renderer);
+ statementsInfo.push_back(statementInfo);
+ return ParseResult();
+}
+
+StatementsParser::ParseResult StatementsParser::ParseElIf(LexScanner& lexer, StatementInfoList& statementsInfo
+ , const Token& stmtTok)
+{
+ auto pivotTok = lexer.PeekNextToken();
+ ExpressionParser exprParser(m_settings);
+ auto valueExpr = exprParser.ParseFullExpression(lexer);
+ if (!valueExpr)
+ return MakeParseError(ErrorCode::ExpectedExpression, pivotTok);
+
+ auto renderer = std::make_shared<ElseBranchStatement>(*valueExpr);
+ StatementInfo statementInfo = StatementInfo::Create(StatementInfo::ElseIfStatement, stmtTok);
+ statementInfo.renderer = std::static_pointer_cast<IRendererBase>(renderer);
+ statementsInfo.push_back(statementInfo);
+ return ParseResult();
+}
+
+StatementsParser::ParseResult StatementsParser::ParseEndIf(LexScanner&, StatementInfoList& statementsInfo, const Token& stmtTok)
+{
+ if (statementsInfo.size() <= 1)
+ return MakeParseError(ErrorCode::UnexpectedStatement, stmtTok);
+
+ auto info = statementsInfo.back();
+ statementsInfo.pop_back();
+
+ std::list<StatementPtr<ElseBranchStatement>> elseBranches;
+
+ auto errorTok = stmtTok;
+ while (info.type != StatementInfo::IfStatement)
+ {
+ if (info.type != StatementInfo::ElseIfStatement)
+ return MakeParseError(ErrorCode::UnexpectedStatement, errorTok);
+
+ auto elseRenderer = std::static_pointer_cast<ElseBranchStatement>(info.renderer);
+ elseRenderer->SetMainBody(info.compositions[0]);
+
+ elseBranches.push_front(elseRenderer);
+ errorTok = info.token;
+ info = statementsInfo.back();
+ statementsInfo.pop_back();
+ }
+
+ auto renderer = static_cast<IfStatement*>(info.renderer.get());
+ renderer->SetMainBody(info.compositions[0]);
+
+ for (auto& b : elseBranches)
+ renderer->AddElseBranch(b);
+
+ statementsInfo.back().currentComposition->AddRenderer(info.renderer);
+
+ return ParseResult();
+}
+
+StatementsParser::ParseResult StatementsParser::ParseSet(LexScanner& lexer, StatementInfoList& statementsInfo, const Token& stmtTok)
+{
+ std::vector<std::string> vars;
+
+ while (lexer.PeekNextToken() == Token::Identifier)
+ {
+ auto tok = lexer.NextToken();
+ vars.push_back(AsString(tok.value));
+ if (lexer.NextToken() != ',')
+ {
+ lexer.ReturnToken();
+ break;
+ }
+ }
+
+ if (vars.empty())
+ return MakeParseError(ErrorCode::ExpectedIdentifier, lexer.PeekNextToken());
+
+ ExpressionParser exprParser(m_settings);
+ if (lexer.EatIfEqual('='))
+ {
+ const auto expr = exprParser.ParseFullExpression(lexer);
+ if (!expr)
+ return expr.get_unexpected();
+ statementsInfo.back().currentComposition->AddRenderer(
+ std::make_shared<SetLineStatement>(std::move(vars), *expr));
+ }
+ else if (lexer.EatIfEqual('|'))
+ {
+ const auto expr = exprParser.ParseFilterExpression(lexer);
+ if (!expr)
+ return expr.get_unexpected();
+ auto statementInfo = StatementInfo::Create(
+ StatementInfo::SetStatement, stmtTok);
+ statementInfo.renderer = std::make_shared<SetFilteredBlockStatement>(
+ std::move(vars), *expr);
+ statementsInfo.push_back(std::move(statementInfo));
+ }
+ else
+ {
+ auto operTok = lexer.NextToken();
+ if (lexer.NextToken() != Token::Eof)
+ return MakeParseError(ErrorCode::YetUnsupported, operTok, {std::move(stmtTok)});
+ auto statementInfo = StatementInfo::Create(
+ StatementInfo::SetStatement, stmtTok);
+ statementInfo.renderer = std::make_shared<SetRawBlockStatement>(
+ std::move(vars));
+ statementsInfo.push_back(std::move(statementInfo));
+ }
+
+ return {};
+}
+
+StatementsParser::ParseResult StatementsParser::ParseEndSet(LexScanner&
+ , StatementInfoList& statementsInfo
+ , const Token& stmtTok)
+{
+ if (statementsInfo.size() <= 1)
+ return MakeParseError(ErrorCode::UnexpectedStatement, stmtTok);
+
+ const auto info = statementsInfo.back();
+ if (info.type != StatementInfo::SetStatement)
+ return MakeParseError(ErrorCode::UnexpectedStatement, stmtTok);
+
+ auto &renderer = *boost::polymorphic_downcast<SetBlockStatement*>(
+ info.renderer.get());
+ renderer.SetBody(info.compositions[0]);
+
+ statementsInfo.pop_back();
+ statementsInfo.back().currentComposition->AddRenderer(info.renderer);
+
+ return {};
+}
+
+StatementsParser::ParseResult StatementsParser::ParseBlock(LexScanner& lexer, StatementInfoList& statementsInfo
+ , const Token& stmtTok)
+{
+ if (statementsInfo.empty())
+ return MakeParseError(ErrorCode::UnexpectedStatement, stmtTok);
+
+ Token nextTok = lexer.NextToken();
+ if (nextTok != Token::Identifier)
+ return MakeParseError(ErrorCode::ExpectedIdentifier, nextTok);
+
+ std::string blockName = AsString(nextTok.value);
+
+ auto& info = statementsInfo.back();
+ RendererPtr blockRenderer;
+ StatementInfo::Type blockType = StatementInfo::ParentBlockStatement;
+ if (info.type == StatementInfo::ExtendsStatement)
+ {
+ blockRenderer = std::make_shared<BlockStatement>(blockName);
+ blockType = StatementInfo::BlockStatement;
+ }
+ else
+ {
+ bool isScoped = false;
+ if (lexer.EatIfEqual(Keyword::Scoped, &nextTok))
+ isScoped = true;
+ else
+ {
+ nextTok = lexer.PeekNextToken();
+ if (nextTok != Token::Eof)
+ return MakeParseErrorTL(ErrorCode::ExpectedToken, nextTok, Token::Scoped);
+ }
+
+ blockRenderer = std::make_shared<ParentBlockStatement>(blockName, isScoped);
+ }
+
+ StatementInfo statementInfo = StatementInfo::Create(blockType, stmtTok);
+ statementInfo.renderer = std::move(blockRenderer);
+ statementsInfo.push_back(statementInfo);
+ return ParseResult();
+}
+
+StatementsParser::ParseResult StatementsParser::ParseEndBlock(LexScanner& lexer, StatementInfoList& statementsInfo, const Token& stmtTok)
+{
+ if (statementsInfo.size() <= 1)
+ return MakeParseError(ErrorCode::UnexpectedStatement, stmtTok);
+
+ Token nextTok = lexer.PeekNextToken();
+ if (nextTok != Token::Identifier && nextTok != Token::Eof)
+ {
+ Token tok2;
+ tok2.type = Token::Identifier;
+ Token tok3;
+ tok3.type = Token::Eof;
+ return MakeParseError(ErrorCode::ExpectedToken, nextTok, {tok2, tok3});
+ }
+
+ if (nextTok == Token::Identifier)
+ lexer.EatToken();
+
+ auto info = statementsInfo.back();
+ statementsInfo.pop_back();
+
+ if (info.type == StatementInfo::BlockStatement)
+ {
+ auto blockStmt = std::static_pointer_cast<BlockStatement>(info.renderer);
+ blockStmt->SetMainBody(info.compositions[0]);
+ auto& extendsInfo = statementsInfo.back();
+ auto extendsStmt = std::static_pointer_cast<ExtendsStatement>(extendsInfo.renderer);
+ extendsStmt->AddBlock(std::static_pointer_cast<BlockStatement>(info.renderer));
+ }
+ else if (info.type == StatementInfo::ParentBlockStatement)
+ {
+ auto blockStmt = std::static_pointer_cast<ParentBlockStatement>(info.renderer);
+ blockStmt->SetMainBody(info.compositions[0]);
+ statementsInfo.back().currentComposition->AddRenderer(info.renderer);
+ }
+ else
+ {
+ return MakeParseError(ErrorCode::UnexpectedStatement, stmtTok);
+ }
+
+ return ParseResult();
+}
+
+StatementsParser::ParseResult StatementsParser::ParseExtends(LexScanner& lexer, StatementInfoList& statementsInfo, const Token& stmtTok)
+{
+ if (statementsInfo.empty())
+ return MakeParseError(ErrorCode::UnexpectedStatement, stmtTok);
+
+ if (!m_env)
+ return MakeParseError(ErrorCode::TemplateEnvAbsent, stmtTok);
+
+ Token tok = lexer.NextToken();
+ if (tok != Token::String && tok != Token::Identifier)
+ {
+ auto tok2 = tok;
+ tok2.type = Token::Identifier;
+ tok2.range.endOffset = tok2.range.startOffset;
+ tok2.value = EmptyValue{};
+ return MakeParseErrorTL(ErrorCode::ExpectedToken, tok, tok2, Token::String);
+ }
+
+ auto renderer = std::make_shared<ExtendsStatement>(AsString(tok.value), tok == Token::String);
+ statementsInfo.back().currentComposition->AddRenderer(renderer);
+
+ StatementInfo statementInfo = StatementInfo::Create(StatementInfo::ExtendsStatement, stmtTok);
+ statementInfo.renderer = renderer;
+ statementsInfo.push_back(statementInfo);
+
+ return ParseResult();
+}
+
+StatementsParser::ParseResult StatementsParser::ParseMacro(LexScanner& lexer, StatementInfoList& statementsInfo, const Token& stmtTok)
+{
+ if (statementsInfo.empty())
+ return MakeParseError(ErrorCode::UnexpectedStatement, stmtTok);
+
+ Token nextTok = lexer.NextToken();
+ if (nextTok != Token::Identifier)
+ return MakeParseError(ErrorCode::ExpectedIdentifier, nextTok);
+
+ std::string macroName = AsString(nextTok.value);
+ MacroParams macroParams;
+
+ if (lexer.EatIfEqual('('))
+ {
+ auto result = ParseMacroParams(lexer);
+ if (!result)
+ return result.get_unexpected();
+
+ macroParams = std::move(result.value());
+ }
+ else if (lexer.PeekNextToken() != Token::Eof)
+ {
+ Token tok = lexer.PeekNextToken();
+
+ return MakeParseErrorTL(ErrorCode::UnexpectedToken, tok, Token::RBracket, Token::Eof);
+ }
+
+ auto renderer = std::make_shared<MacroStatement>(std::move(macroName), std::move(macroParams));
+ StatementInfo statementInfo = StatementInfo::Create(StatementInfo::MacroStatement, stmtTok);
+ statementInfo.renderer = renderer;
+ statementsInfo.push_back(statementInfo);
+
+ return ParseResult();
+}
+
+nonstd::expected<MacroParams, ParseError> StatementsParser::ParseMacroParams(LexScanner& lexer)
+{
+ MacroParams items;
+
+ if (lexer.EatIfEqual(')'))
+ return std::move(items);
+
+ ExpressionParser exprParser(m_settings);
+
+ do
+ {
+ Token name = lexer.NextToken();
+ if (name != Token::Identifier)
+ return MakeParseError(ErrorCode::ExpectedIdentifier, name);
+
+ ExpressionEvaluatorPtr<> defVal;
+ if (lexer.EatIfEqual('='))
+ {
+ auto result = exprParser.ParseFullExpression(lexer, false);
+ if (!result)
+ return result.get_unexpected();
+
+ defVal = *result;
+ }
+
+ MacroParam p;
+ p.paramName = AsString(name.value);
+ p.defaultValue = std::move(defVal);
+ items.push_back(std::move(p));
+
+ } while (lexer.EatIfEqual(','));
+
+ auto tok = lexer.NextToken();
+ if (tok != ')')
+ return MakeParseError(ErrorCode::ExpectedRoundBracket, tok);
+
+ return std::move(items);
+}
+
+StatementsParser::ParseResult StatementsParser::ParseEndMacro(LexScanner&, StatementInfoList& statementsInfo, const Token& stmtTok)
+{
+ if (statementsInfo.size() <= 1)
+ return MakeParseError(ErrorCode::UnexpectedStatement, stmtTok);
+
+ StatementInfo info = statementsInfo.back();
+
+ if (info.type != StatementInfo::MacroStatement)
+ {
+ return MakeParseError(ErrorCode::UnexpectedStatement, stmtTok);
+ }
+
+ statementsInfo.pop_back();
+ auto renderer = static_cast<MacroStatement*>(info.renderer.get());
+ renderer->SetMainBody(info.compositions[0]);
+
+ statementsInfo.back().currentComposition->AddRenderer(info.renderer);
+
+ return ParseResult();
+}
+
+StatementsParser::ParseResult StatementsParser::ParseCall(LexScanner& lexer, StatementInfoList& statementsInfo, const Token& stmtTok)
+{
+ if (statementsInfo.empty())
+ return MakeParseError(ErrorCode::UnexpectedStatement, stmtTok);
+
+ MacroParams callbackParams;
+
+ if (lexer.EatIfEqual('('))
+ {
+ auto result = ParseMacroParams(lexer);
+ if (!result)
+ return result.get_unexpected();
+
+ callbackParams = std::move(result.value());
+ }
+
+ Token nextTok = lexer.NextToken();
+ if (nextTok != Token::Identifier)
+ {
+ Token tok = nextTok;
+ Token tok1;
+ tok1.type = Token::Identifier;
+
+ return MakeParseError(ErrorCode::UnexpectedToken, tok, {tok1});
+ }
+
+ std::string macroName = AsString(nextTok.value);
+
+ CallParamsInfo callParams;
+ if (lexer.EatIfEqual('('))
+ {
+ ExpressionParser exprParser(m_settings);
+ auto result = exprParser.ParseCallParams(lexer);
+ if (!result)
+ return result.get_unexpected();
+
+ callParams = std::move(result.value());
+ }
+
+ auto renderer = std::make_shared<MacroCallStatement>(std::move(macroName), std::move(callParams), std::move(callbackParams));
+ StatementInfo statementInfo = StatementInfo::Create(StatementInfo::MacroCallStatement, stmtTok);
+ statementInfo.renderer = renderer;
+ statementsInfo.push_back(statementInfo);
+
+ return ParseResult();
+}
+
+StatementsParser::ParseResult StatementsParser::ParseEndCall(LexScanner&, StatementInfoList& statementsInfo, const Token& stmtTok)
+{
+ if (statementsInfo.size() <= 1)
+ return MakeParseError(ErrorCode::UnexpectedStatement, stmtTok);
+
+ StatementInfo info = statementsInfo.back();
+
+ if (info.type != StatementInfo::MacroCallStatement)
+ {
+ return MakeParseError(ErrorCode::UnexpectedStatement, stmtTok);
+ }
+
+ statementsInfo.pop_back();
+ auto renderer = static_cast<MacroCallStatement*>(info.renderer.get());
+ renderer->SetMainBody(info.compositions[0]);
+
+ statementsInfo.back().currentComposition->AddRenderer(info.renderer);
+
+ return ParseResult();
+}
+
+StatementsParser::ParseResult StatementsParser::ParseInclude(LexScanner& lexer, StatementInfoList& statementsInfo, const Token& stmtTok)
+{
+ if (statementsInfo.empty())
+ return MakeParseError(ErrorCode::UnexpectedStatement, stmtTok);
+
+ // auto operTok = lexer.NextToken();
+ ExpressionEvaluatorPtr<> valueExpr;
+ ExpressionParser exprParser(m_settings);
+ auto expr = exprParser.ParseFullExpression(lexer);
+ if (!expr)
+ return expr.get_unexpected();
+ valueExpr = *expr;
+
+ Token nextTok = lexer.PeekNextToken();
+ bool isIgnoreMissing = false;
+ bool isWithContext = true;
+ bool hasIgnoreMissing = false;
+ if (lexer.EatIfEqual(Keyword::Ignore))
+ {
+ if (lexer.EatIfEqual(Keyword::Missing))
+ isIgnoreMissing = true;
+ else
+ return MakeParseErrorTL(ErrorCode::ExpectedToken, lexer.PeekNextToken(), Token::Missing);
+
+ hasIgnoreMissing = true;
+ nextTok = lexer.PeekNextToken();
+ }
+
+ auto kw = lexer.GetAsKeyword(nextTok);
+ bool hasContextControl = false;
+ if (kw == Keyword::With || kw == Keyword::Without)
+ {
+ lexer.EatToken();
+ isWithContext = kw == Keyword::With;
+ if (!lexer.EatIfEqual(Keyword::Context))
+ return MakeParseErrorTL(ErrorCode::ExpectedToken, lexer.PeekNextToken(), Token::Context);
+
+ nextTok = lexer.PeekNextToken();
+ hasContextControl = true;
+ }
+
+ if (nextTok != Token::Eof)
+ {
+ if (hasContextControl)
+ return MakeParseErrorTL(ErrorCode::ExpectedEndOfStatement, nextTok, Token::Eof);
+
+ if (hasIgnoreMissing)
+ return MakeParseErrorTL(ErrorCode::UnexpectedToken, nextTok, Token::Eof, Token::With, Token::Without);
+
+ return MakeParseErrorTL(ErrorCode::UnexpectedToken, nextTok, Token::Eof, Token::Ignore, Token::With, Token::Without);
+ }
+
+ if (!m_env && !isIgnoreMissing)
+ return MakeParseError(ErrorCode::TemplateEnvAbsent, stmtTok);
+
+ auto renderer = std::make_shared<IncludeStatement>(isIgnoreMissing, isWithContext);
+ renderer->SetIncludeNamesExpr(valueExpr);
+ statementsInfo.back().currentComposition->AddRenderer(renderer);
+
+ return ParseResult();
+}
+
+StatementsParser::ParseResult StatementsParser::ParseImport(LexScanner& lexer, StatementInfoList& statementsInfo, const Token& stmtTok)
+{
+ if (!m_env)
+ return MakeParseError(ErrorCode::TemplateEnvAbsent, stmtTok);
+
+ ExpressionEvaluatorPtr<> valueExpr;
+ ExpressionParser exprParser(m_settings);
+ auto expr = exprParser.ParseFullExpression(lexer);
+ if (!expr)
+ return expr.get_unexpected();
+ valueExpr = *expr;
+
+ if (!lexer.EatIfEqual(Keyword::As))
+ return MakeParseErrorTL(ErrorCode::ExpectedToken, lexer.PeekNextToken(), Token::As);
+
+ Token name;
+ if (!lexer.EatIfEqual(Token::Identifier, &name))
+ return MakeParseErrorTL(ErrorCode::ExpectedToken, lexer.PeekNextToken(), Token::Identifier);
+
+ Token nextTok = lexer.PeekNextToken();
+ auto kw = lexer.GetAsKeyword(nextTok);
+ bool hasContextControl = false;
+ bool isWithContext = false;
+ if (kw == Keyword::With || kw == Keyword::Without)
+ {
+ lexer.EatToken();
+ isWithContext = kw == Keyword::With;
+ if (!lexer.EatIfEqual(Keyword::Context))
+ return MakeParseErrorTL(ErrorCode::ExpectedToken, lexer.PeekNextToken(), Token::Context);
+
+ nextTok = lexer.PeekNextToken();
+ hasContextControl = true;
+ }
+
+ if (nextTok != Token::Eof)
+ {
+ if (hasContextControl)
+ return MakeParseErrorTL(ErrorCode::ExpectedEndOfStatement, nextTok, Token::Eof);
+
+ return MakeParseErrorTL(ErrorCode::UnexpectedToken, nextTok, Token::Eof, Token::With, Token::Without);
+ }
+
+ auto renderer = std::make_shared<ImportStatement>(isWithContext);
+ renderer->SetImportNameExpr(valueExpr);
+ renderer->SetNamespace(AsString(name.value));
+ statementsInfo.back().currentComposition->AddRenderer(renderer);
+
+ return ParseResult();
+}
+
+StatementsParser::ParseResult StatementsParser::ParseFrom(LexScanner& lexer, StatementInfoList& statementsInfo, const Token& stmtTok)
+{
+ if (!m_env)
+ return MakeParseError(ErrorCode::TemplateEnvAbsent, stmtTok);
+
+ ExpressionEvaluatorPtr<> valueExpr;
+ ExpressionParser exprParser(m_settings);
+ auto expr = exprParser.ParseFullExpression(lexer);
+ if (!expr)
+ return expr.get_unexpected();
+ valueExpr = *expr;
+
+ if (!lexer.EatIfEqual(Keyword::Import))
+ return MakeParseErrorTL(ErrorCode::ExpectedToken, lexer.PeekNextToken(), Token::Identifier);
+
+ std::vector<std::pair<std::string, std::string>> mappedNames;
+
+ Token nextTok;
+ bool hasContextControl = false;
+ bool isWithContext = false;
+
+ for (;;)
+ {
+ bool hasComma = false;
+ if (!mappedNames.empty())
+ {
+ if (!lexer.EatIfEqual(Token::Comma))
+ hasComma = true;;
+ }
+
+ nextTok = lexer.PeekNextToken();
+ auto kw = lexer.GetAsKeyword(nextTok);
+ if (kw == Keyword::With || kw == Keyword::Without)
+ {
+ lexer.NextToken();
+ if (lexer.EatIfEqual(Keyword::Context))
+ {
+ hasContextControl = true;
+ isWithContext = kw == Keyword::With;
+ nextTok = lexer.PeekNextToken();
+ break;
+ }
+ else
+ {
+ lexer.ReturnToken();
+ }
+ }
+
+ if (hasComma)
+ break;
+
+ std::pair<std::string, std::string> macroMap;
+ if (!lexer.EatIfEqual(Token::Identifier, &nextTok))
+ return MakeParseErrorTL(ErrorCode::ExpectedToken, nextTok, Token::Identifier);
+
+ macroMap.first = AsString(nextTok.value);
+
+ if (lexer.EatIfEqual(Keyword::As))
+ {
+ if (!lexer.EatIfEqual(Token::Identifier, &nextTok))
+ return MakeParseErrorTL(ErrorCode::ExpectedToken, nextTok, Token::Identifier);
+ macroMap.second = AsString(nextTok.value);
+ }
+ else
+ {
+ macroMap.second = macroMap.first;
+ }
+ mappedNames.push_back(std::move(macroMap));
+ }
+
+ if (nextTok != Token::Eof)
+ {
+ if (hasContextControl)
+ return MakeParseErrorTL(ErrorCode::ExpectedEndOfStatement, nextTok, Token::Eof);
+
+ if (mappedNames.empty())
+ MakeParseErrorTL(ErrorCode::UnexpectedToken, nextTok, Token::Eof, Token::Identifier);
+ else
+ MakeParseErrorTL(ErrorCode::UnexpectedToken, nextTok, Token::Eof, Token::Comma, Token::With, Token::Without);
+ }
+
+ auto renderer = std::make_shared<ImportStatement>(isWithContext);
+ renderer->SetImportNameExpr(valueExpr);
+
+ for (auto& nameInfo : mappedNames)
+ renderer->AddNameToImport(std::move(nameInfo.first), std::move(nameInfo.second));
+
+ statementsInfo.back().currentComposition->AddRenderer(renderer);
+
+ return ParseResult();
+}
+
+StatementsParser::ParseResult StatementsParser::ParseDo(LexScanner& lexer, StatementInfoList& statementsInfo, const Token& /*stmtTok*/)
+{
+ ExpressionEvaluatorPtr<> valueExpr;
+ ExpressionParser exprParser(m_settings);
+ auto expr = exprParser.ParseFullExpression(lexer);
+ if (!expr)
+ return expr.get_unexpected();
+ valueExpr = *expr;
+
+ auto renderer = std::make_shared<DoStatement>(valueExpr);
+ statementsInfo.back().currentComposition->AddRenderer(renderer);
+
+ return jinja2::StatementsParser::ParseResult();
+}
+
+StatementsParser::ParseResult StatementsParser::ParseWith(LexScanner& lexer, StatementInfoList& statementsInfo, const Token& stmtTok)
+{
+ std::vector<std::pair<std::string, ExpressionEvaluatorPtr<>>> vars;
+
+ ExpressionParser exprParser(m_settings);
+ while (lexer.PeekNextToken() == Token::Identifier)
+ {
+ auto nameTok = lexer.NextToken();
+ if (!lexer.EatIfEqual('='))
+ return MakeParseErrorTL(ErrorCode::ExpectedToken, lexer.PeekNextToken(), '=');
+
+ auto expr = exprParser.ParseFullExpression(lexer);
+ if (!expr)
+ return expr.get_unexpected();
+ auto valueExpr = *expr;
+
+ vars.emplace_back(AsString(nameTok.value), valueExpr);
+
+ if (!lexer.EatIfEqual(','))
+ break;
+ }
+
+ auto nextTok = lexer.PeekNextToken();
+ if (vars.empty())
+ return MakeParseError(ErrorCode::ExpectedIdentifier, nextTok);
+
+ if (nextTok != Token::Eof)
+ return MakeParseErrorTL(ErrorCode::ExpectedToken, nextTok, Token::Eof, ',');
+
+ auto renderer = std::make_shared<WithStatement>();
+ renderer->SetScopeVars(std::move(vars));
+ StatementInfo statementInfo = StatementInfo::Create(StatementInfo::WithStatement, stmtTok);
+ statementInfo.renderer = renderer;
+ statementsInfo.push_back(statementInfo);
+
+ return ParseResult();
+}
+
+StatementsParser::ParseResult StatementsParser::ParseEndWith(LexScanner& /*lexer*/, StatementInfoList& statementsInfo, const Token& stmtTok)
+{
+ if (statementsInfo.size() <= 1)
+ return MakeParseError(ErrorCode::UnexpectedStatement, stmtTok);
+
+ StatementInfo info = statementsInfo.back();
+
+ if (info.type != StatementInfo::WithStatement)
+ {
+ return MakeParseError(ErrorCode::UnexpectedStatement, stmtTok);
+ }
+
+ statementsInfo.pop_back();
+ auto renderer = static_cast<WithStatement*>(info.renderer.get());
+ renderer->SetMainBody(info.compositions[0]);
+
+ statementsInfo.back().currentComposition->AddRenderer(info.renderer);
+
+ return ParseResult();
+}
+
+StatementsParser::ParseResult StatementsParser::ParseFilter(LexScanner& lexer, StatementInfoList& statementsInfo, const Token& stmtTok)
+{
+ ExpressionParser exprParser(m_settings);
+ auto filterExpr = exprParser.ParseFilterExpression(lexer);
+ if (!filterExpr)
+ {
+ return filterExpr.get_unexpected();
+ }
+
+ auto renderer = std::make_shared<FilterStatement>(*filterExpr);
+ auto statementInfo = StatementInfo::Create(
+ StatementInfo::FilterStatement, stmtTok);
+ statementInfo.renderer = std::move(renderer);
+ statementsInfo.push_back(std::move(statementInfo));
+
+ return {};
+}
+
+StatementsParser::ParseResult StatementsParser::ParseEndFilter(LexScanner&, StatementInfoList& statementsInfo, const Token& stmtTok)
+{
+ if (statementsInfo.size() <= 1)
+ return MakeParseError(ErrorCode::UnexpectedStatement, stmtTok);
+
+ const auto info = statementsInfo.back();
+ if (info.type != StatementInfo::FilterStatement)
+ {
+ return MakeParseError(ErrorCode::UnexpectedStatement, stmtTok);
+ }
+
+ statementsInfo.pop_back();
+ auto &renderer = *boost::polymorphic_downcast<FilterStatement*>(info.renderer.get());
+ renderer.SetBody(info.compositions[0]);
+
+ statementsInfo.back().currentComposition->AddRenderer(info.renderer);
+
+ return {};
+}
+
+} // namespace jinja2
diff --git a/contrib/libs/jinja2cpp/src/template_parser.h b/contrib/libs/jinja2cpp/src/template_parser.h
new file mode 100644
index 0000000000..89c4270758
--- /dev/null
+++ b/contrib/libs/jinja2cpp/src/template_parser.h
@@ -0,0 +1,1081 @@
+#ifndef JINJA2CPP_SRC_TEMPLATE_PARSER_H
+#define JINJA2CPP_SRC_TEMPLATE_PARSER_H
+
+#include "error_handling.h"
+#include "expression_parser.h"
+#include "helpers.h"
+#include "lexer.h"
+#include "lexertk.h"
+#include "renderer.h"
+#include "statements.h"
+#include "template_parser.h"
+#include "value_visitors.h"
+
+#include <boost/algorithm/string/classification.hpp>
+#include <jinja2cpp/error_info.h>
+#include <jinja2cpp/template_env.h>
+#include <contrib/restricted/expected-lite/include/nonstd/expected.hpp>
+
+#include <list>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#ifdef JINJA2CPP_USE_REGEX_BOOST
+#include <boost/regex.hpp>
+template <typename CharType>
+using BasicRegex = boost::basic_regex<CharType>;
+using Regex = boost::regex;
+using WideRegex = boost::wregex;
+template <typename CharIterator>
+using RegexIterator = boost::regex_iterator<CharIterator>;
+#else
+#include <regex>
+template <typename CharType>
+using BasicRegex = std::basic_regex<CharType>;
+using Regex = std::regex;
+using WideRegex = std::wregex;
+template <typename CharIterator>
+using RegexIterator = std::regex_iterator<CharIterator>;
+#endif
+
+namespace jinja2
+{
+template<typename CharT>
+struct ParserTraits;
+
+struct KeywordsInfo
+{
+ MultiStringLiteral name;
+ Keyword type;
+};
+
+struct TokenStrInfo : MultiStringLiteral
+{
+ template<typename CharT>
+ auto GetName() const
+ {
+ return MultiStringLiteral::template GetValue<CharT>();
+ }
+};
+
+template<typename T = void>
+struct ParserTraitsBase
+{
+ static Token::Type s_keywords[];
+ static KeywordsInfo s_keywordsInfo[41];
+ static std::unordered_map<int, MultiStringLiteral> s_tokens;
+ static MultiStringLiteral s_regexp;
+};
+
+template<typename T>
+MultiStringLiteral ParserTraitsBase<T>::s_regexp = UNIVERSAL_STR(
+ R"((\{\{)|(\}\})|(\{%[\+\-]?\s+raw\s+[\+\-]?%\})|(\{%[\+\-]?\s+endraw\s+[\+\-]?%\})|(\{%\s+meta\s+%\})|(\{%\s+endmeta\s+%\})|(\{%)|(%\})|(\{#)|(#\})|(\n))");
+
+template<>
+struct ParserTraits<char> : public ParserTraitsBase<>
+{
+ static Regex GetRoughTokenizer()
+ { return Regex(s_regexp.GetValueStr<char>()); }
+ static Regex GetKeywords()
+ {
+ std::string pattern;
+ std::string prefix("(^");
+ std::string postfix("$)");
+
+ bool isFirst = true;
+ for (auto& info : s_keywordsInfo)
+ {
+ if (!isFirst)
+ pattern += "|";
+ else
+ isFirst = false;
+
+ pattern += prefix + info.name.charValue + postfix;
+ }
+ return Regex(pattern);
+ }
+ static std::string GetAsString(const std::string& str, CharRange range) { return str.substr(range.startOffset, range.size()); }
+ static InternalValue RangeToNum(const std::string& str, CharRange range, Token::Type hint)
+ {
+ char buff[std::max(std::numeric_limits<int64_t>::max_digits10, std::numeric_limits<double>::max_digits10) * 2 + 1];
+ std::copy(str.data() + range.startOffset, str.data() + range.endOffset, buff);
+ buff[range.size()] = 0;
+ InternalValue result;
+ if (hint == Token::IntegerNum)
+ {
+ result = InternalValue(static_cast<int64_t>(strtoll(buff, nullptr, 0)));
+ }
+ else
+ {
+ char* endBuff = nullptr;
+ int64_t val = strtoll(buff, &endBuff, 10);
+ if ((errno == ERANGE) || *endBuff)
+ {
+ endBuff = nullptr;
+ double dblVal = strtod(buff, nullptr);
+ result = static_cast<double>(dblVal);
+ }
+ else
+ result = static_cast<int64_t>(val);
+ }
+ return result;
+ }
+};
+
+template<>
+struct ParserTraits<wchar_t> : public ParserTraitsBase<>
+{
+ static WideRegex GetRoughTokenizer()
+ { return WideRegex(s_regexp.GetValueStr<wchar_t>()); }
+ static WideRegex GetKeywords()
+ {
+ std::wstring pattern;
+ std::wstring prefix(L"(^");
+ std::wstring postfix(L"$)");
+
+ bool isFirst = true;
+ for (auto& info : s_keywordsInfo)
+ {
+ if (!isFirst)
+ pattern += L"|";
+ else
+ isFirst = false;
+
+ pattern += prefix + info.name.wcharValue + postfix;
+ }
+ return WideRegex(pattern);
+ }
+ static std::string GetAsString(const std::wstring& str, CharRange range)
+ {
+ auto srcStr = str.substr(range.startOffset, range.size());
+ return detail::StringConverter<std::wstring, std::string>::DoConvert(srcStr);
+ }
+ static InternalValue RangeToNum(const std::wstring& str, CharRange range, Token::Type hint)
+ {
+ wchar_t buff[std::max(std::numeric_limits<int64_t>::max_digits10, std::numeric_limits<double>::max_digits10) * 2 + 1];
+ std::copy(str.data() + range.startOffset, str.data() + range.endOffset, buff);
+ buff[range.size()] = 0;
+ InternalValue result;
+ if (hint == Token::IntegerNum)
+ {
+ result = static_cast<int64_t>(wcstoll(buff, nullptr, 0));
+ }
+ else
+ {
+ wchar_t* endBuff = nullptr;
+ int64_t val = wcstoll(buff, &endBuff, 10);
+ if ((errno == ERANGE) || *endBuff)
+ {
+ endBuff = nullptr;
+ double dblVal = wcstod(buff, nullptr);
+ result = static_cast<double>(dblVal);
+ }
+ else
+ result = static_cast<int64_t>(val);
+ }
+ return result;
+ }
+};
+
+struct StatementInfo
+{
+ enum Type {
+ TemplateRoot,
+ IfStatement,
+ ElseIfStatement,
+ ForStatement,
+ SetStatement,
+ ExtendsStatement,
+ BlockStatement,
+ ParentBlockStatement,
+ MacroStatement,
+ MacroCallStatement,
+ WithStatement,
+ FilterStatement
+ };
+
+ using ComposedPtr = std::shared_ptr<ComposedRenderer>;
+ Type type;
+ ComposedPtr currentComposition;
+ std::vector<ComposedPtr> compositions;
+ Token token;
+ RendererPtr renderer;
+
+ static StatementInfo Create(Type type, const Token& tok, ComposedPtr renderers = std::make_shared<ComposedRenderer>())
+ {
+ StatementInfo result;
+ result.type = type;
+ result.currentComposition = renderers;
+ result.compositions.push_back(renderers);
+ result.token = tok;
+ return result;
+ }
+};
+
+using StatementInfoList = std::list<StatementInfo>;
+
+class StatementsParser
+{
+public:
+ using ParseResult = nonstd::expected<void, ParseError>;
+
+ StatementsParser(const Settings& settings, TemplateEnv* env)
+ : m_settings(settings)
+ , m_env(env)
+ {
+ }
+
+ ParseResult Parse(LexScanner& lexer, StatementInfoList& statementsInfo);
+
+private:
+ ParseResult ParseFor(LexScanner& lexer, StatementInfoList& statementsInfo, const Token& stmtTok);
+ ParseResult ParseEndFor(LexScanner& lexer, StatementInfoList& statementsInfo, const Token& stmtTok);
+ ParseResult ParseIf(LexScanner& lexer, StatementInfoList& statementsInfo, const Token& stmtTok);
+ ParseResult ParseElse(LexScanner& lexer, StatementInfoList& statementsInfo, const Token& stmtTok);
+ ParseResult ParseElIf(LexScanner& lexer, StatementInfoList& statementsInfo, const Token& stmtTok);
+ ParseResult ParseEndIf(LexScanner& lexer, StatementInfoList& statementsInfo, const Token& pos);
+ ParseResult ParseSet(LexScanner& lexer, StatementInfoList& statementsInfo, const Token& pos);
+ ParseResult ParseEndSet(LexScanner& lexer, StatementInfoList& statementsInfo, const Token& stmtTok);
+ ParseResult ParseBlock(LexScanner& lexer, StatementInfoList& statementsInfo, const Token& stmtTok);
+ ParseResult ParseEndBlock(LexScanner& lexer, StatementInfoList& statementsInfo, const Token& stmtTok);
+ ParseResult ParseExtends(LexScanner& lexer, StatementInfoList& statementsInfo, const Token& stmtTok);
+ ParseResult ParseMacro(LexScanner& lexer, StatementInfoList& statementsInfo, const Token& stmtTok);
+ nonstd::expected<MacroParams, ParseError> ParseMacroParams(LexScanner& lexer);
+ ParseResult ParseEndMacro(LexScanner& lexer, StatementInfoList& statementsInfo, const Token& stmtTok);
+ ParseResult ParseCall(LexScanner& lexer, StatementInfoList& statementsInfo, const Token& stmtTok);
+ ParseResult ParseEndCall(LexScanner& lexer, StatementInfoList& statementsInfo, const Token& stmtTok);
+ ParseResult ParseInclude(LexScanner& lexer, StatementInfoList& statementsInfo, const Token& stmtTok);
+ ParseResult ParseImport(LexScanner& lexer, StatementInfoList& statementsInfo, const Token& stmtTok);
+ ParseResult ParseFrom(LexScanner& lexer, StatementInfoList& statementsInfo, const Token& stmtTok);
+ ParseResult ParseDo(LexScanner& lexer, StatementInfoList& statementsInfo, const Token& stmtTok);
+ ParseResult ParseWith(LexScanner& lexer, StatementInfoList& statementsInfo, const Token& token);
+ ParseResult ParseEndWith(LexScanner& lexer, StatementInfoList& statementsInfo, const Token& stmtTok);
+ ParseResult ParseFilter(LexScanner& lexer, StatementInfoList& statementsInfo, const Token& stmtTok);
+ ParseResult ParseEndFilter(LexScanner& lexer, StatementInfoList& statementsInfo, const Token& stmtTok);
+
+private:
+ Settings m_settings;
+ TemplateEnv* m_env;
+};
+
+template<typename CharT>
+class TemplateParser : public LexerHelper
+{
+public:
+ using string_t = std::basic_string<CharT>;
+ using traits_t = ParserTraits<CharT>;
+ using sregex_iterator = RegexIterator<typename string_t::const_iterator>;
+ using ErrorInfo = ErrorInfoTpl<CharT>;
+ using ParseResult = nonstd::expected<RendererPtr, std::vector<ErrorInfo>>;
+
+ TemplateParser(const string_t* tpl, const Settings& setts, TemplateEnv* env, std::string tplName)
+ : m_template(tpl)
+ , m_templateName(std::move(tplName))
+ , m_settings(setts)
+ , m_env(env)
+ , m_roughTokenizer(traits_t::GetRoughTokenizer())
+ , m_keywords(traits_t::GetKeywords())
+ , m_metadataType(setts.m_defaultMetadataType)
+ {
+ }
+
+ ParseResult Parse()
+ {
+ auto roughResult = DoRoughParsing();
+
+ if (!roughResult)
+ {
+ return ParseErrorsToErrorInfo(roughResult.error());
+ }
+
+ auto composeRenderer = std::make_shared<ComposedRenderer>();
+
+ auto fineResult = DoFineParsing(composeRenderer);
+ if (!fineResult)
+ return ParseErrorsToErrorInfo(fineResult.error());
+
+ return composeRenderer;
+ }
+
+ MetadataInfo<CharT> GetMetadataInfo() const
+ {
+ MetadataInfo<CharT> result;
+ result.metadataType = m_metadataType;
+ result.metadata = m_metadata;
+ result.location = m_metadataLocation;
+ return result;
+ }
+
+private:
+ enum {
+ RM_Unknown = 0,
+ RM_ExprBegin = 1,
+ RM_ExprEnd,
+ RM_RawBegin,
+ RM_RawEnd,
+ RM_MetaBegin,
+ RM_MetaEnd,
+ RM_StmtBegin,
+ RM_StmtEnd,
+ RM_CommentBegin,
+ RM_CommentEnd,
+ RM_NewLine
+ };
+
+ struct LineInfo
+ {
+ CharRange range;
+ unsigned lineNumber;
+ };
+
+ enum class TextBlockType { RawText, Expression, Statement, Comment, LineStatement, RawBlock, MetaBlock };
+
+ struct TextBlockInfo
+ {
+ CharRange range;
+ TextBlockType type;
+ };
+
+ nonstd::expected<void, std::vector<ParseError>> DoRoughParsing()
+ {
+ std::vector<ParseError> foundErrors;
+
+ auto matchBegin = sregex_iterator(m_template->begin(), m_template->end(), m_roughTokenizer);
+ auto matchEnd = sregex_iterator();
+
+ auto matches = std::distance(matchBegin, matchEnd);
+ // One line, no customization
+ if (matches == 0)
+ {
+ CharRange range{ 0ULL, m_template->size() };
+ m_lines.push_back(LineInfo{ range, 0 });
+ m_textBlocks.push_back(
+ TextBlockInfo{ range, (!m_template->empty() && m_template->front() == '#') ? TextBlockType::LineStatement : TextBlockType::RawText });
+ return nonstd::expected<void, std::vector<ParseError>>();
+ }
+
+ m_currentBlockInfo.range.startOffset = 0;
+ m_currentBlockInfo.range.endOffset = 0;
+ m_currentLineInfo.range = m_currentBlockInfo.range;
+ m_currentLineInfo.lineNumber = 0;
+ if (m_settings.useLineStatements)
+ m_currentBlockInfo.type = m_template->front() == '#' ? TextBlockType::LineStatement : TextBlockType::RawText;
+ else
+ m_currentBlockInfo.type = TextBlockType::RawText;
+ do
+ {
+ auto result = ParseRoughMatch(matchBegin, matchEnd);
+ if (!result)
+ {
+ foundErrors.push_back(result.error());
+ return nonstd::make_unexpected(std::move(foundErrors));
+ }
+ } while (matchBegin != matchEnd);
+ FinishCurrentLine(m_template->size());
+
+ if (m_currentBlockInfo.type == TextBlockType::RawBlock)
+ {
+ nonstd::expected<void, ParseError> result =
+ MakeParseError(ErrorCode::ExpectedRawEnd, MakeToken(Token::RawEnd, { m_template->size(), m_template->size() }));
+ foundErrors.push_back(result.error());
+ return nonstd::make_unexpected(std::move(foundErrors));
+ }
+ else if (m_currentBlockInfo.type == TextBlockType::MetaBlock)
+ {
+ nonstd::expected<void, ParseError> result =
+ MakeParseError(ErrorCode::ExpectedMetaEnd, MakeToken(Token::RawEnd, { m_template->size(), m_template->size() }));
+ foundErrors.push_back(result.error());
+ return nonstd::make_unexpected(std::move(foundErrors));
+ }
+
+ FinishCurrentBlock(m_template->size(), TextBlockType::RawText);
+
+ if (!foundErrors.empty())
+ return nonstd::make_unexpected(std::move(foundErrors));
+ return nonstd::expected<void, std::vector<ParseError>>();
+ }
+ nonstd::expected<void, ParseError> ParseRoughMatch(sregex_iterator& curMatch, const sregex_iterator& /*endMatch*/)
+ {
+ auto match = *curMatch;
+ ++curMatch;
+ unsigned matchType = RM_Unknown;
+ for (unsigned idx = 1; idx != match.size(); ++idx)
+ {
+ if (match.length(idx) != 0)
+ {
+ matchType = idx;
+ break;
+ }
+ }
+
+ size_t matchStart = static_cast<size_t>(match.position());
+
+ switch (matchType)
+ {
+ case RM_NewLine:
+ FinishCurrentLine(match.position());
+ m_currentLineInfo.range.startOffset = m_currentLineInfo.range.endOffset + 1;
+ if (m_currentLineInfo.range.startOffset < m_template->size() &&
+ (m_currentBlockInfo.type == TextBlockType::RawText || m_currentBlockInfo.type == TextBlockType::LineStatement))
+ {
+ if (m_currentBlockInfo.type == TextBlockType::LineStatement)
+ {
+ FinishCurrentBlock(matchStart, TextBlockType::RawText);
+ m_currentBlockInfo.range.startOffset = m_currentLineInfo.range.startOffset;
+ }
+
+ if (m_settings.useLineStatements)
+ m_currentBlockInfo.type =
+ (*m_template)[m_currentLineInfo.range.startOffset] == '#' ? TextBlockType::LineStatement : TextBlockType::RawText;
+ else
+ m_currentBlockInfo.type = TextBlockType::RawText;
+ }
+ break;
+ case RM_CommentBegin:
+ if (m_currentBlockInfo.type == TextBlockType::RawBlock)
+ break;
+ if (m_currentBlockInfo.type != TextBlockType::RawText)
+ {
+ FinishCurrentLine(match.position() + 2);
+ return MakeParseError(ErrorCode::UnexpectedCommentBegin, MakeToken(Token::CommentBegin, { matchStart, matchStart + 2 }));
+ }
+
+ FinishCurrentBlock(matchStart, TextBlockType::Comment);
+ m_currentBlockInfo.range.startOffset = matchStart + 2;
+ m_currentBlockInfo.type = TextBlockType::Comment;
+ break;
+
+ case RM_CommentEnd:
+ if (m_currentBlockInfo.type == TextBlockType::RawBlock)
+ break;
+ if (m_currentBlockInfo.type != TextBlockType::Comment)
+ {
+ FinishCurrentLine(match.position() + 2);
+ return MakeParseError(ErrorCode::UnexpectedCommentEnd, MakeToken(Token::CommentEnd, { matchStart, matchStart + 2 }));
+ }
+
+ m_currentBlockInfo.range.startOffset = FinishCurrentBlock(matchStart, TextBlockType::RawText);
+ break;
+ case RM_ExprBegin:
+ StartControlBlock(TextBlockType::Expression, matchStart);
+ break;
+ case RM_ExprEnd:
+ if (m_currentBlockInfo.type == TextBlockType::RawText)
+ {
+ FinishCurrentLine(match.position() + 2);
+ return MakeParseError(ErrorCode::UnexpectedExprEnd, MakeToken(Token::ExprEnd, { matchStart, matchStart + 2 }));
+ }
+ else if (m_currentBlockInfo.type != TextBlockType::Expression || (*m_template)[match.position() - 1] == '\'')
+ break;
+
+ m_currentBlockInfo.range.startOffset = FinishCurrentBlock(matchStart, TextBlockType::RawText);
+ break;
+ case RM_StmtBegin:
+ StartControlBlock(TextBlockType::Statement, matchStart);
+ break;
+ case RM_StmtEnd:
+ if (m_currentBlockInfo.type == TextBlockType::RawText)
+ {
+ FinishCurrentLine(match.position() + 2);
+ return MakeParseError(ErrorCode::UnexpectedStmtEnd, MakeToken(Token::StmtEnd, { matchStart, matchStart + 2 }));
+ }
+ else if (m_currentBlockInfo.type != TextBlockType::Statement || (*m_template)[match.position() - 1] == '\'')
+ break;
+
+ m_currentBlockInfo.range.startOffset = FinishCurrentBlock(matchStart, TextBlockType::RawText);
+ break;
+ case RM_RawBegin:
+ if (m_currentBlockInfo.type == TextBlockType::RawBlock)
+ break;
+ else if (m_currentBlockInfo.type != TextBlockType::RawText && m_currentBlockInfo.type != TextBlockType::Comment)
+ {
+ FinishCurrentLine(match.position() + match.length());
+ return MakeParseError(ErrorCode::UnexpectedRawBegin, MakeToken(Token::RawBegin, { matchStart, matchStart + match.length() }));
+ }
+ StartControlBlock(TextBlockType::RawBlock, matchStart, matchStart + match.length());
+ break;
+ case RM_RawEnd:
+ if (m_currentBlockInfo.type == TextBlockType::Comment)
+ break;
+ else if (m_currentBlockInfo.type != TextBlockType::RawBlock)
+ {
+ FinishCurrentLine(match.position() + match.length());
+ return MakeParseError(ErrorCode::UnexpectedRawEnd, MakeToken(Token::RawEnd, { matchStart, matchStart + match.length() }));
+ }
+ m_currentBlockInfo.range.startOffset = FinishCurrentBlock(matchStart + match.length() - 2, TextBlockType::RawText, matchStart);
+ break;
+ case RM_MetaBegin:
+ if (m_currentBlockInfo.type == TextBlockType::Comment)
+ break;
+ if ((m_currentBlockInfo.type != TextBlockType::RawText && m_currentBlockInfo.type != TextBlockType::Comment) || m_hasMetaBlock)
+ {
+ FinishCurrentLine(match.position() + match.length());
+ return MakeParseError(ErrorCode::UnexpectedMetaBegin, MakeToken(Token::MetaBegin, { matchStart, matchStart + match.length() }));
+ }
+ StartControlBlock(TextBlockType::MetaBlock, matchStart, matchStart + match.length());
+ m_metadataLocation.line = m_currentLineInfo.lineNumber + 1;
+ m_metadataLocation.col = static_cast<unsigned>(match.position() - m_currentLineInfo.range.startOffset + 1);
+ m_metadataLocation.fileName = m_templateName;
+ break;
+ case RM_MetaEnd:
+ if (m_currentBlockInfo.type == TextBlockType::Comment)
+ break;
+ if (m_currentBlockInfo.type != TextBlockType::MetaBlock)
+ {
+ FinishCurrentLine(match.position() + match.length());
+ return MakeParseError(ErrorCode::UnexpectedMetaEnd, MakeToken(Token::MetaEnd, { matchStart, matchStart + match.length() }));
+ }
+ m_currentBlockInfo.range.startOffset = FinishCurrentBlock(matchStart + match.length() - 2, TextBlockType::MetaBlock, matchStart);
+ m_hasMetaBlock = true;
+ break;
+ }
+
+ return nonstd::expected<void, ParseError>();
+ }
+
+ void StartControlBlock(TextBlockType blockType, size_t matchStart, size_t startOffset = 0)
+ {
+ if (!startOffset)
+ startOffset = matchStart + 2;
+
+ size_t endOffset = matchStart;
+ if (m_currentBlockInfo.type != TextBlockType::RawText || m_currentBlockInfo.type == TextBlockType::RawBlock)
+ return;
+ else
+ endOffset = StripBlockLeft(m_currentBlockInfo, startOffset, endOffset, blockType == TextBlockType::Expression ? false : m_settings.lstripBlocks);
+
+ FinishCurrentBlock(endOffset, blockType);
+ if (startOffset < m_template->size() && blockType != TextBlockType::MetaBlock)
+ {
+ if ((*m_template)[startOffset] == '+' || (*m_template)[startOffset] == '-')
+ ++startOffset;
+ }
+
+ m_currentBlockInfo.type = blockType;
+
+ if (blockType == TextBlockType::RawBlock)
+ startOffset = StripBlockRight(m_currentBlockInfo, startOffset - 2, m_settings.trimBlocks);
+
+ m_currentBlockInfo.range.startOffset = startOffset;
+ }
+
+ size_t StripBlockRight(TextBlockInfo& /* currentBlockInfo */, size_t position, bool trimBlocks)
+ {
+ bool doTrim = trimBlocks;
+
+ size_t newPos = position + 2;
+
+ if ((m_currentBlockInfo.type != TextBlockType::RawText) && position != 0)
+ {
+ auto ctrlChar = (*m_template)[position - 1];
+ doTrim = ctrlChar == '-' ? true : (ctrlChar == '+' ? false : doTrim);
+ }
+
+ if (doTrim)
+ {
+ auto locale = std::locale();
+ for (; newPos < m_template->size(); ++newPos)
+ {
+ auto ch = (*m_template)[newPos];
+ if (ch == '\n')
+ {
+ ++newPos;
+ break;
+ }
+ if (!std::isspace(ch, locale))
+ break;
+ }
+ }
+ return newPos;
+ }
+
+ size_t StripBlockLeft(TextBlockInfo& currentBlockInfo, size_t ctrlCharPos, size_t endOffset, bool doStrip)
+ {
+ bool doTotalStrip = false;
+ if (ctrlCharPos < m_template->size())
+ {
+ auto ctrlChar = (*m_template)[ctrlCharPos];
+ if (ctrlChar == '+')
+ doStrip = false;
+ else
+ doTotalStrip = ctrlChar == '-';
+
+ doStrip |= doTotalStrip;
+ }
+ if (!doStrip || (currentBlockInfo.type != TextBlockType::RawText && currentBlockInfo.type != TextBlockType::RawBlock))
+ return endOffset;
+
+ auto locale = std::locale();
+ auto& tpl = *m_template;
+ auto originalOffset = endOffset;
+ bool sameLine = true;
+ for (; endOffset != currentBlockInfo.range.startOffset && endOffset > 0; --endOffset)
+ {
+ auto ch = tpl[endOffset - 1];
+ if (!std::isspace(ch, locale))
+ {
+ if (!sameLine)
+ break;
+
+ return doTotalStrip ? endOffset : originalOffset;
+ }
+ if (ch == '\n')
+ {
+ if (!doTotalStrip)
+ break;
+ sameLine = false;
+ }
+ }
+ return endOffset;
+ }
+
+ nonstd::expected<void, std::vector<ParseError>> DoFineParsing(std::shared_ptr<ComposedRenderer> renderers)
+ {
+ std::vector<ParseError> errors;
+ StatementInfoList statementsStack;
+ StatementInfo root = StatementInfo::Create(StatementInfo::TemplateRoot, Token(), renderers);
+ statementsStack.push_back(root);
+ for (auto& origBlock : m_textBlocks)
+ {
+ auto block = origBlock;
+ if (block.type == TextBlockType::LineStatement)
+ ++block.range.startOffset;
+
+ switch (block.type)
+ {
+ case TextBlockType::RawBlock:
+ case TextBlockType::RawText:
+ {
+ auto range = block.range;
+ if (range.size() == 0)
+ break;
+ auto renderer = std::make_shared<RawTextRenderer>(m_template->data() + range.startOffset, range.size());
+ statementsStack.back().currentComposition->AddRenderer(renderer);
+ break;
+ }
+ case TextBlockType::MetaBlock:
+ {
+ auto range = block.range;
+ if (range.size() == 0)
+ break;
+ auto metadata = std::basic_string_view<CharT>(m_template->data() + range.startOffset, range.size());
+ if (!boost::algorithm::all(metadata, boost::algorithm::is_space()))
+ m_metadata = metadata;
+ break;
+ }
+ case TextBlockType::Expression:
+ {
+ auto parseResult = InvokeParser<RendererPtr, ExpressionParser>(block);
+ if (parseResult)
+ statementsStack.back().currentComposition->AddRenderer(*parseResult);
+ else
+ errors.push_back(parseResult.error());
+ break;
+ }
+ case TextBlockType::Statement:
+ case TextBlockType::LineStatement:
+ {
+ auto parseResult = InvokeParser<void, StatementsParser>(block, statementsStack);
+ if (!parseResult)
+ errors.push_back(parseResult.error());
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ if (!errors.empty())
+ return nonstd::make_unexpected(std::move(errors));
+
+ return nonstd::expected<void, std::vector<ParseError>>();
+ }
+ template<typename R, typename P, typename... Args>
+ nonstd::expected<R, ParseError> InvokeParser(const TextBlockInfo& block, Args&&... args)
+ {
+ lexertk::generator<CharT> tokenizer;
+ auto range = block.range;
+ auto start = m_template->data();
+ if (!tokenizer.process(start + range.startOffset, start + range.endOffset))
+ return MakeParseError(ErrorCode::Unspecified, MakeToken(Token::Unknown, { range.startOffset, range.startOffset + 1 }));
+
+ tokenizer.begin();
+ Lexer lexer(
+ [&tokenizer, adjust = range.startOffset]() mutable {
+ lexertk::token tok = tokenizer.next_token();
+ tok.position += adjust;
+ return tok;
+ },
+ this);
+
+ if (!lexer.Preprocess())
+ return MakeParseError(ErrorCode::Unspecified, MakeToken(Token::Unknown, { range.startOffset, range.startOffset + 1 }));
+
+ P praser(m_settings, m_env);
+ LexScanner scanner(lexer);
+ auto result = praser.Parse(scanner, std::forward<Args>(args)...);
+ if (!result)
+ return result.get_unexpected();
+
+ return result;
+ }
+
+ nonstd::unexpected_type<std::vector<ErrorInfo>> ParseErrorsToErrorInfo(const std::vector<ParseError>& errors)
+ {
+ std::vector<ErrorInfo> resultErrors;
+
+ for (auto& e : errors)
+ {
+ typename ErrorInfo::Data errInfoData;
+ errInfoData.code = e.errorCode;
+ errInfoData.srcLoc.fileName = m_templateName;
+ OffsetToLinePos(e.errorToken.range.startOffset, errInfoData.srcLoc.line, errInfoData.srcLoc.col);
+ errInfoData.locationDescr = GetLocationDescr(errInfoData.srcLoc.line, errInfoData.srcLoc.col);
+ errInfoData.extraParams.emplace_back(TokenToString(e.errorToken));
+ for (auto& tok : e.relatedTokens)
+ {
+ errInfoData.extraParams.emplace_back(TokenToString(tok));
+ if (tok.range.startOffset != e.errorToken.range.startOffset)
+ {
+ SourceLocation relLoc;
+ relLoc.fileName = m_templateName;
+ OffsetToLinePos(tok.range.startOffset, relLoc.line, relLoc.col);
+ errInfoData.relatedLocs.push_back(std::move(relLoc));
+ }
+ }
+
+ resultErrors.emplace_back(errInfoData);
+ }
+
+ return nonstd::make_unexpected(std::move(resultErrors));
+ }
+
+ Token MakeToken(Token::Type type, const CharRange& range, string_t value = string_t())
+ {
+ Token tok;
+ tok.type = type;
+ tok.range = range;
+ tok.value = TargetString(static_cast<string_t>(value));
+
+ return tok;
+ }
+
+ auto TokenToString(const Token& tok)
+ {
+ auto p = traits_t::s_tokens.find(tok.type);
+ if (p != traits_t::s_tokens.end())
+ return p->second.template GetValueStr<CharT>();
+
+ if (tok.range.size() != 0)
+ return string_t(m_template->substr(tok.range.startOffset, tok.range.size()));
+ else if (tok.type == Token::Identifier)
+ {
+ if (!tok.value.IsEmpty())
+ {
+ std::basic_string<CharT> tpl;
+ return GetAsSameString(tpl, tok.value).value_or(std::basic_string<CharT>());
+ }
+
+ return UNIVERSAL_STR("<<Identifier>>").template GetValueStr<CharT>();
+ }
+ else if (tok.type == Token::String)
+ return UNIVERSAL_STR("<<String>>").template GetValueStr<CharT>();
+
+ return string_t();
+ }
+
+ size_t FinishCurrentBlock(size_t position, TextBlockType nextBlockType, size_t matchStart = 0)
+ {
+ size_t newPos = position;
+
+ if (m_currentBlockInfo.type == TextBlockType::RawBlock || m_currentBlockInfo.type == TextBlockType::MetaBlock)
+ {
+ size_t currentPosition = matchStart ? matchStart : position;
+ auto origPos = position;
+ position = StripBlockLeft(m_currentBlockInfo, currentPosition + 2, currentPosition, m_settings.lstripBlocks);
+ newPos = StripBlockRight(m_currentBlockInfo, origPos, m_settings.trimBlocks);
+ }
+ else
+ {
+ if (m_currentBlockInfo.type == TextBlockType::RawText)
+ position =
+ StripBlockLeft(m_currentBlockInfo, position + 2, position, nextBlockType == TextBlockType::Expression ? false : m_settings.lstripBlocks);
+ else if (nextBlockType == TextBlockType::RawText)
+ newPos = StripBlockRight(m_currentBlockInfo, position, m_currentBlockInfo.type == TextBlockType::Expression ? false : m_settings.trimBlocks);
+
+ if ((m_currentBlockInfo.type != TextBlockType::RawText) && position != 0)
+ {
+ auto ctrlChar = (*m_template)[position - 1];
+ if (ctrlChar == '+' || ctrlChar == '-')
+ --position;
+ }
+ }
+
+ m_currentBlockInfo.range.endOffset = position;
+ m_textBlocks.push_back(m_currentBlockInfo);
+ m_currentBlockInfo.type = TextBlockType::RawText;
+ return newPos;
+ }
+
+ void FinishCurrentLine(int64_t position)
+ {
+ m_currentLineInfo.range.endOffset = static_cast<size_t>(position);
+ m_lines.push_back(m_currentLineInfo);
+ m_currentLineInfo.lineNumber++;
+ }
+
+ void OffsetToLinePos(size_t offset, unsigned& line, unsigned& col)
+ {
+ auto p = std::find_if(
+ m_lines.begin(), m_lines.end(), [offset](const LineInfo& info) { return offset >= info.range.startOffset && offset < info.range.endOffset; });
+
+ if (p == m_lines.end())
+ {
+ if (m_lines.empty() || offset != m_lines.back().range.endOffset)
+ {
+ line = 1;
+ col = 1;
+ return;
+ }
+ p = m_lines.end() - 1;
+ }
+
+ line = p->lineNumber + 1;
+ col = static_cast<unsigned>(offset - p->range.startOffset + 1);
+ }
+
+ string_t GetLocationDescr(unsigned line, unsigned col)
+ {
+ if (line == 0 && col == 0)
+ return string_t();
+
+ --line;
+ --col;
+
+ auto toCharT = [](char ch) { return static_cast<CharT>(ch); };
+
+ auto& lineInfo = m_lines[line];
+ std::basic_ostringstream<CharT> os;
+ auto origLine = m_template->substr(lineInfo.range.startOffset, lineInfo.range.size());
+ os << origLine << std::endl;
+
+ string_t spacePrefix;
+ auto locale = std::locale();
+ for (auto ch : origLine)
+ {
+ if (!std::isspace(ch, locale))
+ break;
+ spacePrefix.append(1, ch);
+ }
+
+ const int headLen = 3;
+ const int tailLen = 7;
+ auto spacePrefixLen = spacePrefix.size();
+
+ if (col < spacePrefixLen)
+ {
+ for (unsigned i = 0; i < col; ++i)
+ os << toCharT(' ');
+
+ os << toCharT('^');
+ for (int i = 0; i < tailLen; ++i)
+ os << toCharT('-');
+ return os.str();
+ }
+
+ os << spacePrefix;
+ int actualHeadLen = std::min(static_cast<int>(col - spacePrefixLen), headLen);
+
+ if (actualHeadLen == headLen)
+ {
+ for (std::size_t i = 0; i < col - actualHeadLen - spacePrefixLen; ++i)
+ os << toCharT(' ');
+ }
+ for (int i = 0; i < actualHeadLen; ++i)
+ os << toCharT('-');
+ os << toCharT('^');
+ for (int i = 0; i < tailLen; ++i)
+ os << toCharT('-');
+
+ return os.str();
+ }
+
+ // LexerHelper interface
+ std::string GetAsString(const CharRange& range) override { return traits_t::GetAsString(*m_template, range); }
+ InternalValue GetAsValue(const CharRange& range, Token::Type type) override
+ {
+ if (type == Token::String)
+ {
+ auto rawValue = CompileEscapes(m_template->substr(range.startOffset, range.size()));
+ return InternalValue(TargetString(std::move(rawValue)));
+ }
+ if (type == Token::IntegerNum || type == Token::FloatNum)
+ return traits_t::RangeToNum(*m_template, range, type);
+ return InternalValue();
+ }
+ Keyword GetKeyword(const CharRange& range) override
+ {
+ auto matchBegin = sregex_iterator(m_template->begin() + range.startOffset, m_template->begin() + range.endOffset, m_keywords);
+ auto matchEnd = sregex_iterator();
+
+ auto matches = std::distance(matchBegin, matchEnd);
+ // One line, no customization
+ if (matches == 0)
+ return Keyword::Unknown;
+
+ auto& match = *matchBegin;
+ for (size_t idx = 1; idx != match.size(); ++idx)
+ {
+ if (match.length(idx) != 0)
+ {
+ return traits_t::s_keywordsInfo[idx - 1].type;
+ }
+ }
+
+ return Keyword::Unknown;
+ }
+ char GetCharAt(size_t /*pos*/) override { return '\0'; }
+
+private:
+ const string_t* m_template;
+ std::string m_templateName;
+ const Settings& m_settings;
+ TemplateEnv* m_env = nullptr;
+ BasicRegex<CharT> m_roughTokenizer;
+ BasicRegex<CharT> m_keywords;
+ std::vector<LineInfo> m_lines;
+ std::vector<TextBlockInfo> m_textBlocks;
+ LineInfo m_currentLineInfo = {};
+ TextBlockInfo m_currentBlockInfo = {};
+ bool m_hasMetaBlock = false;
+ std::basic_string_view<CharT> m_metadata;
+ std::string m_metadataType;
+ SourceLocation m_metadataLocation;
+};
+
+template<typename T>
+KeywordsInfo ParserTraitsBase<T>::s_keywordsInfo[41] = {
+ { UNIVERSAL_STR("for"), Keyword::For },
+ { UNIVERSAL_STR("endfor"), Keyword::Endfor },
+ { UNIVERSAL_STR("in"), Keyword::In },
+ { UNIVERSAL_STR("if"), Keyword::If },
+ { UNIVERSAL_STR("else"), Keyword::Else },
+ { UNIVERSAL_STR("elif"), Keyword::ElIf },
+ { UNIVERSAL_STR("endif"), Keyword::EndIf },
+ { UNIVERSAL_STR("or"), Keyword::LogicalOr },
+ { UNIVERSAL_STR("and"), Keyword::LogicalAnd },
+ { UNIVERSAL_STR("not"), Keyword::LogicalNot },
+ { UNIVERSAL_STR("is"), Keyword::Is },
+ { UNIVERSAL_STR("block"), Keyword::Block },
+ { UNIVERSAL_STR("endblock"), Keyword::EndBlock },
+ { UNIVERSAL_STR("extends"), Keyword::Extends },
+ { UNIVERSAL_STR("macro"), Keyword::Macro },
+ { UNIVERSAL_STR("endmacro"), Keyword::EndMacro },
+ { UNIVERSAL_STR("call"), Keyword::Call },
+ { UNIVERSAL_STR("endcall"), Keyword::EndCall },
+ { UNIVERSAL_STR("filter"), Keyword::Filter },
+ { UNIVERSAL_STR("endfilter"), Keyword::EndFilter },
+ { UNIVERSAL_STR("set"), Keyword::Set },
+ { UNIVERSAL_STR("endset"), Keyword::EndSet },
+ { UNIVERSAL_STR("include"), Keyword::Include },
+ { UNIVERSAL_STR("import"), Keyword::Import },
+ { UNIVERSAL_STR("true"), Keyword::True },
+ { UNIVERSAL_STR("false"), Keyword::False },
+ { UNIVERSAL_STR("True"), Keyword::True },
+ { UNIVERSAL_STR("False"), Keyword::False },
+ { UNIVERSAL_STR("none"), Keyword::None },
+ { UNIVERSAL_STR("None"), Keyword::None },
+ { UNIVERSAL_STR("recursive"), Keyword::Recursive },
+ { UNIVERSAL_STR("scoped"), Keyword::Scoped },
+ { UNIVERSAL_STR("with"), Keyword::With },
+ { UNIVERSAL_STR("endwith"), Keyword::EndWith },
+ { UNIVERSAL_STR("without"), Keyword::Without },
+ { UNIVERSAL_STR("ignore"), Keyword::Ignore },
+ { UNIVERSAL_STR("missing"), Keyword::Missing },
+ { UNIVERSAL_STR("context"), Keyword::Context },
+ { UNIVERSAL_STR("from"), Keyword::From },
+ { UNIVERSAL_STR("as"), Keyword::As },
+ { UNIVERSAL_STR("do"), Keyword::Do },
+};
+
+template<typename T>
+std::unordered_map<int, MultiStringLiteral> ParserTraitsBase<T>::s_tokens = {
+ { Token::Unknown, UNIVERSAL_STR("<<Unknown>>") },
+ { Token::Lt, UNIVERSAL_STR("<") },
+ { Token::Gt, UNIVERSAL_STR(">") },
+ { Token::Plus, UNIVERSAL_STR("+") },
+ { Token::Minus, UNIVERSAL_STR("-") },
+ { Token::Percent, UNIVERSAL_STR("%") },
+ { Token::Mul, UNIVERSAL_STR("*") },
+ { Token::Div, UNIVERSAL_STR("/") },
+ { Token::LBracket, UNIVERSAL_STR("(") },
+ { Token::RBracket, UNIVERSAL_STR(")") },
+ { Token::LSqBracket, UNIVERSAL_STR("[") },
+ { Token::RSqBracket, UNIVERSAL_STR("]") },
+ { Token::LCrlBracket, UNIVERSAL_STR("{") },
+ { Token::RCrlBracket, UNIVERSAL_STR("}") },
+ { Token::Assign, UNIVERSAL_STR("=") },
+ { Token::Comma, UNIVERSAL_STR(",") },
+ { Token::Eof, UNIVERSAL_STR("<<End of block>>") },
+ { Token::Equal, UNIVERSAL_STR("==") },
+ { Token::NotEqual, UNIVERSAL_STR("!=") },
+ { Token::LessEqual, UNIVERSAL_STR("<=") },
+ { Token::GreaterEqual, UNIVERSAL_STR(">=") },
+ { Token::StarStar, UNIVERSAL_STR("**") },
+ { Token::DashDash, UNIVERSAL_STR("//") },
+ { Token::LogicalOr, UNIVERSAL_STR("or") },
+ { Token::LogicalAnd, UNIVERSAL_STR("and") },
+ { Token::LogicalNot, UNIVERSAL_STR("not") },
+ { Token::MulMul, UNIVERSAL_STR("**") },
+ { Token::DivDiv, UNIVERSAL_STR("//") },
+ { Token::True, UNIVERSAL_STR("true") },
+ { Token::False, UNIVERSAL_STR("false") },
+ { Token::None, UNIVERSAL_STR("none") },
+ { Token::In, UNIVERSAL_STR("in") },
+ { Token::Is, UNIVERSAL_STR("is") },
+ { Token::For, UNIVERSAL_STR("for") },
+ { Token::Endfor, UNIVERSAL_STR("endfor") },
+ { Token::If, UNIVERSAL_STR("if") },
+ { Token::Else, UNIVERSAL_STR("else") },
+ { Token::ElIf, UNIVERSAL_STR("elif") },
+ { Token::EndIf, UNIVERSAL_STR("endif") },
+ { Token::Block, UNIVERSAL_STR("block") },
+ { Token::EndBlock, UNIVERSAL_STR("endblock") },
+ { Token::Extends, UNIVERSAL_STR("extends") },
+ { Token::Macro, UNIVERSAL_STR("macro") },
+ { Token::EndMacro, UNIVERSAL_STR("endmacro") },
+ { Token::Call, UNIVERSAL_STR("call") },
+ { Token::EndCall, UNIVERSAL_STR("endcall") },
+ { Token::Filter, UNIVERSAL_STR("filter") },
+ { Token::EndFilter, UNIVERSAL_STR("endfilter") },
+ { Token::Set, UNIVERSAL_STR("set") },
+ { Token::EndSet, UNIVERSAL_STR("endset") },
+ { Token::Include, UNIVERSAL_STR("include") },
+ { Token::Import, UNIVERSAL_STR("import") },
+ { Token::Recursive, UNIVERSAL_STR("recursive") },
+ { Token::Scoped, UNIVERSAL_STR("scoped") },
+ { Token::With, UNIVERSAL_STR("with") },
+ { Token::EndWith, UNIVERSAL_STR("endwith") },
+ { Token::Without, UNIVERSAL_STR("without") },
+ { Token::Ignore, UNIVERSAL_STR("ignore") },
+ { Token::Missing, UNIVERSAL_STR("missing") },
+ { Token::Context, UNIVERSAL_STR("context") },
+ { Token::From, UNIVERSAL_STR("form") },
+ { Token::As, UNIVERSAL_STR("as") },
+ { Token::Do, UNIVERSAL_STR("do") },
+ { Token::RawBegin, UNIVERSAL_STR("{% raw %}") },
+ { Token::RawEnd, UNIVERSAL_STR("{% endraw %}") },
+ { Token::MetaBegin, UNIVERSAL_STR("{% meta %}") },
+ { Token::MetaEnd, UNIVERSAL_STR("{% endmeta %}") },
+ { Token::CommentBegin, UNIVERSAL_STR("{#") },
+ { Token::CommentEnd, UNIVERSAL_STR("#}") },
+ { Token::StmtBegin, UNIVERSAL_STR("{%") },
+ { Token::StmtEnd, UNIVERSAL_STR("%}") },
+ { Token::ExprBegin, UNIVERSAL_STR("{{") },
+ { Token::ExprEnd, UNIVERSAL_STR("}}") },
+};
+
+} // namespace jinja2
+
+#endif // JINJA2CPP_SRC_TEMPLATE_PARSER_H
diff --git a/contrib/libs/jinja2cpp/src/testers.cpp b/contrib/libs/jinja2cpp/src/testers.cpp
new file mode 100644
index 0000000000..ce9d255d82
--- /dev/null
+++ b/contrib/libs/jinja2cpp/src/testers.cpp
@@ -0,0 +1,379 @@
+#include "testers.h"
+#include "value_visitors.h"
+
+namespace jinja2
+{
+
+template<typename F>
+struct TesterFactory
+{
+ static TesterPtr Create(TesterParams params)
+ {
+ return std::make_shared<F>(std::move(params));
+ }
+
+ template<typename ... Args>
+ static IsExpression::TesterFactoryFn MakeCreator(Args&& ... args)
+ {
+ return [args...](TesterParams params) {return std::make_shared<F>(std::move(params), args...);};
+ }
+};
+
+std::unordered_map<std::string, IsExpression::TesterFactoryFn> s_testers = {
+ {"defined", TesterFactory<testers::ValueTester>::MakeCreator(testers::ValueTester::IsDefinedMode)},
+ {"startsWith", &TesterFactory<testers::StartsWith>::Create},
+ {"eq", TesterFactory<testers::Comparator>::MakeCreator(BinaryExpression::LogicalEq)},
+ {"==", TesterFactory<testers::Comparator>::MakeCreator(BinaryExpression::LogicalEq)},
+ {"equalto", TesterFactory<testers::Comparator>::MakeCreator(BinaryExpression::LogicalEq)},
+ {"even", TesterFactory<testers::ValueTester>::MakeCreator(testers::ValueTester::IsEvenMode)},
+ {"ge", TesterFactory<testers::Comparator>::MakeCreator(BinaryExpression::LogicalGe)},
+ {">=", TesterFactory<testers::Comparator>::MakeCreator(BinaryExpression::LogicalGe)},
+ {"gt", TesterFactory<testers::Comparator>::MakeCreator(BinaryExpression::LogicalGt)},
+ {">", TesterFactory<testers::Comparator>::MakeCreator(BinaryExpression::LogicalGt)},
+ {"greaterthan", TesterFactory<testers::Comparator>::MakeCreator(BinaryExpression::LogicalGt)},
+ {"in", TesterFactory<testers::ValueTester>::MakeCreator(testers::ValueTester::IsInMode)},
+ {"iterable", TesterFactory<testers::ValueTester>::MakeCreator(testers::ValueTester::IsIterableMode)},
+ {"le", TesterFactory<testers::Comparator>::MakeCreator(BinaryExpression::LogicalLe)},
+ {"<=", TesterFactory<testers::Comparator>::MakeCreator(BinaryExpression::LogicalLe)},
+ {"lower", TesterFactory<testers::ValueTester>::MakeCreator(testers::ValueTester::IsLowerMode)},
+ {"lt", TesterFactory<testers::Comparator>::MakeCreator(BinaryExpression::LogicalLt)},
+ {"<", TesterFactory<testers::Comparator>::MakeCreator(BinaryExpression::LogicalLt)},
+ {"lessthan", TesterFactory<testers::Comparator>::MakeCreator(BinaryExpression::LogicalLt)},
+ {"mapping", TesterFactory<testers::ValueTester>::MakeCreator(testers::ValueTester::IsMappingMode)},
+ {"ne", TesterFactory<testers::Comparator>::MakeCreator(BinaryExpression::LogicalNe)},
+ {"!=", TesterFactory<testers::Comparator>::MakeCreator(BinaryExpression::LogicalNe)},
+ {"number", TesterFactory<testers::ValueTester>::MakeCreator(testers::ValueTester::IsNumberMode)},
+ {"odd", TesterFactory<testers::ValueTester>::MakeCreator(testers::ValueTester::IsOddMode)},
+ {"sequence", TesterFactory<testers::ValueTester>::MakeCreator(testers::ValueTester::IsSequenceMode)},
+ {"string", TesterFactory<testers::ValueTester>::MakeCreator(testers::ValueTester::IsStringMode)},
+ {"undefined", TesterFactory<testers::ValueTester>::MakeCreator(testers::ValueTester::IsUndefinedMode)},
+ {"upper", TesterFactory<testers::ValueTester>::MakeCreator(testers::ValueTester::IsUpperMode)},
+};
+
+TesterPtr CreateTester(std::string testerName, CallParamsInfo params)
+{
+ auto p = s_testers.find(testerName);
+ if (p == s_testers.end())
+ return std::make_shared<testers::UserDefinedTester>(std::move(testerName), std::move(params));
+
+ return p->second(std::move(params));
+}
+
+namespace testers
+{
+
+Comparator::Comparator(TesterParams params, BinaryExpression::Operation op)
+ : m_op(op)
+{
+ ParseParams({{"b", true}}, params);
+}
+
+bool Comparator::Test(const InternalValue& baseVal, RenderContext& context)
+{
+ auto b = GetArgumentValue("b", context);
+
+ auto cmpRes = Apply2<visitors::BinaryMathOperation>(baseVal, b, m_op);
+ return ConvertToBool(cmpRes);
+}
+
+#if 0
+bool Defined::Test(const InternalValue& baseVal, RenderContext& /*context*/)
+{
+ return boost::get<EmptyValue>(&baseVal) == nullptr;
+}
+#endif
+
+StartsWith::StartsWith(TesterParams params)
+{
+ bool parsed = true;
+ auto args = helpers::ParseCallParamsInfo({ { "str", true } }, params, parsed);
+ m_stringEval = args["str"];
+}
+
+bool StartsWith::Test(const InternalValue& baseVal, RenderContext& context)
+{
+ InternalValue val = m_stringEval->Evaluate(context);
+ std::string baseStr = AsString(baseVal);
+ std::string str = AsString(val);
+ return baseStr.find(str) == 0;
+}
+
+ValueTester::ValueTester(TesterParams params, ValueTester::Mode mode)
+ : m_mode(mode)
+{
+ switch (m_mode)
+ {
+ case IsDefinedMode:
+ break;
+ case IsEvenMode:
+ break;
+ case IsInMode:
+ ParseParams({{"seq", true}}, params);
+ break;
+ case IsIterableMode:
+ break;
+ case IsLowerMode:
+ break;
+ case IsMappingMode:
+ break;
+ case IsNumberMode:
+ break;
+ case IsOddMode:
+ break;
+ case IsSequenceMode:
+ break;
+ case IsStringMode:
+ break;
+ case IsUndefinedMode:
+ break;
+ case IsUpperMode:
+ break;
+
+ }
+}
+
+enum class ValueKind
+{
+ Empty,
+ Boolean,
+ String,
+ Integer,
+ Double,
+ List,
+ Map,
+ KVPair,
+ Callable,
+ Renderer
+};
+
+struct ValueKindGetter : visitors::BaseVisitor<ValueKind>
+{
+ using visitors::BaseVisitor<ValueKind>::operator ();
+
+ ValueKind operator()(const EmptyValue&) const
+ {
+ return ValueKind::Empty;
+ }
+ ValueKind operator()(bool) const
+ {
+ return ValueKind::Boolean;
+ }
+ template<typename CharT>
+ ValueKind operator()(const std::basic_string<CharT>&) const
+ {
+ return ValueKind::String;
+ }
+ template<typename CharT>
+ ValueKind operator()(const std::basic_string_view<CharT>&) const
+ {
+ return ValueKind::String;
+ }
+ ValueKind operator()(int64_t) const
+ {
+ return ValueKind::Integer;
+ }
+ ValueKind operator()(double) const
+ {
+ return ValueKind::Double;
+ }
+ ValueKind operator()(const ListAdapter&) const
+ {
+ return ValueKind::List;
+ }
+ ValueKind operator()(const MapAdapter&) const
+ {
+ return ValueKind::Map;
+ }
+ ValueKind operator()(const KeyValuePair&) const
+ {
+ return ValueKind::KVPair;
+ }
+ ValueKind operator()(const Callable&) const
+ {
+ return ValueKind::Callable;
+ }
+ ValueKind operator()(IRendererBase*) const
+ {
+ return ValueKind::Renderer;
+ }
+};
+
+bool ValueTester::Test(const InternalValue& baseVal, RenderContext& context)
+{
+ bool result = false;
+ auto valKind = Apply<ValueKindGetter>(baseVal);
+ enum
+ {
+ EvenTest,
+ OddTest
+ };
+
+ int testMode = EvenTest;
+ auto evenOddTest = [&testMode, valKind](const InternalValue& val) -> bool
+ {
+ bool result = false;
+ if (valKind == ValueKind::Integer)
+ {
+ auto intVal = ConvertToInt(val);
+ result = (intVal & 1) == (testMode == EvenTest ? 0 : 1);
+ }
+ else if (valKind == ValueKind::Double)
+ {
+ auto dblVal = ConvertToDouble(val);
+ int64_t intVal = static_cast<int64_t>(dblVal);
+ if (dblVal == intVal)
+ result = (intVal & 1) == (testMode == EvenTest ? 0 : 1);
+ }
+ return result;
+ };
+
+ switch (m_mode)
+ {
+ case IsIterableMode:
+ result = valKind == ValueKind::List || valKind == ValueKind::Map;
+ break;
+ case IsMappingMode:
+ result = valKind == ValueKind::KVPair || valKind == ValueKind::Map;
+ break;
+ case IsNumberMode:
+ result = valKind == ValueKind::Integer || valKind == ValueKind::Double;
+ break;
+ case IsSequenceMode:
+ result = valKind == ValueKind::List;
+ break;
+ case IsStringMode:
+ result = valKind == ValueKind::String;
+ break;
+ case IsDefinedMode:
+ result = valKind != ValueKind::Empty;
+ break;
+ case IsUndefinedMode:
+ result = valKind == ValueKind::Empty;
+ break;
+ case IsInMode:
+ {
+ bool isConverted = false;
+ auto seq = GetArgumentValue("seq", context);
+ auto seqKind = Apply<ValueKindGetter>(seq);
+ if (seqKind == ValueKind::List) {
+ ListAdapter values = ConvertToList(seq, InternalValue(), isConverted);
+
+ if (!isConverted)
+ return false;
+
+ auto equalComparator = [&baseVal](auto& val) {
+ InternalValue cmpRes;
+ cmpRes = Apply2<visitors::BinaryMathOperation>(val, baseVal, BinaryExpression::LogicalEq);
+ return ConvertToBool(cmpRes);
+ };
+
+ auto p = std::find_if(values.begin(), values.end(), equalComparator);
+ result = p != values.end();
+ } else if (seqKind == ValueKind::String) {
+ result = ApplyStringConverter(baseVal, [&](const auto& srcStr) {
+ std::decay_t<decltype(srcStr)> emptyStrView;
+ using CharT = typename decltype(emptyStrView)::value_type;
+ std::basic_string<CharT> emptyStr;
+
+ auto substring = sv_to_string(srcStr);
+ auto seq = GetAsSameString(srcStr, this->GetArgumentValue("seq", context)).value_or(emptyStr);
+
+ return seq.find(substring) != std::string::npos;
+ });
+ }
+ break;
+ }
+ case IsEvenMode:
+ {
+ testMode = EvenTest;
+ result = evenOddTest(baseVal);
+ break;
+ }
+ case IsOddMode:
+ {
+ testMode = OddTest;
+ result = evenOddTest(baseVal);
+ break;
+ }
+ case IsLowerMode:
+ if (valKind != ValueKind::String)
+ {
+ result = false;
+ }
+ else
+ {
+ result = ApplyStringConverter(baseVal, [](const auto& str) {
+ bool result = true;
+ for (auto& ch : str)
+ {
+ if (std::isalpha(ch, std::locale()) && std::isupper(ch, std::locale()))
+ {
+ result = false;
+ break;
+ }
+ }
+ return result;
+ });
+ }
+ break;
+ case IsUpperMode:
+ if (valKind != ValueKind::String)
+ {
+ result = false;
+ }
+ else
+ {
+ result = ApplyStringConverter(baseVal, [](const auto& str) {
+ bool result = true;
+ for (auto& ch : str)
+ {
+ if (std::isalpha(ch, std::locale()) && std::islower(ch, std::locale()))
+ {
+ result = false;
+ break;
+ }
+ }
+ return result;
+ });
+ }
+ break;
+
+ }
+ return result;
+}
+
+UserDefinedTester::UserDefinedTester(std::string testerName, TesterParams params)
+ : m_testerName(std::move(testerName))
+{
+ ParseParams({{"*args"}, {"**kwargs"}}, params);
+ m_callParams.kwParams = m_args.extraKwArgs;
+ m_callParams.posParams = m_args.extraPosArgs;
+}
+
+bool UserDefinedTester::Test(const InternalValue& baseVal, RenderContext& context)
+{
+ bool testerFound = false;
+ auto testerValPtr = context.FindValue(m_testerName, testerFound);
+ if (!testerFound)
+ return false;
+
+ const Callable* callable = GetIf<Callable>(&testerValPtr->second);
+ if (callable == nullptr || callable->GetKind() != Callable::UserCallable)
+ return false;
+
+ CallParams tmpCallParams = helpers::EvaluateCallParams(m_callParams, context);
+ CallParams callParams;
+ callParams.kwParams = std::move(tmpCallParams.kwParams);
+ callParams.posParams.reserve(tmpCallParams.posParams.size() + 1);
+ callParams.posParams.push_back(baseVal);
+ for (auto& p : tmpCallParams.posParams)
+ callParams.posParams.push_back(std::move(p));
+
+ InternalValue result;
+ if (callable->GetType() != Callable::Type::Expression)
+ return false;
+
+ return ConvertToBool(callable->GetExpressionCallable()(callParams, context));
+}
+} // namespace testers
+} // namespace jinja2
diff --git a/contrib/libs/jinja2cpp/src/testers.h b/contrib/libs/jinja2cpp/src/testers.h
new file mode 100644
index 0000000000..9d29e6cbc1
--- /dev/null
+++ b/contrib/libs/jinja2cpp/src/testers.h
@@ -0,0 +1,116 @@
+#ifndef JINJA2CPP_SRC_TESTERS_H
+#define JINJA2CPP_SRC_TESTERS_H
+
+#include "expression_evaluator.h"
+#include "function_base.h"
+#include "jinja2cpp/value.h"
+#include "render_context.h"
+
+#include <memory>
+#include <functional>
+
+namespace jinja2
+{
+using TesterPtr = std::shared_ptr<IsExpression::ITester>;
+using TesterParams = CallParamsInfo;
+
+extern TesterPtr CreateTester(std::string testerName, CallParamsInfo params);
+
+namespace testers
+{
+
+class TesterBase : public FunctionBase, public IsExpression::ITester
+{
+};
+
+class Comparator : public TesterBase
+{
+public:
+ Comparator(TesterParams params, BinaryExpression::Operation op);
+
+ bool Test(const InternalValue& baseVal, RenderContext& context) override;
+ bool IsEqual(const IComparable& other) const override
+ {
+ auto* val = dynamic_cast<const Comparator*>(&other);
+ if (!val)
+ return false;
+ return m_op == val->m_op;
+ }
+private:
+ BinaryExpression::Operation m_op;
+};
+
+class StartsWith : public IsExpression::ITester
+{
+public:
+ StartsWith(TesterParams);
+
+ bool Test(const InternalValue& baseVal, RenderContext& context) override;
+
+ bool IsEqual(const IComparable& other) const override
+ {
+ auto* val = dynamic_cast<const StartsWith*>(&other);
+ if (!val)
+ return false;
+ return m_stringEval == val->m_stringEval;
+ }
+private:
+ ExpressionEvaluatorPtr<> m_stringEval;
+};
+
+class ValueTester : public TesterBase
+{
+public:
+ enum Mode
+ {
+ IsDefinedMode,
+ IsEvenMode,
+ IsInMode,
+ IsIterableMode,
+ IsLowerMode,
+ IsMappingMode,
+ IsNumberMode,
+ IsOddMode,
+ IsSequenceMode,
+ IsStringMode,
+ IsUndefinedMode,
+ IsUpperMode
+ };
+
+ ValueTester(TesterParams params, Mode mode);
+
+ bool Test(const InternalValue& baseVal, RenderContext& context) override;
+
+ bool IsEqual(const IComparable& other) const override
+ {
+ auto* val = dynamic_cast<const ValueTester*>(&other);
+ if (!val)
+ return false;
+ return m_mode == val->m_mode;
+ }
+private:
+ Mode m_mode;
+};
+
+class UserDefinedTester : public TesterBase
+{
+public:
+ UserDefinedTester(std::string filterName, TesterParams params);
+
+ bool Test(const InternalValue& baseVal, RenderContext& context) override;
+
+ bool IsEqual(const IComparable& other) const override
+ {
+ auto* val = dynamic_cast<const UserDefinedTester*>(&other);
+ if (!val)
+ return false;
+ return m_testerName == val->m_testerName && m_callParams == val->m_callParams;
+ }
+private:
+ std::string m_testerName;
+ TesterParams m_callParams;
+};
+} // namespace testers
+} // namespace jinja2
+
+#endif // JINJA2CPP_SRC_TESTERS_H
diff --git a/contrib/libs/jinja2cpp/src/value.cpp b/contrib/libs/jinja2cpp/src/value.cpp
new file mode 100644
index 0000000000..3139b29ac2
--- /dev/null
+++ b/contrib/libs/jinja2cpp/src/value.cpp
@@ -0,0 +1,143 @@
+#if 0
+#include "jinja2cpp/value.h"
+#include <sstream>
+
+namespace jinja2
+{
+template<typename T>
+std::string toString(T val)
+{
+ std::ostringstream os;
+ os << val;
+ return os.str();
+}
+
+namespace
+{
+struct ValueRenderer : boost::static_visitor<std::string>
+{
+ std::string operator() (bool val) const
+ {
+ return val ? "True" : "False";
+ }
+ std::string operator() (const EmptyValue&) const
+ {
+ return std::string();
+ }
+ std::string operator() (const std::wstring&) const
+ {
+ return std::string();
+ }
+
+ std::string operator() (const ValuesList& vals) const
+ {
+ std::string result = "{";
+ bool isFirst = true;
+ for (auto& val : vals)
+ {
+ if (isFirst)
+ isFirst = false;
+ else
+ result += ", ";
+
+ result += boost::apply_visitor(ValueRenderer(), val.data());
+ }
+ result += "}";
+ return result;
+ }
+
+ std::string operator() (const ValuesMap& vals) const
+ {
+ std::string result = "{";
+ bool isFirst = true;
+ for (auto& val : vals)
+ {
+ if (isFirst)
+ isFirst = false;
+ else
+ result += ", ";
+
+ result += "{\"" + val.first + "\",";
+ result += boost::apply_visitor(ValueRenderer(), val.second.data());
+ result += "}";
+ }
+ result += "}";
+ return result;
+ }
+
+ std::string operator() (const GenericMap& /*val*/) const
+ {
+ return "";
+ }
+
+ std::string operator() (const GenericList& /*val*/) const
+ {
+ return "";
+ }
+
+ template<typename T>
+ std::string operator() (const T& val) const
+ {
+ return toString(val);
+ }
+};
+
+struct SubscriptionVisitor : public boost::static_visitor<InternalValue>
+{
+ InternalValue operator() (const ValuesMap& values, const std::string& field) const
+ {
+ auto p = values.find(field);
+ if (p == values.end())
+ return InternalValue();
+
+ return p->second;
+ }
+
+ InternalValue operator() (const GenericMap& values, const std::string& field) const
+ {
+ if (!values.HasValue(field))
+ return InternalValue();
+
+ return values.GetValueByName(field);
+ }
+
+ InternalValue operator() (const GenericMap& values, const int64_t index) const
+ {
+ if (index < 0 || static_cast<size_t>(index) >= values.GetSize())
+ return InternalValue();
+
+ return values.GetValueByIndex(index);
+ }
+
+ InternalValue operator() (const ValuesList& values, int64_t index) const
+ {
+ if (index < 0 || static_cast<size_t>(index) >= values.size())
+ return InternalValue();
+
+ return values[static_cast<size_t>(index)];
+ }
+
+ InternalValue operator() (const GenericList& values, const int64_t index) const
+ {
+ if (index < 0 || static_cast<size_t>(index) >= values.GetSize())
+ return InternalValue();
+
+ return values.GetValueByIndex(index);
+ }
+
+ template<typename T, typename U>
+ InternalValue operator() (T&& /*first*/, U&& /*second*/) const
+ {
+ return InternalValue();
+ }
+};
+
+} //
+
+InternalValue InternalValue::subscript(const InternalValue& index) const
+{
+ return boost::apply_visitor(SubscriptionVisitor(), m_data, index.m_data);
+}
+
+} // jinja2
+#endif
diff --git a/contrib/libs/jinja2cpp/src/value_helpers.h b/contrib/libs/jinja2cpp/src/value_helpers.h
new file mode 100644
index 0000000000..d5ac829fc4
--- /dev/null
+++ b/contrib/libs/jinja2cpp/src/value_helpers.h
@@ -0,0 +1,167 @@
+#ifndef JINJA2CPP_SRC_VALUE_HELPERS_H
+#define JINJA2CPP_SRC_VALUE_HELPERS_H
+
+#include <jinja2cpp/value.h>
+
+#include <boost/iterator/iterator_facade.hpp>
+
+namespace jinja2
+{
+#if 0
+class GenericListIterator
+ : public boost::iterator_facade<
+ GenericListIterator,
+ const InternalValue,
+ boost::random_access_traversal_tag>
+{
+public:
+ GenericListIterator()
+ : m_current(0)
+ , m_list(nullptr)
+ {}
+
+ explicit GenericListIterator(GenericList& list)
+ : m_current(0)
+ , m_list(&list)
+ {}
+
+private:
+ friend class boost::iterator_core_access;
+
+ void increment()
+ {
+ ++ m_current;
+ m_valueIdx = m_current;
+ m_currentVal = m_current == m_list->GetSize() ? InternalValue() : m_list->GetValueByIndex(static_cast<int64_t>(m_current));
+ }
+
+ int distance_to(const GenericListIterator& other) const
+ {
+ if (m_list == nullptr)
+ return other.m_list == nullptr ? 0 : -other.distance_to(*this);
+
+ if (other.m_list == nullptr)
+ return m_list->GetSize() - m_current;
+
+ return other.m_current - m_current;
+ }
+
+ void advance(int distance)
+ {
+ m_current += distance;
+ if (distance != 0)
+ {
+ m_valueIdx = m_current;
+ m_currentVal = m_current == m_list->GetSize() ? InternalValue() : m_list->GetValueByIndex(static_cast<int64_t>(m_current));
+
+ }
+ }
+
+ bool equal(const GenericListIterator& other) const
+ {
+ if (m_list == nullptr)
+ return other.m_list == nullptr ? true : other.equal(*this);
+
+ if (other.m_list == nullptr)
+ return m_current == m_list->GetSize();
+
+ return this->m_list == other.m_list && this->m_current == other.m_current;
+ }
+
+ const InternalValue& dereference() const
+ {
+ if (m_current != m_valueIdx)
+ m_currentVal = m_current == m_list->GetSize() ? InternalValue() : m_list->GetValueByIndex(static_cast<int64_t>(m_current));
+ return m_currentVal;
+ }
+
+ int64_t m_current = 0;
+ mutable int64_t m_valueIdx = -1;
+ mutable InternalValue m_currentVal;
+ GenericList* m_list;
+};
+
+class ConstGenericListIterator
+ : public boost::iterator_facade<
+ GenericListIterator,
+ const InternalValue,
+ boost::random_access_traversal_tag>
+{
+public:
+ ConstGenericListIterator()
+ : m_current(0)
+ , m_list(nullptr)
+ {}
+
+ explicit ConstGenericListIterator(const GenericList& list)
+ : m_current(0)
+ , m_list(&list)
+ {}
+
+private:
+ friend class boost::iterator_core_access;
+
+ void increment()
+ {
+ ++ m_current;
+ }
+
+ int distance_to(const ConstGenericListIterator& other) const
+ {
+ if (m_list == nullptr)
+ return other.m_list == nullptr ? 0 : -other.distance_to(*this);
+
+ if (other.m_list == nullptr)
+ return m_list->GetSize() - m_current;
+
+ return other.m_current - m_current;
+ }
+
+ void advance(int distance)
+ {
+ m_current += distance;
+ }
+
+ bool equal(const ConstGenericListIterator& other) const
+ {
+ if (m_list == nullptr)
+ return other.m_list == nullptr ? true : other.equal(*this);
+
+ if (other.m_list == nullptr)
+ return m_current == m_list->GetSize();
+
+ return this->m_list == other.m_list && this->m_current == other.m_current;
+ }
+
+ const InternalValue& dereference() const
+ {
+ return m_list->GetValueByIndex(static_cast<int64_t>(m_current));
+ }
+
+ size_t m_current;
+ const GenericList* m_list;
+};
+
+inline auto begin(GenericList& list)
+{
+ return GenericListIterator(list);
+}
+
+inline auto end(GenericList& list)
+{
+ return GenericListIterator();
+}
+
+inline auto begin(const GenericList& list)
+{
+ return ConstGenericListIterator(list);
+}
+
+inline auto end(const GenericList& list)
+{
+ return ConstGenericListIterator();
+}
+#endif
+} // namespace jinja2
+
+#endif // JINJA2CPP_SRC_VALUE_HELPERS_H
diff --git a/contrib/libs/jinja2cpp/src/value_visitors.h b/contrib/libs/jinja2cpp/src/value_visitors.h
new file mode 100644
index 0000000000..8814f645cf
--- /dev/null
+++ b/contrib/libs/jinja2cpp/src/value_visitors.h
@@ -0,0 +1,1151 @@
+#ifndef JINJA2CPP_SRC_VALUE_VISITORS_H
+#define JINJA2CPP_SRC_VALUE_VISITORS_H
+
+#include "expression_evaluator.h"
+#include "helpers.h"
+#include "jinja2cpp/value.h"
+
+#include <boost/algorithm/string/predicate.hpp>
+#include <boost/optional.hpp>
+#include <fmt/format.h>
+#include <fmt/xchar.h>
+
+#include <iostream>
+#include <cmath>
+#include <limits>
+#include <utility>
+#include <typeinfo>
+
+namespace jinja2
+{
+
+namespace detail
+{
+
+template<typename V>
+struct RecursiveUnwrapper
+{
+ V* m_visitor{};
+
+ RecursiveUnwrapper(V* v)
+ : m_visitor(v)
+ {}
+
+
+ template<typename T>
+ static const auto& UnwrapRecursive(const T& arg)
+ {
+ return arg; // std::forward<T>(arg);
+ }
+
+ template<typename T>
+ static auto& UnwrapRecursive(const RecursiveWrapper<T>& arg)
+ {
+ return arg.GetValue();
+ }
+
+// template<typename T>
+// static auto& UnwrapRecursive(RecursiveWrapper<T>& arg)
+// {
+// return arg.GetValue();
+// }
+
+ template<typename ... Args>
+ auto operator()(const Args& ... args) const
+ {
+ assert(m_visitor != nullptr);
+ return (*m_visitor)(UnwrapRecursive(args)...);
+ }
+};
+
+template<typename Fn>
+auto ApplyUnwrapped(const InternalValueData& val, Fn&& fn)
+{
+ auto valueRef = GetIf<ValueRef>(&val);
+ auto targetString = GetIf<TargetString>(&val);
+ auto targetSV = GetIf<TargetStringView>(&val);
+ // auto internalValueRef = GetIf<InternalValueRef>(&val);
+
+ if (valueRef != nullptr)
+ return fn(valueRef->get().data());
+ else if (targetString != nullptr)
+ return fn(*targetString);
+ else if (targetSV != nullptr)
+ return fn(*targetSV);
+// else if (internalValueRef != nullptr)
+// return fn(internalValueRef->get());
+
+ return fn(val);
+}
+} // namespace detail
+
+template<typename V, typename ... Args>
+auto Apply(const InternalValue& val, Args&& ... args)
+{
+ return detail::ApplyUnwrapped(val.GetData(), [&args...](auto& val) {
+ auto v = V(args...);
+ return std::visit(detail::RecursiveUnwrapper<V>(&v), val);
+ });
+}
+
+template<typename V, typename ... Args>
+auto Apply2(const InternalValue& val1, const InternalValue& val2, Args&& ... args)
+{
+ return detail::ApplyUnwrapped(val1.GetData(), [&val2, &args...](auto& uwVal1) {
+ return detail::ApplyUnwrapped(val2.GetData(), [&uwVal1, &args...](auto& uwVal2) {
+ auto v = V(args...);
+ return std::visit(detail::RecursiveUnwrapper<V>(&v), uwVal1, uwVal2);
+ });
+ });
+}
+
+bool ConvertToBool(const InternalValue& val);
+
+namespace visitors
+{
+template<typename R = InternalValue>
+struct BaseVisitor
+{
+ R operator() (const GenericMap&) const
+ {
+ assert(false);
+ return R();
+ }
+
+ R operator() (const GenericList&) const
+ {
+ assert(false);
+ return R();
+ }
+
+ R operator() (const ValueRef&) const
+ {
+ assert(false);
+ return R();
+ }
+
+ R operator() (const TargetString&) const
+ {
+ assert(false);
+ return R();
+ }
+
+ template<typename T>
+ R operator() (T&&) const
+ {
+ return R();
+ }
+
+ template<typename T, typename U>
+ R operator() (T&&, U&&) const
+ {
+ return R();
+ }
+};
+
+
+template<typename CharT>
+struct ValueRendererBase
+{
+ ValueRendererBase(std::basic_string<CharT>& os)
+ : m_os(&os)
+ {
+ }
+
+ template<typename T>
+ void operator()(const T& val) const;
+ void operator()(double val) const;
+ void operator()(const std::basic_string_view<CharT>& val) const
+ {
+ m_os->append(val.begin(), val.end());
+ }
+ void operator()(const std::basic_string<CharT>& val) const
+ {
+ m_os->append(val.begin(), val.end());
+ }
+
+ void operator()(const EmptyValue&) const {}
+ void operator()(const ValuesList&) const {}
+ void operator()(const ValuesMap&) const {}
+ void operator()(const GenericMap&) const {}
+ void operator()(const GenericList&) const {}
+ void operator()(const MapAdapter&) const {}
+ void operator()(const ListAdapter&) const {}
+ void operator()(const ValueRef&) const {}
+ void operator()(const TargetString&) const {}
+ void operator()(const TargetStringView&) const {}
+ void operator()(const KeyValuePair&) const {}
+ void operator()(const Callable&) const {}
+ void operator()(const UserCallable&) const {}
+ void operator()(const std::shared_ptr<IRendererBase>) const {}
+ template<typename T>
+ void operator()(const boost::recursive_wrapper<T>&) const {}
+ template<typename T>
+ void operator()(const RecWrapper<T>&) const {}
+
+ auto GetOs() const { return std::back_inserter(*m_os); }
+
+ std::basic_string<CharT>* m_os;
+};
+
+template<>
+template<typename T>
+void ValueRendererBase<char>::operator()(const T& val) const
+{
+ fmt::format_to(GetOs(), "{}", val);
+}
+
+template<>
+template<typename T>
+void ValueRendererBase<wchar_t>::operator()(const T& val) const
+{
+ fmt::format_to(GetOs(), L"{}", val);
+}
+
+template<>
+inline void ValueRendererBase<char>::operator()(double val) const
+{
+ fmt::format_to(GetOs(), "{:.8g}", val);
+}
+
+template<>
+inline void ValueRendererBase<wchar_t>::operator()(double val) const
+{
+ fmt::format_to(GetOs(), L"{:.8g}", val);
+}
+
+struct InputValueConvertor
+{
+ using result_t = boost::optional<InternalValue>;
+
+ InputValueConvertor(bool byValue, bool allowStringRef)
+ : m_byValue(byValue)
+ , m_allowStringRef(allowStringRef)
+ {
+ }
+
+ template<typename ChT>
+ result_t operator()(const std::basic_string<ChT>& val) const
+ {
+ if (m_allowStringRef)
+ return result_t(TargetStringView(std::basic_string_view<ChT>(val)));
+
+ return result_t(TargetString(val));
+ }
+
+ template<typename ChT>
+ result_t operator()(std::basic_string<ChT>& val) const
+ {
+ return result_t(TargetString(std::move(val)));
+ }
+
+ result_t operator()(const ValuesList& vals) const
+ {
+ if (m_byValue)
+ {
+ ValuesList newVals(vals);
+ return result_t(InternalValue(ListAdapter::CreateAdapter(std::move(newVals))));
+ }
+
+ return result_t(InternalValue(ListAdapter::CreateAdapter(vals)));
+ }
+
+ result_t operator() (ValuesList& vals) const
+ {
+ return result_t(InternalValue(ListAdapter::CreateAdapter(std::move(vals))));
+ }
+
+ result_t operator() (const GenericList& vals) const
+ {
+ if (m_byValue)
+ {
+ GenericList newVals(vals);
+ return result_t(InternalValue(ListAdapter::CreateAdapter(std::move(newVals))));
+ }
+
+ return result_t(InternalValue(ListAdapter::CreateAdapter(vals)));
+ }
+
+ result_t operator() (GenericList& vals) const
+ {
+ return result_t(InternalValue(ListAdapter::CreateAdapter(std::move(vals))));
+ }
+
+ result_t operator()(const ValuesMap& vals) const
+ {
+ if (m_byValue)
+ {
+ ValuesMap newVals(vals);
+ return result_t(CreateMapAdapter(std::move(newVals)));
+ }
+
+ return result_t(CreateMapAdapter(vals));
+ }
+
+ result_t operator()(ValuesMap& vals) const { return result_t(CreateMapAdapter(std::move(vals))); }
+
+ result_t operator()(const GenericMap& vals) const
+ {
+ if (m_byValue)
+ {
+ GenericMap newVals(vals);
+ return result_t(CreateMapAdapter(std::move(newVals)));
+ }
+
+ return result_t(CreateMapAdapter(vals));
+ }
+
+ result_t operator()(GenericMap& vals) const { return result_t(CreateMapAdapter(std::move(vals))); }
+
+ result_t operator()(const UserCallable& val) const { return ConvertUserCallable(val); }
+
+ result_t operator()(UserCallable& val) const { return ConvertUserCallable(std::move(val)); }
+
+ template<typename T>
+ result_t operator()(const RecWrapper<T>& val) const
+ {
+ return this->operator()(const_cast<const T&>(*val));
+ }
+
+ template<typename T>
+ result_t operator()(RecWrapper<T>& val) const
+ {
+ return this->operator()(*val);
+ }
+
+ template<typename T>
+ result_t operator()(const T& val) const
+ {
+ return result_t(InternalValue(val));
+ }
+
+ static result_t ConvertUserCallable(const UserCallable& val);
+
+ bool m_byValue{};
+ bool m_allowStringRef{};
+};
+
+template<typename CharT>
+struct ValueRenderer;
+
+template<>
+struct ValueRenderer<char> : ValueRendererBase<char>
+{
+ ValueRenderer(std::string& os)
+ : ValueRendererBase<char>::ValueRendererBase<char>(os)
+ {
+ }
+
+ using ValueRendererBase<char>::operator ();
+ void operator()(const std::wstring& str) const
+ {
+ (*m_os) += ConvertString<std::string>(str);
+ }
+ void operator()(const std::wstring_view& str) const
+ {
+ (*m_os) += ConvertString<std::string>(str);
+ }
+ void operator() (bool val) const
+ {
+ m_os->append(val ? "true" : "false");
+ }
+};
+
+template<>
+struct ValueRenderer<wchar_t> : ValueRendererBase<wchar_t>
+{
+ ValueRenderer(std::wstring& os)
+ : ValueRendererBase<wchar_t>::ValueRendererBase<wchar_t>(os)
+ {
+ }
+
+ using ValueRendererBase<wchar_t>::operator ();
+ void operator()(const std::string& str) const
+ {
+ (*m_os) += ConvertString<std::wstring>(str);
+ }
+ void operator()(const std::string_view& str) const
+ {
+ (*m_os) += ConvertString<std::wstring>(str);
+ }
+ void operator() (bool val) const
+ {
+ // fmt::format_to(GetOs(), L"{}", (const wchar_t*)(val ? "true" : "false"));
+ m_os->append(val ? L"true" : L"false");
+ }
+};
+
+struct UnaryOperation : BaseVisitor<InternalValue>
+{
+ using BaseVisitor::operator ();
+
+ UnaryOperation(UnaryExpression::Operation oper)
+ : m_oper(oper)
+ {
+ }
+
+ InternalValue operator() (int64_t val) const
+ {
+ InternalValue result;
+ switch (m_oper)
+ {
+ case jinja2::UnaryExpression::LogicalNot:
+ result = val ? false : true;
+ break;
+ case jinja2::UnaryExpression::UnaryPlus:
+ result = +val;
+ break;
+ case jinja2::UnaryExpression::UnaryMinus:
+ result = -val;
+ break;
+ }
+
+ return result;
+ }
+
+ InternalValue operator() (double val) const
+ {
+ InternalValue result;
+ switch (m_oper)
+ {
+ case jinja2::UnaryExpression::LogicalNot:
+ result = fabs(val) > std::numeric_limits<double>::epsilon() ? false : true;
+ break;
+ case jinja2::UnaryExpression::UnaryPlus:
+ result = +val;
+ break;
+ case jinja2::UnaryExpression::UnaryMinus:
+ result = -val;
+ break;
+ }
+
+ return result;
+ }
+
+ InternalValue operator() (bool val) const
+ {
+ InternalValue result;
+ switch (m_oper)
+ {
+ case jinja2::UnaryExpression::LogicalNot:
+ result = !val;
+ break;
+ default:
+ break;
+ }
+
+ return result;
+ }
+
+ InternalValue operator() (const MapAdapter&) const
+ {
+ InternalValue result;
+ switch (m_oper)
+ {
+ case jinja2::UnaryExpression::LogicalNot:
+ result = true;
+ break;
+ default:
+ break;
+ }
+
+ return result;
+ }
+
+ InternalValue operator() (const ListAdapter&) const
+ {
+ InternalValue result;
+ switch (m_oper)
+ {
+ case jinja2::UnaryExpression::LogicalNot:
+ result = true;
+ break;
+ default:
+ break;
+ }
+
+ return result;
+ }
+
+ template<typename CharT>
+ InternalValue operator() (const std::basic_string<CharT>& val) const
+ {
+ InternalValue result;
+ switch (m_oper)
+ {
+ case jinja2::UnaryExpression::LogicalNot:
+ result = val.empty();
+ break;
+ default:
+ break;
+ }
+
+ return result;
+ }
+
+ template<typename CharT>
+ InternalValue operator() (const std::basic_string_view<CharT>& val) const
+ {
+ InternalValue result;
+ switch (m_oper)
+ {
+ case jinja2::UnaryExpression::LogicalNot:
+ result = val.empty();
+ break;
+ default:
+ break;
+ }
+
+ return result;
+ }
+
+ InternalValue operator() (const EmptyValue&) const
+ {
+ InternalValue result;
+ switch (m_oper)
+ {
+ case jinja2::UnaryExpression::LogicalNot:
+ result = true;
+ break;
+ default:
+ break;
+ }
+
+ return result;
+ }
+
+ UnaryExpression::Operation m_oper;
+};
+
+struct BinaryMathOperation : BaseVisitor<>
+{
+ using BaseVisitor::operator ();
+ using ResultType = InternalValue;
+ // InternalValue operator() (int, int) const {return InternalValue();}
+
+ bool AlmostEqual(double x, double y) const
+ {
+ return std::abs(x - y) <= std::numeric_limits<double>::epsilon() * std::abs(x + y) * 6
+ || std::abs(x - y) < std::numeric_limits<double>::min();
+ }
+
+ BinaryMathOperation(BinaryExpression::Operation oper, BinaryExpression::CompareType compType = BinaryExpression::CaseSensitive)
+ : m_oper(oper)
+ , m_compType(compType)
+ {
+ }
+
+ ResultType operator() (double left, double right) const
+ {
+ ResultType result = 0.0;
+ switch (m_oper)
+ {
+ case jinja2::BinaryExpression::Plus:
+ result = left + right;
+ break;
+ case jinja2::BinaryExpression::Minus:
+ result = left - right;
+ break;
+ case jinja2::BinaryExpression::Mul:
+ result = left * right;
+ break;
+ case jinja2::BinaryExpression::Div:
+ result = left / right;
+ break;
+ case jinja2::BinaryExpression::DivReminder:
+ result = std::remainder(left, right);
+ break;
+ case jinja2::BinaryExpression::DivInteger:
+ {
+ double val = left / right;
+ result = val < 0 ? ceil(val) : floor(val);
+ break;
+ }
+ case jinja2::BinaryExpression::Pow:
+ result = pow(left, right);
+ break;
+ case jinja2::BinaryExpression::LogicalEq:
+ result = AlmostEqual(left, right);
+ break;
+ case jinja2::BinaryExpression::LogicalNe:
+ result = !AlmostEqual(left, right);
+ break;
+ case jinja2::BinaryExpression::LogicalGt:
+ result = left > right;
+ break;
+ case jinja2::BinaryExpression::LogicalLt:
+ result = left < right;
+ break;
+ case jinja2::BinaryExpression::LogicalGe:
+ result = left > right || AlmostEqual(left, right);
+ break;
+ case jinja2::BinaryExpression::LogicalLe:
+ result = left < right || AlmostEqual(left, right);
+ break;
+ default:
+ break;
+ }
+
+ return result;
+ }
+
+ ResultType operator() (int64_t left, int64_t right) const
+ {
+ ResultType result;
+ switch (m_oper)
+ {
+ case jinja2::BinaryExpression::Plus:
+ result = left + right;
+ break;
+ case jinja2::BinaryExpression::Minus:
+ result = left - right;
+ break;
+ case jinja2::BinaryExpression::Mul:
+ result = left * right;
+ break;
+ case jinja2::BinaryExpression::DivInteger:
+ result = left / right;
+ break;
+ case jinja2::BinaryExpression::Div:
+ case jinja2::BinaryExpression::DivReminder:
+ case jinja2::BinaryExpression::Pow:
+ result = this->operator ()(static_cast<double>(left), static_cast<double>(right));
+ break;
+ case jinja2::BinaryExpression::LogicalEq:
+ result = left == right;
+ break;
+ case jinja2::BinaryExpression::LogicalNe:
+ result = left != right;
+ break;
+ case jinja2::BinaryExpression::LogicalGt:
+ result = left > right;
+ break;
+ case jinja2::BinaryExpression::LogicalLt:
+ result = left < right;
+ break;
+ case jinja2::BinaryExpression::LogicalGe:
+ result = left >= right;
+ break;
+ case jinja2::BinaryExpression::LogicalLe:
+ result = left <= right;
+ break;
+ default:
+ break;
+ }
+
+ return result;
+ }
+
+ ResultType operator() (int64_t left, double right) const
+ {
+ return this->operator ()(static_cast<double>(left), static_cast<double>(right));
+ }
+
+ ResultType operator() (double left, int64_t right) const
+ {
+ return this->operator ()(static_cast<double>(left), static_cast<double>(right));
+ }
+
+ template<typename CharT>
+ ResultType operator() (const std::basic_string<CharT> &left, const std::basic_string<CharT> &right) const
+ {
+ return ProcessStrings(std::basic_string_view<CharT>(left), std::basic_string_view<CharT>(right));
+ }
+
+ template<typename CharT1, typename CharT2>
+ std::enable_if_t<!std::is_same<CharT1, CharT2>::value, ResultType> operator() (const std::basic_string<CharT1>& left, const std::basic_string<CharT2>& right) const
+ {
+ auto rightStr = ConvertString<std::basic_string<CharT1>>(right);
+ return ProcessStrings(std::basic_string_view<CharT1>(left), std::basic_string_view<CharT1>(rightStr));
+ }
+
+ template<typename CharT>
+ ResultType operator() (const std::basic_string_view<CharT> &left, const std::basic_string<CharT> &right) const
+ {
+ return ProcessStrings(left, std::basic_string_view<CharT>(right));
+ }
+
+ template<typename CharT1, typename CharT2>
+ std::enable_if_t<!std::is_same<CharT1, CharT2>::value, ResultType> operator() (const std::basic_string_view<CharT1>& left, const std::basic_string<CharT2>& right) const
+ {
+ auto rightStr = ConvertString<std::basic_string<CharT1>>(right);
+ return ProcessStrings(left, std::basic_string_view<CharT1>(rightStr));
+ }
+
+ template<typename CharT>
+ ResultType operator() (const std::basic_string<CharT> &left, const std::basic_string_view<CharT> &right) const
+ {
+ return ProcessStrings(std::basic_string_view<CharT>(left), right);
+ }
+
+ template<typename CharT1, typename CharT2>
+ std::enable_if_t<!std::is_same<CharT1, CharT2>::value, ResultType> operator() (const std::basic_string<CharT1>& left, const std::basic_string_view<CharT2>& right) const
+ {
+ auto rightStr = ConvertString<std::basic_string<CharT1>>(right);
+ return ProcessStrings(std::basic_string_view<CharT1>(left), std::basic_string_view<CharT1>(rightStr));
+ }
+
+ template<typename CharT>
+ ResultType operator() (const std::basic_string_view<CharT> &left, const std::basic_string_view<CharT> &right) const
+ {
+ return ProcessStrings(left, right);
+ }
+
+ template<typename CharT1, typename CharT2>
+ std::enable_if_t<!std::is_same<CharT1, CharT2>::value, ResultType> operator() (const std::basic_string_view<CharT1>& left, const std::basic_string_view<CharT2>& right) const
+ {
+ auto rightStr = ConvertString<std::basic_string<CharT1>>(right);
+ return ProcessStrings(left, std::basic_string_view<CharT1>(rightStr));
+ }
+
+ template<typename CharT>
+ ResultType operator() (const std::basic_string<CharT> &left, int64_t right) const
+ {
+ return RepeatString(std::basic_string_view<CharT>(left), right);
+ }
+
+ template<typename CharT>
+ ResultType operator() (const std::basic_string_view<CharT> &left, int64_t right) const
+ {
+ return RepeatString(left, right);
+ }
+
+ template<typename CharT>
+ ResultType RepeatString(const std::basic_string_view<CharT>& left, const int64_t right) const
+ {
+ using string = std::basic_string<CharT>;
+ ResultType result;
+
+ if(m_oper == jinja2::BinaryExpression::Mul)
+ {
+ string str;
+ for (int i = 0; i < right; ++i)
+ str.append(left.begin(), left.end());
+ result = TargetString(std::move(str));
+ }
+ return result;
+ }
+
+ template<typename CharT>
+ ResultType ProcessStrings(const std::basic_string_view<CharT>& left, const std::basic_string_view<CharT>& right) const
+ {
+ using string = std::basic_string<CharT>;
+ ResultType result;
+
+ switch (m_oper)
+ {
+ case jinja2::BinaryExpression::Plus:
+ {
+ auto str = string(left.begin(), left.end());
+ str.append(right.begin(), right.end());
+ result = TargetString(std::move(str));
+ break;
+ }
+ case jinja2::BinaryExpression::LogicalEq:
+ result = m_compType == BinaryExpression::CaseSensitive ? left == right : boost::iequals(left, right);
+ break;
+ case jinja2::BinaryExpression::LogicalNe:
+ result = m_compType == BinaryExpression::CaseSensitive ? left != right : !boost::iequals(left, right);
+ break;
+ case jinja2::BinaryExpression::LogicalGt:
+ result = m_compType == BinaryExpression::CaseSensitive ? left > right : boost::lexicographical_compare(right, left, boost::algorithm::is_iless());
+ break;
+ case jinja2::BinaryExpression::LogicalLt:
+ result = m_compType == BinaryExpression::CaseSensitive ? left < right : boost::lexicographical_compare(left, right, boost::algorithm::is_iless());
+ break;
+ case jinja2::BinaryExpression::LogicalGe:
+ if (m_compType == BinaryExpression::CaseSensitive)
+ {
+ result = left >= right;
+ }
+ else
+ {
+ result = boost::iequals(left, right) ? true : boost::lexicographical_compare(right, left, boost::algorithm::is_iless());
+ }
+ break;
+ case jinja2::BinaryExpression::LogicalLe:
+ if (m_compType == BinaryExpression::CaseSensitive)
+ {
+ result = left <= right;
+ }
+ else
+ {
+ result = boost::iequals(left, right) ? true : boost::lexicographical_compare(left, right, boost::algorithm::is_iless());
+ }
+ break;
+ default:
+ break;
+ }
+
+ return result;
+ }
+
+ ResultType operator() (const KeyValuePair& left, const KeyValuePair& right) const
+ {
+ ResultType result;
+ switch (m_oper)
+ {
+ case jinja2::BinaryExpression::LogicalEq:
+ result = ConvertToBool(this->operator ()(left.key, right.key)) && ConvertToBool(Apply2<BinaryMathOperation>(left.value, right.value, BinaryExpression::LogicalEq, m_compType));
+ break;
+ case jinja2::BinaryExpression::LogicalNe:
+ result = ConvertToBool(this->operator ()(left.key, right.key)) || ConvertToBool(Apply2<BinaryMathOperation>(left.value, right.value, BinaryExpression::LogicalNe, m_compType));
+ break;
+ default:
+ break;
+ }
+
+ return result;
+ }
+
+ ResultType operator() (const ListAdapter& left, const ListAdapter& right) const
+ {
+ ResultType result;
+ if (m_oper == jinja2::BinaryExpression::Plus)
+ {
+ InternalValueList values;
+ values.reserve(left.GetSize().value_or(0) + right.GetSize().value_or(0));
+ for (auto& v : left)
+ values.push_back(v);
+ for (auto& v : right)
+ values.push_back(v);
+ result = ListAdapter::CreateAdapter(std::move(values));
+ }
+
+ return result;
+ }
+
+ ResultType operator() (const ListAdapter& left, int64_t right) const
+ {
+ ResultType result;
+ if (right >= 0 && m_oper == jinja2::BinaryExpression::Mul)
+ {
+ InternalValueList values;
+ values.reserve(left.GetSize().value_or(0));
+ for (auto& v : left)
+ values.push_back(v);
+ auto listSize = values.size() * right;
+ result = ListAdapter::CreateAdapter(static_cast<size_t>(listSize),
+ [size = values.size(), values = std::move(values)](size_t idx) { return values[idx % size]; });
+ }
+
+ return result;
+ }
+
+ ResultType operator() (bool left, bool right) const
+ {
+ ResultType result;
+ switch (m_oper)
+ {
+ case jinja2::BinaryExpression::LogicalEq:
+ result = left == right;
+ break;
+ case jinja2::BinaryExpression::LogicalNe:
+ result = left != right;
+ break;
+ case jinja2::BinaryExpression::LogicalLt:
+ result = (left ? 1 : 0) < (right ? 1 : 0);
+ break;
+ default:
+ break;
+ }
+
+ return result;
+ }
+
+ ResultType operator() (EmptyValue, EmptyValue) const
+ {
+ ResultType result;
+ switch (m_oper)
+ {
+ case jinja2::BinaryExpression::LogicalEq:
+ result = true;
+ break;
+ case jinja2::BinaryExpression::LogicalNe:
+ result = false;
+ break;
+ default:
+ break;
+ }
+
+ return result;
+ }
+
+ template<typename T>
+ ResultType operator() (EmptyValue, T&&) const
+ {
+ ResultType result;
+ switch (m_oper)
+ {
+ case jinja2::BinaryExpression::LogicalEq:
+ result = false;
+ break;
+ case jinja2::BinaryExpression::LogicalNe:
+ result = true;
+ break;
+ default:
+ break;
+ }
+
+ return result;
+ }
+
+ template<typename T>
+ ResultType operator() (T&&, EmptyValue) const
+ {
+ ResultType result;
+ switch (m_oper)
+ {
+ case jinja2::BinaryExpression::LogicalEq:
+ result = false;
+ break;
+ case jinja2::BinaryExpression::LogicalNe:
+ result = true;
+ break;
+ default:
+ break;
+ }
+
+ return result;
+ }
+
+ BinaryExpression::Operation m_oper;
+ BinaryExpression::CompareType m_compType;
+};
+
+struct BooleanEvaluator : BaseVisitor<bool>
+{
+ using BaseVisitor::operator ();
+
+ bool operator() (int64_t val) const
+ {
+ return val != 0;
+ }
+
+ bool operator() (double val) const
+ {
+ return fabs(val) < std::numeric_limits<double>::epsilon();
+ }
+
+ bool operator() (bool val) const
+ {
+ return val;
+ }
+
+ template<typename CharT>
+ bool operator()(const std::basic_string<CharT>& str) const
+ {
+ return !str.empty();
+ }
+
+ template<typename CharT>
+ bool operator()(const std::basic_string_view<CharT>& str) const
+ {
+ return !str.empty();
+ }
+
+ bool operator() (const MapAdapter& val) const
+ {
+ return val.GetSize() != 0ULL;
+ }
+
+ bool operator() (const ListAdapter& val) const
+ {
+ return val.GetSize() != 0ULL;
+ }
+
+ bool operator() (const EmptyValue&) const
+ {
+ return false;
+ }
+};
+
+template<typename TargetType>
+struct NumberEvaluator
+{
+ NumberEvaluator(TargetType def = 0) : m_def(def)
+ {}
+
+ TargetType operator ()(int64_t val) const
+ {
+ return static_cast<TargetType>(val);
+ }
+ TargetType operator ()(double val) const
+ {
+ return static_cast<TargetType>(val);
+ }
+ TargetType operator ()(bool val) const
+ {
+ return static_cast<TargetType>(val);
+ }
+ template<typename U>
+ TargetType operator()(U&&) const
+ {
+ return m_def;
+ }
+
+ TargetType m_def;
+};
+
+using IntegerEvaluator = NumberEvaluator<int64_t>;
+using DoubleEvaluator = NumberEvaluator<double>;
+
+
+struct StringJoiner : BaseVisitor<TargetString>
+{
+ using BaseVisitor::operator ();
+
+ template<typename CharT>
+ TargetString operator() (EmptyValue, const std::basic_string<CharT>& str) const
+ {
+ return str;
+ }
+
+ template<typename CharT>
+ TargetString operator() (EmptyValue, const std::basic_string_view<CharT>& str) const
+ {
+ return std::basic_string<CharT>(str.begin(), str.end());
+ }
+
+ template<typename CharT>
+ TargetString operator() (const std::basic_string<CharT>& left, const std::basic_string<CharT>& right) const
+ {
+ return left + right;
+ }
+
+ template<typename CharT1, typename CharT2>
+ std::enable_if_t<!std::is_same<CharT1, CharT2>::value, TargetString> operator() (const std::basic_string<CharT1>& left, const std::basic_string<CharT2>& right) const
+ {
+ return left + ConvertString<std::basic_string<CharT1>>(right);
+ }
+
+ template<typename CharT>
+ TargetString operator() (std::basic_string<CharT> left, const std::basic_string_view<CharT>& right) const
+ {
+ left.append(right.begin(), right.end());
+ return std::move(left);
+ }
+
+ template<typename CharT1, typename CharT2>
+ std::enable_if_t<!std::is_same<CharT1, CharT2>::value, TargetString> operator() (std::basic_string<CharT1> left, const std::basic_string_view<CharT2>& right) const
+ {
+ auto r = ConvertString<std::basic_string<CharT1>>(right);
+ left.append(r.begin(), r.end());
+ return std::move(left);
+ }
+};
+
+template<typename Fn>
+struct StringConverterImpl : public BaseVisitor<decltype(std::declval<Fn>()(std::declval<std::string_view>()))>
+{
+ using R = decltype(std::declval<Fn>()(std::string_view()));
+ using BaseVisitor<R>::operator ();
+
+ StringConverterImpl(const Fn& fn) : m_fn(fn) {}
+
+ template<typename CharT>
+ R operator()(const std::basic_string<CharT>& str) const
+ {
+ return m_fn(std::basic_string_view<CharT>(str));
+ }
+
+ template<typename CharT>
+ R operator()(const std::basic_string_view<CharT>& str) const
+ {
+ return m_fn(str);
+ }
+
+ const Fn& m_fn;
+};
+
+template<typename CharT>
+struct SameStringGetter : public visitors::BaseVisitor<nonstd::expected<void, std::basic_string<CharT>>>
+{
+ using ResultString = std::basic_string<CharT>;
+ using OtherString = std::conditional_t<std::is_same<CharT, char>::value, std::wstring, std::string>;
+ using ResultStringView = std::basic_string_view<CharT>;
+ using OtherStringView = std::conditional_t<std::is_same<CharT, char>::value, std::wstring_view, std::string_view>;
+ using Result = nonstd::expected<void, ResultString>;
+ using BaseVisitor<Result>::operator ();
+
+ Result operator()(const ResultString& str) const
+ {
+ return nonstd::make_unexpected(str);
+ }
+
+ Result operator()(const ResultStringView& str) const
+ {
+ return nonstd::make_unexpected(ResultString(str.begin(), str.end()));
+ }
+
+ Result operator()(const OtherString& str) const
+ {
+ return nonstd::make_unexpected(ConvertString<ResultString>(str));
+ }
+
+ Result operator()(const OtherStringView& str) const
+ {
+ return nonstd::make_unexpected(ConvertString<ResultString>(str));
+ }
+};
+
+} // namespace visitors
+
+inline bool ConvertToBool(const InternalValue& val)
+{
+ return Apply<visitors::BooleanEvaluator>(val);
+}
+
+inline int64_t ConvertToInt(const InternalValue& val, int64_t def = 0)
+{
+ return Apply<visitors::IntegerEvaluator>(val, def);
+}
+
+inline double ConvertToDouble(const InternalValue& val, double def = 0)
+{
+ return Apply<visitors::DoubleEvaluator>(val, def);
+}
+
+template<template<typename> class Cvt = visitors::StringConverterImpl, typename Fn>
+auto ApplyStringConverter(const InternalValue& str, Fn&& fn)
+{
+ return Apply<Cvt<Fn>>(str, std::forward<Fn>(fn));
+}
+
+template<typename CharT>
+auto GetAsSameString(const std::basic_string<CharT>&, const InternalValue& val)
+{
+ using Result = std::optional<std::basic_string<CharT>>;
+ auto result = Apply<visitors::SameStringGetter<CharT>>(val);
+ if (!result)
+ return Result(result.error());
+
+ return Result();
+}
+
+template<typename CharT>
+auto GetAsSameString(const std::basic_string_view<CharT>&, const InternalValue& val)
+{
+ using Result = std::optional<std::basic_string<CharT>>;
+ auto result = Apply<visitors::SameStringGetter<CharT>>(val);
+ if (!result)
+ return Result(result.error());
+
+ return Result();
+}
+
+inline bool operator==(const InternalValueData& lhs, const InternalValueData& rhs)
+{
+ InternalValue cmpRes;
+ cmpRes = Apply2<visitors::BinaryMathOperation>(lhs, rhs, BinaryExpression::LogicalEq);
+ return ConvertToBool(cmpRes);
+}
+
+inline bool operator!=(const InternalValueData& lhs, const InternalValueData& rhs)
+{
+ return !(lhs == rhs);
+}
+
+} // namespace jinja2
+
+#endif // JINJA2CPP_SRC_VALUE_VISITORS_H
diff --git a/contrib/libs/jinja2cpp/ya.make b/contrib/libs/jinja2cpp/ya.make
new file mode 100644
index 0000000000..fff6152672
--- /dev/null
+++ b/contrib/libs/jinja2cpp/ya.make
@@ -0,0 +1,68 @@
+# Generated by devtools/yamaker from nixpkgs 22.11.
+
+LIBRARY()
+
+LICENSE(
+ MIT AND
+ MPL-1.1 AND
+ MPL-2.0
+)
+
+LICENSE_TEXTS(.yandex_meta/licenses.list.txt)
+
+VERSION(1.3.1)
+
+ORIGINAL_SOURCE(https://github.com/jinja2cpp/Jinja2Cpp/archive/1.3.1.tar.gz)
+
+PEERDIR(
+ contrib/libs/fmt
+ contrib/libs/rapidjson
+ contrib/restricted/boost/algorithm
+ contrib/restricted/boost/container
+ contrib/restricted/boost/filesystem
+ contrib/restricted/boost/numeric_conversion
+ contrib/restricted/boost/unordered
+ contrib/restricted/boost/variant
+ contrib/restricted/expected-lite
+)
+
+ADDINCL(
+ GLOBAL contrib/libs/jinja2cpp/include
+ GLOBAL contrib/libs/rapidjson/include
+)
+
+NO_COMPILER_WARNINGS()
+
+NO_UTIL()
+
+CFLAGS(
+ -DBOOST_ERROR_CODE_HEADER_ONLY
+ -DBOOST_SYSTEM_NO_DEPRECATED
+ -DFMT_HEADER_ONLY=1
+ -DFMT_USE_INTERNAL=TRUE
+ -DJINJA2CPP_BUILD_AS_SHARED
+ -DJINJA2CPP_LINK_AS_SHARED
+ -DJINJA2CPP_USE_REGEX_BOOST
+)
+
+SRCS(
+ src/binding/rapid_json_serializer.cpp
+ src/error_info.cpp
+ src/expression_evaluator.cpp
+ src/expression_parser.cpp
+ src/filesystem_handler.cpp
+ src/filters.cpp
+ src/generic_list.cpp
+ src/internal_value.cpp
+ src/lexer.cpp
+ src/serialize_filters.cpp
+ src/statements.cpp
+ src/string_converter_filter.cpp
+ src/template.cpp
+ src/template_env.cpp
+ src/template_parser.cpp
+ src/testers.cpp
+ src/value.cpp
+)
+
+END()
diff --git a/contrib/libs/libc_compat/memfd_create.c b/contrib/libs/libc_compat/memfd_create/memfd_create.c
index 6805d807d6..6805d807d6 100644
--- a/contrib/libs/libc_compat/memfd_create.c
+++ b/contrib/libs/libc_compat/memfd_create/memfd_create.c
diff --git a/contrib/libs/libc_compat/memfd_create/sys/mman.h b/contrib/libs/libc_compat/memfd_create/sys/mman.h
new file mode 100644
index 0000000000..d36e9bdbe4
--- /dev/null
+++ b/contrib/libs/libc_compat/memfd_create/sys/mman.h
@@ -0,0 +1,16 @@
+#pragma once
+
+#include_next <sys/mman.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define MFD_CLOEXEC 0x0001U
+#define MADV_WIPEONFORK 18
+
+int memfd_create(const char *name, unsigned flags);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/contrib/libs/libc_compat/ya.make b/contrib/libs/libc_compat/ya.make
index a8d7af0cf7..537ecdb9c5 100644
--- a/contrib/libs/libc_compat/ya.make
+++ b/contrib/libs/libc_compat/ya.make
@@ -107,11 +107,12 @@ IF (OS_LINUX AND NOT MUSL)
# getrandom and getentropy were added in glibc=2.25
ENABLE(PROVIDE_GETRANDOM_GETENTROPY)
+ # memfd_create was added in glibc=2.27
+ ENABLE(PROVIDE_MEMFD_CREATE)
+
SRCS(
# explicit_bzero was added in glibc=2.25
explicit_bzero.c
- # memfd_create was added in glibc=2.27
- memfd_create.c
)
ENDIF()
IF (OS_SDK != "ubuntu-20" AND OS_SDK != "ubuntu-22")
@@ -160,4 +161,13 @@ IF (PROVIDE_GETSERVBYNAME)
)
ENDIF()
+IF (PROVIDE_MEMFD_CREATE)
+ SRCS(
+ memfd_create/memfd_create.c
+ )
+ ADDINCL(
+ GLOBAL contrib/libs/libc_compat/memfd_create
+ )
+ENDIF()
+
END()
diff --git a/contrib/libs/llvm16/include/llvm/Config/llvm-config-linux-aarch64.h b/contrib/libs/llvm16/include/llvm/Config/llvm-config-linux-aarch64.h
new file mode 100644
index 0000000000..708cd9addd
--- /dev/null
+++ b/contrib/libs/llvm16/include/llvm/Config/llvm-config-linux-aarch64.h
@@ -0,0 +1,35 @@
+#pragma once
+
+#include "llvm-config-linux.h"
+
+/* Host triple LLVM will be executed on */
+#undef LLVM_HOST_TRIPLE
+#define LLVM_HOST_TRIPLE "aarch64-unknown-linux-gnu"
+
+/* LLVM architecture name for the native architecture, if available */
+#undef LLVM_NATIVE_ARCH
+#define LLVM_NATIVE_ARCH AArch64
+
+/* LLVM name for the native AsmParser init function, if available */
+#undef LLVM_NATIVE_ASMPARSER
+#define LLVM_NATIVE_ASMPARSER LLVMInitializeAArch64AsmParser
+
+/* LLVM name for the native AsmPrinter init function, if available */
+#undef LLVM_NATIVE_ASMPRINTER
+#define LLVM_NATIVE_ASMPRINTER LLVMInitializeAArch64AsmPrinter
+
+/* LLVM name for the native Disassembler init function, if available */
+#undef LLVM_NATIVE_DISASSEMBLER
+#define LLVM_NATIVE_DISASSEMBLER LLVMInitializeAArch64Disassembler
+
+/* LLVM name for the native Target init function, if available */
+#undef LLVM_NATIVE_TARGET
+#define LLVM_NATIVE_TARGET LLVMInitializeAArch64Target
+
+/* LLVM name for the native TargetInfo init function, if available */
+#undef LLVM_NATIVE_TARGETINFO
+#define LLVM_NATIVE_TARGETINFO LLVMInitializeAArch64TargetInfo
+
+/* LLVM name for the native target MC init function, if available */
+#undef LLVM_NATIVE_TARGETMC
+#define LLVM_NATIVE_TARGETMC LLVMInitializeAArch64TargetMC
diff --git a/contrib/libs/llvm16/include/llvm/Config/llvm-config.h b/contrib/libs/llvm16/include/llvm/Config/llvm-config.h
index 0ab964dcd1..06f9c57d27 100644
--- a/contrib/libs/llvm16/include/llvm/Config/llvm-config.h
+++ b/contrib/libs/llvm16/include/llvm/Config/llvm-config.h
@@ -4,6 +4,8 @@
# include "llvm-config-osx.h"
#elif defined(_MSC_VER)
# include "llvm-config-win.h"
+#elif defined(__linux__) && (defined(__aarch64__) || defined(_M_ARM64))
+# include "llvm-config-linux-aarch64.h"
#else
# include "llvm-config-linux.h"
#endif
diff --git a/contrib/libs/llvm16/tools/lli/ya.make b/contrib/libs/llvm16/tools/lli/ya.make
index 3f2bcc8143..e172246e8b 100644
--- a/contrib/libs/llvm16/tools/lli/ya.make
+++ b/contrib/libs/llvm16/tools/lli/ya.make
@@ -76,6 +76,15 @@ IF (OS_LINUX)
)
ENDIF()
+IF (ARCH_AARCH64)
+ PEERDIR(
+ contrib/libs/llvm16/lib/Target/AArch64
+ contrib/libs/llvm16/lib/Target/AArch64/AsmParser
+ contrib/libs/llvm16/lib/Target/AArch64/MCTargetDesc
+ contrib/libs/llvm16/lib/Target/AArch64/TargetInfo
+ )
+ENDIF()
+
ADDINCL(
contrib/libs/llvm16/tools/lli
)
diff --git a/contrib/libs/openssl/include/openssl/bnerr.h b/contrib/libs/openssl/include/openssl/bnerr.h
index a703efc92b..5c83777f9f 100644
--- a/contrib/libs/openssl/include/openssl/bnerr.h
+++ b/contrib/libs/openssl/include/openssl/bnerr.h
@@ -72,6 +72,7 @@ int ERR_load_BN_strings(void);
# define BN_F_BN_SET_WORDS 144
# define BN_F_BN_STACK_PUSH 148
# define BN_F_BN_USUB 115
+# define BN_F_OSSL_BN_RSA_DO_UNBLIND 151
/*
* BN reason codes.
diff --git a/contrib/libs/openssl/include/openssl/crypto.h b/contrib/libs/openssl/include/openssl/crypto.h
index 7d0b526236..5fdd7c3d04 100644
--- a/contrib/libs/openssl/include/openssl/crypto.h
+++ b/contrib/libs/openssl/include/openssl/crypto.h
@@ -161,6 +161,10 @@ const char *OpenSSL_version(int type);
# define OPENSSL_DIR 4
# define OPENSSL_ENGINES_DIR 5
+# ifndef OPENSSL_NO_QUIC
+# define OPENSSL_INFO_QUIC 2000
+# endif
+
int OPENSSL_issetugid(void);
typedef void CRYPTO_EX_new (void *parent, void *ptr, CRYPTO_EX_DATA *ad,
diff --git a/contrib/libs/openssl/include/openssl/dh.h b/contrib/libs/openssl/include/openssl/dh.h
index 3527540cdd..892e31559d 100644
--- a/contrib/libs/openssl/include/openssl/dh.h
+++ b/contrib/libs/openssl/include/openssl/dh.h
@@ -29,6 +29,9 @@ extern "C" {
# ifndef OPENSSL_DH_MAX_MODULUS_BITS
# define OPENSSL_DH_MAX_MODULUS_BITS 10000
# endif
+# ifndef OPENSSL_DH_CHECK_MAX_MODULUS_BITS
+# define OPENSSL_DH_CHECK_MAX_MODULUS_BITS 32768
+# endif
# define OPENSSL_DH_FIPS_MIN_MODULUS_BITS 1024
diff --git a/contrib/libs/openssl/include/openssl/dherr.h b/contrib/libs/openssl/include/openssl/dherr.h
index 916b3bed0b..9955f24652 100644
--- a/contrib/libs/openssl/include/openssl/dherr.h
+++ b/contrib/libs/openssl/include/openssl/dherr.h
@@ -30,6 +30,7 @@ int ERR_load_DH_strings(void);
# define DH_F_COMPUTE_KEY 102
# define DH_F_DHPARAMS_PRINT_FP 101
# define DH_F_DH_BUILTIN_GENPARAMS 106
+# define DH_F_DH_CHECK 126
# define DH_F_DH_CHECK_EX 121
# define DH_F_DH_CHECK_PARAMS_EX 122
# define DH_F_DH_CHECK_PUB_KEY_EX 123
diff --git a/contrib/libs/openssl/include/openssl/evp.h b/contrib/libs/openssl/include/openssl/evp.h
index a411f3f2f9..275b7a4acc 100644
--- a/contrib/libs/openssl/include/openssl/evp.h
+++ b/contrib/libs/openssl/include/openssl/evp.h
@@ -1324,6 +1324,10 @@ void EVP_PKEY_asn1_set_security_bits(EVP_PKEY_ASN1_METHOD *ameth,
*/
# define EVP_PKEY_FLAG_SIGCTX_CUSTOM 4
+/* Used by Chromium/QUIC */
+# define X25519_PRIVATE_KEY_LEN 32
+# define X25519_PUBLIC_VALUE_LEN 32
+
const EVP_PKEY_METHOD *EVP_PKEY_meth_find(int type);
EVP_PKEY_METHOD *EVP_PKEY_meth_new(int id, int flags);
void EVP_PKEY_meth_get0_info(int *ppkey_id, int *pflags,
diff --git a/contrib/libs/openssl/include/openssl/ossl_typ.h b/contrib/libs/openssl/include/openssl/ossl_typ.h
index e0edfaaf47..d2fdce8fdf 100644
--- a/contrib/libs/openssl/include/openssl/ossl_typ.h
+++ b/contrib/libs/openssl/include/openssl/ossl_typ.h
@@ -176,6 +176,8 @@ typedef struct ct_policy_eval_ctx_st CT_POLICY_EVAL_CTX;
typedef struct ossl_store_info_st OSSL_STORE_INFO;
typedef struct ossl_store_search_st OSSL_STORE_SEARCH;
+typedef struct ssl_quic_method_st SSL_QUIC_METHOD;
+
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L && \
defined(INTMAX_MAX) && defined(UINTMAX_MAX)
typedef intmax_t ossl_intmax_t;
diff --git a/contrib/libs/openssl/include/openssl/ssl.h b/contrib/libs/openssl/include/openssl/ssl.h
index 9af0c8995e..63ee3baae7 100644
--- a/contrib/libs/openssl/include/openssl/ssl.h
+++ b/contrib/libs/openssl/include/openssl/ssl.h
@@ -1931,6 +1931,7 @@ int SSL_get_key_update_type(const SSL *s);
int SSL_renegotiate(SSL *s);
int SSL_renegotiate_abbreviated(SSL *s);
__owur int SSL_renegotiate_pending(const SSL *s);
+int SSL_new_session_ticket(SSL *s);
int SSL_shutdown(SSL *s);
__owur int SSL_verify_client_post_handshake(SSL *s);
void SSL_CTX_set_post_handshake_auth(SSL_CTX *ctx, int val);
@@ -2442,6 +2443,66 @@ void SSL_set_allow_early_data_cb(SSL *s,
SSL_allow_early_data_cb_fn cb,
void *arg);
+# ifndef OPENSSL_NO_QUIC
+/*
+ * QUIC integration - The QUIC interface matches BoringSSL
+ *
+ * ssl_encryption_level_t represents a specific QUIC encryption level used to
+ * transmit handshake messages. BoringSSL has this as an 'enum'.
+ */
+typedef enum ssl_encryption_level_t {
+ ssl_encryption_initial = 0,
+ ssl_encryption_early_data,
+ ssl_encryption_handshake,
+ ssl_encryption_application
+} OSSL_ENCRYPTION_LEVEL;
+
+struct ssl_quic_method_st {
+ int (*set_encryption_secrets)(SSL *ssl, OSSL_ENCRYPTION_LEVEL level,
+ const uint8_t *read_secret,
+ const uint8_t *write_secret, size_t secret_len);
+ int (*add_handshake_data)(SSL *ssl, OSSL_ENCRYPTION_LEVEL level,
+ const uint8_t *data, size_t len);
+ int (*flush_flight)(SSL *ssl);
+ int (*send_alert)(SSL *ssl, enum ssl_encryption_level_t level, uint8_t alert);
+};
+
+__owur int SSL_CTX_set_quic_method(SSL_CTX *ctx, const SSL_QUIC_METHOD *quic_method);
+__owur int SSL_set_quic_method(SSL *ssl, const SSL_QUIC_METHOD *quic_method);
+__owur int SSL_set_quic_transport_params(SSL *ssl,
+ const uint8_t *params,
+ size_t params_len);
+void SSL_get_peer_quic_transport_params(const SSL *ssl,
+ const uint8_t **out_params,
+ size_t *out_params_len);
+__owur size_t SSL_quic_max_handshake_flight_len(const SSL *ssl, OSSL_ENCRYPTION_LEVEL level);
+__owur OSSL_ENCRYPTION_LEVEL SSL_quic_read_level(const SSL *ssl);
+__owur OSSL_ENCRYPTION_LEVEL SSL_quic_write_level(const SSL *ssl);
+__owur int SSL_provide_quic_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL level,
+ const uint8_t *data, size_t len);
+__owur int SSL_process_quic_post_handshake(SSL *ssl);
+
+__owur int SSL_is_quic(SSL *ssl);
+
+/* BoringSSL API */
+void SSL_set_quic_use_legacy_codepoint(SSL *ssl, int use_legacy);
+
+/*
+ * Set an explicit value that you want to use
+ * If 0 (default) the server will use the highest extenstion the client sent
+ * If 0 (default) the client will send both extensions
+ */
+void SSL_set_quic_transport_version(SSL *ssl, int version);
+__owur int SSL_get_quic_transport_version(const SSL *ssl);
+/* Returns the negotiated version, or -1 on error */
+__owur int SSL_get_peer_quic_transport_version(const SSL *ssl);
+
+int SSL_CIPHER_get_prf_nid(const SSL_CIPHER *c);
+
+void SSL_set_quic_early_data_enabled(SSL *ssl, int enabled);
+
+# endif
+
# ifdef __cplusplus
}
# endif
diff --git a/contrib/libs/openssl/include/openssl/sslerr.h b/contrib/libs/openssl/include/openssl/sslerr.h
index 701d61c6e9..64e152cc51 100644
--- a/contrib/libs/openssl/include/openssl/sslerr.h
+++ b/contrib/libs/openssl/include/openssl/sslerr.h
@@ -71,6 +71,7 @@ int ERR_load_SSL_strings(void);
# define SSL_F_FINAL_KEY_SHARE 503
# define SSL_F_FINAL_MAXFRAGMENTLEN 557
# define SSL_F_FINAL_PSK 639
+# define SSL_F_FINAL_QUIC_TRANSPORT_PARAMS 3012
# define SSL_F_FINAL_RENEGOTIATE 483
# define SSL_F_FINAL_SERVER_NAME 558
# define SSL_F_FINAL_SIG_ALGS 497
@@ -97,6 +98,9 @@ int ERR_load_SSL_strings(void);
# define SSL_F_PITEM_NEW 624
# define SSL_F_PQUEUE_NEW 625
# define SSL_F_PROCESS_KEY_SHARE_EXT 439
+# define SSL_F_QUIC_CHANGE_CIPHER_STATE 3000
+# define SSL_F_QUIC_GET_MESSAGE 3001
+# define SSL_F_QUIC_SET_ENCRYPTION_SECRETS 3002
# define SSL_F_READ_STATE_MACHINE 352
# define SSL_F_SET_CLIENT_CIPHERSUITE 540
# define SSL_F_SRP_GENERATE_CLIENT_MASTER_SECRET 595
@@ -107,7 +111,9 @@ int ERR_load_SSL_strings(void);
# define SSL_F_SSL3_CTRL 213
# define SSL_F_SSL3_CTX_CTRL 133
# define SSL_F_SSL3_DIGEST_CACHED_RECORDS 293
+# define SSL_F_SSL3_DISPATCH_ALERT 3003
# define SSL_F_SSL3_DO_CHANGE_CIPHER_SPEC 292
+# define SSL_F_SSL3_DO_WRITE 3004
# define SSL_F_SSL3_ENC 608
# define SSL_F_SSL3_FINAL_FINISH_MAC 285
# define SSL_F_SSL3_FINISH_MAC 587
@@ -212,6 +218,8 @@ int ERR_load_SSL_strings(void);
# define SSL_F_SSL_PEEK 270
# define SSL_F_SSL_PEEK_EX 432
# define SSL_F_SSL_PEEK_INTERNAL 522
+# define SSL_F_SSL_PROCESS_QUIC_POST_HANDSHAKE 3005
+# define SSL_F_SSL_PROVIDE_QUIC_DATA 3006
# define SSL_F_SSL_READ 223
# define SSL_F_SSL_READ_EARLY_DATA 529
# define SSL_F_SSL_READ_EX 434
@@ -261,6 +269,7 @@ int ERR_load_SSL_strings(void);
# define SSL_F_SSL_WRITE_EARLY_FINISH 527
# define SSL_F_SSL_WRITE_EX 433
# define SSL_F_SSL_WRITE_INTERNAL 524
+# define SSL_F_STATEM_FLUSH 3007
# define SSL_F_STATE_MACHINE 353
# define SSL_F_TLS12_CHECK_PEER_SIGALG 333
# define SSL_F_TLS12_COPY_SIGALGS 533
@@ -320,6 +329,8 @@ int ERR_load_SSL_strings(void);
# define SSL_F_TLS_CONSTRUCT_CTOS_POST_HANDSHAKE_AUTH 619
# define SSL_F_TLS_CONSTRUCT_CTOS_PSK 501
# define SSL_F_TLS_CONSTRUCT_CTOS_PSK_KEX_MODES 509
+# define SSL_F_TLS_CONSTRUCT_CTOS_QUIC_TRANSPORT_PARAMS 3008
+# define SSL_F_TLS_CONSTRUCT_CTOS_QUIC_TRANSPORT_PARAMS_DRAFT 3013
# define SSL_F_TLS_CONSTRUCT_CTOS_RENEGOTIATE 473
# define SSL_F_TLS_CONSTRUCT_CTOS_SCT 474
# define SSL_F_TLS_CONSTRUCT_CTOS_SERVER_NAME 475
@@ -359,6 +370,8 @@ int ERR_load_SSL_strings(void);
# define SSL_F_TLS_CONSTRUCT_STOC_MAXFRAGMENTLEN 548
# define SSL_F_TLS_CONSTRUCT_STOC_NEXT_PROTO_NEG 457
# define SSL_F_TLS_CONSTRUCT_STOC_PSK 504
+# define SSL_F_TLS_CONSTRUCT_STOC_QUIC_TRANSPORT_PARAMS 3009
+# define SSL_F_TLS_CONSTRUCT_STOC_QUIC_TRANSPORT_PARAMS_DRAFT 3014
# define SSL_F_TLS_CONSTRUCT_STOC_RENEGOTIATE 458
# define SSL_F_TLS_CONSTRUCT_STOC_SERVER_NAME 459
# define SSL_F_TLS_CONSTRUCT_STOC_SESSION_TICKET 460
@@ -384,6 +397,8 @@ int ERR_load_SSL_strings(void);
# define SSL_F_TLS_PARSE_CTOS_POST_HANDSHAKE_AUTH 620
# define SSL_F_TLS_PARSE_CTOS_PSK 505
# define SSL_F_TLS_PARSE_CTOS_PSK_KEX_MODES 572
+# define SSL_F_TLS_PARSE_CTOS_QUIC_TRANSPORT_PARAMS 3010
+# define SSL_F_TLS_PARSE_CTOS_QUIC_TRANSPORT_PARAMS_DRAFT 3015
# define SSL_F_TLS_PARSE_CTOS_RENEGOTIATE 464
# define SSL_F_TLS_PARSE_CTOS_SERVER_NAME 573
# define SSL_F_TLS_PARSE_CTOS_SESSION_TICKET 574
@@ -402,6 +417,8 @@ int ERR_load_SSL_strings(void);
# define SSL_F_TLS_PARSE_STOC_MAXFRAGMENTLEN 581
# define SSL_F_TLS_PARSE_STOC_NPN 582
# define SSL_F_TLS_PARSE_STOC_PSK 502
+# define SSL_F_TLS_PARSE_STOC_QUIC_TRANSPORT_PARAMS 3011
+# define SSL_F_TLS_PARSE_STOC_QUIC_TRANSPORT_PARAMS_DRAFT 3016
# define SSL_F_TLS_PARSE_STOC_RENEGOTIATE 448
# define SSL_F_TLS_PARSE_STOC_SCT 564
# define SSL_F_TLS_PARSE_STOC_SERVER_NAME 583
@@ -594,6 +611,7 @@ int ERR_load_SSL_strings(void);
# define SSL_R_MISSING_FATAL 256
# define SSL_R_MISSING_PARAMETERS 290
# define SSL_R_MISSING_PSK_KEX_MODES_EXTENSION 310
+# define SSL_R_MISSING_QUIC_TRANSPORT_PARAMETERS_EXTENSION 801
# define SSL_R_MISSING_RSA_CERTIFICATE 168
# define SSL_R_MISSING_RSA_ENCRYPTING_CERT 169
# define SSL_R_MISSING_RSA_SIGNING_CERT 170
@@ -765,6 +783,7 @@ int ERR_load_SSL_strings(void);
# define SSL_R_WRONG_CERTIFICATE_TYPE 383
# define SSL_R_WRONG_CIPHER_RETURNED 261
# define SSL_R_WRONG_CURVE 378
+# define SSL_R_WRONG_ENCRYPTION_LEVEL_RECEIVED 800
# define SSL_R_WRONG_SIGNATURE_LENGTH 264
# define SSL_R_WRONG_SIGNATURE_SIZE 265
# define SSL_R_WRONG_SIGNATURE_TYPE 370
diff --git a/contrib/libs/openssl/include/openssl/tls1.h b/contrib/libs/openssl/include/openssl/tls1.h
index 76d9fda46e..2cbf53265f 100644
--- a/contrib/libs/openssl/include/openssl/tls1.h
+++ b/contrib/libs/openssl/include/openssl/tls1.h
@@ -148,6 +148,10 @@ extern "C" {
/* Temporary extension type */
# define TLSEXT_TYPE_renegotiate 0xff01
+/* ExtensionType value from draft-ietf-quic-tls-27 */
+# define TLSEXT_TYPE_quic_transport_parameters_draft 0xffa5
+# define TLSEXT_TYPE_quic_transport_parameters 0x0039
+
# ifndef OPENSSL_NO_NEXTPROTONEG
/* This is not an IANA defined extension number */
# define TLSEXT_TYPE_next_proto_neg 13172
diff --git a/contrib/libs/openssl/libssl.map b/contrib/libs/openssl/libssl.map
index bf624d3612..153358459d 100644
--- a/contrib/libs/openssl/libssl.map
+++ b/contrib/libs/openssl/libssl.map
@@ -510,4 +510,34 @@ OPENSSL_1_1_1a {
local: *;
} OPENSSL_1_1_1;
+OPENSSL_1_1_1i {
+ global:
+ SSL_CIPHER_get_prf_nid;
+ SSL_CTX_set_quic_method;
+ SSL_get_peer_quic_transport_params;
+ SSL_get_peer_quic_transport_version;
+ SSL_get_quic_transport_version;
+ SSL_is_quic;
+ SSL_process_quic_post_handshake;
+ SSL_provide_quic_data;
+ SSL_quic_max_handshake_flight_len;
+ SSL_quic_read_level;
+ SSL_quic_write_level;
+ SSL_set_quic_method;
+ SSL_set_quic_transport_params;
+ SSL_set_quic_transport_version;
+ SSL_set_quic_use_legacy_codepoint;
+} OPENSSL_1_1_1a;
+
+OPENSSL_1_1_1j {
+ global:
+ SSL_set_quic_early_data_enabled;
+} OPENSSL_1_1_1i;
+
+OPENSSL_1_1_1k {
+ global:
+ SSL_new_session_ticket;
+ local: *;
+} OPENSSL_1_1_1j;
+
diff --git a/contrib/libs/openssl/ssl/record/rec_layer_s3.c b/contrib/libs/openssl/ssl/record/rec_layer_s3.c
index 1db1712a09..fe746249a7 100644
--- a/contrib/libs/openssl/ssl/record/rec_layer_s3.c
+++ b/contrib/libs/openssl/ssl/record/rec_layer_s3.c
@@ -387,10 +387,12 @@ int ssl3_write_bytes(SSL *s, int type, const void *buf_, size_t len,
s->rlayer.wnum = 0;
/*
- * If we are supposed to be sending a KeyUpdate then go into init unless we
- * have writes pending - in which case we should finish doing that first.
+ * If we are supposed to be sending a KeyUpdate or NewSessionTicket then go
+ * into init unless we have writes pending - in which case we should finish
+ * doing that first.
*/
- if (wb->left == 0 && s->key_update != SSL_KEY_UPDATE_NONE)
+ if (wb->left == 0 && (s->key_update != SSL_KEY_UPDATE_NONE
+ || s->ext.extra_tickets_expected > 0))
ossl_statem_set_in_init(s, 1);
/*
diff --git a/contrib/libs/openssl/ssl/s3_msg.c b/contrib/libs/openssl/ssl/s3_msg.c
index 707e962d73..1adf564e95 100644
--- a/contrib/libs/openssl/ssl/s3_msg.c
+++ b/contrib/libs/openssl/ssl/s3_msg.c
@@ -77,6 +77,16 @@ int ssl3_dispatch_alert(SSL *s)
s->s3->alert_dispatch = 0;
alertlen = 2;
+#ifndef OPENSSL_NO_QUIC
+ if (SSL_IS_QUIC(s)) {
+ if (!s->quic_method->send_alert(s, s->quic_write_level,
+ s->s3->send_alert[1])) {
+ SSLerr(SSL_F_SSL3_DISPATCH_ALERT, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+ i = 1;
+ } else
+#endif
i = do_ssl3_write(s, SSL3_RT_ALERT, &s->s3->send_alert[0], &alertlen, 1, 0,
&written);
if (i <= 0) {
diff --git a/contrib/libs/openssl/ssl/ssl_ciph.c b/contrib/libs/openssl/ssl/ssl_ciph.c
index a3ca5294be..bc26aad7bb 100644
--- a/contrib/libs/openssl/ssl/ssl_ciph.c
+++ b/contrib/libs/openssl/ssl/ssl_ciph.c
@@ -2161,3 +2161,37 @@ int ssl_cert_is_disabled(size_t idx)
return 1;
return 0;
}
+
+#ifndef OPENSSL_NO_QUIC
+int SSL_CIPHER_get_prf_nid(const SSL_CIPHER *c)
+{
+ switch (c->algorithm2 & (0xFF << TLS1_PRF_DGST_SHIFT)) {
+ default:
+ break;
+ case TLS1_PRF_SHA1_MD5: /* TLS1_PRF */
+ return NID_md5_sha1;
+ case TLS1_PRF_SHA256:
+ return NID_sha256;
+ case TLS1_PRF_SHA384:
+ return NID_sha384;
+ case TLS1_PRF_GOST94:
+ return NID_id_GostR3411_94_prf;
+ case TLS1_PRF_GOST12_256:
+ return NID_id_GostR3411_2012_256;
+ case TLS1_PRF_GOST12_512:
+ return NID_id_GostR3411_2012_512;
+ }
+ /* TLSv1.3 ciphers don't specify separate PRF */
+ switch (c->algorithm2 & SSL_HANDSHAKE_MAC_MASK) {
+ default:
+ break;
+ case SSL_HANDSHAKE_MAC_MD5_SHA1: /* SSL_HANDSHAKE_MAC_DEFAULT */
+ return NID_md5_sha1;
+ case SSL_HANDSHAKE_MAC_SHA256:
+ return NID_sha256;
+ case SSL_HANDSHAKE_MAC_SHA384:
+ return NID_sha384;
+ }
+ return NID_undef;
+}
+#endif
diff --git a/contrib/libs/openssl/ssl/ssl_err.c b/contrib/libs/openssl/ssl/ssl_err.c
index 324f2ccbb0..56adfdca42 100644
--- a/contrib/libs/openssl/ssl/ssl_err.c
+++ b/contrib/libs/openssl/ssl/ssl_err.c
@@ -86,6 +86,8 @@ static const ERR_STRING_DATA SSL_str_functs[] = {
{ERR_PACK(ERR_LIB_SSL, SSL_F_FINAL_MAXFRAGMENTLEN, 0),
"final_maxfragmentlen"},
{ERR_PACK(ERR_LIB_SSL, SSL_F_FINAL_PSK, 0), "final_psk"},
+ {ERR_PACK(ERR_LIB_SSL, SSL_F_FINAL_QUIC_TRANSPORT_PARAMS, 0),
+ "final_quic_transport_params"},
{ERR_PACK(ERR_LIB_SSL, SSL_F_FINAL_RENEGOTIATE, 0), "final_renegotiate"},
{ERR_PACK(ERR_LIB_SSL, SSL_F_FINAL_SERVER_NAME, 0), "final_server_name"},
{ERR_PACK(ERR_LIB_SSL, SSL_F_FINAL_SIG_ALGS, 0), "final_sig_algs"},
@@ -113,6 +115,8 @@ static const ERR_STRING_DATA SSL_str_functs[] = {
"ossl_statem_server_post_process_message"},
{ERR_PACK(ERR_LIB_SSL, SSL_F_OSSL_STATEM_SERVER_POST_WORK, 0),
"ossl_statem_server_post_work"},
+ {ERR_PACK(ERR_LIB_SSL, SSL_F_OSSL_STATEM_SERVER_PRE_WORK, 0),
+ "ossl_statem_server_pre_work"},
{ERR_PACK(ERR_LIB_SSL, SSL_F_OSSL_STATEM_SERVER_PROCESS_MESSAGE, 0),
"ossl_statem_server_process_message"},
{ERR_PACK(ERR_LIB_SSL, SSL_F_OSSL_STATEM_SERVER_READ_TRANSITION, 0),
@@ -123,6 +127,11 @@ static const ERR_STRING_DATA SSL_str_functs[] = {
{ERR_PACK(ERR_LIB_SSL, SSL_F_PITEM_NEW, 0), "pitem_new"},
{ERR_PACK(ERR_LIB_SSL, SSL_F_PQUEUE_NEW, 0), "pqueue_new"},
{ERR_PACK(ERR_LIB_SSL, SSL_F_PROCESS_KEY_SHARE_EXT, 0), ""},
+ {ERR_PACK(ERR_LIB_SSL, SSL_F_QUIC_CHANGE_CIPHER_STATE, 0),
+ "quic_change_cipher_state"},
+ {ERR_PACK(ERR_LIB_SSL, SSL_F_QUIC_GET_MESSAGE, 0), "quic_get_message"},
+ {ERR_PACK(ERR_LIB_SSL, SSL_F_QUIC_SET_ENCRYPTION_SECRETS, 0),
+ "quic_set_encryption_secrets"},
{ERR_PACK(ERR_LIB_SSL, SSL_F_READ_STATE_MACHINE, 0), "read_state_machine"},
{ERR_PACK(ERR_LIB_SSL, SSL_F_SET_CLIENT_CIPHERSUITE, 0),
"set_client_ciphersuite"},
@@ -140,8 +149,11 @@ static const ERR_STRING_DATA SSL_str_functs[] = {
{ERR_PACK(ERR_LIB_SSL, SSL_F_SSL3_CTX_CTRL, 0), "ssl3_ctx_ctrl"},
{ERR_PACK(ERR_LIB_SSL, SSL_F_SSL3_DIGEST_CACHED_RECORDS, 0),
"ssl3_digest_cached_records"},
+ {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL3_DISPATCH_ALERT, 0),
+ "ssl3_dispatch_alert"},
{ERR_PACK(ERR_LIB_SSL, SSL_F_SSL3_DO_CHANGE_CIPHER_SPEC, 0),
"ssl3_do_change_cipher_spec"},
+ {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL3_DO_WRITE, 0), "ssl3_do_write"},
{ERR_PACK(ERR_LIB_SSL, SSL_F_SSL3_ENC, 0), "ssl3_enc"},
{ERR_PACK(ERR_LIB_SSL, SSL_F_SSL3_FINAL_FINISH_MAC, 0),
"ssl3_final_finish_mac"},
@@ -303,6 +315,10 @@ static const ERR_STRING_DATA SSL_str_functs[] = {
{ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_PEEK, 0), "SSL_peek"},
{ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_PEEK_EX, 0), "SSL_peek_ex"},
{ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_PEEK_INTERNAL, 0), "ssl_peek_internal"},
+ {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_PROCESS_QUIC_POST_HANDSHAKE, 0),
+ "SSL_process_quic_post_handshake"},
+ {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_PROVIDE_QUIC_DATA, 0),
+ "SSL_provide_quic_data"},
{ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_READ, 0), "SSL_read"},
{ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_READ_EARLY_DATA, 0),
"SSL_read_early_data"},
@@ -379,6 +395,7 @@ static const ERR_STRING_DATA SSL_str_functs[] = {
{ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_WRITE_EARLY_FINISH, 0), ""},
{ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_WRITE_EX, 0), "SSL_write_ex"},
{ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_WRITE_INTERNAL, 0), "ssl_write_internal"},
+ {ERR_PACK(ERR_LIB_SSL, SSL_F_STATEM_FLUSH, 0), "statem_flush"},
{ERR_PACK(ERR_LIB_SSL, SSL_F_STATE_MACHINE, 0), "state_machine"},
{ERR_PACK(ERR_LIB_SSL, SSL_F_TLS12_CHECK_PEER_SIGALG, 0),
"tls12_check_peer_sigalg"},
@@ -480,6 +497,10 @@ static const ERR_STRING_DATA SSL_str_functs[] = {
"tls_construct_ctos_psk"},
{ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_CTOS_PSK_KEX_MODES, 0),
"tls_construct_ctos_psk_kex_modes"},
+ {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_CTOS_QUIC_TRANSPORT_PARAMS, 0),
+ "tls_construct_ctos_quic_transport_params"},
+ {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_CTOS_QUIC_TRANSPORT_PARAMS_DRAFT, 0),
+ "tls_construct_ctos_quic_transport_params_draft"},
{ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_CTOS_RENEGOTIATE, 0),
"tls_construct_ctos_renegotiate"},
{ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_CTOS_SCT, 0),
@@ -551,6 +572,10 @@ static const ERR_STRING_DATA SSL_str_functs[] = {
"tls_construct_stoc_next_proto_neg"},
{ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_STOC_PSK, 0),
"tls_construct_stoc_psk"},
+ {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_STOC_QUIC_TRANSPORT_PARAMS, 0),
+ "tls_construct_stoc_quic_transport_params"},
+ {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_STOC_QUIC_TRANSPORT_PARAMS_DRAFT, 0),
+ "tls_construct_stoc_quic_transport_params_draft"},
{ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_STOC_RENEGOTIATE, 0),
"tls_construct_stoc_renegotiate"},
{ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_CONSTRUCT_STOC_SERVER_NAME, 0),
@@ -597,6 +622,10 @@ static const ERR_STRING_DATA SSL_str_functs[] = {
{ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PARSE_CTOS_PSK, 0), "tls_parse_ctos_psk"},
{ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PARSE_CTOS_PSK_KEX_MODES, 0),
"tls_parse_ctos_psk_kex_modes"},
+ {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PARSE_CTOS_QUIC_TRANSPORT_PARAMS, 0),
+ "tls_parse_ctos_quic_transport_params"},
+ {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PARSE_CTOS_QUIC_TRANSPORT_PARAMS_DRAFT, 0),
+ "tls_parse_ctos_quic_transport_params_draft"},
{ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PARSE_CTOS_RENEGOTIATE, 0),
"tls_parse_ctos_renegotiate"},
{ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PARSE_CTOS_SERVER_NAME, 0),
@@ -629,6 +658,10 @@ static const ERR_STRING_DATA SSL_str_functs[] = {
"tls_parse_stoc_maxfragmentlen"},
{ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PARSE_STOC_NPN, 0), "tls_parse_stoc_npn"},
{ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PARSE_STOC_PSK, 0), "tls_parse_stoc_psk"},
+ {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PARSE_STOC_QUIC_TRANSPORT_PARAMS, 0),
+ "tls_parse_stoc_quic_transport_params"},
+ {ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PARSE_STOC_QUIC_TRANSPORT_PARAMS_DRAFT, 0),
+ "tls_parse_stoc_quic_transport_params_draft"},
{ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PARSE_STOC_RENEGOTIATE, 0),
"tls_parse_stoc_renegotiate"},
{ERR_PACK(ERR_LIB_SSL, SSL_F_TLS_PARSE_STOC_SCT, 0), "tls_parse_stoc_sct"},
@@ -951,6 +984,8 @@ static const ERR_STRING_DATA SSL_str_reasons[] = {
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_PARAMETERS), "missing parameters"},
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_PSK_KEX_MODES_EXTENSION),
"missing psk kex modes extension"},
+ {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_QUIC_TRANSPORT_PARAMETERS_EXTENSION),
+ "missing quic transport parameters extension"},
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_RSA_CERTIFICATE),
"missing rsa certificate"},
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_RSA_ENCRYPTING_CERT),
@@ -1253,6 +1288,8 @@ static const ERR_STRING_DATA SSL_str_reasons[] = {
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_WRONG_CIPHER_RETURNED),
"wrong cipher returned"},
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_WRONG_CURVE), "wrong curve"},
+ {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_WRONG_ENCRYPTION_LEVEL_RECEIVED),
+ "wrong encryption level received"},
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_WRONG_SIGNATURE_LENGTH),
"wrong signature length"},
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_WRONG_SIGNATURE_SIZE),
diff --git a/contrib/libs/openssl/ssl/ssl_lib.c b/contrib/libs/openssl/ssl/ssl_lib.c
index 47adc3211c..1085f86c50 100644
--- a/contrib/libs/openssl/ssl/ssl_lib.c
+++ b/contrib/libs/openssl/ssl/ssl_lib.c
@@ -574,8 +574,57 @@ static void clear_ciphers(SSL *s)
ssl_clear_hash_ctx(&s->write_hash);
}
+#ifndef OPENSSL_NO_QUIC
int SSL_clear(SSL *s)
{
+ if (!SSL_clear_not_quic(s))
+ return 0;
+ return SSL_clear_quic(s);
+}
+
+int SSL_clear_quic(SSL *s)
+{
+ OPENSSL_free(s->ext.peer_quic_transport_params_draft);
+ s->ext.peer_quic_transport_params_draft = NULL;
+ s->ext.peer_quic_transport_params_draft_len = 0;
+ OPENSSL_free(s->ext.peer_quic_transport_params);
+ s->ext.peer_quic_transport_params = NULL;
+ s->ext.peer_quic_transport_params_len = 0;
+ s->quic_read_level = ssl_encryption_initial;
+ s->quic_write_level = ssl_encryption_initial;
+ s->quic_latest_level_received = ssl_encryption_initial;
+ while (s->quic_input_data_head != NULL) {
+ QUIC_DATA *qd;
+
+ qd = s->quic_input_data_head;
+ s->quic_input_data_head = qd->next;
+ OPENSSL_free(qd);
+ }
+ s->quic_input_data_tail = NULL;
+ BUF_MEM_free(s->quic_buf);
+ s->quic_buf = NULL;
+ s->quic_next_record_start = 0;
+ memset(s->client_hand_traffic_secret, 0, EVP_MAX_MD_SIZE);
+ memset(s->server_hand_traffic_secret, 0, EVP_MAX_MD_SIZE);
+ memset(s->client_early_traffic_secret, 0, EVP_MAX_MD_SIZE);
+ /*
+ * CONFIG - DON'T CLEAR
+ * s->ext.quic_transport_params
+ * s->ext.quic_transport_params_len
+ * s->quic_transport_version
+ * s->quic_method = NULL;
+ */
+ return 1;
+}
+#endif
+
+/* Keep this conditional very local */
+#ifndef OPENSSL_NO_QUIC
+int SSL_clear_not_quic(SSL *s)
+#else
+int SSL_clear(SSL *s)
+#endif
+{
if (s->method == NULL) {
SSLerr(SSL_F_SSL_CLEAR, SSL_R_NO_METHOD_SPECIFIED);
return 0;
@@ -845,6 +894,10 @@ SSL *SSL_new(SSL_CTX *ctx)
s->job = NULL;
+#ifndef OPENSSL_NO_QUIC
+ s->quic_method = ctx->quic_method;
+#endif
+
#ifndef OPENSSL_NO_CT
if (!SSL_set_ct_validation_callback(s, ctx->ct_validation_callback,
ctx->ct_validation_callback_arg))
@@ -1212,6 +1265,20 @@ void SSL_free(SSL *s)
OPENSSL_free(s->pha_context);
EVP_MD_CTX_free(s->pha_dgst);
+#ifndef OPENSSL_NO_QUIC
+ OPENSSL_free(s->ext.quic_transport_params);
+ OPENSSL_free(s->ext.peer_quic_transport_params_draft);
+ OPENSSL_free(s->ext.peer_quic_transport_params);
+ BUF_MEM_free(s->quic_buf);
+ while (s->quic_input_data_head != NULL) {
+ QUIC_DATA *qd;
+
+ qd = s->quic_input_data_head;
+ s->quic_input_data_head = qd->next;
+ OPENSSL_free(qd);
+ }
+#endif
+
sk_X509_NAME_pop_free(s->ca_names, X509_NAME_free);
sk_X509_NAME_pop_free(s->client_ca_names, X509_NAME_free);
@@ -1747,6 +1814,12 @@ static int ssl_io_intern(void *vargs)
int ssl_read_internal(SSL *s, void *buf, size_t num, size_t *readbytes)
{
+#ifndef OPENSSL_NO_QUIC
+ if (SSL_IS_QUIC(s)) {
+ SSLerr(SSL_F_SSL_READ_INTERNAL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+ return -1;
+ }
+#endif
if (s->handshake_func == NULL) {
SSLerr(SSL_F_SSL_READ_INTERNAL, SSL_R_UNINITIALIZED);
return -1;
@@ -1879,6 +1952,12 @@ int SSL_get_early_data_status(const SSL *s)
static int ssl_peek_internal(SSL *s, void *buf, size_t num, size_t *readbytes)
{
+#ifndef OPENSSL_NO_QUIC
+ if (SSL_IS_QUIC(s)) {
+ SSLerr(SSL_F_SSL_PEEK_INTERNAL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+ return -1;
+ }
+#endif
if (s->handshake_func == NULL) {
SSLerr(SSL_F_SSL_PEEK_INTERNAL, SSL_R_UNINITIALIZED);
return -1;
@@ -1939,6 +2018,12 @@ int SSL_peek_ex(SSL *s, void *buf, size_t num, size_t *readbytes)
int ssl_write_internal(SSL *s, const void *buf, size_t num, size_t *written)
{
+#ifndef OPENSSL_NO_QUIC
+ if (SSL_IS_QUIC(s)) {
+ SSLerr(SSL_F_SSL_WRITE_INTERNAL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+ return -1;
+ }
+#endif
if (s->handshake_func == NULL) {
SSLerr(SSL_F_SSL_WRITE_INTERNAL, SSL_R_UNINITIALIZED);
return -1;
@@ -2196,6 +2281,19 @@ int SSL_renegotiate_pending(const SSL *s)
return (s->renegotiate != 0);
}
+int SSL_new_session_ticket(SSL *s)
+{
+ /* If we are in init because we're sending tickets, okay to send more. */
+ if ((SSL_in_init(s) && s->ext.extra_tickets_expected == 0)
+ || SSL_IS_FIRST_HANDSHAKE(s) || !s->server
+ || !SSL_IS_TLS13(s))
+ return 0;
+ s->ext.extra_tickets_expected++;
+ if (s->rlayer.wbuf[0].left == 0 && !SSL_in_init(s))
+ ossl_statem_set_in_init(s, 1);
+ return 1;
+}
+
long SSL_ctrl(SSL *s, int cmd, long larg, void *parg)
{
long l;
@@ -3635,6 +3733,11 @@ int SSL_get_error(const SSL *s, int i)
}
if (SSL_want_read(s)) {
+#ifndef OPENSSL_NO_QUIC
+ if (SSL_IS_QUIC(s)) {
+ return SSL_ERROR_WANT_READ;
+ }
+#endif
bio = SSL_get_rbio(s);
if (BIO_should_read(bio))
return SSL_ERROR_WANT_READ;
@@ -3732,6 +3835,21 @@ int SSL_do_handshake(SSL *s)
ret = s->handshake_func(s);
}
}
+#ifndef OPENSSL_NO_QUIC
+ if (SSL_IS_QUIC(s) && ret == 1) {
+ if (s->server) {
+ if (s->early_data_state == SSL_EARLY_DATA_ACCEPTING) {
+ s->early_data_state = SSL_EARLY_DATA_FINISHED_READING;
+ s->rwstate = SSL_READING;
+ ret = 0;
+ }
+ } else if (s->early_data_state == SSL_EARLY_DATA_CONNECTING) {
+ s->early_data_state = SSL_EARLY_DATA_WRITE_RETRY;
+ s->rwstate = SSL_READING;
+ ret = 0;
+ }
+ }
+#endif
return ret;
}
diff --git a/contrib/libs/openssl/ssl/ssl_local.h b/contrib/libs/openssl/ssl/ssl_local.h
index 5c79215423..5795b9e802 100644
--- a/contrib/libs/openssl/ssl/ssl_local.h
+++ b/contrib/libs/openssl/ssl/ssl_local.h
@@ -315,6 +315,13 @@
/* Flag used on OpenSSL ciphersuite ids to indicate they are for SSLv3+ */
# define SSL3_CK_CIPHERSUITE_FLAG 0x03000000
+/* Check if an SSL structure is using QUIC (which uses TLSv1.3) */
+# ifndef OPENSSL_NO_QUIC
+# define SSL_IS_QUIC(s) (s->quic_method != NULL)
+# else
+# define SSL_IS_QUIC(s) 0
+# endif
+
/* Check if an SSL structure is using DTLS */
# define SSL_IS_DTLS(s) (s->method->ssl3_enc->enc_flags & SSL_ENC_FLAG_DTLS)
@@ -714,6 +721,8 @@ typedef enum tlsext_index_en {
TLSEXT_IDX_cryptopro_bug,
TLSEXT_IDX_early_data,
TLSEXT_IDX_certificate_authorities,
+ TLSEXT_IDX_quic_transport_params_draft,
+ TLSEXT_IDX_quic_transport_params,
TLSEXT_IDX_padding,
TLSEXT_IDX_psk,
/* Dummy index - must always be the last entry */
@@ -1063,7 +1072,24 @@ struct ssl_ctx_st {
/* Do we advertise Post-handshake auth support? */
int pha_enabled;
+
+#ifndef OPENSSL_NO_QUIC
+ const SSL_QUIC_METHOD *quic_method;
+#endif
+};
+
+typedef struct cert_pkey_st CERT_PKEY;
+
+#ifndef OPENSSL_NO_QUIC
+struct quic_data_st {
+ struct quic_data_st *next;
+ OSSL_ENCRYPTION_LEVEL level;
+ size_t start; /* offset into quic_buf->data */
+ size_t length;
};
+typedef struct quic_data_st QUIC_DATA;
+int quic_set_encryption_secrets(SSL *ssl, OSSL_ENCRYPTION_LEVEL level);
+#endif
struct ssl_st {
/*
@@ -1152,6 +1178,11 @@ struct ssl_st {
unsigned char handshake_traffic_hash[EVP_MAX_MD_SIZE];
unsigned char client_app_traffic_secret[EVP_MAX_MD_SIZE];
unsigned char server_app_traffic_secret[EVP_MAX_MD_SIZE];
+# ifndef OPENSSL_NO_QUIC
+ unsigned char client_hand_traffic_secret[EVP_MAX_MD_SIZE];
+ unsigned char server_hand_traffic_secret[EVP_MAX_MD_SIZE];
+ unsigned char client_early_traffic_secret[EVP_MAX_MD_SIZE];
+# endif
unsigned char exporter_master_secret[EVP_MAX_MD_SIZE];
unsigned char early_exporter_master_secret[EVP_MAX_MD_SIZE];
EVP_CIPHER_CTX *enc_read_ctx; /* cryptographic state */
@@ -1289,6 +1320,8 @@ struct ssl_st {
/* RFC4507 session ticket expected to be received or sent */
int ticket_expected;
+ /* TLS 1.3 tickets requested by the application. */
+ int extra_tickets_expected;
# ifndef OPENSSL_NO_EC
size_t ecpointformats_len;
/* our list */
@@ -1364,8 +1397,35 @@ struct ssl_st {
* selected.
*/
int tick_identity;
+
+#ifndef OPENSSL_NO_QUIC
+ uint8_t *quic_transport_params;
+ size_t quic_transport_params_len;
+ uint8_t *peer_quic_transport_params_draft;
+ size_t peer_quic_transport_params_draft_len;
+ uint8_t *peer_quic_transport_params;
+ size_t peer_quic_transport_params_len;
+#endif
} ext;
+#ifndef OPENSSL_NO_QUIC
+ OSSL_ENCRYPTION_LEVEL quic_read_level;
+ OSSL_ENCRYPTION_LEVEL quic_write_level;
+ OSSL_ENCRYPTION_LEVEL quic_latest_level_received;
+ /*
+ * defaults to 0, but can be set to:
+ * - TLSEXT_TYPE_quic_transport_parameters_draft
+ * - TLSEXT_TYPE_quic_transport_parameters
+ * Client: if 0, send both
+ * Server: if 0, use same version as client sent
+ */
+ int quic_transport_version;
+ BUF_MEM *quic_buf; /* buffer incoming handshake messages */
+ QUIC_DATA *quic_input_data_head;
+ QUIC_DATA *quic_input_data_tail;
+ size_t quic_next_record_start;
+ const SSL_QUIC_METHOD *quic_method;
+#endif
/*
* Parsed form of the ClientHello, kept around across client_hello_cb
* calls.
@@ -2660,6 +2720,11 @@ void custom_exts_free(custom_ext_methods *exts);
void ssl_comp_free_compression_methods_int(void);
+#ifndef OPENSSL_NO_QUIC
+__owur int SSL_clear_not_quic(SSL *s);
+__owur int SSL_clear_quic(SSL *s);
+#endif
+
/* ssl_mcnf.c */
void ssl_ctx_system_config(SSL_CTX *ctx);
diff --git a/contrib/libs/openssl/ssl/ssl_quic.c b/contrib/libs/openssl/ssl/ssl_quic.c
new file mode 100644
index 0000000000..c5f20c20af
--- /dev/null
+++ b/contrib/libs/openssl/ssl/ssl_quic.c
@@ -0,0 +1,385 @@
+/*
+ * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License"). You may not use
+ * this file except in compliance with the License. You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include "ssl_local.h"
+#include "internal/cryptlib.h"
+#include "internal/refcount.h"
+
+int SSL_set_quic_transport_params(SSL *ssl, const uint8_t *params,
+ size_t params_len)
+{
+ uint8_t *tmp;
+
+ if (params == NULL || params_len == 0) {
+ tmp = NULL;
+ params_len = 0;
+ } else {
+ tmp = OPENSSL_memdup(params, params_len);
+ if (tmp == NULL)
+ return 0;
+ }
+
+ OPENSSL_free(ssl->ext.quic_transport_params);
+ ssl->ext.quic_transport_params = tmp;
+ ssl->ext.quic_transport_params_len = params_len;
+ return 1;
+}
+
+void SSL_get_peer_quic_transport_params(const SSL *ssl,
+ const uint8_t **out_params,
+ size_t *out_params_len)
+{
+ if (ssl->ext.peer_quic_transport_params_len) {
+ *out_params = ssl->ext.peer_quic_transport_params;
+ *out_params_len = ssl->ext.peer_quic_transport_params_len;
+ } else {
+ *out_params = ssl->ext.peer_quic_transport_params_draft;
+ *out_params_len = ssl->ext.peer_quic_transport_params_draft_len;
+ }
+}
+
+/* Returns the negotiated version, or -1 on error */
+int SSL_get_peer_quic_transport_version(const SSL *ssl)
+{
+ if (ssl->ext.peer_quic_transport_params_len != 0
+ && ssl->ext.peer_quic_transport_params_draft_len != 0)
+ return -1;
+ if (ssl->ext.peer_quic_transport_params_len != 0)
+ return TLSEXT_TYPE_quic_transport_parameters;
+ if (ssl->ext.peer_quic_transport_params_draft_len != 0)
+ return TLSEXT_TYPE_quic_transport_parameters_draft;
+
+ return -1;
+}
+
+void SSL_set_quic_use_legacy_codepoint(SSL *ssl, int use_legacy)
+{
+ if (use_legacy)
+ ssl->quic_transport_version = TLSEXT_TYPE_quic_transport_parameters_draft;
+ else
+ ssl->quic_transport_version = TLSEXT_TYPE_quic_transport_parameters;
+}
+
+void SSL_set_quic_transport_version(SSL *ssl, int version)
+{
+ ssl->quic_transport_version = version;
+}
+
+int SSL_get_quic_transport_version(const SSL *ssl)
+{
+ return ssl->quic_transport_version;
+}
+
+size_t SSL_quic_max_handshake_flight_len(const SSL *ssl, OSSL_ENCRYPTION_LEVEL level)
+{
+ /*
+ * Limits flights to 16K by default when there are no large
+ * (certificate-carrying) messages.
+ */
+ static const size_t DEFAULT_FLIGHT_LIMIT = 16384;
+
+ switch (level) {
+ case ssl_encryption_initial:
+ return DEFAULT_FLIGHT_LIMIT;
+ case ssl_encryption_early_data:
+ /* QUIC does not send EndOfEarlyData. */
+ return 0;
+ case ssl_encryption_handshake:
+ if (ssl->server) {
+ /*
+ * Servers may receive Certificate message if configured to request
+ * client certificates.
+ */
+ if ((ssl->verify_mode & SSL_VERIFY_PEER)
+ && ssl->max_cert_list > DEFAULT_FLIGHT_LIMIT)
+ return ssl->max_cert_list;
+ } else {
+ /*
+ * Clients may receive both Certificate message and a CertificateRequest
+ * message.
+ */
+ if (2*ssl->max_cert_list > DEFAULT_FLIGHT_LIMIT)
+ return 2 * ssl->max_cert_list;
+ }
+ return DEFAULT_FLIGHT_LIMIT;
+ case ssl_encryption_application:
+ return DEFAULT_FLIGHT_LIMIT;
+ }
+
+ return 0;
+}
+
+OSSL_ENCRYPTION_LEVEL SSL_quic_read_level(const SSL *ssl)
+{
+ return ssl->quic_read_level;
+}
+
+OSSL_ENCRYPTION_LEVEL SSL_quic_write_level(const SSL *ssl)
+{
+ return ssl->quic_write_level;
+}
+
+int SSL_provide_quic_data(SSL *ssl, OSSL_ENCRYPTION_LEVEL level,
+ const uint8_t *data, size_t len)
+{
+ size_t l, offset;
+
+ if (!SSL_IS_QUIC(ssl)) {
+ SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+ return 0;
+ }
+
+ /* Level can be different than the current read, but not less */
+ if (level < ssl->quic_read_level
+ || (ssl->quic_input_data_tail != NULL && level < ssl->quic_input_data_tail->level)
+ || level < ssl->quic_latest_level_received) {
+ SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, SSL_R_WRONG_ENCRYPTION_LEVEL_RECEIVED);
+ return 0;
+ }
+
+ if (len == 0)
+ return 1;
+
+ if (ssl->quic_buf == NULL) {
+ BUF_MEM *buf;
+ if ((buf = BUF_MEM_new()) == NULL) {
+ SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+ if (!BUF_MEM_grow(buf, SSL3_RT_MAX_PLAIN_LENGTH)) {
+ SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, ERR_R_INTERNAL_ERROR);
+ BUF_MEM_free(buf);
+ return 0;
+ }
+ ssl->quic_buf = buf;
+ /* We preallocated storage, but there's still no *data*. */
+ ssl->quic_buf->length = 0;
+ buf = NULL;
+ }
+
+ /* A TLS message must not cross an encryption level boundary */
+ if (ssl->quic_buf->length != ssl->quic_next_record_start
+ && level != ssl->quic_latest_level_received) {
+ SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA,
+ SSL_R_WRONG_ENCRYPTION_LEVEL_RECEIVED);
+ return 0;
+ }
+ ssl->quic_latest_level_received = level;
+
+ offset = ssl->quic_buf->length;
+ if (!BUF_MEM_grow(ssl->quic_buf, offset + len)) {
+ SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+ memcpy(ssl->quic_buf->data + offset, data, len);
+
+ /* Split on handshake message boundaries */
+ while (ssl->quic_buf->length > ssl->quic_next_record_start
+ + SSL3_HM_HEADER_LENGTH) {
+ QUIC_DATA *qd;
+ const uint8_t *p;
+
+ /* TLS Handshake message header has 1-byte type and 3-byte length */
+ p = (const uint8_t *)ssl->quic_buf->data
+ + ssl->quic_next_record_start + 1;
+ n2l3(p, l);
+ l += SSL3_HM_HEADER_LENGTH;
+ /* Don't allocate a QUIC_DATA if we don't have a full record */
+ if (l > ssl->quic_buf->length - ssl->quic_next_record_start)
+ break;
+
+ qd = OPENSSL_zalloc(sizeof(*qd));
+ if (qd == NULL) {
+ SSLerr(SSL_F_SSL_PROVIDE_QUIC_DATA, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+
+ qd->next = NULL;
+ qd->length = l;
+ qd->start = ssl->quic_next_record_start;
+ qd->level = level;
+
+ if (ssl->quic_input_data_tail != NULL)
+ ssl->quic_input_data_tail->next = qd;
+ else
+ ssl->quic_input_data_head = qd;
+ ssl->quic_input_data_tail = qd;
+ ssl->quic_next_record_start += l;
+ }
+
+ return 1;
+}
+
+int SSL_CTX_set_quic_method(SSL_CTX *ctx, const SSL_QUIC_METHOD *quic_method)
+{
+ if (ctx->method->version != TLS_ANY_VERSION)
+ return 0;
+ ctx->quic_method = quic_method;
+ ctx->options &= ~SSL_OP_ENABLE_MIDDLEBOX_COMPAT;
+ return 1;
+}
+
+int SSL_set_quic_method(SSL *ssl, const SSL_QUIC_METHOD *quic_method)
+{
+ if (ssl->method->version != TLS_ANY_VERSION)
+ return 0;
+ ssl->quic_method = quic_method;
+ ssl->options &= ~SSL_OP_ENABLE_MIDDLEBOX_COMPAT;
+ return 1;
+}
+
+int quic_set_encryption_secrets(SSL *ssl, OSSL_ENCRYPTION_LEVEL level)
+{
+ uint8_t *c2s_secret = NULL;
+ uint8_t *s2c_secret = NULL;
+ size_t len;
+ const EVP_MD *md;
+
+ if (!SSL_IS_QUIC(ssl))
+ return 1;
+
+ /* secrets from the POV of the client */
+ switch (level) {
+ case ssl_encryption_early_data:
+ c2s_secret = ssl->client_early_traffic_secret;
+ break;
+ case ssl_encryption_handshake:
+ c2s_secret = ssl->client_hand_traffic_secret;
+ s2c_secret = ssl->server_hand_traffic_secret;
+ break;
+ case ssl_encryption_application:
+ c2s_secret = ssl->client_app_traffic_secret;
+ s2c_secret = ssl->server_app_traffic_secret;
+ break;
+ default:
+ return 1;
+ }
+
+ if (level == ssl_encryption_early_data) {
+ const SSL_CIPHER *c = SSL_SESSION_get0_cipher(ssl->session);
+ if (ssl->early_data_state == SSL_EARLY_DATA_CONNECTING
+ && ssl->max_early_data > 0
+ && ssl->session->ext.max_early_data == 0) {
+ if (!ossl_assert(ssl->psksession != NULL
+ && ssl->max_early_data
+ == ssl->psksession->ext.max_early_data)) {
+ SSLfatal(ssl, SSL_AD_INTERNAL_ERROR,
+ SSL_F_QUIC_SET_ENCRYPTION_SECRETS,
+ ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+ c = SSL_SESSION_get0_cipher(ssl->psksession);
+ }
+
+ if (c == NULL) {
+ SSLfatal(ssl, SSL_AD_INTERNAL_ERROR,
+ SSL_F_QUIC_SET_ENCRYPTION_SECRETS, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+
+ md = ssl_md(c->algorithm2);
+ } else {
+ md = ssl_handshake_md(ssl);
+ if (md == NULL) {
+ /* May not have selected cipher, yet */
+ const SSL_CIPHER *c = NULL;
+
+ /*
+ * It probably doesn't make sense to use an (external) PSK session,
+ * but in theory some kinds of external session caches could be
+ * implemented using it, so allow psksession to be used as well as
+ * the regular session.
+ */
+ if (ssl->session != NULL)
+ c = SSL_SESSION_get0_cipher(ssl->session);
+ else if (ssl->psksession != NULL)
+ c = SSL_SESSION_get0_cipher(ssl->psksession);
+
+ if (c != NULL)
+ md = SSL_CIPHER_get_handshake_digest(c);
+ }
+ }
+
+ if ((len = EVP_MD_size(md)) <= 0) {
+ SSLfatal(ssl, SSL_AD_INTERNAL_ERROR, SSL_F_QUIC_SET_ENCRYPTION_SECRETS,
+ ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+
+ if (ssl->server) {
+ if (!ssl->quic_method->set_encryption_secrets(ssl, level, c2s_secret,
+ s2c_secret, len)) {
+ SSLfatal(ssl, SSL_AD_INTERNAL_ERROR, SSL_F_QUIC_SET_ENCRYPTION_SECRETS,
+ ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+ } else {
+ if (!ssl->quic_method->set_encryption_secrets(ssl, level, s2c_secret,
+ c2s_secret, len)) {
+ SSLfatal(ssl, SSL_AD_INTERNAL_ERROR, SSL_F_QUIC_SET_ENCRYPTION_SECRETS,
+ ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+int SSL_process_quic_post_handshake(SSL *ssl)
+{
+ int ret;
+
+ if (SSL_in_init(ssl) || !SSL_IS_QUIC(ssl)) {
+ SSLerr(SSL_F_SSL_PROCESS_QUIC_POST_HANDSHAKE, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+ return 0;
+ }
+
+ /* if there is no data, return success as BoringSSL */
+ while (ssl->quic_input_data_head != NULL) {
+ /*
+ * This is always safe (we are sure to be at a record boundary) because
+ * SSL_read()/SSL_write() are never used for QUIC connections -- the
+ * application data is handled at the QUIC layer instead.
+ */
+ ossl_statem_set_in_init(ssl, 1);
+ ret = ssl->handshake_func(ssl);
+ ossl_statem_set_in_init(ssl, 0);
+
+ if (ret <= 0)
+ return 0;
+ }
+ return 1;
+}
+
+int SSL_is_quic(SSL* ssl)
+{
+ return SSL_IS_QUIC(ssl);
+}
+
+void SSL_set_quic_early_data_enabled(SSL *ssl, int enabled)
+{
+ if (!SSL_is_quic(ssl) || !SSL_in_before(ssl))
+ return;
+
+ if (!enabled) {
+ ssl->early_data_state = SSL_EARLY_DATA_NONE;
+ return;
+ }
+
+ if (ssl->server) {
+ ssl->early_data_state = SSL_EARLY_DATA_ACCEPTING;
+ return;
+ }
+
+ if ((ssl->session == NULL || ssl->session->ext.max_early_data == 0)
+ && ssl->psk_use_session_cb == NULL)
+ return;
+
+ ssl->early_data_state = SSL_EARLY_DATA_CONNECTING;
+}
diff --git a/contrib/libs/openssl/ssl/statem/extensions.c b/contrib/libs/openssl/ssl/statem/extensions.c
index 0f39275baa..cc9233b772 100644
--- a/contrib/libs/openssl/ssl/statem/extensions.c
+++ b/contrib/libs/openssl/ssl/statem/extensions.c
@@ -58,6 +58,11 @@ static int final_early_data(SSL *s, unsigned int context, int sent);
static int final_maxfragmentlen(SSL *s, unsigned int context, int sent);
static int init_post_handshake_auth(SSL *s, unsigned int context);
static int final_psk(SSL *s, unsigned int context, int sent);
+#ifndef OPENSSL_NO_QUIC
+static int init_quic_transport_params(SSL *s, unsigned int context);
+static int final_quic_transport_params_draft(SSL *s, unsigned int context, int sent);
+static int final_quic_transport_params(SSL *s, unsigned int context, int sent);
+#endif
/* Structure to define a built-in extension */
typedef struct extensions_definition_st {
@@ -377,6 +382,29 @@ static const EXTENSION_DEFINITION ext_defs[] = {
tls_construct_certificate_authorities,
tls_construct_certificate_authorities, NULL,
},
+#ifndef OPENSSL_NO_QUIC
+ {
+ TLSEXT_TYPE_quic_transport_parameters_draft,
+ SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS
+ | SSL_EXT_TLS_IMPLEMENTATION_ONLY | SSL_EXT_TLS1_3_ONLY,
+ init_quic_transport_params,
+ tls_parse_ctos_quic_transport_params_draft, tls_parse_stoc_quic_transport_params_draft,
+ tls_construct_stoc_quic_transport_params_draft, tls_construct_ctos_quic_transport_params_draft,
+ final_quic_transport_params_draft,
+ },
+ {
+ TLSEXT_TYPE_quic_transport_parameters,
+ SSL_EXT_CLIENT_HELLO | SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS
+ | SSL_EXT_TLS_IMPLEMENTATION_ONLY | SSL_EXT_TLS1_3_ONLY,
+ init_quic_transport_params,
+ tls_parse_ctos_quic_transport_params, tls_parse_stoc_quic_transport_params,
+ tls_construct_stoc_quic_transport_params, tls_construct_ctos_quic_transport_params,
+ final_quic_transport_params,
+ },
+#else
+ INVALID_EXTENSION,
+ INVALID_EXTENSION,
+#endif
{
/* Must be immediately before pre_shared_key */
TLSEXT_TYPE_padding,
@@ -1745,3 +1773,45 @@ static int final_psk(SSL *s, unsigned int context, int sent)
return 1;
}
+
+#ifndef OPENSSL_NO_QUIC
+static int init_quic_transport_params(SSL *s, unsigned int context)
+{
+ return 1;
+}
+
+static int final_quic_transport_params_draft(SSL *s, unsigned int context,
+ int sent)
+{
+ return 1;
+}
+
+static int final_quic_transport_params(SSL *s, unsigned int context, int sent)
+{
+ /* called after final_quic_transport_params_draft */
+ if (SSL_IS_QUIC(s)) {
+ if (s->ext.peer_quic_transport_params_len == 0
+ && s->ext.peer_quic_transport_params_draft_len == 0) {
+ SSLfatal(s, SSL_AD_MISSING_EXTENSION,
+ SSL_F_FINAL_QUIC_TRANSPORT_PARAMS,
+ SSL_R_MISSING_QUIC_TRANSPORT_PARAMETERS_EXTENSION);
+ return 0;
+ }
+ /* if we got both, discard the one we can't use */
+ if (s->ext.peer_quic_transport_params_len != 0
+ && s->ext.peer_quic_transport_params_draft_len != 0) {
+ if (s->quic_transport_version == TLSEXT_TYPE_quic_transport_parameters_draft) {
+ OPENSSL_free(s->ext.peer_quic_transport_params);
+ s->ext.peer_quic_transport_params = NULL;
+ s->ext.peer_quic_transport_params_len = 0;
+ } else {
+ OPENSSL_free(s->ext.peer_quic_transport_params_draft);
+ s->ext.peer_quic_transport_params_draft = NULL;
+ s->ext.peer_quic_transport_params_draft_len = 0;
+ }
+ }
+ }
+
+ return 1;
+}
+#endif
diff --git a/contrib/libs/openssl/ssl/statem/extensions_clnt.c b/contrib/libs/openssl/ssl/statem/extensions_clnt.c
index 1cbaefa9f1..8f485b46dc 100644
--- a/contrib/libs/openssl/ssl/statem/extensions_clnt.c
+++ b/contrib/libs/openssl/ssl/statem/extensions_clnt.c
@@ -1228,7 +1228,49 @@ EXT_RETURN tls_construct_ctos_post_handshake_auth(SSL *s, WPACKET *pkt,
#endif
}
+#ifndef OPENSSL_NO_QUIC
+EXT_RETURN tls_construct_ctos_quic_transport_params_draft(SSL *s, WPACKET *pkt,
+ unsigned int context, X509 *x,
+ size_t chainidx)
+{
+ if (s->quic_transport_version == TLSEXT_TYPE_quic_transport_parameters
+ || s->ext.quic_transport_params == NULL
+ || s->ext.quic_transport_params_len == 0) {
+ return EXT_RETURN_NOT_SENT;
+ }
+
+ if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_quic_transport_parameters_draft)
+ || !WPACKET_sub_memcpy_u16(pkt, s->ext.quic_transport_params,
+ s->ext.quic_transport_params_len)) {
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+ SSL_F_TLS_CONSTRUCT_CTOS_QUIC_TRANSPORT_PARAMS_DRAFT, ERR_R_INTERNAL_ERROR);
+ return EXT_RETURN_FAIL;
+ }
+
+ return EXT_RETURN_SENT;
+}
+
+EXT_RETURN tls_construct_ctos_quic_transport_params(SSL *s, WPACKET *pkt,
+ unsigned int context, X509 *x,
+ size_t chainidx)
+{
+ if (s->quic_transport_version == TLSEXT_TYPE_quic_transport_parameters_draft
+ || s->ext.quic_transport_params == NULL
+ || s->ext.quic_transport_params_len == 0) {
+ return EXT_RETURN_NOT_SENT;
+ }
+
+ if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_quic_transport_parameters)
+ || !WPACKET_sub_memcpy_u16(pkt, s->ext.quic_transport_params,
+ s->ext.quic_transport_params_len)) {
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+ SSL_F_TLS_CONSTRUCT_CTOS_QUIC_TRANSPORT_PARAMS, ERR_R_INTERNAL_ERROR);
+ return EXT_RETURN_FAIL;
+ }
+ return EXT_RETURN_SENT;
+}
+#endif
/*
* Parse the server's renegotiation binding and abort if it's not right
*/
@@ -1938,6 +1980,18 @@ int tls_parse_stoc_early_data(SSL *s, PACKET *pkt, unsigned int context,
return 0;
}
+#ifndef OPENSSL_NO_QUIC
+ /*
+ * QUIC server must send 0xFFFFFFFF or it's a PROTOCOL_VIOLATION
+ * per draft-ietf-quic-tls-27 S4.5
+ */
+ if (SSL_IS_QUIC(s) && max_early_data != 0xFFFFFFFF) {
+ SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_TLS_PARSE_STOC_EARLY_DATA,
+ SSL_R_INVALID_MAX_EARLY_DATA);
+ return 0;
+ }
+#endif
+
s->session->ext.max_early_data = max_early_data;
return 1;
@@ -2025,3 +2079,40 @@ int tls_parse_stoc_psk(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
return 1;
}
+#ifndef OPENSSL_NO_QUIC
+int tls_parse_stoc_quic_transport_params_draft(SSL *s, PACKET *pkt,
+ unsigned int context, X509 *x,
+ size_t chainidx)
+{
+ OPENSSL_free(s->ext.peer_quic_transport_params_draft);
+ s->ext.peer_quic_transport_params_draft = NULL;
+ s->ext.peer_quic_transport_params_draft_len = 0;
+
+ if (!PACKET_memdup(pkt,
+ &s->ext.peer_quic_transport_params_draft,
+ &s->ext.peer_quic_transport_params_draft_len)) {
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+ SSL_F_TLS_PARSE_STOC_QUIC_TRANSPORT_PARAMS_DRAFT, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+ return 1;
+}
+
+int tls_parse_stoc_quic_transport_params(SSL *s, PACKET *pkt, unsigned int context,
+ X509 *x, size_t chainidx)
+{
+ OPENSSL_free(s->ext.peer_quic_transport_params);
+ s->ext.peer_quic_transport_params = NULL;
+ s->ext.peer_quic_transport_params_len = 0;
+
+ if (!PACKET_memdup(pkt,
+ &s->ext.peer_quic_transport_params,
+ &s->ext.peer_quic_transport_params_len)) {
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+ SSL_F_TLS_PARSE_STOC_QUIC_TRANSPORT_PARAMS,
+ ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+ return 1;
+}
+#endif
diff --git a/contrib/libs/openssl/ssl/statem/extensions_srvr.c b/contrib/libs/openssl/ssl/statem/extensions_srvr.c
index 47541101db..52800902e7 100644
--- a/contrib/libs/openssl/ssl/statem/extensions_srvr.c
+++ b/contrib/libs/openssl/ssl/statem/extensions_srvr.c
@@ -1302,6 +1302,43 @@ int tls_parse_ctos_post_handshake_auth(SSL *s, PACKET *pkt, unsigned int context
return 1;
}
+#ifndef OPENSSL_NO_QUIC
+int tls_parse_ctos_quic_transport_params_draft(SSL *s, PACKET *pkt, unsigned int context,
+ X509 *x, size_t chainidx)
+{
+ OPENSSL_free(s->ext.peer_quic_transport_params_draft);
+ s->ext.peer_quic_transport_params_draft = NULL;
+ s->ext.peer_quic_transport_params_draft_len = 0;
+
+ if (!PACKET_memdup(pkt,
+ &s->ext.peer_quic_transport_params_draft,
+ &s->ext.peer_quic_transport_params_draft_len)) {
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+ SSL_F_TLS_PARSE_CTOS_QUIC_TRANSPORT_PARAMS_DRAFT, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+ return 1;
+}
+
+int tls_parse_ctos_quic_transport_params(SSL *s, PACKET *pkt, unsigned int context,
+ X509 *x, size_t chainidx)
+{
+ OPENSSL_free(s->ext.peer_quic_transport_params);
+ s->ext.peer_quic_transport_params = NULL;
+ s->ext.peer_quic_transport_params_len = 0;
+
+ if (!PACKET_memdup(pkt,
+ &s->ext.peer_quic_transport_params,
+ &s->ext.peer_quic_transport_params_len)) {
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+ SSL_F_TLS_PARSE_CTOS_QUIC_TRANSPORT_PARAMS,
+ ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+ return 1;
+}
+#endif
+
/*
* Add the server's renegotiation binding
*/
@@ -1932,12 +1969,20 @@ EXT_RETURN tls_construct_stoc_early_data(SSL *s, WPACKET *pkt,
size_t chainidx)
{
if (context == SSL_EXT_TLS1_3_NEW_SESSION_TICKET) {
+ uint32_t max_early_data = s->max_early_data;
+
if (s->max_early_data == 0)
return EXT_RETURN_NOT_SENT;
+#ifndef OPENSSL_NO_QUIC
+ /* QUIC server must always send 0xFFFFFFFF, per draft-ietf-quic-tls-27 S4.5 */
+ if (SSL_IS_QUIC(s))
+ max_early_data = 0xFFFFFFFF;
+#endif
+
if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_early_data)
|| !WPACKET_start_sub_packet_u16(pkt)
- || !WPACKET_put_bytes_u32(pkt, s->max_early_data)
+ || !WPACKET_put_bytes_u32(pkt, max_early_data)
|| !WPACKET_close(pkt)) {
SSLfatal(s, SSL_AD_INTERNAL_ERROR,
SSL_F_TLS_CONSTRUCT_STOC_EARLY_DATA, ERR_R_INTERNAL_ERROR);
@@ -1978,3 +2023,51 @@ EXT_RETURN tls_construct_stoc_psk(SSL *s, WPACKET *pkt, unsigned int context,
return EXT_RETURN_SENT;
}
+
+#ifndef OPENSSL_NO_QUIC
+EXT_RETURN tls_construct_stoc_quic_transport_params_draft(SSL *s, WPACKET *pkt,
+ unsigned int context,
+ X509 *x,
+ size_t chainidx)
+{
+ if (s->quic_transport_version == TLSEXT_TYPE_quic_transport_parameters
+ || s->ext.peer_quic_transport_params_draft_len == 0
+ || s->ext.quic_transport_params == NULL
+ || s->ext.quic_transport_params_len == 0) {
+ return EXT_RETURN_NOT_SENT;
+ }
+
+ if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_quic_transport_parameters_draft)
+ || !WPACKET_sub_memcpy_u16(pkt, s->ext.quic_transport_params,
+ s->ext.quic_transport_params_len)) {
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+ SSL_F_TLS_CONSTRUCT_STOC_QUIC_TRANSPORT_PARAMS_DRAFT, ERR_R_INTERNAL_ERROR);
+ return EXT_RETURN_FAIL;
+ }
+
+ return EXT_RETURN_SENT;
+}
+
+EXT_RETURN tls_construct_stoc_quic_transport_params(SSL *s, WPACKET *pkt,
+ unsigned int context, X509 *x,
+ size_t chainidx)
+{
+ if (s->quic_transport_version == TLSEXT_TYPE_quic_transport_parameters_draft
+ || s->ext.peer_quic_transport_params_len == 0
+ || s->ext.quic_transport_params == NULL
+ || s->ext.quic_transport_params_len == 0) {
+ return EXT_RETURN_NOT_SENT;
+ }
+
+ if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_quic_transport_parameters)
+ || !WPACKET_sub_memcpy_u16(pkt, s->ext.quic_transport_params,
+ s->ext.quic_transport_params_len)) {
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+ SSL_F_TLS_CONSTRUCT_STOC_QUIC_TRANSPORT_PARAMS,
+ ERR_R_INTERNAL_ERROR);
+ return EXT_RETURN_FAIL;
+ }
+
+ return EXT_RETURN_SENT;
+}
+#endif
diff --git a/contrib/libs/openssl/ssl/statem/statem.c b/contrib/libs/openssl/ssl/statem/statem.c
index 20f5bd584e..d984fba93e 100644
--- a/contrib/libs/openssl/ssl/statem/statem.c
+++ b/contrib/libs/openssl/ssl/statem/statem.c
@@ -319,8 +319,13 @@ static int state_machine(SSL *s, int server)
* If we are stateless then we already called SSL_clear() - don't do
* it again and clear the STATELESS flag itself.
*/
+#ifndef OPENSSL_NO_QUIC
+ if ((s->s3->flags & TLS1_FLAGS_STATELESS) == 0 && !SSL_clear_not_quic(s))
+ return -1;
+#else
if ((s->s3->flags & TLS1_FLAGS_STATELESS) == 0 && !SSL_clear(s))
return -1;
+#endif
}
#ifndef OPENSSL_NO_SCTP
if (SSL_IS_DTLS(s) && BIO_dgram_is_sctp(SSL_get_wbio(s))) {
@@ -575,6 +580,11 @@ static SUB_STATE_RETURN read_state_machine(SSL *s)
* In DTLS we get the whole message in one go - header and body
*/
ret = dtls_get_message(s, &mt, &len);
+#ifndef OPENSSL_NO_QUIC
+ } else if (SSL_IS_QUIC(s)) {
+ /* QUIC behaves like DTLS -- all in one go. */
+ ret = quic_get_message(s, &mt, &len);
+#endif
} else {
ret = tls_get_message_header(s, &mt);
}
@@ -604,8 +614,8 @@ static SUB_STATE_RETURN read_state_machine(SSL *s)
return SUB_STATE_ERROR;
}
- /* dtls_get_message already did this */
- if (!SSL_IS_DTLS(s)
+ /* dtls_get_message/quic_get_message already did this */
+ if (!SSL_IS_DTLS(s) && !SSL_IS_QUIC(s)
&& s->s3->tmp.message_size > 0
&& !grow_init_buf(s, s->s3->tmp.message_size
+ SSL3_HM_HEADER_LENGTH)) {
@@ -618,8 +628,8 @@ static SUB_STATE_RETURN read_state_machine(SSL *s)
/* Fall through */
case READ_STATE_BODY:
- if (!SSL_IS_DTLS(s)) {
- /* We already got this above for DTLS */
+ if (!SSL_IS_DTLS(s) && !SSL_IS_QUIC(s)) {
+ /* We already got this above for DTLS & QUIC */
ret = tls_get_message_body(s, &len);
if (ret == 0) {
/* Could be non-blocking IO */
@@ -900,6 +910,14 @@ static SUB_STATE_RETURN write_state_machine(SSL *s)
int statem_flush(SSL *s)
{
s->rwstate = SSL_WRITING;
+#ifndef OPENSSL_NO_QUIC
+ if (SSL_IS_QUIC(s)) {
+ if (!s->quic_method->flush_flight(s)) {
+ SSLerr(SSL_F_STATEM_FLUSH, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+ } else
+#endif
if (BIO_flush(s->wbio) <= 0) {
return 0;
}
diff --git a/contrib/libs/openssl/ssl/statem/statem_clnt.c b/contrib/libs/openssl/ssl/statem/statem_clnt.c
index d19c44e8d9..c8b9097180 100644
--- a/contrib/libs/openssl/ssl/statem/statem_clnt.c
+++ b/contrib/libs/openssl/ssl/statem/statem_clnt.c
@@ -909,6 +909,14 @@ int ossl_statem_client_construct_message(SSL *s, WPACKET *pkt,
break;
case TLS_ST_CW_END_OF_EARLY_DATA:
+#ifndef OPENSSL_NO_QUIC
+ /* QUIC does not send EndOfEarlyData, draft-ietf-quic-tls-24 S8.3 */
+ if (SSL_IS_QUIC(s)) {
+ *confunc = NULL;
+ *mt = SSL3_MT_DUMMY;
+ break;
+ }
+#endif
*confunc = tls_construct_end_of_early_data;
*mt = SSL3_MT_END_OF_EARLY_DATA;
break;
diff --git a/contrib/libs/openssl/ssl/statem/statem_lib.c b/contrib/libs/openssl/ssl/statem/statem_lib.c
index 695caab3d6..54aa39ec3c 100644
--- a/contrib/libs/openssl/ssl/statem/statem_lib.c
+++ b/contrib/libs/openssl/ssl/statem/statem_lib.c
@@ -43,8 +43,28 @@ int ssl3_do_write(SSL *s, int type)
int ret;
size_t written = 0;
- ret = ssl3_write_bytes(s, type, &s->init_buf->data[s->init_off],
- s->init_num, &written);
+#ifndef OPENSSL_NO_QUIC
+ if (SSL_IS_QUIC(s)) {
+ if (type == SSL3_RT_HANDSHAKE) {
+ ret = s->quic_method->add_handshake_data(s, s->quic_write_level,
+ (const uint8_t*)&s->init_buf->data[s->init_off],
+ s->init_num);
+ if (!ret) {
+ ret = -1;
+ /* QUIC can't sent anything out sice the above failed */
+ SSLerr(SSL_F_SSL3_DO_WRITE, ERR_R_INTERNAL_ERROR);
+ } else {
+ written = s->init_num;
+ }
+ } else {
+ /* QUIC doesn't use ChangeCipherSpec */
+ ret = -1;
+ SSLerr(SSL_F_SSL3_DO_WRITE, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
+ }
+ } else
+#endif
+ ret = ssl3_write_bytes(s, type, &s->init_buf->data[s->init_off],
+ s->init_num, &written);
if (ret < 0)
return -1;
if (type == SSL3_RT_HANDSHAKE)
@@ -610,6 +630,14 @@ int tls_construct_finished(SSL *s, WPACKET *pkt)
int tls_construct_key_update(SSL *s, WPACKET *pkt)
{
+#ifndef OPENSSL_NO_QUIC
+ if (SSL_is_quic(s)) {
+ /* TLS KeyUpdate is not used for QUIC, so this is an error. */
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_KEY_UPDATE,
+ ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+#endif
if (!WPACKET_put_bytes_u8(pkt, s->key_update)) {
SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_KEY_UPDATE,
ERR_R_INTERNAL_ERROR);
@@ -634,6 +662,14 @@ MSG_PROCESS_RETURN tls_process_key_update(SSL *s, PACKET *pkt)
return MSG_PROCESS_ERROR;
}
+#ifndef OPENSSL_NO_QUIC
+ if (SSL_is_quic(s)) {
+ SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_F_TLS_PROCESS_KEY_UPDATE,
+ SSL_R_UNEXPECTED_MESSAGE);
+ return MSG_PROCESS_ERROR;
+ }
+#endif
+
if (!PACKET_get_1(pkt, &updatetype)
|| PACKET_remaining(pkt) != 0) {
SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PROCESS_KEY_UPDATE,
diff --git a/contrib/libs/openssl/ssl/statem/statem_local.h b/contrib/libs/openssl/ssl/statem/statem_local.h
index eae88053dc..7bf905f3df 100644
--- a/contrib/libs/openssl/ssl/statem/statem_local.h
+++ b/contrib/libs/openssl/ssl/statem/statem_local.h
@@ -95,6 +95,9 @@ WORK_STATE ossl_statem_server_post_process_message(SSL *s, WORK_STATE wst);
__owur int tls_get_message_header(SSL *s, int *mt);
__owur int tls_get_message_body(SSL *s, size_t *len);
__owur int dtls_get_message(SSL *s, int *mt, size_t *len);
+#ifndef OPENSSL_NO_QUIC
+__owur int quic_get_message(SSL *s, int *mt, size_t *len);
+#endif
/* Message construction and processing functions */
__owur int tls_process_initial_server_flight(SSL *s);
@@ -238,6 +241,14 @@ int tls_parse_ctos_psk(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
size_t chainidx);
int tls_parse_ctos_post_handshake_auth(SSL *, PACKET *pkt, unsigned int context,
X509 *x, size_t chainidx);
+#ifndef OPENSSL_NO_QUIC
+int tls_parse_ctos_quic_transport_params_draft(SSL *s, PACKET *pkt,
+ unsigned int context, X509 *x,
+ size_t chainidx);
+
+int tls_parse_ctos_quic_transport_params(SSL *s, PACKET *pkt, unsigned int context,
+ X509 *x, size_t chainidx);
+#endif
EXT_RETURN tls_construct_stoc_renegotiate(SSL *s, WPACKET *pkt,
unsigned int context, X509 *x,
@@ -300,6 +311,16 @@ EXT_RETURN tls_construct_stoc_cryptopro_bug(SSL *s, WPACKET *pkt,
size_t chainidx);
EXT_RETURN tls_construct_stoc_psk(SSL *s, WPACKET *pkt, unsigned int context,
X509 *x, size_t chainidx);
+#ifndef OPENSSL_NO_QUIC
+EXT_RETURN tls_construct_stoc_quic_transport_params_draft(SSL *s, WPACKET *pkt,
+ unsigned int context,
+ X509 *x,
+ size_t chainidx);
+
+EXT_RETURN tls_construct_stoc_quic_transport_params(SSL *s, WPACKET *pkt,
+ unsigned int context, X509 *x,
+ size_t chainidx);
+#endif
/* Client Extension processing */
EXT_RETURN tls_construct_ctos_renegotiate(SSL *s, WPACKET *pkt, unsigned int context,
@@ -370,6 +391,15 @@ EXT_RETURN tls_construct_ctos_psk(SSL *s, WPACKET *pkt, unsigned int context,
X509 *x, size_t chainidx);
EXT_RETURN tls_construct_ctos_post_handshake_auth(SSL *s, WPACKET *pkt, unsigned int context,
X509 *x, size_t chainidx);
+#ifndef OPENSSL_NO_QUIC
+EXT_RETURN tls_construct_ctos_quic_transport_params_draft(SSL *s, WPACKET *pkt,
+ unsigned int context, X509 *x,
+ size_t chainidx);
+
+EXT_RETURN tls_construct_ctos_quic_transport_params(SSL *s, WPACKET *pkt,
+ unsigned int context, X509 *x,
+ size_t chainidx);
+#endif
int tls_parse_stoc_renegotiate(SSL *s, PACKET *pkt, unsigned int context,
X509 *x, size_t chainidx);
@@ -415,6 +445,14 @@ int tls_parse_stoc_cookie(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
size_t chainidx);
int tls_parse_stoc_psk(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
size_t chainidx);
+#ifndef OPENSSL_NO_QUIC
+int tls_parse_stoc_quic_transport_params_draft(SSL *s, PACKET *pkt,
+ unsigned int context, X509 *x,
+ size_t chainidx);
+
+int tls_parse_stoc_quic_transport_params(SSL *s, PACKET *pkt, unsigned int context,
+ X509 *x, size_t chainidx);
+#endif
int tls_handle_alpn(SSL *s);
diff --git a/contrib/libs/openssl/ssl/statem/statem_quic.c b/contrib/libs/openssl/ssl/statem/statem_quic.c
new file mode 100644
index 0000000000..2843938ce2
--- /dev/null
+++ b/contrib/libs/openssl/ssl/statem/statem_quic.c
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License"). You may not use
+ * this file except in compliance with the License. You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include "../ssl_local.h"
+#include "statem_local.h"
+#include "internal/cryptlib.h"
+
+int quic_get_message(SSL *s, int *mt, size_t *len)
+{
+ size_t l;
+ QUIC_DATA *qd = s->quic_input_data_head;
+ uint8_t *p;
+
+ if (qd == NULL) {
+ s->rwstate = SSL_READING;
+ *mt = *len = 0;
+ return 0;
+ }
+
+ if (!ossl_assert(qd->length >= SSL3_HM_HEADER_LENGTH)) {
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_QUIC_GET_MESSAGE,
+ SSL_R_BAD_LENGTH);
+ *mt = *len = 0;
+ return 0;
+ }
+
+ /* This is where we check for the proper level, not when data is given */
+ if (qd->level != s->quic_read_level) {
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_QUIC_GET_MESSAGE,
+ SSL_R_WRONG_ENCRYPTION_LEVEL_RECEIVED);
+ *mt = *len = 0;
+ return 0;
+ }
+
+ if (!BUF_MEM_grow_clean(s->init_buf, (int)qd->length)) {
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_QUIC_GET_MESSAGE,
+ ERR_R_BUF_LIB);
+ *mt = *len = 0;
+ return 0;
+ }
+
+ /* Copy buffered data */
+ memcpy(s->init_buf->data, s->quic_buf->data + qd->start, qd->length);
+ s->init_buf->length = qd->length;
+ s->quic_input_data_head = qd->next;
+ if (s->quic_input_data_head == NULL)
+ s->quic_input_data_tail = NULL;
+ OPENSSL_free(qd);
+
+ s->s3->tmp.message_type = *mt = *(s->init_buf->data);
+ p = (uint8_t*)s->init_buf->data + 1;
+ n2l3(p, l);
+ s->init_num = s->s3->tmp.message_size = *len = l;
+ s->init_msg = s->init_buf->data + SSL3_HM_HEADER_LENGTH;
+
+ /* No CCS in QUIC/TLSv1.3? */
+ if (*mt == SSL3_MT_CHANGE_CIPHER_SPEC) {
+ SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE,
+ SSL_F_QUIC_GET_MESSAGE,
+ SSL_R_CCS_RECEIVED_EARLY);
+ *len = 0;
+ return 0;
+ }
+ /* No KeyUpdate in QUIC */
+ if (*mt == SSL3_MT_KEY_UPDATE) {
+ SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_F_QUIC_GET_MESSAGE,
+ SSL_R_UNEXPECTED_MESSAGE);
+ *len = 0;
+ return 0;
+ }
+
+
+ /*
+ * If receiving Finished, record MAC of prior handshake messages for
+ * Finished verification.
+ */
+ if (*mt == SSL3_MT_FINISHED && !ssl3_take_mac(s)) {
+ /* SSLfatal() already called */
+ *len = 0;
+ return 0;
+ }
+
+ /*
+ * We defer feeding in the HRR until later. We'll do it as part of
+ * processing the message
+ * The TLsv1.3 handshake transcript stops at the ClientFinished
+ * message.
+ */
+#define SERVER_HELLO_RANDOM_OFFSET (SSL3_HM_HEADER_LENGTH + 2)
+ /* KeyUpdate and NewSessionTicket do not need to be added */
+ if (s->s3->tmp.message_type != SSL3_MT_NEWSESSION_TICKET
+ && s->s3->tmp.message_type != SSL3_MT_KEY_UPDATE) {
+ if (s->s3->tmp.message_type != SSL3_MT_SERVER_HELLO
+ || s->init_num < SERVER_HELLO_RANDOM_OFFSET + SSL3_RANDOM_SIZE
+ || memcmp(hrrrandom,
+ s->init_buf->data + SERVER_HELLO_RANDOM_OFFSET,
+ SSL3_RANDOM_SIZE) != 0) {
+ if (!ssl3_finish_mac(s, (unsigned char *)s->init_buf->data,
+ s->init_num + SSL3_HM_HEADER_LENGTH)) {
+ /* SSLfatal() already called */
+ *len = 0;
+ return 0;
+ }
+ }
+ }
+ if (s->msg_callback)
+ s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE, s->init_buf->data,
+ (size_t)s->init_num + SSL3_HM_HEADER_LENGTH, s,
+ s->msg_callback_arg);
+
+ return 1;
+}
diff --git a/contrib/libs/openssl/ssl/statem/statem_srvr.c b/contrib/libs/openssl/ssl/statem/statem_srvr.c
index 43f77a5899..a6980c32a8 100644
--- a/contrib/libs/openssl/ssl/statem/statem_srvr.c
+++ b/contrib/libs/openssl/ssl/statem/statem_srvr.c
@@ -72,7 +72,8 @@ static int ossl_statem_server13_read_transition(SSL *s, int mt)
return 1;
}
break;
- } else if (s->ext.early_data == SSL_EARLY_DATA_ACCEPTED) {
+ } else if (s->ext.early_data == SSL_EARLY_DATA_ACCEPTED
+ && !SSL_IS_QUIC(s)) {
if (mt == SSL3_MT_END_OF_EARLY_DATA) {
st->hand_state = TLS_ST_SR_END_OF_EARLY_DATA;
return 1;
@@ -436,6 +437,10 @@ static WRITE_TRAN ossl_statem_server13_write_transition(SSL *s)
st->hand_state = TLS_ST_SW_CERT_REQ;
return WRITE_TRAN_CONTINUE;
}
+ if (s->ext.extra_tickets_expected > 0) {
+ st->hand_state = TLS_ST_SW_SESSION_TICKET;
+ return WRITE_TRAN_CONTINUE;
+ }
/* Try to read from the client instead */
return WRITE_TRAN_FINISHED;
@@ -526,7 +531,9 @@ static WRITE_TRAN ossl_statem_server13_write_transition(SSL *s)
* Following an initial handshake we send the number of tickets we have
* been configured for.
*/
- if (s->hit || s->num_tickets <= s->sent_tickets) {
+ if (!SSL_IS_FIRST_HANDSHAKE(s) && s->ext.extra_tickets_expected > 0) {
+ return WRITE_TRAN_CONTINUE;
+ } else if (s->hit || s->num_tickets <= s->sent_tickets) {
/* We've written enough tickets out. */
st->hand_state = TLS_ST_OK;
}
@@ -722,7 +729,8 @@ WORK_STATE ossl_statem_server_pre_work(SSL *s, WORK_STATE wst)
return WORK_FINISHED_CONTINUE;
case TLS_ST_SW_SESSION_TICKET:
- if (SSL_IS_TLS13(s) && s->sent_tickets == 0) {
+ if (SSL_IS_TLS13(s) && s->sent_tickets == 0
+ && s->ext.extra_tickets_expected == 0) {
/*
* Actually this is the end of the handshake, but we're going
* straight into writing the session ticket out. So we finish off
@@ -964,6 +972,16 @@ WORK_STATE ossl_statem_server_post_work(SSL *s, WORK_STATE wst)
SSL3_CC_APPLICATION | SSL3_CHANGE_CIPHER_SERVER_WRITE))
/* SSLfatal() already called */
return WORK_ERROR;
+
+#ifndef OPENSSL_NO_QUIC
+ if (SSL_IS_QUIC(s) && s->ext.early_data == SSL_EARLY_DATA_ACCEPTED) {
+ s->early_data_state = SSL_EARLY_DATA_FINISHED_READING;
+ if (!s->method->ssl3_enc->change_cipher_state(
+ s, SSL3_CC_HANDSHAKE | SSL3_CHANGE_CIPHER_SERVER_READ))
+ /* SSLfatal() already called */
+ return WORK_ERROR;
+ }
+#endif
}
break;
@@ -1578,6 +1596,16 @@ MSG_PROCESS_RETURN tls_process_client_hello(SSL *s, PACKET *pkt)
goto err;
}
}
+#ifndef OPENSSL_NO_QUIC
+ if (SSL_IS_QUIC(s)) {
+ /* Any other QUIC checks on ClientHello here */
+ if (clienthello->session_id_len > 0) {
+ SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_TLS_PROCESS_CLIENT_HELLO,
+ SSL_R_LENGTH_MISMATCH);
+ goto err;
+ }
+ }
+#endif
}
if (!PACKET_copy_all(&compression, clienthello->compressions,
@@ -4183,10 +4211,13 @@ int tls_construct_new_session_ticket(SSL *s, WPACKET *pkt)
/*
* Increment both |sent_tickets| and |next_ticket_nonce|. |sent_tickets|
* gets reset to 0 if we send more tickets following a post-handshake
- * auth, but |next_ticket_nonce| does not.
+ * auth, but |next_ticket_nonce| does not. If we're sending extra
+ * tickets, decrement the count of pending extra tickets.
*/
s->sent_tickets++;
s->next_ticket_nonce++;
+ if (s->ext.extra_tickets_expected > 0)
+ s->ext.extra_tickets_expected--;
ssl_update_cache(s, SSL_SESS_CACHE_SERVER);
}
diff --git a/contrib/libs/openssl/ssl/tls13_enc.c b/contrib/libs/openssl/ssl/tls13_enc.c
index ff85df4483..af48d83718 100644
--- a/contrib/libs/openssl/ssl/tls13_enc.c
+++ b/contrib/libs/openssl/ssl/tls13_enc.c
@@ -435,8 +435,6 @@ static int derive_secret_key_and_iv(SSL *s, int sending, const EVP_MD *md,
return 0;
}
-int tls13_change_cipher_state(SSL *s, int which)
-{
#ifdef CHARSET_EBCDIC
static const unsigned char client_early_traffic[] = {0x63, 0x20, 0x65, 0x20, /*traffic*/0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x00};
static const unsigned char client_handshake_traffic[] = {0x63, 0x20, 0x68, 0x73, 0x20, /*traffic*/0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x00};
@@ -456,6 +454,217 @@ int tls13_change_cipher_state(SSL *s, int which)
static const unsigned char resumption_master_secret[] = "res master";
static const unsigned char early_exporter_master_secret[] = "e exp master";
#endif
+
+#ifndef OPENSSL_NO_QUIC
+static int quic_change_cipher_state(SSL *s, int which)
+{
+ unsigned char hash[EVP_MAX_MD_SIZE];
+ size_t hashlen = 0;
+ int hashleni;
+ int ret = 0;
+ const EVP_MD *md = NULL;
+ OSSL_ENCRYPTION_LEVEL level;
+ int is_handshake = ((which & SSL3_CC_HANDSHAKE) == SSL3_CC_HANDSHAKE);
+ int is_client_read = ((which & SSL3_CHANGE_CIPHER_CLIENT_READ) == SSL3_CHANGE_CIPHER_CLIENT_READ);
+ int is_server_write = ((which & SSL3_CHANGE_CIPHER_SERVER_WRITE) == SSL3_CHANGE_CIPHER_SERVER_WRITE);
+ int is_early = (which & SSL3_CC_EARLY);
+
+ if (is_early) {
+ EVP_MD_CTX *mdctx = NULL;
+ long handlen;
+ void *hdata;
+ unsigned int hashlenui;
+ const SSL_CIPHER *sslcipher = SSL_SESSION_get0_cipher(s->session);
+
+ handlen = BIO_get_mem_data(s->s3->handshake_buffer, &hdata);
+ if (handlen <= 0) {
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_QUIC_CHANGE_CIPHER_STATE,
+ SSL_R_BAD_HANDSHAKE_LENGTH);
+ goto err;
+ }
+
+ if (s->early_data_state == SSL_EARLY_DATA_CONNECTING
+ && s->max_early_data > 0 && s->session->ext.max_early_data == 0) {
+ /*
+ * If we are attempting to send early data, and we've decided to
+ * actually do it but max_early_data in s->session is 0 then we
+ * must be using an external PSK.
+ */
+ if (!ossl_assert(s->psksession != NULL
+ && s->max_early_data
+ == s->psksession->ext.max_early_data)) {
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+ SSL_F_QUIC_CHANGE_CIPHER_STATE, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+ sslcipher = SSL_SESSION_get0_cipher(s->psksession);
+ }
+ if (sslcipher == NULL) {
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_QUIC_CHANGE_CIPHER_STATE,
+ SSL_R_BAD_PSK);
+ goto err;
+ }
+
+ /*
+ * We need to calculate the handshake digest using the digest from
+ * the session. We haven't yet selected our ciphersuite so we can't
+ * use ssl_handshake_md().
+ */
+ mdctx = EVP_MD_CTX_new();
+ if (mdctx == NULL) {
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_QUIC_CHANGE_CIPHER_STATE,
+ ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ md = ssl_md(sslcipher->algorithm2);
+ if (md == NULL || !EVP_DigestInit_ex(mdctx, md, NULL)
+ || !EVP_DigestUpdate(mdctx, hdata, handlen)
+ || !EVP_DigestFinal_ex(mdctx, hash, &hashlenui)) {
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_QUIC_CHANGE_CIPHER_STATE,
+ ERR_R_INTERNAL_ERROR);
+ EVP_MD_CTX_free(mdctx);
+ goto err;
+ }
+ hashlen = hashlenui;
+ EVP_MD_CTX_free(mdctx);
+ } else {
+ md = ssl_handshake_md(s);
+ if (!ssl3_digest_cached_records(s, 1)
+ || !ssl_handshake_hash(s, hash, sizeof(hash), &hashlen)) {
+ /* SSLfatal() already called */;
+ goto err;
+ }
+
+ /* Ensure cast to size_t is safe */
+ hashleni = EVP_MD_size(md);
+ if (!ossl_assert(hashleni >= 0)) {
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_QUIC_CHANGE_CIPHER_STATE,
+ ERR_R_EVP_LIB);
+ goto err;
+ }
+ hashlen = (size_t)hashleni;
+ }
+
+ if (is_client_read || is_server_write) {
+ if (is_handshake) {
+ /*
+ * This looks a bit weird, since the condition is basically "the
+ * server is writing" but we set both the server *and* client
+ * handshake traffic keys here. That's because there's only a fixed
+ * number of change-cipher-state events in the TLS 1.3 handshake,
+ * and in particular there's not an event in between when the server
+ * writes encrypted handshake messages and when the client writes
+ * encrypted handshake messages, so we generate both here.
+ */
+ level = ssl_encryption_handshake;
+
+ if (!tls13_hkdf_expand(s, md, s->handshake_secret,
+ client_handshake_traffic,
+ sizeof(client_handshake_traffic)-1, hash,
+ hashlen, s->client_hand_traffic_secret,
+ hashlen, 1)
+ || !ssl_log_secret(s, CLIENT_HANDSHAKE_LABEL,
+ s->client_hand_traffic_secret, hashlen)
+ || !tls13_derive_finishedkey(s, md,
+ s->client_hand_traffic_secret,
+ s->client_finished_secret, hashlen)
+ || !tls13_hkdf_expand(s, md, s->handshake_secret,
+ server_handshake_traffic,
+ sizeof(server_handshake_traffic)-1, hash,
+ hashlen, s->server_hand_traffic_secret,
+ hashlen, 1)
+ || !ssl_log_secret(s, SERVER_HANDSHAKE_LABEL,
+ s->server_hand_traffic_secret, hashlen)
+ || !tls13_derive_finishedkey(s, md,
+ s->server_hand_traffic_secret,
+ s->server_finished_secret,
+ hashlen)) {
+ /* SSLfatal() already called */
+ goto err;
+ }
+ } else {
+ /*
+ * As above, we generate both sets of application traffic keys at
+ * the same time.
+ */
+ level = ssl_encryption_application;
+
+ if (!tls13_hkdf_expand(s, md, s->master_secret,
+ client_application_traffic,
+ sizeof(client_application_traffic)-1, hash,
+ hashlen, s->client_app_traffic_secret,
+ hashlen, 1)
+ || !ssl_log_secret(s, CLIENT_APPLICATION_LABEL,
+ s->client_app_traffic_secret, hashlen)
+ || !tls13_hkdf_expand(s, md, s->master_secret,
+ server_application_traffic,
+ sizeof(server_application_traffic)-1,
+ hash, hashlen,
+ s->server_app_traffic_secret, hashlen, 1)
+ || !ssl_log_secret(s, SERVER_APPLICATION_LABEL,
+ s->server_app_traffic_secret, hashlen)) {
+ /* SSLfatal() already called */
+ goto err;
+ }
+ }
+ if (!quic_set_encryption_secrets(s, level)) {
+ /* SSLfatal() already called */
+ goto err;
+ }
+ if (s->server)
+ s->quic_write_level = level;
+ else
+ s->quic_read_level = level;
+ } else {
+ /* is_client_write || is_server_read */
+
+ if (is_early) {
+ level = ssl_encryption_early_data;
+
+ if (!tls13_hkdf_expand(s, md, s->early_secret, client_early_traffic,
+ sizeof(client_early_traffic)-1, hash,
+ hashlen, s->client_early_traffic_secret,
+ hashlen, 1)
+ || !ssl_log_secret(s, CLIENT_EARLY_LABEL,
+ s->client_early_traffic_secret, hashlen)
+ || !quic_set_encryption_secrets(s, level)) {
+ /* SSLfatal() already called */
+ goto err;
+ }
+ } else if (is_handshake) {
+ level = ssl_encryption_handshake;
+ } else {
+ level = ssl_encryption_application;
+ /*
+ * We also create the resumption master secret, but this time use the
+ * hash for the whole handshake including the Client Finished
+ */
+ if (!tls13_hkdf_expand(s, md, s->master_secret,
+ resumption_master_secret,
+ sizeof(resumption_master_secret)-1, hash,
+ hashlen, s->resumption_master_secret,
+ hashlen, 1)) {
+ /* SSLfatal() already called */
+ goto err;
+ }
+ }
+
+ if (level != ssl_encryption_early_data) {
+ if (s->server)
+ s->quic_read_level = level;
+ else
+ s->quic_write_level = level;
+ }
+ }
+
+ ret = 1;
+ err:
+ return ret;
+}
+#endif /* OPENSSL_NO_QUIC */
+
+int tls13_change_cipher_state(SSL *s, int which)
+{
unsigned char *iv;
unsigned char secret[EVP_MAX_MD_SIZE];
unsigned char hashval[EVP_MAX_MD_SIZE];
@@ -471,6 +680,11 @@ int tls13_change_cipher_state(SSL *s, int which)
const EVP_MD *md = NULL;
const EVP_CIPHER *cipher = NULL;
+#ifndef OPENSSL_NO_QUIC
+ if (SSL_IS_QUIC(s))
+ return quic_change_cipher_state(s, which);
+#endif
+
if (which & SSL3_CC_READ) {
if (s->enc_read_ctx != NULL) {
EVP_CIPHER_CTX_reset(s->enc_read_ctx);
diff --git a/contrib/libs/openssl/ya.make b/contrib/libs/openssl/ya.make
index 802b2c76c3..c5962936a6 100644
--- a/contrib/libs/openssl/ya.make
+++ b/contrib/libs/openssl/ya.make
@@ -215,6 +215,7 @@ SRCS(
ssl/ssl_sess.c
ssl/ssl_stat.c
ssl/ssl_txt.c
+ ssl/ssl_quic.c
ssl/ssl_utst.c
ssl/statem/extensions.c
ssl/statem/extensions_clnt.c
@@ -224,6 +225,7 @@ SRCS(
ssl/statem/statem_clnt.c
ssl/statem/statem_dtls.c
ssl/statem/statem_lib.c
+ ssl/statem/statem_quic.c
ssl/statem/statem_srvr.c
ssl/t1_enc.c
ssl/t1_lib.c
diff --git a/contrib/libs/pire/ut/approx_matching_ut.cpp b/contrib/libs/pire/ut/approx_matching_ut.cpp
index 3b4cb972f6..3920f6ebce 100644
--- a/contrib/libs/pire/ut/approx_matching_ut.cpp
+++ b/contrib/libs/pire/ut/approx_matching_ut.cpp
@@ -240,7 +240,7 @@ Y_UNIT_TEST_SUITE(ApproxMatchingTest) {
text += ystring(3, letter + 'a');
}
const ystring regexp = "^" + text + "$";
- auto fsm = BuildFsm(regexp.Data());
+ auto fsm = BuildFsm(regexp.data());
APPROXIMATE_SCANNER(fsm, 1) {
ACCEPTS(text);
@@ -349,7 +349,7 @@ Y_UNIT_TEST_SUITE(ApproxMatchingTest) {
text += ystring(1, (letter % 26) + 'a');
}
const ystring regexp = "^" + text + "$";
- auto fsm = BuildFsm(regexp.Data());
+ auto fsm = BuildFsm(regexp.data());
auto changedText = text;
APPROXIMATE_SCANNER(fsm, 1) {